昨天留下多签的代码还没写,今天还是写了一会会儿,前文在这里:ECDSA使用,实现多签 (一) | 登链社区 | 深入浅出区块链技术 (learnblockchain.cn)
这篇文章有参考一个老外的文章,但是做了一些优化,思路一致。
Signature Replay | Hack Solidity #13 | by Zuhaib Mohammed | Jan, 2022 | CoinsBench (medium.com)
一个简单的多签,运用到一个转账业务中就是,一个老板小李建立了一个多签合约,初始化公司股东,小张,小王,小陈,小马几个人做为操作人,有这几个人同意,就可以通过多签合约给其他人转钱。
首先初始化合约,最多5个操作人,最少3个人同意就可以转:
constructor(address[] memory _operators) public payable {
owner = msg.sender;
require(_operators.length <= 5, "Too many operators");
for (uint8 i = 0; i < _operators.length; i++) {
operators[i] = _operators[i];
}
}
转账函数定义:
function transfer(
address _to,
uint256 _amount,
bytes[] memory sigs
) external {
bytes32 txHash = getTxHash(_to, _amount);
require(_checkSigs(txHash, sigs, 2), "Only operators can transfer");
(bool sender, ) = _to.call{value: _amount}("");
require(sender, "sender failed");
}
_checkSigs是我们的关键函数,检查签名是不是这个人签出来的。
function _checkSigs(
bytes32 txhash,
bytes[] memory sigs,
uint8 numSigs //
) private view returns (bool) {
uint8 c = 0;
//emit log_named_uint("sigs len", sigs.length);
bool[] memory bops = new bool[](operators.length);
for (uint8 i = 0; i < sigs.length; i++) {
//emit log_named_bytes("txHash", txHash);
if (!_findOpt(txhash.recover(sigs[i]), bops)) {
return false;
}
c++;
}
//emit log_named_uint("c", c);
if (c > numSigs) {
return true;
} else {
return false;
}
}
function _findOpt(address sigaddr, bool[] memory bops)
private
view
returns (
bool
)
{
for (uint8 i = 0; i < operators.length; i++) {
//emit log_named_address("operators", operators[i]);
if (operators[i] != address(0x0)) {
if (bops[i] == false) {
if (operators[i] == sigaddr) {
//emit log_named_address("find", operators[i]);
bops[i] = true;
//emit log("set true");
return true;
}
}
} else {
break;
}
}
return false;
}
为什么这样就可以?
检查签名是不是这个人签出来的,看我前面的ECDSA用法讲解。 ECDSA使用,实现多签 (一) | 登链社区 | 深入浅出区块链技术 (learnblockchain.cn)
相对于老外的代码,我做了一些升级,操作人变成5个,转账时候的签名,可以不按照顺序进行签名对比。
对比网站上其他人的文章,我这个更像一个技术原型,所以我会继续更新,弄一个更偏向业务的合约。测试用例什么的,都在github上,看测试用例,应该更能理解是怎么回事。
更详细的,看我github上的仓库:
SimpleMultiSig
Top comments (0)