What is multisig wallet ?
- Multisig means Multiple signatures. That means a multisig wallet has not one owner but has multiple owners.
- To spend from this wallet, owner need to get approval from other owners.
Example
- 2 out of 3 MULTISIG WALLET - which requires atleast 2 owners approval out of 3 owners.
- Let's say there is a wallet with three owners(Alice, bob, carol). And Alice wants to withdraw 1BTC from this wallet. So, for Alice to withdraw 1BTC successfully atleat 2 owners should agree out of three owners.
- If one owner from bob or carol approves the txn then alice can withdraw 1BTC.
- If both Bob and Carol rejects the txn then the txn by Alice for withdrawing 1BTC will be revoked. Because the wallet here is 2 out of 3 multisig wallet. So atleast 2 approvals are required including alice approval.
Everything about owners setting, number of approvals required, revoking transaction etc.. all will be done in a Smart Contract.
Here I will explain the variables, events, functions etc which are there in Multisig wallet in my github repo SaikrishnaReddy/multisig-wallet
Let's start with the events :
event SubmitTxn(address indexed owner, address indexed to, uint indexed txIndex, uint value, bytes data);
event ConfirmTxn(address indexed owner, uint indexed txIndex);
event ExecuteTxn(address indexed owner, uint indexed txIndex);
event RevokeTxn(address indexed owner, uint indexed txIndex);
event Deposit(address indexed owner, uint value, uint balances);
Events :
Events are used to inform the calling application (Dapp) about the current state of the contract. Then depending on the information from the event, Dapp can perform other actions.
- SubmitTxn : this event will emitted when user submits a transaction.
- ConfirmTxn : this event will emitted when txn is confirmed.
- ExecuteTxn : this event will emitted when txn is executed.
- RevokeTxn : this event will emitted when a txn is revoked or cancelled.
- Deposit : this event will emitted when ether is deposited.
-> address[] public owners;
: this line will declare the owners
array variable of type address
.
-> mapping(address => bool) public isOwner;
: this isOwner
will be used while performing actions like submittxn, executetxn etc.. to check whether the user who is performing the action is owner or not. Values for is variable will be initialized at the time of contract intialization or deploying.(see constructor explanation below)
-> uint public numOfConfirmationsRequired;
: this is to tell the contract that before executing a txn, txn should require atleast mentioned number of owner confirmations. Value will be intialized at the time contract deployment.(see constructor explanation below)
->mapping(uint => mapping(address => bool)) public isConfirmed;
: this is to check the whether a particular txn(with index) is confirmed by the owner(of address).
-> Struct(this keyword is used to create custom data type):
struct Txn {
address to;
uint value;
bytes data;
bool executed;
uint numConfirmations;
}
Txn
is the data type for a transaction and it contains :to
: to whom the user is sending the ether.value
: amount or value that user is sending.data
: this is the extra data that you can attach to a transaction. This can be regular text or a number (formatted as a hexadecimal), or one can use this field to tell the contract to run a certain function. Here in this contract we will be using this data to execute a function which in another contract. (This is how one can call a function in other contract from one contract)executed
: this is to know whether the particular txn is executed or not. Default value isfalse
.numConfirmations
: this will tell whether a txn is ready to be executed or not. Minimum confirmationa required for a txn to be executed is 2(in this multisig contract only, can be different for other contracts, depends on the creator). Default value will be 0.
Contructor :
constructor(address[] memory _owners, uint _numOfConirmationsRequired) {
require(_owners.length > 0, "Owners required");
require(_numOfConirmationsRequired > 0 && _numOfConirmationsRequired <= _owners.length, "Invalid number of required confirmations");
for(uint i = 0;i < _owners.length; i++){
address owner = _owners[i];
require(owner != address(0), "Invalid owner");
require(!isOwner[owner], "Not a unique owner, duplicate owner found");
isOwner[owner] = true;
owners.push(owner);
}
numOfConfirmationsRequired = _numOfConirmationsRequired;
}
When deployed, the contract constructor will take two inputs :
-
_owners
: array of owners(addresses) for the contract. These owners will be responsible for the txns executions, revoking, confirming. If any address(which is not in these owners array of addresses) tries to execute, revoke or perform any other action, contract will throw an error. -
_numOfConirmationsRequired
: This value will tell the contract that for any txn to be executed, it requires min of mentioned number confirmations. This value cannot be 0 or greater than the total number of owners.
Constructor will check (before initializing owners array):
-
_owners
length should be greater than 0. -
_numOfConirmationsRequired
should be >0 and should be <= to the length of _owners.
After checking above two conditions, by looping through the input array of owners :
- get the first owner to the variable
owner
. - check that the address
owner
should not be equal toaddress(0)
. Hereaddress(0)
is a zero account which is a special case used to indicate that a new contract is being deployed. That means if the address 0, then txn creates a new contract. - Check whether the current
owner
is already declared or or not by usingisOwner
mapping variable. - If everything goes correctly, then make the current
owner
as a new owner by settingisOwner[owner] = true;
. and push theowner
to theowners
array. - Initialize
numOfConfirmationsRequired
with the value in_numOfConfirmationsRequired
variable.
At this step, the owners
for the contract will be decided and contract also knows the number of confirmations required to execute the transaction. Let's see the flow :
STEP-1:(assuming you are using remix)
Select any three addresses from all the accounts on top and pass them to the contract while deploying in the following format :
["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db"], 2]
- Submit the txn by clicking on
submitTxn
. (takes three inputs, theaddress
(select any address other than owners),value
(send 1Eth), anddata
(0X00-no data)) - assume txn index as 0 - Confirm the txn by clicking on
confirmTxn
. - send 0 as input here. - Change the owner (from the dropdown on top left, at
Account
you can change the owner.) and confirm the txn again. At this step,
txn with index 0
has two confirmations. Now, this txn is ready to be executed. Execute the txn by clicking theexecutetxn
and pass 0 as input.At this step, if the you check the balance of the address which is used to submit the txn will be now become 1ETH lesser than the initial amount. And if you check the balance of the address which you passed to
submitTxn
as first input, will be added with 1ETH.
This is the basic flow of multisig wallet. If you still need some more explanation or if you want to know more about me, you can reach me at krishnasvr9393@gmail.com and my DM are open on twitter.
Are you a beginner and want to connect for live explanation ? DM me on twitter.
This is my first blog, so your feedback is much appreciated.
Follow me on
twitter-SaikrishnaReddy
Top comments (0)