-
Notifications
You must be signed in to change notification settings - Fork 4
changes for SoulETH #19
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
Conversation
This reverts commit 06f9ecd.
| contract SoulGasToken is ERC20Upgradeable, OwnableUpgradeable { | ||
| /// @custom:storage-location erc7201:openzeppelin.storage.SoulGasToken | ||
| struct SoulGasTokenStorage { | ||
| // _minters are be whitelist EOAs, only used when !Constants.IS_SOUL_QKC | ||
| mapping(address => bool) _minters; | ||
| // _burners are whitelist EOAs, only used when !Constants.IS_SOUL_QKC | ||
| mapping(address => bool) _burners; | ||
| } | ||
|
|
||
| // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.SoulGasToken")) - 1)) & ~bytes32(uint256(0xff)) | ||
| bytes32 private constant _SOULGASTOKEN_STORAGE_LOCATION = | ||
| 0x135c38e215d95c59dcdd8fe622dccc30d04cacb8c88c332e4e7441bac172dd00; | ||
|
|
||
| function _getSoulGasTokenStorage() private pure returns (SoulGasTokenStorage storage $) { | ||
| assembly { | ||
| $.slot := _SOULGASTOKEN_STORAGE_LOCATION | ||
| } | ||
| } | ||
|
|
||
| constructor() { | ||
| _disableInitializers(); | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice initialize is used to initialize SoulGasToken contract. | ||
| function initialize( | ||
| string calldata name_, | ||
| string calldata symbol_, | ||
| address owner_, | ||
| address[] calldata minters_, | ||
| address[] calldata burners_ | ||
| ) | ||
| external | ||
| initializer | ||
| { | ||
| if (Constants.IS_SOUL_QKC) { | ||
| // when Constants.IS_SOUL_QKC, we want owner_ to be a dead account, we choose DEPOSITOR_ACCOUNT since | ||
| // transferOwnership doesn't accept zero address | ||
| require( | ||
| owner_ == Constants.DEPOSITOR_ACCOUNT, "owner_ should be DEPOSITOR_ACCOUNT when Constants.IS_SOUL_QKC" | ||
| ); | ||
| require(minters_.length == 0, "minters_ should be empty when Constants.IS_SOUL_QKC"); | ||
| require(burners_.length == 0, "burners_ should be empty when Constants.IS_SOUL_QKC"); | ||
| } else { | ||
| require( | ||
| owner_ != Constants.DEPOSITOR_ACCOUNT && owner_ != address(0), | ||
| "owner_ should not be neither DEPOSITOR_ACCOUNT nor zero when !Constants.IS_SOUL_QKC" | ||
| ); | ||
| } | ||
|
|
||
| // even though owner is only used when Constants.IS_SOUL_QKC, we always initialize the inherited | ||
| // OwnableUpgradeable | ||
| __Ownable_init(); | ||
| transferOwnership(owner_); | ||
| // initialize the inherited ERC20Upgradeable | ||
| __ERC20_init(name_, symbol_); | ||
|
|
||
| SoulGasTokenStorage storage $ = _getSoulGasTokenStorage(); | ||
| uint256 i; | ||
| for (i = 0; i < minters_.length; i++) { | ||
| $._minters[minters_[i]] = true; | ||
| } | ||
| for (i = 0; i < burners_.length; i++) { | ||
| $._burners[burners_[i]] = true; | ||
| } | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice deposit can be called by anyone to deposit native token for SoulGasToken when Constants.IS_SOUL_QKC. | ||
| function deposit() external payable { | ||
| require(Constants.IS_SOUL_QKC, "deposit should only be called when Constants.IS_SOUL_QKC"); | ||
|
|
||
| _mint(_msgSender(), msg.value); | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice batchDeposit can be called by anyone to deposit native token for SoulGasToken in batch when | ||
| /// Constants.IS_SOUL_QKC. | ||
| function batchDeposit(address[] calldata accounts, uint256[] calldata values) external payable { | ||
| require(accounts.length == values.length, "invalid arguments"); | ||
|
|
||
| require(Constants.IS_SOUL_QKC, "batchDeposit should only be called when Constants.IS_SOUL_QKC"); | ||
|
|
||
| uint256 totalValue = 0; | ||
| for (uint256 i = 0; i < accounts.length; i++) { | ||
| _mint(accounts[i], values[i]); | ||
| totalValue += values[i]; | ||
| } | ||
| require(msg.value == totalValue, "unexpected msg.value"); | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice batchMint is called: | ||
| /// 1. by EOA minters to mint SoulGasToken in batch when !Constants.IS_SOUL_QKC. | ||
| /// 2. by DEPOSITOR_ACCOUNT to refund SoulGasToken | ||
| function batchMint(address[] calldata accounts, uint256[] calldata values) external { | ||
| require(accounts.length == values.length, "invalid arguments"); | ||
|
|
||
| SoulGasTokenStorage storage $ = _getSoulGasTokenStorage(); | ||
| require(_msgSender() == Constants.DEPOSITOR_ACCOUNT || $._minters[_msgSender()], "not a minter"); | ||
|
|
||
| for (uint256 i = 0; i < accounts.length; i++) { | ||
| _mint(accounts[i], values[i]); | ||
| } | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice addMinters is called by the owner to add minters when !Constants.IS_SOUL_QKC. | ||
| function addMinters(address[] calldata minters_) external onlyOwner { | ||
| // addMinters should only be called when !Constants.IS_SOUL_QKC, but we don't check it explicitly since it's | ||
| // ensured by | ||
| // onlyOwner | ||
| SoulGasTokenStorage storage $ = _getSoulGasTokenStorage(); | ||
| uint256 i; | ||
| for (i = 0; i < minters_.length; i++) { | ||
| $._minters[minters_[i]] = true; | ||
| } | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice delMinters is called by the owner to delete minters when !Constants.IS_SOUL_QKC. | ||
| function delMinters(address[] calldata minters_) external onlyOwner { | ||
| // delMinters should only be called when !Constants.IS_SOUL_QKC, but we don't check it explicitly since it's | ||
| // ensured by onlyOwner | ||
| SoulGasTokenStorage storage $ = _getSoulGasTokenStorage(); | ||
| uint256 i; | ||
| for (i = 0; i < minters_.length; i++) { | ||
| delete $._minters[minters_[i]]; | ||
| } | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice addBurners is called by the owner to add burners when !Constants.IS_SOUL_QKC. | ||
| function addBurners(address[] calldata burners_) external onlyOwner { | ||
| // addBurners should only be called when !Constants.IS_SOUL_QKC, but we don't check it explicitly since it's | ||
| // ensured by onlyOwner | ||
| SoulGasTokenStorage storage $ = _getSoulGasTokenStorage(); | ||
| uint256 i; | ||
| for (i = 0; i < burners_.length; i++) { | ||
| $._burners[burners_[i]] = true; | ||
| } | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice delBurners is called by the owner to delete burners when !Constants.IS_SOUL_QKC. | ||
| function delBurners(address[] calldata burners_) external onlyOwner { | ||
| // delBurners should only be called when !Constants.IS_SOUL_QKC, but we don't check it explicitly since it's | ||
| // ensured by onlyOwner | ||
| SoulGasTokenStorage storage $ = _getSoulGasTokenStorage(); | ||
| uint256 i; | ||
| for (i = 0; i < burners_.length; i++) { | ||
| delete $._burners[burners_[i]]; | ||
| } | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice burnFrom is called: | ||
| /// 1. by the burner to burn SoulGasToken. | ||
| /// 2. by DEPOSITOR_ACCOUNT to burn SoulGasToken. | ||
| function burnFrom(address account, uint256 value) external { | ||
| SoulGasTokenStorage storage $ = _getSoulGasTokenStorage(); | ||
| require(_msgSender() == Constants.DEPOSITOR_ACCOUNT || $._burners[_msgSender()], "not the burner"); | ||
| _burn(account, value); | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice transferFrom is disabled for SoulGasToken. | ||
| function transfer(address, uint256) public virtual override returns (bool) { | ||
| revert("transfer is disabled for SoulGasToken"); | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice transferFrom is disabled for SoulGasToken. | ||
| function transferFrom(address, address, uint256) public virtual override returns (bool) { | ||
| revert("transferFrom is disabled for SoulGasToken"); | ||
| } | ||
|
|
||
| /// @custom:legacy | ||
| /// @notice approve is disabled for SoulGasToken. | ||
| function approve(address, uint256) public virtual override returns (bool) { | ||
| revert("approve is disabled for SoulGasToken"); | ||
| } | ||
| } |
Check warning
Code scanning / Slither
Contracts that lock Ether
op-bindings/predeploys/addresses.go
Outdated
| L1FeeVault = "0x420000000000000000000000000000000000001a" | ||
| SchemaRegistry = "0x4200000000000000000000000000000000000020" | ||
| EAS = "0x4200000000000000000000000000000000000021" | ||
| SoulETH = "0x42000000000000000000000000000000000000FE" |
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.
We can use an address that never conflicts with OP's. May be
"0x42000... 536f756c455448", where "536f756c455448" is the hex of "SoulETH".
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.
It's out of the range allowed for predeploys. There can be only 2048 predeploys with fixed prefix uint160(0x420) << 148:source . That is, we can only tweak the lowest 11 bits.
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.
Can we create a method like creating special predeploys?
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.
Making it special will make this PR harder to be accepted by upstream? And once it's accepted by upstream, there won't be collision. Maybe we just need to keep an eye on it for now?
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.
Changing the address to upstream's version will be easy, but changing the address will be much more difficult once we deploy the code.
| /// @notice Address of the EAS predeploy. | ||
| address internal constant EAS = 0x4200000000000000000000000000000000000021; | ||
|
|
||
| /// @notice Address of the SOUL_GAS_TOKEN predeploy. |
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.
I guess we should use an address that avoid potential collision with OP's
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.
As discussed, PREDEPLOY_COUNT is now 4096 and the address of SOUL_GAS_TOKEN is the 2048th predeploy address.
| function setSoulGasToken() public { | ||
| address impl = _setImplementationCode(Predeploys.SOUL_GAS_TOKEN); | ||
|
|
||
| if (Constants.IS_SOUL_QKC) { |
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.
Maybe we should change the name "isSoulQKC" to "backedByNative"?
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.
Good idea, I renamed it to IS_SOUL_BACKED_BY_NATIVE so that the context is clear.
| external | ||
| initializer | ||
| { | ||
| if (Constants.IS_SOUL_QKC) { |
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.
Since we already rely on owner_ to set minters_ and burners_, I think we can remove minters_ and burners_ parameters and set them later by owner
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.
Good point! Fixed.
|
|
||
| if (Constants.IS_SOUL_BACKED_BY_NATIVE) { | ||
| SoulGasToken(payable(impl)).initialize({ | ||
| name_: "SoulQKC", |
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.
I think we could use SoulGasToken for all the names.
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.
Fixed.
| // 1B,1C,1D,1E,1F: not used. | ||
| setSchemaRegistry(); // 20 | ||
| setEAS(); // 21 | ||
| setSoulGasToken(); // FE |
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.
The comment should be // 800?
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.
Fixed, I made a forced push to make the address change within a single commit.
…48th predeploy addr
2. split init calls from constructor to separate initializer
|
Close since already merged into op-es branch. |
…11776) * chore: configure medusa with basic supERC20 self-bridging (#19) - used --foundry-compile-all to ensure the test contract under `test/properties` is compiled (otherwise it is not compiled and medusa crashes when it can't find it's compiled representation) - set src,test,script to test/properties/medusa to not waste time compiling contracts that are not required for the medusa campaign - used an atomic bridge, which doesnt allow for testing of several of the proposed invariants fix: delete dead code test: give the fuzzer a head start docs: fix properties order test: document & implement assertions 22, 23 and 24 fix: fixes from self-review test: guide the fuzzer a little bit less previously: initial mint, bound on transfer amount: 146625 calls in 200s now: no initial mint, no bound on transfer amount: 176835 calls in 200s it doesn't seem to slow the fuzzer down fix: fixes after lovely feedback by disco docs: merge both documents and categorized properties by their milestone fix: fixes from parti's review fix: feedback from disco fix: feedback from doc refactor: separate state transitions from pure properties docs: update tested properties refactor: move all assertions into properties contract fix: move function without assertions back into handler test: only use assertion mode fix: improve justfile recipie for medusa * feat: halmos symbolic tests (#21) * feat: introduce OptimismSuperchainERC20 * fix: contract fixes * feat: add snapshots and semver * test: add supports interface tests * test: add invariant test * feat: add parameters to the RelayERC20 event * fix: typo * fix: from param description * fix: event signature and interface pragma * feat: add initializer * feat: use unstructured storage and OZ v5 * feat: update superchain erc20 interfaces * fix: adapt storage to ERC7201 * test: add initializable OZ v5 test * fix: invariant docs * fix: ERC165 implementation * test: improve superc20 invariant (#11) * fix: gas snapshot * chore: configure medusa with basic supERC20 self-bridging - used --foundry-compile-all to ensure the test contract under `test/properties` is compiled (otherwise it is not compiled and medusa crashes when it can't find it's compiled representation) - set src,test,script to test/properties/medusa to not waste time compiling contracts that are not required for the medusa campaign - used an atomic bridge, which doesnt allow for testing of several of the proposed invariants * fix: delete dead code * test: give the fuzzer a head start * feat: create suite for sybolic tests with halmos * test: setup and 3 properties with symbolic tests * chore: remove todo comment * docs: fix properties order * test: document & implement assertions 22, 23 and 24 * fix: fixes from self-review * test: guide the fuzzer a little bit less previously: initial mint, bound on transfer amount: 146625 calls in 200s now: no initial mint, no bound on transfer amount: 176835 calls in 200s it doesn't seem to slow the fuzzer down * feat: add property for burn * refactor: remove symbolic address on mint property * refactor: order the tests based on the property id * feat: checkpoint * chore: set xdomain sender on failing test * chore: enhance mocks * Revert "Merge branch 'chore/setup-medusa' into feat/halmos-symbolic-tests" This reverts commit 945d6b6, reversing changes made to 5dcb3a8. * refactor: remove symbolic addresses to make all of the test work * chore: remove console logs * feat: add properties file * chore: polish * refactor: enhance test on property 7 using direct try catch (now works) * fix: review comments * refactor: add symbolic addresses on test functions * feat: create halmos toml * chore: polish test contract and mock * chore: update property * refactor: move symbolic folder into properties one * feat: create advanced tests helper contract * refactor: enhance tests using symbolic addresses instead of concrete ones * chore: remove 0 property natspec * feat: add halmos profile and just script * chore: rename symbolic folder to halmos * feat: add halmos commands to justfile * chore: reorder assertions on one test * refactor: complete test property seven * chore: mark properties as completed * chore: add halmos-cheatcodes dependency * chore: rename advancedtest->halmosbase * chore: minimize mocked messenger * chore: delete empty halmos file * chore: revert changes to medusa.json * docs: update changes to PROPERTIES.md from base branch * test: sendERC20 destination fix * chore: natspec fixes --------- Co-authored-by: agusduha <agusnduha@gmail.com> Co-authored-by: 0xng <ng@defi.sucks> Co-authored-by: teddy <teddy@defi.sucks> * test: remaining protocol properties (#26) * test: cross-user fuzzed bridges + actor setup * test: fuzz properties 8 and 9 * test: properties 7 and 25 * fix: implement doc's feedback * test: superc20 tob properties (#27) * chore: add crytic/properties dependency * test: extend protocol properties so it also covers ToB erc20 properties * chore: small linter fixes * docs: update property list * test: handlers for remaining superc20 state transitions * fix: disable ToB properties we are not using and guide the fuzzer a bit more * fix: disable another ToB property not implemented by solady * chore: remove zero-initializations * fix: feedback from disco * chore: separate fuzz campaign tests in guided vs unguided * test: dont revert on successful unguided relay * test: add fuzzed calls to burn and mint * docs: document the separation of fuzz test functions * chore: move the properties file to its own directory * chore: consistently use fuzz_ and property_ + camelcase * chore: fix typo * chore: camelcase for handlers as well * fix: revert change that broke halmos campaign compile :D * test: fuzz non atomic bridging (#31) * test: changed mocked messenger ABI for message sending but kept assertions the same * docs: add new properties 26&27 * test: queue cross-chain messages and test related properties * test: relay random messages from queue and check associated invariants * chore: rename bridge->senderc20 method for consistency with relayerc20 * test: not-yet-deployed supertokens can get funds sent to them * chore: medusa runs forever by default doable since it also handles SIGINTs gracefully * chore: document the reason behind relay zero and send zero inconsistencies * fix: feedback from doc * fix: walk around possible medusa issue I'm getting an 'unknown opcode 0x4e' in ProtocolAtomic constructor when calling the MockL2ToL2CrossDomainMessenger for the first time * test: unguided handler for sendERC20 * fix: feedback from disco * chore: remove halmos testsuite * chore: foundry migration (#40) * chore: track assertion failures this is so foundry's invariant contract can check that an assertion returned false in the handler, while still allowing `fail_on_revert = false` so we can still take full advantage of medusa's fuzzer & coverage reports * fix: explicitly skip duplicate supertoken deployments * chore: remove duplicated PROPERTIES.md file * chore: expose data to foundry's external invariant checker * test: run medusa fuzzing campaign from within foundry * fix: eagerly check for duplicate deployments * fix: feedback from doc * chore: shoehorn medusa campaign into foundry dir structure * chore: remove PROPERTIES.md file * chore: delete medusa config * docs: limited support for subdirectories in test/invariant * chore: rename contracts to be more sneaky about medusa * docs: rewrite invariant docs in a way compliant with autogen scripts * chore: fixes from rebase * fix: cleanup superc20 invariants (#46) * chore: revert modifications from medusa campaign * docs: extra docs on why ForTest contract is required * doc: add list of all supertoken properties * chore: run forge fmt * ci: allow for testfiles to be deleted * fix: run doc autogen script after rebase --------- Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com> Co-authored-by: agusduha <agusnduha@gmail.com> Co-authored-by: 0xng <ng@defi.sucks>
TODO: