![]() |
VOOZH | about |
Digital wallets are financial accounts that store funds and make transactions. You can also track transaction histories. Instead of using rupees, dollars we can also use cryptocurrencies such as Bitcoin, Ether, and many more. Generally, a wallet needs one signature to sign a transaction. We can also have multisignature wallets whose access is shared with more than one member i.e we can have copayers. To simplify it, to complete a transaction successfully, we need more than one signature. It has the functionality of setting a minimum signature count i.e the minimum number of signatures required to complete the transaction.
For example, A multisignature wallet has 10000 tokens and is shared between Ajay, Neha, and Amit and the minimum signature count is 2. So at least two of them need to sign a transaction for it to become successful.
This concept is not new. It has been used to secure assets for quite some time but digital implementation has been done recently. For example, limited access such as partial keys of a locker was given earlier to protect the assets.
There are several other wallets such as Carbon, BitGo, Casa, and many more and you can choose one depending on your need.
There are a lot of ways we can code a multi signature wallet.
To begin, let's define the requirements for our multi-signature wallet. Our wallet will have a fixed number of co-signers, each with its unique private key. A transaction will only be authorized if a certain number of these co-signers approve. For example, if our wallet has 3 co-signers and requires 2 approvals for a transaction to be made, then at least 2 of the 3 co-signers must provide their private key to authorize the transaction.
Now that we have defined the requirements for our wallet let's start implementing it in Solidity.
First, we will define the struct for our co-signer. This struct will store the address and the public key of the co-signer.
Next, we will define the multi signature wallet contract. This contract will store the array of co-signers, the required number of approvals for a transaction, and the current number of approvals for the current transaction.
Now, let's define the function that allows a co-signer to add their approval to the current transaction. This function will take in the co-signer's address and their signed message as parameters. It will then verify the signature using the co-signer's public key, and if the signature is valid, it will add the co-signer's approval to the current transaction.
We also need to define the function that allows a co-signer to revoke their approval from the current transaction. This function will simply decrease the current number of approvals by one.
Finally, we will define the function executing the transaction if the required approvals have been reached. This function will take in the destination address and the transfer value as parameters. It will then send the specified amount.
Below is the complete code for a multi signature wallet:
Here is a brief overview of the main features and functions in the contract:
Here is a detailed explanation of the above code:
The start and end variables store the start and end times for the timelock period, respectively. The timeIsOver modifier ensures that a function can only be called if the current block's timestamp is within the timelock period.
The startTimer function sets the start variable to the current block's timestamp, and the endTimer function sets the end variable to the sum of the desired timelock period and the start variable. The timeLeft function returns the time left in the timelock period.
The owners array stores the addresses of the owners of the wallet. The isOwner mapping is used to track which addresses are owners. The numConfirmationsRequired variable stores the number of confirmations required for a transaction to be executed. The Transaction struct stores information about a transaction, such as a recipient address, the number of funds to be transferred, and any associated data. The transactions array stores all the transactions submitted to the wallet. The isConfirmed mapping is used to track the confirmations received for each transaction.
The onlyOwner modifier ensures that only owners can call certain functions. The txExists modifier ensures that a transaction with the specified index exists. The notExecuted modifier is used to ensure that a transaction has not already been executed. The notConfirmed modifier is used to ensure that the calling address has not already confirmed a transaction.
The constructor is used to initialize the wallet. It takes an array of owner addresses as input and stores them in the owner's array. It also sets the isOwner mapping for each owner address and calculates the number of confirmations required for a transaction to be executed.
The receive function is the fallback function for the contract. It allows the contract to receive funds from external sources. It emits the Deposit event to track the incoming funds.
The submitTransaction function is used to submit a new transaction to the wallet. It takes the recipient address, the transfer value, and associated data as input. It also takes a timelock period as input, which determines how long the transaction will be open for confirmations. The function adds a new transaction to the transactions array and sets the end variable to the sum of the timelock period and the start variable. It also emits the SubmitTransactionDetails event to track the submission of the transaction.
The confirmTransaction function is used to confirm a transaction. It takes the index of the transaction as input and increments the numConfirmations field in the Transaction struct. It also sets the isConfirmed mapping for the transaction and the calling address to true. The function is restricted to only owners, and it checks that the transaction exists, has not been executed, and has not already been confirmed by the calling address. It emits the ConfirmTransaction event to track the confirmation of the transaction.
The executeTransaction function is used to execute a transaction. It takes the index of the transaction as input and checks that the transaction has received enough confirm
However, we are free to add several functionalities to the contract. Here are some of the extra functionalities we can add to the contract. Please take it as an exercise.