CREATE2是以太坊在2019年2月的康斯坦丁包硬分叉中引入的一个新操作码。利用CREATE2操作码可以在部署智能合约前就预先计算出合约的部署地址。在这个教程中,我们将学习使用CRAETE2
计算智能合约部署地址的基本方法,理解CREATE2操作码可以在同一地址多次部署合约,并利用CREATE2提出了交易平台开发中一个常见问题的解决方案 —— 为用户生成以太坊钱包地址。
正如EIP中说明的,CREATE2操作码主要用于状态通道,不过我们可以用它来解决交易所或平台开发中经常遇到的另一个问题。
用自己熟悉的语言学习 以太坊DApp开发 :Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart
对于交易所的每个用户,都需要向其提供一个以太坊地址以便接收用户充入的代币,我们将这些地址称为钱包。当用户充值进入钱包后,我们需要将重入的代币发送到一个中心钱包(热钱包)。
下面我们分析一下在没有CREATE2操作码时解决上述问题的方案,以及为什么这些方案被弃用。如果你只对最终结果感兴趣,可以直接查看最后一节的内容。
最简单的解决方案是为新用户生成以太坊外部地址(EOA)作为用户的平台钱包。要将代币从用户钱包归集到中心热钱包,我们需要在后台用钱包的私钥签名代币合约的transfer()
调用。
这个方案的优点是:
不过我们决定放弃这个方案,因为它有一个重大的缺点:你需要在某处保存私钥,这不仅仅是私钥有可能丢失的问题,你还需要仔细管理对这些私钥的访问。如果其中一个私钥被盗,那么这个用户的代币就不会归集到中心热钱包了。
第二个方案是为每个用户创建一个单独的智能合约并使用智能合约的部署地址作为用户的平台钱包,这避免了在服务器上保存用户钱包的私钥,并且交易所或平台可以调用这个智能合约来将用户代币归集到中心热钱包。
不过我们也没有选择这个方案,因为在部署合约之前用户没有办法显示其钱包地址(实际上是可能的,但是会非常复杂,并且有一些其他问题)。在交易所或平台上,一个用户应该可以创建任意多的账号,这意味着我们需要在合约部署上浪费资金,并且还不能确认用户是否使用这个有成本的账号。
我们还是决定继续研究采用智能合约地址作为用户钱包账号。为了解决前面提到的问题,我们决定使用以太坊的CREATE2操作码。这样我们就可以先不用部署合约了。
CREATE2
允许提前计算要部署的智能合约的地址,计算公式如下:
keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
其中:
因此,可以保证要提供给用户的地址中包含了期望的字节码。此外,这个智能合约可以在需要的时候才部署。例如,当决定使用用户的钱包时。
更进一步,交易所或平台可以随时计算智能合约的地址而无需保存这个地址:
前面的解决方案还有一个问题:平台需要为智能合约的部署支付手续费,不过我们可以想办法避免这一点。为此可以先调用transfer()方法,然后调用selfdestruct()方法,那么部署合约的手续费就可以得到返还。
与通常的错误认识相反,事实上你可以 在同一个地址使用CREATE2操作码多次部署智能合约 ,这是因为CREATE2会检查目标地址的nonce是否为0。在这个示例中,selfdestruct()方法将复位地址的nonce值。因此,如果你使用同样的参数再次调用CREATE2操作码,对nonce的检查就可以通过。
注意这个解决方案类似于使用以太坊地址的方案,但是不需要保存用户钱包的私钥。将用户钱包的资金归集到中心热钱包的成本基本等同于调用transfer()方法的成本,因为我们不再需要为智能合约的部署付费。
首先准备以下实现代码:
constructor () {
address hotWallet = 0x …;
address token = 0x …;
token.transfer (hotWallet, token.balanceOf (address (this)));
selfdestruct (address (0));
}
对于每个新用户,我们通过计算展示其平台钱包地址:
keccak256 (0xff ++ fabric_addr ++ hash (user_id) ++ keccak256 (wallet_init_code)) [12:]
当用户将代币转入其在平台上的钱包地址时,我们的后台系统会监控到Transfer事件,其 _to参数表示转账目标地址。这时在实际部署钱包合约前,已经可以增加用户在交易所的余额了。
当用户钱包中累积了足够的代币,我们就可以将其一次转入平台热钱包。为此,后台调用工厂合约的方法:
function deployWallet (uint256 salt) {
bytes memory walletBytecode = …;
// invoke CREATE2 with wallet bytecode and salt
}
因此钱包智能合约的构造函数被调用,这会将所有代币转入平台热钱包然后自动销毁。
可以在这里下载完整的代码.注意,这不是我们的生产代码,因为我们还要优化钱包合约的字节码。
原文链接:以太坊智能合约如何提前计算部署地址 — 汇智网