-
Notifications
You must be signed in to change notification settings - Fork 0
/
multisig-wallet.sol
93 lines (72 loc) · 3.55 KB
/
multisig-wallet.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
pragma solidity 0.7.5;
pragma abicoder v2;
contract MultiSigWallet {
address public contractCreator;
mapping (address => bool) public owners;
uint public requiredApprovals;
uint public balance;
struct TransferRequest {
uint requestId;
address to;
uint amount;
mapping (address => bool) approvals;
uint numApprovals;
}
mapping (uint => TransferRequest) transferRequests;
uint numTransferRequests;
modifier onlyOwners {
require(owners[msg.sender]);
_;
}
// ✅ 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.
constructor(address[] memory _owners, uint _requiredApprovals) {
contractCreator = msg.sender;
for (uint i = 0; i < _owners.length; i++) {
owners[_owners[i]] = true;
}
requiredApprovals = _requiredApprovals;
}
// ✅ Anyone should be able to deposit ether into the smart contract
function deposit() public payable returns (uint) {
balance += msg.value;
return balance;
}
function getSmartContractBalance() public view returns (uint) {
return address(this).balance;
}
// ✅ 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.
function createTransferRequest(address _to, uint _amount) public onlyOwners returns (uint) {
uint currentRequestIndex = numTransferRequests;
TransferRequest storage transferRequest = transferRequests[numTransferRequests++];
transferRequest.requestId = currentRequestIndex;
transferRequest.to = _to;
transferRequest.amount = _amount;
transferRequest.numApprovals = 0;
return currentRequestIndex;
}
function checkTransferRequestIsAtSendThreshold(uint currentNumApprovals) private view returns (bool) {
return currentNumApprovals == requiredApprovals;
}
// ✅ When a transfer request has the required approvals, the transfer should be sent.
function sendTransferIfEnoughApprovals(uint _requestId) private {
TransferRequest storage transferRequest = transferRequests[_requestId];
if (checkTransferRequestIsAtSendThreshold(transferRequest.numApprovals)) {
// send transfer
payable(transferRequest.to).transfer(transferRequest.amount);
balance -= transferRequest.amount;
}
}
// ✅ Owners should be able to approve transfer requests.
function approveTransferRequest(uint _requestId) public onlyOwners {
TransferRequest storage transferRequest = transferRequests[_requestId];
// ensure approval not already given by the owner
require(transferRequest.approvals[msg.sender] != true, "You already approved this transfer request");
// ensure transfer request is not already sent
require(checkTransferRequestIsAtSendThreshold(transferRequest.numApprovals) == false, "This transfer request has already been sent");
// ensure that the transfer request, if sent, is possible
require(transferRequest.amount <= balance, "This transfer request is not possible with current balance. Please deposit more re-attempting approval!");
transferRequest.approvals[msg.sender] = true;
transferRequest.numApprovals += 1;
sendTransferIfEnoughApprovals(_requestId);
}
}