-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add EIP: Minimal Upgradable Proxy Contract #7229
Changes from all commits
3f1510e
7b4397c
3733147
e06a07d
dbc9287
dc3d4a8
b463e85
2dbe6de
b69f11d
8184ce4
6214913
62fdc1d
7a6d177
0de4b2a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,249 @@ | ||||||||||||||||||||||||||||||
--- | ||||||||||||||||||||||||||||||
eip: 7229 | ||||||||||||||||||||||||||||||
title: Minimal Upgradable Proxy Contract | ||||||||||||||||||||||||||||||
description: A lightweight contract upgrade pattern designed to save gas costs while providing the ability to upgrade contracts. | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should probably mention custom assembly in here somewhere. |
||||||||||||||||||||||||||||||
author: xiaobaiskill (@xiaobaiskill) | ||||||||||||||||||||||||||||||
discussions-to: https://ethereum-magicians.org/t/eip-xxxx-minimal-upgradable-proxy/14754 | ||||||||||||||||||||||||||||||
status: Draft | ||||||||||||||||||||||||||||||
type: Standards Track | ||||||||||||||||||||||||||||||
category: ERC | ||||||||||||||||||||||||||||||
created: 2023-06-24 | ||||||||||||||||||||||||||||||
--- | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Abstract | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
This proposal introduces the Minimal Upgradable Contract, a lightweight alternative to the existing upgradable contract implementation provided by OpenZeppelin. The Minimal Upgradable Contract aims to significantly reduce gas consumption during deployment while maintaining upgradability features. | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The abstract should be a terse technical summary of the proposal. The reader should be able to get a high level understanding of how the proposal accomplishes its goal (in this case, handrolled assembly.) |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Motivation | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Current upgradable contract solutions, such as OpenZeppelin's [ERC-1967](./eip-1967.md) implementation, often incur high gas costs during deployment. The goal of this proposal is to present an alternative approach that offers a significant reduction in gas consumption while maintaining the ability to upgrade contract logic. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Specification | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The exact bytecode of the standard minimal upgradable contract is this: | ||||||||||||||||||||||||||||||
`7fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx73yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy81556009604c3d396009526010605560293960395ff3365f5f375f5f365f7f545af43d5f5f3e3d5f82603757fd5bf3`; In this bytecode, the 1st to 32nd byte (inclusive) needs to be replaced with a 32-byte slot, and the 34th to 53rd byte (inclusive) needs to be replaced with a 20-byte address. | ||||||||||||||||||||||||||||||
Please note that the placeholders `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` represent the 32-byte slot and `yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy` represents the 20-byte address. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should probably mention what the "slot" and "address" mean. To someone very familiar with solidity/proxies, it's obvious that the address is the implementation contract, but it's good to be explicit. |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Rationale | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The Minimal Upgradeable Contract proposal introduces a novel approach to minimize gas consumption while preserving the upgradability feature of smart contracts. By predefining the slot that stores the logic contract during the contract creation phase, we can optimize gas efficiency during contract execution by directly accessing and performing delegate calls to the logic contract stored in the designated slot. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The rationale behind this approach is to eliminate the need for additional storage operations or costly lookups, which are commonly required in traditional upgradeable contract implementations. By predefining the slot and accessing the logic contract directly, we achieve significant gas savings and improve overall contract performance. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Key considerations for adopting this rationale include: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
1、 Gas Optimization: By eliminating redundant storage operations and lookup procedures, we reduce gas consumption during contract execution. This optimization ensures that the contract remains cost-effective, especially when performing frequent contract calls or upgrades. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
2、 Deterministic Contract Logic: By fixing the slot for storing the logic contract during contract creation, we establish a deterministic relationship between the contract and its logic. This deterministic mapping enables seamless contract upgrades without requiring additional storage or lookup mechanisms. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
3、 Contract Compatibility: The rationale aligns with existing Ethereum Virtual Machine (EVM) environments and does not introduce any compatibility issues or modifications to the underlying infrastructure. It can be easily integrated into the current Ethereum ecosystem, ensuring seamless adoption by developers and users. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
4、 Developer-Friendly Implementation: The rationale simplifies the implementation process for upgradeable contracts. By providing a straightforward mechanism to access and delegate calls to the logic contract, developers can focus on contract logic and functionality rather than complex storage management. | ||||||||||||||||||||||||||||||
Comment on lines
+36
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
By adopting this rationale, we aim to strike a balance between gas efficiency and contract upgradability. It allows developers to deploy upgradeable contracts with minimal gas consumption, making them more accessible and economically viable for a wide range of applications. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
### Gas Efficiency | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Compared to existing upgradable contract solutions, the Minimal Upgradable Contract demonstrates a significant reduction in gas consumption during deployment. While OpenZeppelin's [ERC-1967](./eip-1967.md) implementation may consumes nearly several hundred thousand gas for deployment, the Minimal Upgradable Contract can be deployed with just a few tens of thousands of gas, resulting in substantial cost savings. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
- [Transaction deploying the Minimal Upgradable Contract (32bytes slot)](../assets/eip-7229/img/minimal-upgradable-proxy-32slot.png) | ||||||||||||||||||||||||||||||
- [Transaction deploying the Minimal Upgradable Contract (1bytes slot)](../assets/eip-7229/img/minimal-upgradable-proxy-1slot.png) | ||||||||||||||||||||||||||||||
- [Transaction deploying using OpenZeppelin's ERC-1967](../assets/eip-7229/img/openzepplin-ERC-1967.png) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
### Implementation | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
A reference implementation of the Minimal Upgradable Contract, including the proxy contract and an example implementation contract, will be provided as open-source code. This implementation will serve as a starting point for developers to adopt and customize the Minimal Upgradable Contract in their projects. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#### Example implementations | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
- [deploy proxy contract when deploying logic contract (32bytes slot)](../assets/eip-7229/contracts/mock/mock32/Example.sol) | ||||||||||||||||||||||||||||||
- [deploy proxy contract (32bytes slot)](../assets/eip-7229/contracts/mock/mock32/DeployContract.sol) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
- [deploy proxy contract when deploying logic contract (1bytes slot)](../assets/eip-7229/contracts/mock/mock1/Example.sol) | ||||||||||||||||||||||||||||||
- [deploy proxy contract (1bytes slot)](../assets/eip-7229/contracts/mock/mock1/DeployContract.sol) | ||||||||||||||||||||||||||||||
Comment on lines
+55
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should should move this to the Reference Implementation section (after Test Cases.) |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#### Standard Proxy | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The disassembly of the standard deployed proxy contract code | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
# store logic address to slot of proxy contract | ||||||||||||||||||||||||||||||
PUSH32 <slot> [slot] | ||||||||||||||||||||||||||||||
PUSH20 <logicAddress> [logicAddress slot] | ||||||||||||||||||||||||||||||
DUP2 [slot logicAddress slot] | ||||||||||||||||||||||||||||||
SSTORE [slot] => storage(slot => logicAddress) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# return deployedCode | ||||||||||||||||||||||||||||||
PUSH1 0x9 [0x9 slot] | ||||||||||||||||||||||||||||||
PUSH1 0x4c [0x4c 0x9 slot] | ||||||||||||||||||||||||||||||
PUSH0 [00 0x4c 0x9 slot] | ||||||||||||||||||||||||||||||
CODECOPY [slot] ==> memory(0x00~0x8: 0x4c~0x54(deployedCode1stPart)) | ||||||||||||||||||||||||||||||
PUSH1 0x9 [0x9 slot] | ||||||||||||||||||||||||||||||
MSTORE [] ==> memory(0x9~0x28: slot(deployedCode2ndPart)) | ||||||||||||||||||||||||||||||
PUSH1 0x10 [0x10] | ||||||||||||||||||||||||||||||
PUSH1 0x55 [0x55 0x10] | ||||||||||||||||||||||||||||||
PUSH1 0x29 [0x29 0x55 0x10] | ||||||||||||||||||||||||||||||
CODECOPY [] ==> memory(0x29~0x38: 0x55~0x64(deployedCode3rdPart)) | ||||||||||||||||||||||||||||||
PUSH1 0x39 [0x39] | ||||||||||||||||||||||||||||||
PUSH0 [00 0x39] | ||||||||||||||||||||||||||||||
RETURN | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# proxy contract (deployedcode) | ||||||||||||||||||||||||||||||
CALLDATASIZE [calldatasize] | ||||||||||||||||||||||||||||||
PUSH0 [00 calldatasize] | ||||||||||||||||||||||||||||||
PUSH0 [00 00 calldatasize] | ||||||||||||||||||||||||||||||
CALLDATACOPY [] ==> memory(00~(calldatasize-1) => codedata) | ||||||||||||||||||||||||||||||
PUSH0 [00] | ||||||||||||||||||||||||||||||
PUSH0 [00 00] | ||||||||||||||||||||||||||||||
CALLDATASIZE [calldatasize 00 00] | ||||||||||||||||||||||||||||||
PUSH0 [00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
PUSH32 [slot 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
SLOAD [logicAddress 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
GAS [gas logicAddress 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
DELEGATECALL [result] | ||||||||||||||||||||||||||||||
RETURNDATASIZE [returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 00 returnDataSize result] | ||||||||||||||||||||||||||||||
RETURNDATACOPY [result] => memory(00~(RETURNDATASIZE - 1) => RETURNDATA) | ||||||||||||||||||||||||||||||
RETURNDATASIZE [returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 returnDataSize result] | ||||||||||||||||||||||||||||||
DUP3 [result 00 returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH1 0x37 [0x37 result 00 returnDataSize result] | ||||||||||||||||||||||||||||||
JUMPI [00 returnDataSize result] | ||||||||||||||||||||||||||||||
REVERT [result] | ||||||||||||||||||||||||||||||
JUMPDEST [00 returnDataSize result] | ||||||||||||||||||||||||||||||
RETURN [result] | ||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
NOTE: To push a zero value onto the stack without abusing the `RETURNDATASIZE` opcode, the above code utilizes [EIP-3855](./eip-3855.md). It achieves this by using the `PUSH0` instruction to push the zero value. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#### Storage slot of 1 byte optimization | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
To further optimize the minimal upgradeable proxy by controlling the slot value for the logic address within 1 ~ 255(inclusive), you can use the following opcode to reduce gas consumption: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
# store logic address to slot of proxy contract | ||||||||||||||||||||||||||||||
PUSH1 <slot> [slot] | ||||||||||||||||||||||||||||||
PUSH20 <logicAddress> [logicAddress slot] | ||||||||||||||||||||||||||||||
DUP2 [slot logicAddress slot] | ||||||||||||||||||||||||||||||
SSTORE [slot] => storage(slot => logicAddress) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# return deployedCode | ||||||||||||||||||||||||||||||
PUSH1 0x9 [0x9 slot] | ||||||||||||||||||||||||||||||
PUSH1 0x30 [0x30 0x9 slot] | ||||||||||||||||||||||||||||||
PUSH0 [00 0x30 0x9 slot] | ||||||||||||||||||||||||||||||
CODECOPY [slot] ==> memory(0x00~0x8: 0x30~0x38(deployedCode1stPart)) | ||||||||||||||||||||||||||||||
PUSH1 0xf8 [0xf8 slot] | ||||||||||||||||||||||||||||||
SHL [slotAfterShl] | ||||||||||||||||||||||||||||||
PUSH1 0x9 [0x9 slotAfterShl] | ||||||||||||||||||||||||||||||
MSTORE [] ==> memory(0x9: slotAfterShl(deployedCode2ndPart)) | ||||||||||||||||||||||||||||||
PUSH1 0x10 [0x10] | ||||||||||||||||||||||||||||||
PUSH1 0x39 [0x39 0x10] | ||||||||||||||||||||||||||||||
PUSH1 0xa [0xa 0x39 0x10] | ||||||||||||||||||||||||||||||
CODECOPY [] ==> memory(0xa~0x19: 0x39~0x48(deployedCode3rdPart)) | ||||||||||||||||||||||||||||||
PUSH1 0x1a [0x1a] | ||||||||||||||||||||||||||||||
PUSH0 [00 0x1a] | ||||||||||||||||||||||||||||||
RETURN | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# proxy contract (deployedcode) | ||||||||||||||||||||||||||||||
CALLDATASIZE [calldatasize] | ||||||||||||||||||||||||||||||
PUSH0 [00 calldatasize] | ||||||||||||||||||||||||||||||
PUSH0 [00 00 calldatasize] | ||||||||||||||||||||||||||||||
CALLDATACOPY [] ==> memory(00~(calldatasize-1) => codedata) | ||||||||||||||||||||||||||||||
PUSH0 [00] | ||||||||||||||||||||||||||||||
PUSH0 [00 00] | ||||||||||||||||||||||||||||||
CALLDATASIZE [calldatasize 00 00] | ||||||||||||||||||||||||||||||
PUSH0 [00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
PUSH1 [slot 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
SLOAD [logicAddress 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
GAS [gas logicAddress 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
DELEGATECALL [result] | ||||||||||||||||||||||||||||||
RETURNDATASIZE [returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 00 returnDataSize result] | ||||||||||||||||||||||||||||||
RETURNDATACOPY [result] => memory(00~(RETURNDATASIZE - 1) => RETURNDATA) | ||||||||||||||||||||||||||||||
RETURNDATASIZE [returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 returnDataSize result] | ||||||||||||||||||||||||||||||
DUP3 [result 00 returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH1 0x18 [0x18 result 00 returnDataSize result] | ||||||||||||||||||||||||||||||
JUMPI [00 returnDataSize result] | ||||||||||||||||||||||||||||||
REVERT [result] | ||||||||||||||||||||||||||||||
JUMPDEST [00 returnDataSize result] | ||||||||||||||||||||||||||||||
RETURN [result] | ||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The bytecode generated by the above opcodes is as follows `60xx73yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy8155600960305f3960f81b60095260106039600a39601a5ff3365f5f375f5f365f60545af43d5f5f3e3d5f82601857fd5bf3`, replace `xx` to a slot of 1byte and replace `yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy` to a address of 20bytes before deploying contract | ||||||||||||||||||||||||||||||
Comment on lines
+122
to
+177
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're introducing new content in your rationale section. The rationale section should only explain the stuff in the specification section, and shouldn't introduce any new requirements. |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#### Optimization for Logic Address Storage in Slot 0 | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
To further optimize the minimal upgradeable proxy by controlling the slot value for the logic address to 0, you can use the following opcode to reduce gas consumption: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
# store logic address to slot of proxy contract | ||||||||||||||||||||||||||||||
PUSH20 <logicAddress> [logicAddress] | ||||||||||||||||||||||||||||||
PUSH0 [00 logicAddress] | ||||||||||||||||||||||||||||||
SSTORE [] => storage(00 => logicAddress) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# return deployedCode | ||||||||||||||||||||||||||||||
PUSH1 0x9 [0x9] | ||||||||||||||||||||||||||||||
PUSH1 0x28 [0x28 0x9] | ||||||||||||||||||||||||||||||
PUSH0 [00 0x28 0x9] | ||||||||||||||||||||||||||||||
CODECOPY [] ==> memory(0x00~0x8: 0x28~0x30(deployedCode1stPart)) | ||||||||||||||||||||||||||||||
PUSH1 0x10 [0x10] | ||||||||||||||||||||||||||||||
PUSH1 0x31 [0x31 0x10] | ||||||||||||||||||||||||||||||
PUSH1 0x9 [0x9 0x31 0x10] | ||||||||||||||||||||||||||||||
CODECOPY [] ==> memory(0x9~0x19: 0x31~0x41(deployedCode2ndPart)) | ||||||||||||||||||||||||||||||
PUSH1 0x19 [0x19] | ||||||||||||||||||||||||||||||
PUSH0 [00 0x19] | ||||||||||||||||||||||||||||||
RETURN | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
# proxy contract (deployedcode) | ||||||||||||||||||||||||||||||
CALLDATASIZE [calldatasize] | ||||||||||||||||||||||||||||||
PUSH0 [00 calldatasize] | ||||||||||||||||||||||||||||||
PUSH0 [00 00 calldatasize] | ||||||||||||||||||||||||||||||
CALLDATACOPY [] ==> memory(00~(calldatasize-1) => codedata) | ||||||||||||||||||||||||||||||
PUSH0 [00] | ||||||||||||||||||||||||||||||
PUSH0 [00 00] | ||||||||||||||||||||||||||||||
CALLDATASIZE [calldatasize 00 00] | ||||||||||||||||||||||||||||||
PUSH0 [00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
PUSH0 [00 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
SLOAD [logicAddress 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
GAS [gas logicAddress 00 calldatasize 00 00] | ||||||||||||||||||||||||||||||
DELEGATECALL [result] | ||||||||||||||||||||||||||||||
RETURNDATASIZE [returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 00 returnDataSize result] | ||||||||||||||||||||||||||||||
RETURNDATACOPY [result] => memory(00~(RETURNDATASIZE - 1) => RETURNDATA) | ||||||||||||||||||||||||||||||
RETURNDATASIZE [returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH0 [00 returnDataSize result] | ||||||||||||||||||||||||||||||
DUP3 [result 00 returnDataSize result] | ||||||||||||||||||||||||||||||
PUSH1 0x17 [0x17 result 00 returnDataSize result] | ||||||||||||||||||||||||||||||
JUMPI [00 returnDataSize result] | ||||||||||||||||||||||||||||||
REVERT [result] | ||||||||||||||||||||||||||||||
JUMPDEST [00 returnDataSize result] | ||||||||||||||||||||||||||||||
RETURN [result] | ||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
The bytecode generated by the above opcodes is as follows `73yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy5f55600960285f396010603160093960195ff3365f5f375f5f365f5f545af43d5f5f3e3d5f82601757fd5bf3`, replace `yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy` to a address of 20bytes before deploying contract | ||||||||||||||||||||||||||||||
Comment on lines
+180
to
+230
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Test Cases | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
You can use the following commands: | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
cd ../assets/eip-7229 | ||||||||||||||||||||||||||||||
npm install | ||||||||||||||||||||||||||||||
npx hardhat test | ||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Security Considerations | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
None. | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sure there are at least some security considerations 🙃
Suggested change
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
## Copyright | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Copyright and related rights waived via [CC0](../LICENSE.md). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
artifacts | ||
cache | ||
node_modules | ||
package-lock.json | ||
typechain |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,43 @@ | ||||||
// SPDX-License-Identifier: UNLICENSED | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
We can't have UNLICENSED code in the EIPs repository. |
||||||
pragma solidity ^0.8.13; | ||||||
|
||||||
contract PayableTokenV1 { | ||||||
address private implementation; | ||||||
address public owner; | ||||||
uint256 public number; | ||||||
|
||||||
event Upgraded(address indexed implementation); | ||||||
|
||||||
receive() external payable { | ||||||
number += 1; | ||||||
} | ||||||
|
||||||
fallback() external payable { | ||||||
number += 2; | ||||||
} | ||||||
|
||||||
modifier OnlyOwner() { | ||||||
require(owner == msg.sender, "only owner"); | ||||||
_; | ||||||
} | ||||||
|
||||||
function init() external { | ||||||
owner = msg.sender; | ||||||
} | ||||||
|
||||||
function getImplementSlot() external pure returns (bytes32 slot) { | ||||||
assembly { | ||||||
slot := implementation.slot | ||||||
} | ||||||
} | ||||||
|
||||||
function upgrade(address _newImplementation) external OnlyOwner { | ||||||
implementation = _newImplementation; | ||||||
emit Upgraded(_newImplementation); | ||||||
} | ||||||
|
||||||
function setNumber(uint256 _number) external payable { | ||||||
require(msg.value >= 1 ether, "Insufficient amount"); | ||||||
number = _number; | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No |
||
pragma solidity ^0.8.13; | ||
|
||
contract PayableTokenV2 { | ||
address private implementation; | ||
address public owner; | ||
uint256 public number; | ||
|
||
event Upgraded(address indexed implementation); | ||
|
||
modifier OnlyOwner() { | ||
require(owner == msg.sender, "only owner"); | ||
_; | ||
} | ||
|
||
function init() external { | ||
owner = msg.sender; | ||
} | ||
|
||
function getImplementSlot() external pure returns (bytes32 slot) { | ||
assembly { | ||
slot := implementation.slot | ||
} | ||
} | ||
|
||
function upgrade(address _newImplementation) external OnlyOwner { | ||
implementation = _newImplementation; | ||
emit Upgraded(_newImplementation); | ||
} | ||
|
||
function setNumber(uint256 _number) external payable { | ||
require(msg.value >= 1 ether, "Insufficient amount"); | ||
number = _number; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// SPDX-License-Identifier: MIT | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We prefer |
||
pragma solidity ^0.8.13; | ||
|
||
contract SimV1 { | ||
address public owner; | ||
uint256 public number; | ||
address private implementation; | ||
|
||
event Upgraded(address indexed implementation); | ||
|
||
constructor(uint256 _number) { | ||
number = _number; | ||
} | ||
|
||
modifier OnlyOwner() { | ||
require(owner == msg.sender, "only owner"); | ||
_; | ||
} | ||
|
||
function init() external { | ||
owner = msg.sender; | ||
} | ||
|
||
function getImplementSlot() external pure returns (bytes32 slot) { | ||
assembly { | ||
slot := implementation.slot | ||
} | ||
} | ||
|
||
function upgrade(address _newImplementation) external OnlyOwner { | ||
implementation = _newImplementation; | ||
emit Upgraded(_newImplementation); | ||
} | ||
|
||
function setNumber(uint256 _number) external OnlyOwner { | ||
number = _number; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your title doesn't differentiate itself enough form the other proxy contract standards. Maybe something like: