/** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 // 这是“eip1967.proxy.rollback”的 keccak-256 哈希减 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ // 带有当前实现地址的存储槽。这是“eip1967.proxy.implementation”的 keccak-256 哈希减 1,并在构造函数中验证。 bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation);
/** * @dev Returns the current implementation address. */ // 返回当前的逻辑合约地址。 function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; }
/** * @dev Stores a new address in the EIP1967 implementation slot. */ // 在 EIP1967 实现槽中存储一个新地址。 function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; }
/** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ // 执行逻辑合约升级操作,并额外使用 delegatecall 来调用传入的 data function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } }
/** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ // 执行逻辑合约升级操作,对 UUPS 代理进行安全检查,并额外使用 delegatecall 来调用传入的 data function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. //从旧实现升级将执行回滚测试。 此测试需要新的实施升级回旧的、不符合 ERC1822 的实施。 删除这种特殊情况将打破从旧 UUPS 实施到新 UUPS 实施的升级路径。 if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } }
/** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ //这是“eip1967.proxy.admin”的 keccak-256 哈希减 1,并且是在构造函数中验证。 bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin);
/** * @dev Returns the current admin. */ // 返回当前管理员 function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; }
/** * @dev Stores a new address in the EIP1967 admin slot. */ // 添加新的管理员 function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; }
/** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ // 更改管理员 function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); }
/** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ // UpgradeableBeacon 合约的存储槽,它定义了这个代理的实现。 // 这是 bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) 并在构造函数中验证。 bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon);
/** * @dev Returns the current beacon. */ // 返回当前 beacon function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; }
/** * @dev Stores a new beacon in the EIP1967 beacon slot. */ // 添加一个新的 beacon function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; }
/** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ // 通过额外的delegatecall调用执行信标升级。 注意:这会升级信标的地址,它不会升级信标中包含的实现(参见{UpgradeableBeacon-_setImplementation})。 function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Proxy.sol";
/** * @dev This contract implements a proxy that is upgradeable by an admin. * * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector * clashing], which can potentially be used in an attack, this contract uses the * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two * things that go hand in hand: * * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if * that call matches one of the admin functions exposed by the proxy itself. * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the * implementation. If the admin tries to call a function on the implementation it will fail with an error that says * "admin cannot fallback to proxy target". * * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due * to sudden errors when trying to call a function from the proxy implementation. * * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. */ // 初始化由 `_admin` 管理的可升级代理,由 `_logic` 作为逻辑合约,以及如 {ERC1967Proxy-constructor} 中所述,可选择使用 `_data` 进行初始化。 constructor( address _logic, address admin_, bytes memory _data ) payable ERC1967Proxy(_logic, _data) { _changeAdmin(admin_); }
/** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. */ // 如果不是管理员,则会使用 delegatecall 来调用逻辑合约 modifier ifAdmin() { if (msg.sender == _getAdmin()) { _; } else { _fallback(); } }
/** * @dev Returns the current admin. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ // 只有管理员能调用这个函数 function admin() external ifAdmin returns (address admin_) { admin_ = _getAdmin(); }
/** * @dev Returns the current implementation. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ // 返回当前的逻辑合约 function implementation() external ifAdmin returns (address implementation_) { implementation_ = _implementation(); }
/** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. * * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ function changeAdmin(address newAdmin) external virtual ifAdmin { _changeAdmin(newAdmin); }
/** * @dev Upgrade the implementation of the proxy. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ // 升级逻辑合约 function upgradeTo(address newImplementation) external ifAdmin { _upgradeToAndCall(newImplementation, bytes(""), false); }
/** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. */ // 升级逻辑合约,并额外使用 delegatecall 调用 data function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin { _upgradeToAndCall(newImplementation, data, true); }
/** * @dev Returns the current admin. */ // 返回现在的管理员 function _admin() internal view virtual returns (address) { return _getAdmin(); }
/** * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. */ // 确保管理员无法访问 Fallback 函数 function _beforeFallback() internal virtual override { require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); super._beforeFallback(); } }
/** * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. */ contract ProxyAdmin is Ownable { /** * @dev Returns the current implementation of `proxy`. * * Requirements: * * - This contract must be the admin of `proxy`. */ // 返回代理合约的逻辑合约,并要求此合约必须是代理合约的管理员 function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); require(success); return abi.decode(returndata, (address)); }
/** * @dev Returns the current admin of `proxy`. * * Requirements: * * - This contract must be the admin of `proxy`. */ // 返回代理合约的管理员,并要求此合约必须是代理合约的管理员 function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); require(success); return abi.decode(returndata, (address)); }
/** * @dev Changes the admin of `proxy` to `newAdmin`. * * Requirements: * * - This contract must be the current admin of `proxy`. */ // 更改代理合约的管理员,并要求此合约必须是代理合约的管理员 function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { proxy.changeAdmin(newAdmin); }
/** * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. * * Requirements: * * - This contract must be the admin of `proxy`. */ // 升级,并要求此合约必须是代理合约的管理员 function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { proxy.upgradeTo(implementation); }
/** * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See * {TransparentUpgradeableProxy-upgradeToAndCall}. * * Requirements: * * - This contract must be the admin of `proxy`. */ // 升级,额外使用 delegatecall 调用 data,并要求此合约必须是代理合约的管理员 function upgradeAndCall( TransparentUpgradeableProxy proxy, address implementation, bytes memory data ) public payable virtual onlyOwner { proxy.upgradeToAndCall{value: msg.value}(implementation, data); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ // 返回可代理合约假定用于存储实现地址的存储槽。 // 指向可代理合约的代理本身不应该被认为是可代理的,因为这可能会通过委托给自己直到耗尽gas而破坏升级到它的代理。 因此,如果通过代理调用此函数,则该函数revert至关重要。 function proxiableUUID() external view returns (bytes32); }
/** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this);
/** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ // 检查执行是否通过委托调用执行,并且执行上下文是一个代理合约,其实现(如 ERC1967 中定义)指向 self. 这应该只适用于使用当前合同作为其实现的 UUPS 和透明代理。通过 ERC1167 最小代理(克隆)执行函数通常不会通过此测试,但不能保证会失败。 modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; }
/** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ // 检查执行是否不是通过委托调用执行的。这允许函数可以在执行合约上调用,但不能通过代理调用。 modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; }
/** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ // ERC1822proxiableUUID功能的实现。这将返回实现使用的存储槽。它用于验证此实现在升级后是否仍然有效。 // 指向可代理合约的代理本身不应该被认为是可代理的,因为这可能会通过委托给自己直到耗尽gas而破坏升级到它的代理。因此,如果通过代理调用此函数,则该函数恢复至关重要。这是由notDelegated修饰符保证的。 function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; }
/** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ // 将代理的实施升级到newImplementation. function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); }
/** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ // 将代理的实现升级到newImplementation,然后执行编码在 中的函数调用data。 function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); }
/** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ // 当 `msg.sender` 无权升级合约时应该revert的功能。 function _authorizeUpgrade(address newImplementation) internal virtual; }
/** * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. * * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't * conflict with the storage layout of the implementation behind the proxy. * * _Available since v3.4._ */ contract BeaconProxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the proxy with `beacon`. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity * constructor. * * Requirements: * * - `beacon` must be a contract with the interface {IBeacon}. */ // 初始化 beacon 代理 // 如果 `data` 不为空,它会在对信标返回的实现的委托调用中用作数据。 这通常是一个编码的函数调用,并允许像 Solidity 构造函数一样初始化代理的存储 constructor(address beacon, bytes memory data) payable { _upgradeBeaconToAndCall(beacon, data, false); }
/** * @dev Returns the current beacon address. */ // 返回当前信标地址 function _beacon() internal view virtual returns (address) { return _getBeacon(); }
/** * @dev Returns the current implementation address of the associated beacon. */ // 返回关联信标的当前逻辑合约地址 function _implementation() internal view virtual override returns (address) { return IBeacon(_getBeacon()).implementation(); }
/** * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. * * Requirements: * * - `beacon` must be a contract. * - The implementation returned by `beacon` must be a contract. */ // 更改代理以使用新信标。已弃用,参阅 _upgradeBeaconToAndCall function _setBeacon(address beacon, bytes memory data) internal virtual { _upgradeBeaconToAndCall(beacon, data, false); } }
IBeacon
接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ // 必须返回可用作委托调用目标的地址。 function implementation() external view returns (address); }
/** * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their * implementation contract, which is where they will delegate all function calls. * * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. */ contract UpgradeableBeacon is IBeacon, Ownable { address private _implementation;
/** * @dev Emitted when the implementation returned by the beacon is changed. */ event Upgraded(address indexed implementation);
/** * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the * beacon. */ // 设置初始实现的地址,部署者帐户为可以升级信标的所有者。 constructor(address implementation_) { _setImplementation(implementation_); }
/** * @dev Returns the current implementation address. */ // 返回当前逻辑合约地址 function implementation() public view virtual override returns (address) { return _implementation; }
/** * @dev Upgrades the beacon to a new implementation. * * Emits an {Upgraded} event. * * Requirements: * * - msg.sender must be the owner of the contract. * - `newImplementation` must be a contract. */ // 升级信标 // 要求:msg.sender必须是合同的所有者。newImplementation必须是合同。 function upgradeTo(address newImplementation) public virtual onlyOwner { _setImplementation(newImplementation); emit Upgraded(newImplementation); }
/** * @dev Sets the implementation contract address for this beacon * * Requirements: * * - `newImplementation` must be a contract. */ // 设置此信标的实现合约地址 function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract"); _implementation = newImplementation; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)
pragma solidity ^0.8.0;
/** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ // 部署并返回模仿其行为的克隆的地址 implementation。此函数使用创建操作码,该操作码不应还原。 function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(0, 0x09, 0x37) } require(instance != address(0), "ERC1167: create failed"); }
/** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ // 部署并返回模仿“实现”行为的克隆的地址。 // 此函数使用 create2 操作码和 `salt` 来确定性地部署克隆。 多次使用相同的 `implementation` 和 `salt` 将 revert,因为克隆不能在同一地址部署两次。 function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(0, 0x09, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); }
/** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ // 计算使用 {Clones-cloneDeterministic} 部署的克隆的地址。 function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := keccak256(add(ptr, 0x43), 0x55) } }
/** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ // 计算使用 {Clones-cloneDeterministic} 部署的克隆的地址。 function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
function upgrade(address implementation) external onlyProxyOwner { _setImplementation(implementation); }
function _setImplementation(address imp) private { implementation = imp; }
function () payable external { address impl = implementation;
assembly { calldatacopy(0, 0, calldatasize) let result := delegatecall(gas, impl, 0, calldatasize, 0, 0) returndatacopy(0, 0, returndatasize)
switch result case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } }
// This is the function we're adding now function collate_propagate_storage(bytes16) external { implementation.delegatecall(abi.encodeWithSignature( "transfer(address,uint256)", proxyOwner, 1000 )); } }
// Fun Fact: An ExplodingKitten can be exploded by another ExplodingKitten contract ExplodingKitten is UUPSUpgradeable { bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
function explode() public { StorageSlotUpgradeable.BooleanSlot storage rollbackTesting = StorageSlotUpgradeable.getBooleanSlot( _ROLLBACK_SLOT ); rollbackTesting.value = true; selfdestruct(payable(msg.sender)); }
// Any can call upgrade function _authorizeUpgrade(address newImplementation) internal override {} }
// Verify logic contract is zero // 验证逻辑合约为0 expect(await ethers.provider.getCode(implementationAddress)).to.equal("0x");
// Verify that proxy is no longer functioning // 验证代理不再运行 await expect(simpleToken.balanceOf(deployer.address)).to.be.reverted; await expect(simpleToken.totalSupply()).to.be.reverted;
// Verify that proxy can no longer upgrade // 验证代理不能再进行升级 const SimpleTokenV2 = await ethers.getContractFactory("SimpleTokenV2"); const simpleTokenV2 = await SimpleTokenV2.deploy(); // Tx 不会失败,因为它与现在发送到没有代码的地址相同 await simpleToken.upgradeTo(simpleTokenV2.address); // Tx not failing as it's same as sending to an address without code now
// Verify that the implementation code did not upgrade and is irrecoverable // 验证实现代码未升级且不可恢复 expect(await getImplementationAddress(simpleToken.address)).to.equal( implementationAddress ); await expect(simpleToken.balanceOf(deployer.address)).to.be.reverted; await expect(simpleToken.totalSupply()).to.be.reverted; }); });
为此目的编写的临时智能合约可以用作存储。因此,无论当前的代币代码版本如何,数据都将始终保存在该合约的存储中。该合约的代码可以移动到库中,但现在不在议程上。无需将数据从存储迁移到存储;相反,存储访问权限从一个版本转移到另一个版本。然而,使用这种类型的存储并非没有问题。它将需要定义一个可用于任何版本的代币智能合约的接口,例如类似 SQL 的或面向文档的。说到这种存储类型的例子,看看 EOS 表。让我们在数据方案