# 地址生成规则 **Published by:** [kool](https://paragraph.com/@kool/) **Published on:** 2022-06-09 **URL:** https://paragraph.com/@kool/LjsYGpQZusaCq19MZzyQ ## Content 部署智能合约使用CREATE2操作码使我们能够预测将CREATE2部署合约的地址,而无需这样做。这为提高用户引导和可扩展性提供了许多可能性。 在本指南中,我们将预先计算将部署合约的地址并将 Ether 发送到该地址。然后,我们将在同一个地址部署一个可升级的合约,并使用它来检索之前发送到那里的资金。 本指南介绍了 OpenZeppelin 工具的高级用法,并且需要熟悉 Solidity、开发区块链和 OpenZeppelin CLI。 如需复习这些主题,请前往部署智能合约并与之交互。创建智能合约部署智能合约的主要方式有两种:使用CREATE和CREATE2流。我们将简要概述它们的工作原理及其核心区别。 如果您已经熟悉背后的目标CREATE2,请随意跳过。CREATE智能合约既可以由其他合约(使用Solidity 的new关键字)创建,也可以由普通账户(例如运行时oz deploy)创建。在这两种情况下,新合约的地址都以相同的方式计算:作为发送者自己的地址和随机数的函数。new_address = hash(sender, nonce) 每个账户都有一个关联的 nonce:对于普通账户,它在每笔交易中都会增加,而对于合约账户,它会在每次合约创建时增加。随机数不能重复使用,它们必须是顺序的。 这意味着可以预测下一个创建的合约将被部署到的地址,但前提是在此之前没有其他交易发生——这对于反事实系统来说是一个不受欢迎的属性。CREATE2这个操作码背后的整个想法是使生成的地址独立于未来的事件。无论区块链上可能发生什么,始终可以在预先计算的地址上部署合约。 新地址具有以下功能:0xFF, 一个防止与CREATE发件人自己的地址盐(发件人提供的任意值)待部署合约的字节码new_address = hash(0xFF, sender, salt, bytecode) CREATE2保证如果sender部署bytecodeusingCREATE2和提供的salt,它将存储在new_address. 因为bytecode包含在这个计算中,所以其他代理可以依赖这样一个事实,即如果一个合约被部署到new_address,它将是他们知道的一个。这是反事实部署背后的关键概念。CREATE2从 CLI使用因为CREATE2是 EVM 操作码,它通常只能由智能合约使用,而不能由外部账户使用。然而,OpenZeppelin CLI 提供了一种CREATE2直接从终端运行类似部署的便捷方式。 我们将从使用合约初始化一个新的 OpenZeppelin 项目Vault开始:// contracts/Vault.sol pragma solidity ^0.5.0; import "@openzeppelin/upgrades/contracts/Initializable.sol"; contract Vault is Initializable { address payable owner; function initialize(address payable _owner) initializer public { owner = _owner; } function withdraw() public { require(owner == msg.sender); owner.transfer(address(this).balance); } } 我们将计算Vault将要部署的地址,并将以太币发送到那里。然后,我们将Vault使用CREATE2并调用该withdraw方法进行部署,检索在部署之前发送给它的资金。 虽然这个简单的例子听起来很傻,但能够与尚不存在的合约交互是一个非常强大的工具,并且是状态通道、入职解决方案和抢先预防计划背后的关键构建块。计算部署地址回想一下,只有智能合约可以使用CREATE2:为了让 OpenZeppelin CLI 能够提供等效的行为,我们需要先进行一些设置。 在底层,CLI 将使用合约工厂来部署来自 Solidity 的可升级合约。这意味着我们需要使用两个不经常使用的低级 CLI 命令:oz add和oz push:$ npx oz add ? Pick which contracts you want to add Vault ✓ Added contract Vault $ npx oz push ✓ Contract Vault deployed All contracts have been deployed 您可以在不了解幕后情况的情况下安全使用CREATE2,但如果您想深入了解血淋淋的细节,请从了解OpenZeppelin 升级代理开始。 有了这个设置,我们可以通过调用任意命令查询CLI 以获取我们的合约将被部署的地址:saltoz create2$ npx oz create2 --query --salt 12345 --network development ✓ Deployed ProxyFactory at 0x4e08589Cd399474157f24f591B9fB100D1adD5d9 Any contract created with salt 12345 will be deployed to the following address 0x4e08589Cd399474157f24f591B9fB100D1adD5d9 整洁的!我们现在可以与计算出的地址进行交互,知道我们以后可以在那里部署合约。与反事实合约交互在正常情况下,将资金发送到随机的以太坊地址是一个坏主意。然而,在这里,我们知道我们将能够Vault在计算出的地址进行部署并取回我们的资金。所以让我们开始吧! 发送 Ether 的最简单方法是使用oz transfer:$ $ npx oz transfer ? Pick a network development ? Choose the account to send transactions from (0) 0xA84577357099567A750f542C2C002B0aA680d477 ? Enter the receiver account 0x98329e006610472e6B372C080833f6D79ED833cf ? Enter an amount to transfer 10 ether ✓ Funds sent. Transaction hash: 0x9cff31198a80cefb9541e5cf406433f985490a4d786b72bb7e07139ae293657d 因为该地址没有字节码,我们也没有它的私钥,所以除了检查资金是否确实存在之外,我们无能为力:$ npx oz balance ? Enter an address to query its balance 0x98329e006610472e6B372C080833f6D79ED833cf Balance: 10 ETH 让我们把他们找回来。退出我们的VaultCREATE2dpeloyments 使用相同的oz create2命令执行,这次没有--query选项。 回想一下,它的所有者Vault有一个initialize方法:我们将使用我们控制的一个帐户来调用它。$ npx oz create2 Vault --salt 12345 --init --args 0xA84577357099567A750f542C2C002B0aA680d477 --network development ✓ Instance created at 0x98329e006610472e6B372C080833f6D79ED833cf 如果一切顺利,我们现在应该能够withdraw从我们的Vault:$ npx oz send-tx ? Pick a network development ? Pick an instance Vault at 0x272F769068bDB8740e44E6e0E852b97c8C4865b0 ? Select which function withdraw() ✓ Transaction successful. Transaction hash: 0xb0a67ba8a198a0d86814519ed12de8fbeaaaab151ae3b70f67a608236627ec4b 成功!可以肯定的是,让我们验证一下Vault确实是空的:$ npx oz balance ? Enter an address to query its balance 0x98329e006610472e6B372C080833f6D79ED833cf Balance: 0 ETH 我们已经将资金发送到我们预先计算好的地址,知道我们以后可以在那里部署合约并取回它们。作为奖励,我们的Vault合约可以通过oz upgrade! ## Publication Information - [kool](https://paragraph.com/@kool/): Publication homepage - [All Posts](https://paragraph.com/@kool/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@kool): Subscribe to updates