前几天听一个好友说起argent这个数字货币钱包软件,说它有个特色——转账免手续费。我问他转的是什么币,他说是ETH。这让我大吃一惊。因为很久以前我研究过以太坊转账免手续费的问题,总的来说,就是很复杂。
用中心化的方式:先让用户转账,然后中心化系统给用户把手续费补给用户。
去中心化的方式:好像没找到合理的方式,时间太久忘了。
听到好友说有这么个钱包软件做到了免手续费转ETH,我非常兴奋,好奇心爆棚,一定要一探究竟。下面就是我探究argent转账免手续费的经历。
下载argent钱包软件
这个钱包软件目前在国内还不能下载,只能翻墙去下载。
安装注册钱包
这个没什么好说的,跟普通钱包差不多,都是备份密钥种子那一套。
开始体验软件
打开软件,会给你的钱包提前分配一个以太坊账户地址,要你网这个地址里转入ETH,激活它。你还能自定义一个专属你钱包的ENS。
我激活之后就这样子:
经过查询etherscan,我发现事情并不简单。
注意看上面显示我是16天之前转的ETH,但是这个合约账户是13天前创建的
也就是说当我看到我钱包里的这个账号的时候,这个账号地址是个智能合约地址,此时这个智能合约还没有被创建。我转账之后第三天这个智能合约地址被创建了。
也就是说,智能合约与地址是能够提前被预订的!!!能够提前预订!!!能够提前预订!!!
原谅我以前不学无术,孤陋寡闻,我真不知道还有这种事情,我以前真的以为那串像乱码一样的字符串可能像区块哈希一样,是不能被提前预测到的。
后来我就研究了一下以太坊智能合约地址生成规则,于是就有了前面几篇博客的内容:
以太坊智能合约地址生成之CREATE指令 https://blog.csdn.net/console/editor/html/106541978
以太坊智能合约地址生成之CREATE2指令 https://blog.csdn.net/maxdaic/article/details/106542548
钱包合约创建流程
通过etherscan查到,我的钱包智能合约是由0x40C84310Ef15B0c0E5c69d25138e0E16e8000fE9(合约名:WalletFactory)创建的,而这个地址也是一个智能合约地址。当然通过智能合约创建另一个智能合约这已经是很常规的操作了。
问题来了,WalletFactory是通过哪个接口给我创建的钱包合约?
通过查看我的钱包智能合约事件日志也许可以看出一些端倪。如下图:
可以看到,这里事件是创建合约的时候记录下来的。并且这里有个有用的信息,那就是箭头上的method id。
method id是什么?就是调用智能合约接口的时候,对智能合约接口做keccak256运算,取其前四个字节。如baz(uint32,bool)的method id为0xcdcd77c0
用golang实现method id代码如下:
func MustGenerateMethodID(method string) string {
buf := Keccak256Hash([]byte(method))
return "0x"+hex.EncodeToString(buf[:4])
}
测试代码:
func TestMustGenerateMethodID(t *testing.T) {
var testcases = []struct{
method string
want string
} {
{
"baz(uint32,bool)",
"0xcdcd77c0",
},
{
"bar(bytes3[2])",
"0xfce353f6",
},
//{
// "createCounterfactualWallet(address,address[],string,bytes32)",
// "0xc3606c88",
//},
{
"createCounterfactualWalletWithGuardian(address,address[],string,address,bytes32)",
"0xc3606c88",
},
}
for _,oneCase := range testcases {
got := MustGenerateMethodID(oneCase.method)
if got != oneCase.want {
t.Error("generate method id error")
t.Error("want:", oneCase.want)
t.Error("got: ", got)
return
}
}
}
通过测试,我发现这个method id是 函数createCounterfactualWalletWithGuardian(address,address[],string,address,bytes32)的。于是可以顺藤摸瓜,摸清楚整个流程。
对了,argent智能合约已经开源,地址是:https://github.com/argentlabs/argent-contracts
创建钱包智能合约的关键代码如下:
function _createCounterfactualWallet(
address _owner,
address[] memory _modules,
string memory _label,
address _guardian,
bytes32 _salt
)
internal
{
_validateInputs(_owner, _modules, _label);
bytes32 newsalt = _newSalt(_salt, _owner, _modules, _guardian);
bytes memory code = abi.encodePacked(type(Proxy).creationCode, uint256(walletImplementation));
address payable wallet;
// solium-disable-next-line security/no-inline-assembly
assembly {
wallet := create2(0, add(code, 0x20), mload(code), newsalt)
if iszero(extcodesize(wallet)) { revert(0, returndatasize) }
}
_configureWallet(BaseWallet(wallet), _owner, _modules, _label, _guardian);
}
可以看到,这里创建智能合约是使用以太坊虚拟机的create2指令。而newsalt是使用官方指定的_salt, _owner, _modules, _guardian这几个参数生成的。所以argent官方通过这几个参数就可以提前生成钱包智能合约的地址。
到此,梳理一下整个钱包创建的业务流程:
(1)先通过一些列参数提前生成一批智能合约地址;
(2)当用户注册argent钱包的时候,提取一个地址并把它分配给用户;
(3)用户往这个地址转账ETH;
(4)检测到用户转了ETH到其钱包智能合约地址上,通过WalletFactory智能合约创建用户钱包智能合约。
更多精彩,下回分析
(全文完)
参考资料:
https://solidity.readthedocs.io/en/develop/abi-spec.html
https://etherscan.io/address/0x8b55c928602896a1e078e23a3fee33393821eec7#events
https://github.com/argentlabs/argent-contracts