Project - Multisig Wallet

Hi!

Need some help. This is my take on the assignment:

pragma solidity 0.8.1;

contract MultiSigWallet{
    
    address creator;
    constructor(){
        creator = msg.sender;
    }
    
    modifier onlyCreator{
        require(msg.sender == creator, "You need to be creator.");
        _;
    }
    
    
    mapping(address => bool) wallOwners;
    
    uint addedOwners = 0;
    function addOwners(address _owner) public onlyCreator {
        wallOwners[_owner] = true;
        addedOwners += 1;
    }
    
    uint nApprovals;
    function setApprovals(uint _reqApprovals) public onlyCreator {
        require(_reqApprovals <= addedOwners, "Amount of approvers has to be less or equal than the amount of owners.");
        nApprovals = _reqApprovals;
    }
    
    modifier onlyOwners{
        require(wallOwners[msg.sender], "You need to be an owner.");
        _;
    }


    mapping(address => uint) balance;

    event depositDone(uint amount, address indexed depositedTo);
    event transferDone(uint amount, address indexed depositedTo);

    function deposit() public payable returns(uint){
        balance[address(this)] += msg.value;
        emit depositDone(msg.value, address(this));
        return balance[address(this)];
    }
    
    function getBalance() public view returns(uint){
        return address(this).balance;
    }
    
    struct Transaction {
        address payable rec;
        uint amt;
        address[] signatures;
    }
    
    mapping(uint => Transaction) Transactions;
    
    
    function createTransferRequest(address payable recipient, uint amount, uint id) public onlyOwners {
        require(balance[address(this)] >= amount, "Balance not enough");
        require(address(this) != recipient, "Don't transfer to yourself");
        
        Transactions[id] = Transaction(recipient, amount, new address[](0));
    }
    
    function signAndTransfer(uint inputID) public onlyOwners {
        uint amountOfSignatures = Transactions[inputID].signatures.length;
        bool signedBySender = false;
        for (uint i=0; i < amountOfSignatures; i++) {
            if(Transactions[inputID].signatures[i]==msg.sender){
                signedBySender = true;
                break;
            }
        }
        if (signedBySender = false){
            Transactions[inputID].signatures.push(msg.sender);
            amountOfSignatures = Transactions[inputID].signatures.length;
            if(amountOfSignatures == nApprovals){
                uint previousSenderBalance = balance[address(this)];
                _transfer(address(this), Transactions[inputID].rec, Transactions[inputID].amt);
                assert(balance[address(this)] == previousSenderBalance - Transactions[inputID].amt);
                emit transferDone(Transactions[inputID].amt, Transactions[inputID].rec);
            }
        }
    }
        
        
    
    function _transfer(address from, address payable to, uint amount) private {
        to.transfer(amount);
        balance[from] -= amount;
        balance[to] += amount;
    }
    
}

The Transactions mapping points to a Transaction struct for each transaction request. Inside each Transaction struct there is an array that holds the signatures in form of addresses of the signers.

The idea is that the signAndTransfer function pushes the addresses of the signers to the signatures array of each transaction request and once the length of the array reaches nApprovals the transfer should execute.

The issue I’m facing seems to be that the signatures/addresses don’t get added to the signatures array. However I can’t figure out why. This is in this line:

Transactions[inputID].signatures.push(msg.sender);

Could you please help me with that?

Thanks!
Max

1 Like

Have you called addOwners so that the creator is also in the list of owners?

Also the createTransferRequest is a bit dangerous since there is the risk of overwriting an existing transaction (the caller is specifying the id).

In the video, why is deposit() {} empty in the function implementation?

Hello, I’m still having quite a bit of trouble, I’m unsure if my require() statement is working when checking to make sure the same address cannot approve the same transaction twice. When I am using the same address and press approve, the approvals count still continues to go up. I’m following along with Filip’s code but am unsure where I veered off.

/*REQUIREMENTS:
- Anyone should be able to deposit ether into the smart contract
- The contract creator should be able to input 
    (1): the addresses of the owners and 
    (2):  the numbers of approvals required for a transfer, in the constructor. For example, input 3 addresses and set the approval limit to 2. 
- Anyone of the owners should be able to create a transfer request. 
    The creator of the transfer request will specify what amount and to what address the transfer will be made.
- Owners should be able to approve transfer requests.
- When a transfer request has the required approvals, the transfer should be sent. 

OWNERS FOR TEST PURPOSES:
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db

FOR CONTRUCTOR:
["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db"], 2
1000000000000000000, "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2"
*/

