From c5c87c04fd1d1bab0519bef6a02dfd625e8a1e46 Mon Sep 17 00:00:00 2001 From: Anna Carroll Date: Thu, 9 May 2024 15:07:11 -0400 Subject: [PATCH 1/2] feat: withdraw tokens from Passage --- src/Passage.sol | 37 +++++++++++++++++++++++++++++++++++-- src/Zenith.sol | 9 ++------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/Passage.sol b/src/Passage.sol index 8c02049..04940db 100644 --- a/src/Passage.sol +++ b/src/Passage.sol @@ -3,10 +3,12 @@ pragma solidity ^0.8.24; // import IERC20 from OpenZeppelin import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import {AccessControlDefaultAdminRules} from + "openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol"; /// @notice A contract deployed to Host chain that allows tokens to enter the rollup, /// and enables Builders to fulfill requests to exchange tokens on the Rollup for tokens on the Host. -contract Passage { +contract Passage is AccessControlDefaultAdminRules { /// @notice The chainId of the default rollup chain. uint256 immutable defaultRollupChainId; @@ -25,6 +27,16 @@ contract Passage { /// @param amount - The amount of the token transferred to the recipient. event ExitFilled(uint256 rollupChainId, address indexed token, address indexed hostRecipient, uint256 amount); + /// @notice Emitted when the admin withdraws tokens from the contract. + event Withdraw(Withdrawal withdrawal); + + struct Withdrawal { + address recipient; + uint256 ethAmount; + address[] tokens; + uint256[] tokenAmounts; + } + /// @notice Details of an exit order to be fulfilled by the Builder. /// @param token - The address of the token to be transferred to the recipient. /// If token is the zero address, the amount is native Ether. @@ -40,7 +52,12 @@ contract Passage { uint256 amount; } - constructor(uint256 _defaultRollupChainId) { + /// @notice Initializes the Admin role. + /// @dev See `AccessControlDefaultAdminRules` for information on contract administration. + /// - Admin role can grant and revoke Sequencer roles. + /// - Admin role can be transferred via two-step process with a 1 day timelock. + /// @param admin - the address that will be the initial admin. + constructor(uint256 _defaultRollupChainId, address admin) AccessControlDefaultAdminRules(1 days, admin) { defaultRollupChainId = _defaultRollupChainId; } @@ -111,6 +128,22 @@ contract Passage { emit ExitFilled(orders[i].rollupChainId, orders[i].token, orders[i].recipient, orders[i].amount); } } + + /// @notice Allows the admin to withdraw tokens from the contract. + /// @dev Only the admin can call this function. + function withdraw(Withdrawal[] calldata withdrawals) external onlyRole(DEFAULT_ADMIN_ROLE) { + for (uint256 i = 0; i < withdrawals.length; i++) { + // transfer ether + if (withdrawals[i].ethAmount > 0) { + payable(withdrawals[i].recipient).transfer(withdrawals[i].ethAmount); + } + // transfer ERC20 tokens + for (uint256 j = 0; j < withdrawals[i].tokens.length; j++) { + IERC20(withdrawals[i].tokens[j]).transfer(withdrawals[i].recipient, withdrawals[i].tokenAmounts[j]); + } + emit Withdraw(withdrawals[i]); + } + } } /// @notice A contract deployed to the Rollup that allows users to atomically exchange tokens on the Rollup for tokens on the Host. diff --git a/src/Zenith.sol b/src/Zenith.sol index 2e5af99..cc5b069 100644 --- a/src/Zenith.sol +++ b/src/Zenith.sol @@ -3,10 +3,8 @@ pragma solidity ^0.8.24; // import openzeppelin Role contracts import {Passage} from "./Passage.sol"; -import {AccessControlDefaultAdminRules} from - "openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol"; -contract Zenith is Passage, AccessControlDefaultAdminRules { +contract Zenith is Passage { /// @notice Block header information for the rollup block, signed by the sequencer. /// @param rollupChainId - the chainId of the rollup chain. Any chainId is accepted by the contract. /// @param sequence - the sequence number of the rollup block. Must be monotonically increasing. Enforced by the contract. @@ -74,10 +72,7 @@ contract Zenith is Passage, AccessControlDefaultAdminRules { /// - Admin role can grant and revoke Sequencer roles. /// - Admin role can be transferred via two-step process with a 1 day timelock. /// @param admin - the address that will be the initial admin. - constructor(uint256 defaultRollupChainId, address admin) - Passage(defaultRollupChainId) - AccessControlDefaultAdminRules(1 days, admin) - {} + constructor(uint256 defaultRollupChainId, address admin) Passage(defaultRollupChainId, admin) {} /// @notice Submit a rollup block with block data submitted via calldata. /// @dev Blocks are submitted by Builders, with an attestation to the block data signed by a Sequencer. From 68ede6b91658a2f2ca4b86b987c723042437e70d Mon Sep 17 00:00:00 2001 From: Anna Carroll Date: Fri, 10 May 2024 15:23:32 -0400 Subject: [PATCH 2/2] natspec --- src/Passage.sol | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Passage.sol b/src/Passage.sol index 04940db..691d608 100644 --- a/src/Passage.sol +++ b/src/Passage.sol @@ -9,7 +9,7 @@ import {AccessControlDefaultAdminRules} from /// @notice A contract deployed to Host chain that allows tokens to enter the rollup, /// and enables Builders to fulfill requests to exchange tokens on the Rollup for tokens on the Host. contract Passage is AccessControlDefaultAdminRules { - /// @notice The chainId of the default rollup chain. + /// @notice The chainId of rollup that Ether will be sent to by default when entering the rollup via fallback() or receive(). uint256 immutable defaultRollupChainId; /// @notice Thrown when attempting to fulfill an exit order with a deadline that has passed. @@ -30,6 +30,11 @@ contract Passage is AccessControlDefaultAdminRules { /// @notice Emitted when the admin withdraws tokens from the contract. event Withdraw(Withdrawal withdrawal); + /// @notice A bundled withdrawal of Ether and ERC20 tokens. + /// @param recipient - The address to receive the Ether and ERC20 tokens. + /// @param ethAmount - The amount of Ether to transfer to the recipient. Zero if no Ether to transfer. + /// @param tokens - The addresses of the ERC20 tokens to transfer to the recipient. + /// @param tokenAmounts - The amounts of the ERC20 tokens to transfer to the recipient. struct Withdrawal { address recipient; uint256 ethAmount; @@ -56,6 +61,8 @@ contract Passage is AccessControlDefaultAdminRules { /// @dev See `AccessControlDefaultAdminRules` for information on contract administration. /// - Admin role can grant and revoke Sequencer roles. /// - Admin role can be transferred via two-step process with a 1 day timelock. + /// @param _defaultRollupChainId - the chainId of the rollup that Ether will be sent to by default + /// when entering the rollup via fallback() or receive() fns. /// @param admin - the address that will be the initial admin. constructor(uint256 _defaultRollupChainId, address admin) AccessControlDefaultAdminRules(1 days, admin) { defaultRollupChainId = _defaultRollupChainId; @@ -131,6 +138,7 @@ contract Passage is AccessControlDefaultAdminRules { /// @notice Allows the admin to withdraw tokens from the contract. /// @dev Only the admin can call this function. + /// @param withdrawals - The withdrawals to process. See Withdrawal struct docs for details. function withdraw(Withdrawal[] calldata withdrawals) external onlyRole(DEFAULT_ADMIN_ROLE) { for (uint256 i = 0; i < withdrawals.length; i++) { // transfer ether