Solidity(七)多签钱包合约程序wallet

单签钱包:只由一个私钥或者助记词来管理、由一个人管理钱包私钥的方式;执行持有对应的私钥就能控制该钱包中的资金;包括收款、转账、提现等交易操作;

单签钱包的优点是方便管理;单签钱包的缺点是一旦私钥被盗,将面临资金全部丢失的风险;

1 简单的单签钱包合约

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
// author:hqd8080
// contracts/EtherWallet.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9;

/**
* 简单的单签钱包实例
**/
contract EtherWallet {
//合约的所有者
address payable public owner;

//定义转账事件
event TransferEvent(address from, address to, uint256 amount);

//构造函数
constructor() {
owner = payable(msg.sender);
}

//收款时合约会自动调用的函数
receive() external payable { }

//函数修改器
modifier onlyOwner() {
require(msg.sender == owner, "wallet: caller is not owner");
_;
}

//提现函数,限制只有合约的所有者才能体现
function withdraw(uint256 amount) external onlyOwner{
payable (msg.sender).transfer(amount);
}

//转账函数,限制只有合约的所有者才能转账
function transfer(address payable to, uint256 amount) public onlyOwner {
require(owner.balance >= amount, "wallet: balance not enough");
// 使用 call 函数实现转账
(bool succeed, ) = to.call{value: amount}("");
require(succeed, "wallet: transfer failed");
emit TransferEvent(owner, to, amount);
}

//获取账户余额
function getBalance() external view returns (uint256) {
return address(this).balance;
}
}

2 多签钱包合约

所谓多签钱包,是指设定多个人共同来管理一个地址;必须满足一定数量的管理者签名同意之后才能动用地址账户内的资金;大大降低了资产被盗取的风险;

多签钱包的最大特点是:需要有多个私钥所有者的授权才能执行钱包的交易操作;与单签钱包相比多签钱包在使用和操作上多了授权和撤销两个操作;因为多签钱包机制是由多个用户共同管理一份资产;

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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// author:hqd8080
// contracts/MultiSignWallet.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9;

/**
* 多签钱包合约
**/
contract MultiSignWallet {
//存款事件,记录两个数据:存款方地址,存款金额
event Deposit(address indexed sender, uint256 amount);
//提交交易申请
event Submit(uint256 indexed txId);
//授权批准事件,记录两个数据:批准者账号,批准的交易序号
event Approve(address indexed owner, uint256 indexed txId);
//撤销批准事件,记录两个数据:撤销者账号,撤销批准的交易序号
event Revoke(address indexed owner, uint256 txId);
//执行的交易
event Execute(uint256 indexed txId);

//存储所有的私钥持有人,类型为address,总的签名个数
address[] public owners;

//存储和判断某个地址是不是私钥持有人
mapping (address => bool) public isOwner;
//执行签名的最少人数
uint public required;

struct Transaction {
address to; //接收方地址
uint256 value; //交易金额
bytes data; //如果发送到的是合约地址,可以执行此合约代码
bool executed; // 该交易是否执行
}

//存储提交的交易
Transaction[] public transactions;
//用户判断持有人是否同意了某一笔交易
mapping (uint => mapping (address => bool)) public approved;

//构造函数,初始化私钥持有人和确认数量
constructor (address[] memory _owners, uint256 _required) {
require(_owners.length > 0, "wallet: owners is required");
require(_required > 0 && _required <= _owners.length, "wallet: invalid require number of owners");

for (uint256 i = 0; i < _owners.length; i ++) {
address _owner = _owners[i];
require(_owner != address(0), "wallet: invalid owner");
require(!isOwner[_owner], "wallet: owner had");

isOwner[_owner] = true;
owners.push(_owner);
}
//执行签名的最少人数
required = _required;
}

//收款时合约会自动调用的函数
receive() external payable {
//记录存款地址和数量
emit Deposit(msg.sender, msg.value);
}

//函数修改器
modifier onlyOwner() {
require(isOwner[msg.sender], "wallet: invalid is owner");
_;
}

//判断是否存在txId
modifier isTxId(uint _txId) {
require(_txId < transactions.length, "wallet: invalid txId");
_;
}

//用于判断txId的地址是否已授权
modifier notApproved(uint _txId) {
require(!approved[_txId][msg.sender], "wallet: had approved");
_;
}

//用于判断txId对应的交易是否已经执行
modifier notExecuted(uint _txId) {
require(!transactions[_txId].executed, "wallet: had executed");
_;
}

//提交交易申请
function submitTransaction(address _to, uint256 _value, bytes calldata _data) external onlyOwner {
transactions.push(Transaction({to: _to, value: _value, data: _data, executed: false}));
emit Submit(transactions.length - 1);
}

//私钥持有人授权函数
function approve(uint _txId) external onlyOwner isTxId(_txId) notApproved(_txId) notExecuted(_txId) {
approved[_txId][msg.sender] = true;
emit Approve(msg.sender, _txId);
}

//授权人数
function getApproveCount(uint _txId) private view returns (uint256){
uint256 count = 0;
for (uint256 i = 0; i < owners.length; i ++) {
address owner = owners[i];
if (approved[_txId][owner]) {
count ++;
}
}
return count;
}

//执行交易方法
function execute(uint _txId) external isTxId(_txId) notExecuted(_txId) {
require(getApproveCount(_txId) >= required, "wallet: approveCount < required");

Transaction storage transaction = transactions[_txId];
transaction.executed = true;
(bool successed,) = transaction.to.call{value: transaction.value}(transaction.data);
require(successed, "wallet: execute failed");
emit Execute(_txId);
}

//撤销批准
function revoke(uint _txId) external onlyOwner isTxId(_txId) notExecuted(_txId) {
require(approved[_txId][msg.sender], "wallet: not approved");
approved[_txId][msg.sender] = false;
emit Revoke(msg.sender, _txId);
}
}