pragma solidity 0.7.5;
pragma abicoder v2;

struct Transfer {
    uint amount;
    address payable to;
    uint approvals;
    bool sent;
    uint id;
}

contract Wallet {
    
    address[] public owners;    //array of owners allowed to approve
    uint limit;                 //required limit of approvals before being sent
    
    Transfer[] transferRequests;    //array of pending transfers waiting to reach limit of approvals
    
    mapping (address => mapping(uint => bool)) approvals;   //map of address => transfer id => approved flag
    
    event transferCreated(uint amount, address indexed to, uint id);    //event log for when transfer is created
    
    modifier onlyOwners() {
        bool isOwner = false;
        
        //loop through owner list to ensure sender is owner
        for(uint i = 0; i < owners.length; i++) {
            if(msg.sender == owners[i]) {
                isOwner = true;
            }
        }
        
        //only proceed if owner is true
        require(isOwner == true);
        _;
    }
    
    //constructor, initialize owners and limit
    constructor(address[] memory _owners, uint _limit) {
        //check to make sure non repeat owners
        owners = _owners;
        limit = _limit;
    }
    
    function deposit() public payable {}
    
    function createTransfer(uint _amount, address payable _to) public onlyOwners {
        transferRequests.push(
            Transfer(_amount, _to, 0, false, transferRequests.length)
        );
        
        emit transferCreated(_amount, _to, transferRequests.length-1);
    }
    
    function approve(uint _id) public {
        require(approvals[msg.sender][_id] == false, "You already approved this transaction!");   //ensure this address has not approved this transaction id yet, owners cannot approve same transaction twice
        require(transferRequests[_id].sent == false, "Cannot approve already sent transactions!");   //ensure this transaction has not been sent, owners can only approve unsent transactions
    
        approvals[msg.sender][_id] == true;     //set this transaction id as approved from this owner address to true
        transferRequests[_id].approvals++;      //increment approval count for this transaction id
        
        //if transaction id has reached number of required approvals, set sent flag and send transaction
        /*
        if(transferRequests[_id].approvals >= limit) {
            transferRequests[_id].sent = true;
            transferRequests[_id].to.transfer(transferRequests[_id].amount);
        }
        */
    }
        
    function getTransferRequests() public view returns (Transfer[] memory) {
        return transferRequests;
    }
    
    function getOwners() public view returns (address[] memory) {
        return owners;
    }
    
    function getValue() public payable returns (uint) {
        return msg.value;
    }
1 Like

How did I forget a withdraw :blush:

All good advice, I will continue touching up that code to keep my skills fresh.

1 Like

Hi Niclas,

Yes, I added the creator to the list of owners before trying to transfer, but the signatures still don’t get added to the list. I neither get error messages.

And agree, as it stands now the risk of overwriting transactions is there. Have to implement some checks or change that id system.

Hello. It is strange.
I did same steps and i got my transfer executed.
I transfered 0.5 ether. Wallet with balance 1 ether and treshold is 2. Transfer fired after second approval.


image

1 Like

I think I found the problem.
The problem is in the createTransferRequest function on this line:

Transactions[id] = Transaction(recipient, amount, new address);

When you are creating the Transaction you are defining the signature array to a fixed size of 0.
So when you later try to push to it no thing gets added since it is already ā€œfullā€

Thanks for your reply Niclas. Thought about that but according to the following resource, wouldn’t the array be dynamic?

image
https://www.tutorialspoint.com/solidity/solidity_arrays.htm#:~:text=Array%20is%20a%20data%20structure,variables%20of%20the%20same%20type.

Also tried different ways of creating the array and that’s the only one that compiles. For example Transactions[id] = Transaction(recipient, amount, new address); throws ā€œContract or array type expectedā€ and not providing the intial length beween the parentheses won’t work neither. Is there any way of creating dynamic arrays that I’m missing?

What I’m thinking now is that this may have to do with memory management. Maybe the array in createTransferRequest is not accessable for signAndTransfer?

It will not be Dynamics since you are specifying the size (0) when you are creating it.
What you could do is to define the array on the line above.

address[] memory emptyAddressArray;
Transactions[id] = Transaction(recipient, amount, emptyAddressArray);

Thanks a lot! Did this and it didn’t work right away but I started removing parts of the signAndTransfer function and it turns out that the if (signedBySender = false) condition is the problem. When removing that condition the array works and the transfers execute perfectly. However I still don’t understand why that condition was failing… :confused:

Hey @maxs, hope you are great.

The problem with arrays inside of structs is quite complex some times, like the one you are facing, loops and iterations on them are also quite gas consuming processes.

Instead you can use mappints and double mappings to expect the same result than arrays.
I teawk a little bit your code so you can understand how the mappings works.

    struct Transaction {
        address payable rec;
        uint amt;
        uint approvals;
        bool sent;
    }
    
    mapping(uint => Transaction) Transactions;
    mapping(address => mapping(uint => bool)) approvals; 
    
    function createTransferRequest(address payable recipient, uint amount, uint id) public onlyOwners {
        require(balance[address(this)] >= amount, "Balance not enough");
        require(address(this) != recipient, "Don't transfer to yourself");
        
        Transactions[id] = Transaction(recipient, amount, 0,false);
    }
    
    function signAndTransfer(uint inputID) public onlyOwners {
        require(approvals[msg.sender][inputID] == false, "Transaction already signed by this account.");
        require(Transactions[inputID].sent == false, "Transaction already sent.");
        approvals[msg.sender][inputID] = true;
        Transactions[inputID].approvals++;
        
        if(Transactions[inputID].approvals == nApprovals){
            uint previousSenderBalance = balance[address(this)];
            _transfer(address(this), Transactions[inputID].rec, Transactions[inputID].amt);
            assert(balance[address(this)] == previousSenderBalance - Transactions[inputID].amt);
            emit transferDone(Transactions[inputID].amt, Transactions[inputID].rec);
        }
    }

You can read my previous post about mappings here: Project - Multisig Wallet

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.

Maybe something like this could work, just find out how to include it in your function body :nerd_face:

        if (transferRequests[_id].approvals < signaturesLimit){
            transferRequests[_id].approvals++;
    }

Carlos Z

Hey Carlos, thanks for that!

Yes, seems to be a simpler solution. Saw that it is more alligned with the model that Filip proposes in his videos.
Still wanted to understand what was wrong in my approach and see if it was ā€œsaveableā€ :slight_smile:
Thanks again ,
Max

2 Likes

Aah I see it now @maxs …

Still wanted to understand what was wrong in my approach and see if it was ā€œsaveableā€ :slight_smile:

You are using ā€œ=ā€ instead of ā€œ==ā€.
That means that you are assigning signedBySender to false instead of comparing it.
This is a common mistake that can be hard to spot in many languages. :wink:

2 Likes

Wooow, thanks a lot Niclas! Can’t belive how much it took to find this simple mistake :sweat_smile: Code runs perfectly now.

Here’s a new version with that corrected and also with a check so that no more than one transaction can be created for each id.

pragma solidity 0.8.1;

contract MultiSigWallet{
    
    address creator;
    constructor(){
        creator = msg.sender;
    }
    
    modifier onlyCreator{
        require(msg.sender == creator, "You need to be creator.");
        _;
    }
    
    
    mapping(address => bool) wallOwners;
    
    uint addedOwners = 0;
    function addOwners(address _owner) public onlyCreator {
        wallOwners[_owner] = true;
        addedOwners += 1;
    }
    
    uint nApprovals;
    function setApprovals(uint _reqApprovals) public onlyCreator {
        require(_reqApprovals <= addedOwners, "Amount of approvers has to be less or equal than the amount of owners.");
        nApprovals = _reqApprovals;
    }
    
    modifier onlyOwners{
        require(wallOwners[msg.sender], "You need to be an owner.");
        _;
    }


    mapping(address => uint) balance;

    event depositDone(uint amount, address indexed depositedTo);
    event transferDone(uint amount, address indexed depositedTo);

    function deposit() public payable returns(uint){
        balance[address(this)] += msg.value;
        emit depositDone(msg.value, address(this));
        return balance[address(this)];
    }
    
    function getBalance() public view returns(uint){
        return address(this).balance;
    }
    
    struct Transaction {
        address payable rec;
        uint amt;
        address[] signatures;
    }
    
    mapping(uint => Transaction) Transactions;
    
    
    function createTransferRequest(address payable recipient, uint amount, uint id) public onlyOwners {
        require(balance[address(this)] >= amount, "Balance not enough");
        require(address(this) != recipient, "Don't transfer to yourself");
        require(Transactions[id].amt == 0, "There is already a transaction with this id. Please enter another id.");
        
        address[] memory emptyAddressArray;
        Transactions[id] = Transaction(recipient, amount, emptyAddressArray);
    }
    
    function signAndTransfer(uint inputID) public onlyOwners {
        uint amountOfSignatures = Transactions[inputID].signatures.length;
        bool signedBySender = false;
        for (uint i=0; i < amountOfSignatures; i++) {
            if(Transactions[inputID].signatures[i]==msg.sender){
                signedBySender = true;
                break;
            }
        }
        if (signedBySender == false){
            Transactions[inputID].signatures.push(msg.sender);
            amountOfSignatures = Transactions[inputID].signatures.length;
            if(amountOfSignatures == nApprovals){
                uint previousSenderBalance = balance[address(this)];
                _transfer(address(this), Transactions[inputID].rec, Transactions[inputID].amt);
                assert(balance[address(this)] == previousSenderBalance - Transactions[inputID].amt);
                emit transferDone(Transactions[inputID].amt, Transactions[inputID].rec);
            }
        }
    }
        
        
    
    function _transfer(address from, address payable to, uint amount) private {
        to.transfer(amount);
        balance[from] -= amount;
        balance[to] += amount;
    }
    
}
2 Likes

OK I wanted to give it a crack without looking at anything. I may be way off base with what you are looking for but I got a wallet. And it has three owners that require two approvals to make an authorized transfer. And it will get the balance after the transfer is made. It will also get the owners information ex. address, balance, sender, Id, and any message. It will allow for anyone to make a deposit It will record, using boolean the owners approval and will make the transaction if approved by two Owners. It will then also show in the console if approval Authorization is true or false.

pragma solidity 0.7.5;

pragma abicoder v2;

contract multiSigWallet{
    
    mapping(uint => Owner)owners;
    
    struct Owner{
        uint  id;
        address owner;
        address recipient;
        uint balance;  
        string message;
       
    }
    
     event transferDone(uint amount, address recipeint);
    
    
    
    function addOwner(uint _id, address _owner, address _recipient, uint _balance, string memory _message)public{
        
            
     owners[_id] = Owner(_id, _owner, _recipient, _balance, _message);
            
        }

        
        function getOwnerinfo(uint _id)public view returns(uint, address, address, uint, string memory){
            
            Owner memory ownerinfo = owners[_id];
            
            return (ownerinfo.id, ownerinfo.owner, ownerinfo.recipient, ownerinfo.balance, ownerinfo.message);
            
        }
        
    event depositedTo(uint indexed balamce, address indexed depositedTo);
     
     event balanceAdded(uint balance, address depositedTo);
     
       
       function Deposit(uint _id)public payable returns(uint){
          
           owners[_id].balance += msg.value;
           
           emit depositedTo(msg.value, owners[_id].owner);
           
           return owners[_id].balance;
       }
       
   // To get balance from any account 
  // function getMoreBalance(address _to)public view returns ( uint){
       
      // return balance[ _to];
      
      //To get balance from msg.sender account
       
       function getDepositBalance(uint _id )public view returns ( uint){
           
           return owners[_id].balance;
   }
   
   //Get approvals using boolean.  
   
   bool []approval;
   
   function IsApproved (bool  _1stOwnerApproves, bool _2ndOwnerApproves, bool _3rdOwnerApproves)public {
       
       approval.push(_1stOwnerApproves);
       approval.push(_2ndOwnerApproves);
       approval.push(_3rdOwnerApproves);
   }
   
   
   function listapprovals()public view returns (bool [] memory){
       
       return approval;
   }
   
 bool approved;
   
   function Authorization()public returns (bool){
       
       if ((approval[0] = true) || (approval[1] = true) &&  (approval[2] = true)){
           
            approved = true;
       }
   else if ((approval[0] = true) || (approval[1] = true) && (approval[2])){
           
            approved = true;
      }
   
        else if ((approval[1]= true) || (approval[2]= true) && (approval[0] = true)){
       
       approved = true;
       
   }
   
   else if((approval[2]= true) || (approval[0] = true) && (approval[1] = true)){
       
       approved = true;
   }
   
   else approved = false;
   
   return approved;
   
   
   }
      //To transfer money from msg.sender to any recipient
   //And to add requirements before function is executed.
   //add event to check transferFund
   
  
   
   function transferFunds(uint _id, uint _amount) public {
      
      //call made to execute the transfer function using these parameters from "msg.sender" to "recipient" and "amount:.
       //Add code to check for balance before transfer
       
       Owner memory mytransfer = owners[_id];
           
       require(approved = true,"You dont have approval to make this transfer");

       require(owners[_id].balance >= _amount, "Your money is too short to make this transaction");
      
       require(mytransfer.owner != mytransfer.recipient,"You cannot send money to yourself that would be money laundering");  
      
       uint previousBalance = owners[_id].balance;  //determine previous balance before transfer
       
       _transfer (_id, _amount);
       
       emit transferDone(_amount, owners[_id].recipient);
       
       assert(owners[_id].balance == previousBalance - _amount); //determine balance after transfer
   }
   
   //Transfer function private.  
    //use underscore when the function is private
     function _transfer (uint id, uint amount)private {
           owners[id].balance -= amount;
         
           
       }
       
      function  getTransferBalance(uint _id)public view returns(address, uint) {
          
          
           return (owners[_id].owner, owners[_id].balance);
   
    }
1 Like

Hey @Imhotep, hope you are well.

You did a good job on many of the basic structure on the contract, but there are some issues that I think you should consider to improve your contract.

First of all, none of your functions are restricted to owners, you are not using any modifier like onlyOwner for example, so any kind of user can approve, create, transfer funds.

Now here:

   //Get approvals using boolean.  
   
   bool []approval;
   
   function IsApproved (bool  _1stOwnerApproves, bool _2ndOwnerApproves, bool _3rdOwnerApproves)public {
       
       approval.push(_1stOwnerApproves);
       approval.push(_2ndOwnerApproves);
       approval.push(_3rdOwnerApproves);
   }

I don’t understand completely the use case for this, i can add 3 arguments at the start (true, true, true) and it will add those 3 to the array, then i can do the same, it will add 3 more, so now i have 6 elements in that array.

This next one does not have too much sense to me If you continue with the above example of 3 arguments.

 bool approved;
   
   function Authorization()public returns (bool){
       
       if ((approval[0] = true) || (approval[1] = true) &&  (approval[2] = true)){
           
            approved = true;
       }
   else if ((approval[0] = true) || (approval[1] = true) && (approval[2])){
           
            approved = true;
      }
   
        else if ((approval[1]= true) || (approval[2]= true) && (approval[0] = true)){
       
       approved = true;
       
   }
   
   else if((approval[2]= true) || (approval[0] = true) && (approval[1] = true)){
       
       approved = true;
   }
   
   else approved = false;
   
   return approved;
   
   
   }

If I add the 3 first elements of the approval array has (true, true, true), this function will always return true on any of the conditions.

In your transferFunds function you have this require which have a wrong condition, instead of comparing ==, you are assigning =.

require(approved = true,"You dont have approval to make this transfer");

Finally, this function only substract the amount from the sender, but does not increase the balance on the receiver.

     function _transfer (uint id, uint amount)private {
           owners[id].balance -= amount;
         
           
       }

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.

Hi guys. I didn’t use multimapping (didnt occur to me). I assume that its not very elegant, but here goes:
There are three owners. I establish who is owner number one, two and three. Anybody can register a transfer. The transfer is registered with 0 approvals. Once registered, an owner can authorize the transfer. I create a mapping that says that transfer with ID X now has an approval(not any approval, either approval of owner one, two or three). I also add +1 to the cont of approvals of the registered transfer.If the same owner authorizes again, then it will throw an error because I know which owner he is, and I know that he as given his authorization again. If a second owner approves the same transfer, it gets sent.

pragma solidity 0.7.5;
pragma abicoder v2;

contract Multisigwallet{
    
    mapping (address => bool) Owners;
    mapping (uint => approvals) Approvalsoftrnsfr;
    mapping (address => uint) balance;
    uint numberofauthorizations; 
    int[] Ids;
    struct Transfer{
        //uint id;
        address _sentby;
        address _sentto;
        uint amount;
        uint approvals;
    }
    struct Approvers{
        address _1approver;
        address _2approver;
        address _3approver;
    }    
    struct approvals {
        bool _1approval;
        bool _2approval;
        bool _3approval;
    }   
    Approvers approvers;
    
    event Transferauthorized(uint ID, address sender, address receiver, uint fundstransfered);
    modifier Onlyowners {
        require( Owners[msg.sender] == true, "You are not part of the Owners");
        _;
    }
    modifier Transferpossible(uint _funds, address _recipient) {
        require(balance[msg.sender]>= _funds, "You dont have enough funds");
        require(msg.sender != _recipient, "You cant send to yourself");
         _;
    }
     Transfer[] Transfers; 
    constructor (address _1owner, address _2owner, address _3owner, uint _numberofauthorizations){
        //set to test for owners. So that only owners can use functions
        Owners[_1owner] = true;
        Owners[_2owner] = true;
        Owners[_3owner] = true;
        numberofauthorizations= _numberofauthorizations;
        //To set who is first, second , and thirt approver
        approvers._1approver = _1owner;
        approvers._2approver = _2owner;
        approvers._3approver = _3owner;
    }
    function viewapprovers() view public returns (string memory, address, string memory, address, string memory, address){
        return ("first approver:" , approvers._1approver, "second approver:", approvers._2approver, "third approver", approvers._3approver) ;
        
    }
    function deposit ()public  payable  returns (string memory, uint){
        balance[msg.sender] += msg.value;
        return ("transfered:", balance[msg.sender]);
    }
    function Viewbalance() public view returns(string memory, uint){
        return ("My balance is:", balance[msg.sender]);
    }
    function Initiatetransfer (address _recipient, uint _funds) public Transferpossible(_funds, _recipient){
        balance[msg.sender] -= _funds;
        Transfer memory Thistransfer = Transfer(msg.sender, _recipient, _funds, 0);
        Transfers.push(Thistransfer);
    }
    
    function Viewpendingtransfers() public view Onlyowners returns(Transfer[] memory) {
        return (Transfers);
    }
    function viewapprovals(uint _idtransaction) view public Onlyowners returns(string memory, uint, string memory, bool, string memory, bool, string memory, bool){
        return("Transaction ID", _idtransaction, "Firstapproval:", Approvalsoftrnsfr[_idtransaction]._1approval, "Secondapproval:", Approvalsoftrnsfr[_idtransaction]._2approval,"Thirdapproval:", Approvalsoftrnsfr[_idtransaction]._3approval);
        
    }
    function Authorizetransfer(uint _idtransaction) private Onlyowners{
        //make sure the owner hasnt already authorized (no duplicate authorizations)
        /// IF msg.sender is first approver, then check if he has given his approval. If not, add that he/she approved it. (that for every approval)
        if(approvers._1approver == msg.sender ){
            require(Approvalsoftrnsfr[_idtransaction]._1approval == false, "You have already approved this Transfer.");
            //means that first approver already gave approval
            Approvalsoftrnsfr[_idtransaction]._1approval = true;
            Transfers[_idtransaction].approvals += 1;
        }
        if(msg.sender == approvers._2approver){
            require(Approvalsoftrnsfr[_idtransaction]._2approval == false, "You have already approved this Transfer.");
            //means that second approver already gave approval
            Approvalsoftrnsfr[_idtransaction]._2approval = true;
            Transfers[_idtransaction].approvals += 1;
        }        
        if(msg.sender == approvers._3approver){
            require(Approvalsoftrnsfr[_idtransaction]._3approval == false, "You have already approved this Transfer.");
            //means that third approver already gave approval
            Approvalsoftrnsfr[_idtransaction]._3approval = true;
            Transfers[_idtransaction].approvals += 1;
        }
      }
    function Confirmtransfer(uint _idtransaction) public returns (string memory){
        require(Transfers.length-1 >= _idtransaction, "the transaction doesnt exist");
        Authorizetransfer (_idtransaction);
        if(Transfers[_idtransaction].approvals >=numberofauthorizations){
            balance[Transfers[_idtransaction]._sentto] +=Transfers[_idtransaction].amount;
            //leave a log of the actual transfer
            emit Transferauthorized(_idtransaction, Transfers[_idtransaction]._sentby,Transfers[_idtransaction]._sentto,Transfers[_idtransaction].amount);
            //delete part of the array that was transfered
            //make transfer if enough authorizations have been..authorized
            //return the emit statement
            return ("Transfered!");
        }
        else{
            return("Authorized. More authorizations required.");
        }
    }
}

I tried to avoid iterations and fors and such.

1 Like

Feeling kinda silly now after watching filips explanation

1 Like