address public owners:
uint public numConfirmationsRequired
event transactionsubmitted
event TransactionConfirmed
event transactionExecuted
constructor
for loop
function submitTransaction
function confirmTransaction
function executeTransaction
function isTransactionConfirmed
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract MultiSig {
address[] public owners; // the people who control this smart contract
uint public numConfirmationsRequired; // how many people voted for this tx
struct Transaction{
address to; // the address of the person we care sending ether to
uint value; // the amount of value we will be sending
bool executed; // whether the transaction is success or not
}
// neseted mapping
mapping(uint=>mapping(address=>bool)) isConfirmed;
Transaction[] public transactions;
event TransactionSubmitted(uint transactionId,address sender, address receiver, uint amount);
event TransactionConfirmed(uint transactionId);
event TransactionExecuted(uint transactionId);
constructor(address[] memory _owners,uint _numConfirmationsRequired){ // the person who sign this tx
require(_owners.length>1, "Owners Required[Must Be Greater than 1"); // owners should be greater than 1 person
require(_numConfirmationsRequired>0 && numConfirmationsRequired<=_owners.length,"Num of confirmation are not in sync with the number of owners"); // make sure the voted person qty is align with
for(uint i=0;i<_owners.length;i++){
require(_owners[i]!=address(0), "Invalid Owner");
owners.push(_owners[i]);
}
numConfirmationsRequired=_numConfirmationsRequired;
}
function submitTransaction(address _to) public payable {
require(_to!=address(0),"Invalid Receiver's Address");
require(msg.value>0,"Transfer Amount Must Be Greater Than 0");
uint transactionId = transactions.length;
transactions.push(Transaction({to:_to,value:msg.value,executed:false}));
emit TransactionSubmitted(transactionId,msg.sender,_to,msg.value);
}
function confirmTransaction(uint _transactionId) public{
require(_transactionId<transactions.length, "Invalid Transaction Id");
require(!isConfirmed[_transactionId][msg.sender], "Transaction Is Already Confirmed By The Owner");
isConfirmed[_transactionId][msg.sender]=true;
emit TransactionConfirmed(_transactionId);
if(isTransactionConfirmed(_transactionId)){
executeTransaction(_transactionId);
}
}
function executeTransaction(uint _transactionId) public payable{
require(_transactionId<transactions.length, "Invalid Transaction Id");
require(!transactions[_transactionId].executed,"Transaction is already executed");
// transaction[_transactionId].executed=true;
(bool success,)=transactions[_transactionId].to.call{value: transactions[_transactionId].value}("")
require(success,"Transaction Execution Failed");
emit TransactionExecuted(_transactionId);
}
function isTransactionConfirmed(uint _transactionId) public view returns(bool){
require(_transactionId<transactions.length, "Invalid Transaction Id");
uint confirmationCount;//initially zero
for(uint i=0; i<owners.length;i++){
if(isConfirmed[_transactionId][owners[i]]){
confirmationCount++;
}
}
return confirmationCount>=numConfirmationsRequired;
}
}