diff --git a/contracts/Arbitrum_SpokePool.sol b/contracts/Arbitrum_SpokePool.sol index ecdd5bab..7620b855 100644 --- a/contracts/Arbitrum_SpokePool.sol +++ b/contracts/Arbitrum_SpokePool.sol @@ -6,15 +6,7 @@ pragma solidity ^0.8.19; import "./SpokePool.sol"; import "./libraries/CircleCCTPAdapter.sol"; - -interface StandardBridgeLike { - function outboundTransfer( - address _l1Token, - address _to, - uint256 _amount, - bytes calldata _data - ) external payable returns (bytes memory); -} +import { ArbitrumL2ERC20GatewayLike } from "./interfaces/ArbitrumBridgeInterfaces.sol"; /** * @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions. @@ -100,7 +92,7 @@ contract Arbitrum_SpokePool is SpokePool, CircleCCTPAdapter { address ethereumTokenToBridge = whitelistedTokens[l2TokenAddress]; require(ethereumTokenToBridge != address(0), "Uninitialized mainnet token"); //slither-disable-next-line unused-return - StandardBridgeLike(l2GatewayRouter).outboundTransfer( + ArbitrumL2ERC20GatewayLike(l2GatewayRouter).outboundTransfer( ethereumTokenToBridge, // _l1Token. Address of the L1 token to bridge over. hubPool, // _to. Withdraw, over the bridge, to the l1 hub pool contract. amountToReturn, // _amount. diff --git a/contracts/chain-adapters/ArbitrumForwarderBase.sol b/contracts/chain-adapters/ArbitrumForwarderBase.sol index 1ecc4388..3832519d 100644 --- a/contracts/chain-adapters/ArbitrumForwarderBase.sol +++ b/contracts/chain-adapters/ArbitrumForwarderBase.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import { ArbitrumERC20Bridge, ArbitrumInboxLike, ArbitrumERC20GatewayLike } from "../interfaces/ArbitrumBridgeInterfaces.sol"; +import { ArbitrumERC20Bridge, ArbitrumInboxLike, ArbitrumL1ERC20GatewayLike } from "../interfaces/ArbitrumBridgeInterfaces.sol"; // solhint-disable-next-line contract-name-camelcase abstract contract ArbitrumForwarderBase { @@ -44,7 +44,7 @@ abstract contract ArbitrumForwarderBase { // Generic gateway: https://github.com/OffchainLabs/token-bridge-contracts/blob/main/contracts/tokenbridge/ethereum/gateway/L1ArbitrumGateway.sol // Gateway used for communicating with chains that use custom gas tokens: // https://github.com/OffchainLabs/token-bridge-contracts/blob/main/contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol - ArbitrumERC20GatewayLike public immutable L2_ERC20_GATEWAY_ROUTER; + ArbitrumL1ERC20GatewayLike public immutable L2_ERC20_GATEWAY_ROUTER; event TokensForwarded(address indexed l2Token, uint256 amount); event MessageForwarded(address indexed target, bytes message); @@ -75,7 +75,7 @@ abstract contract ArbitrumForwarderBase { */ constructor( ArbitrumInboxLike _l2ArbitrumInbox, - ArbitrumERC20GatewayLike _l2ERC20GatewayRouter, + ArbitrumL1ERC20GatewayLike _l2ERC20GatewayRouter, address _l3RefundL3Address, uint256 _l3MaxSubmissionCost, uint256 _l3GasPrice, diff --git a/contracts/chain-adapters/Arbitrum_Adapter.sol b/contracts/chain-adapters/Arbitrum_Adapter.sol index 8c58b911..f8ec507e 100644 --- a/contracts/chain-adapters/Arbitrum_Adapter.sol +++ b/contracts/chain-adapters/Arbitrum_Adapter.sol @@ -7,7 +7,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../external/interfaces/CCTPInterfaces.sol"; import "../libraries/CircleCCTPAdapter.sol"; -import { ArbitrumInboxLike as ArbitrumL1InboxLike, ArbitrumERC20GatewayLike as ArbitrumL1ERC20GatewayLike } from "../interfaces/ArbitrumBridgeInterfaces.sol"; +import { ArbitrumInboxLike as ArbitrumL1InboxLike, ArbitrumL1ERC20GatewayLike } from "../interfaces/ArbitrumBridgeInterfaces.sol"; /** * @notice Contract containing logic to send messages from L1 to Arbitrum. diff --git a/contracts/chain-adapters/Arbitrum_CustomGasToken_Adapter.sol b/contracts/chain-adapters/Arbitrum_CustomGasToken_Adapter.sol index 2cdddd34..203ee227 100644 --- a/contracts/chain-adapters/Arbitrum_CustomGasToken_Adapter.sol +++ b/contracts/chain-adapters/Arbitrum_CustomGasToken_Adapter.sol @@ -7,7 +7,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ITokenMessenger as ICCTPTokenMessenger } from "../external/interfaces/CCTPInterfaces.sol"; import { CircleCCTPAdapter, CircleDomainIds } from "../libraries/CircleCCTPAdapter.sol"; -import { ArbitrumERC20Bridge as ArbitrumL1ERC20Bridge, ArbitrumInboxLike as ArbitrumL1InboxLike, ArbitrumERC20GatewayLike as ArbitrumL1ERC20GatewayLike } from "../interfaces/ArbitrumBridgeInterfaces.sol"; +import { ArbitrumERC20Bridge as ArbitrumL1ERC20Bridge, ArbitrumCustomGasTokenInbox as ArbitrumL1InboxLike, ArbitrumL1ERC20GatewayLike } from "../interfaces/ArbitrumBridgeInterfaces.sol"; /** * @notice Interface for funder contract that this contract pulls from to pay for relayMessage()/relayTokens() diff --git a/contracts/interfaces/ArbitrumBridgeInterfaces.sol b/contracts/interfaces/ArbitrumBridgeInterfaces.sol index 31ce1197..a2b31724 100644 --- a/contracts/interfaces/ArbitrumBridgeInterfaces.sol +++ b/contracts/interfaces/ArbitrumBridgeInterfaces.sol @@ -70,24 +70,23 @@ interface ArbitrumInboxLike { ) external payable returns (uint256); /** - * @notice Put a message in the inbox that can be reexecuted for some fixed amount of time if it reverts - * @notice Overloads the `createRetryableTicket` function but is not payable, and should only be called when paying - * for message using a custom gas token. - * @dev all tokenTotalFeeAmount will be deposited to callValueRefundAddress on upper layer + * @notice Put a message in the source chain inbox that can be reexecuted for some fixed amount of time if it reverts + * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed + * funds come from the deposit alone, rather than falling back on the user's balance + * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress). + * createRetryableTicket method is the recommended standard. * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error - * @dev In case of native token having non-18 decimals: tokenTotalFeeAmount is denominated in native token's decimals. All other value params - callValue, maxSubmissionCost and maxFeePerGas are denominated in child chain's native 18 decimals. * @param to destination contract address * @param callValue call value for retryable message - * @param maxSubmissionCost Max gas deducted from user's upper layer balance to cover base submission fee - * @param excessFeeRefundAddress the address which receives the difference between execution fee paid and the actual execution cost. In case this address is a contract, funds will be received in its alias on upper layer. - * @param callValueRefundAddress callvalue gets credited here on upper layer if retryable txn times out or gets cancelled. In case this address is a contract, funds will be received in its alias on upper layer. + * @param maxSubmissionCost Max gas deducted from user's source chain balance to cover base submission fee + * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on source chain balance + * @param callValueRefundAddress callvalue gets credited here on source chain if retryable txn times out or gets cancelled * @param gasLimit Max gas deducted from user's balance to cover execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param maxFeePerGas price bid for execution. Should not be set to 1 (magic value used to trigger the RetryableData error) - * @param tokenTotalFeeAmount amount of fees to be deposited in native token to cover for retryable ticket cost - * @param data ABI encoded data of message + * @param data ABI encoded data of the message * @return unique message number of the retryable transaction */ - function createRetryableTicket( + function unsafeCreateRetryableTicket( address to, uint256 callValue, uint256 maxSubmissionCost, @@ -95,28 +94,33 @@ interface ArbitrumInboxLike { address callValueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, - uint256 tokenTotalFeeAmount, bytes calldata data - ) external returns (uint256); + ) external payable returns (uint256); +} +/** + * @notice Interface which extends ArbitrumInboxLike with functions used to interact with bridges that use a custom gas token. + */ +interface ArbitrumCustomGasTokenInbox is ArbitrumInboxLike { /** - * @notice Put a message in the source chain inbox that can be reexecuted for some fixed amount of time if it reverts - * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed - * funds come from the deposit alone, rather than falling back on the user's balance - * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress). - * createRetryableTicket method is the recommended standard. + * @notice Put a message in the inbox that can be reexecuted for some fixed amount of time if it reverts + * @notice Overloads the `createRetryableTicket` function but is not payable, and should only be called when paying + * for message using a custom gas token. + * @dev all tokenTotalFeeAmount will be deposited to callValueRefundAddress on upper layer * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error + * @dev In case of native token having non-18 decimals: tokenTotalFeeAmount is denominated in native token's decimals. All other value params - callValue, maxSubmissionCost and maxFeePerGas are denominated in child chain's native 18 decimals. * @param to destination contract address * @param callValue call value for retryable message - * @param maxSubmissionCost Max gas deducted from user's source chain balance to cover base submission fee - * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on source chain balance - * @param callValueRefundAddress callvalue gets credited here on source chain if retryable txn times out or gets cancelled + * @param maxSubmissionCost Max gas deducted from user's upper layer balance to cover base submission fee + * @param excessFeeRefundAddress the address which receives the difference between execution fee paid and the actual execution cost. In case this address is a contract, funds will be received in its alias on upper layer. + * @param callValueRefundAddress callvalue gets credited here on upper layer if retryable txn times out or gets cancelled. In case this address is a contract, funds will be received in its alias on upper layer. * @param gasLimit Max gas deducted from user's balance to cover execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param maxFeePerGas price bid for execution. Should not be set to 1 (magic value used to trigger the RetryableData error) - * @param data ABI encoded data of the message + * @param tokenTotalFeeAmount amount of fees to be deposited in native token to cover for retryable ticket cost + * @param data ABI encoded data of message * @return unique message number of the retryable transaction */ - function unsafeCreateRetryableTicket( + function createRetryableTicket( address to, uint256 callValue, uint256 maxSubmissionCost, @@ -124,14 +128,46 @@ interface ArbitrumInboxLike { address callValueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, + uint256 tokenTotalFeeAmount, bytes calldata data - ) external payable returns (uint256); + ) external returns (uint256); } /** - * @notice Generic gateway contract for bridging standard ERC20s to Arbitrum-like networks. + * @notice Generic gateway contract for bridging standard ERC20s to/from Arbitrum-like networks. + * @notice These function signatures are shared between the L1 and L2 gateway router contracts. */ -interface ArbitrumERC20GatewayLike { +interface ArbitrumL1ERC20GatewayLike { + /** + * @notice Deprecated in favor of outboundTransferCustomRefund but still used in custom bridges + * like the DAI bridge. + * @dev Refunded to aliased address of sender if sender has code on source chain, otherwise to to sender's EOA on destination chain. + * @param _sourceToken address of ERC20 + * @param _to Account to be credited with the tokens at the destination (can be the user's account or a contract), + * not subject to aliasing. This account, or its alias if it has code in the source chain, will also be able to + * cancel the retryable ticket and receive callvalue refund + * @param _amount Token Amount + * @param _maxGas Max gas deducted from user's balance to cover execution + * @param _gasPriceBid Gas price for execution + * @param _data encoded data from router and user + * @return res abi encoded inbox sequence number + */ + function outboundTransfer( + address _sourceToken, + address _to, + uint256 _amount, + uint256 _maxGas, + uint256 _gasPriceBid, + bytes calldata _data + ) external payable returns (bytes memory); + + /** + * @notice get ERC20 gateway for token. + * @param _token ERC20 address. + * @return address of ERC20 gateway. + */ + function getGateway(address _token) external view returns (address); + /** * @notice Deposit ERC20 token from Ethereum into Arbitrum-like networks. * @dev Upper layer address alias will not be applied to the following types of addresses on lower layer: @@ -159,34 +195,26 @@ interface ArbitrumERC20GatewayLike { uint256 _gasPriceBid, bytes calldata _data ) external payable returns (bytes memory); +} +interface ArbitrumL2ERC20GatewayLike { /** - * @notice Deprecated in favor of outboundTransferCustomRefund but still used in custom bridges - * like the DAI bridge. - * @dev Refunded to aliased address of sender if sender has code on source chain, otherwise to to sender's EOA on destination chain. - * @param _sourceToken address of ERC20 - * @param _to Account to be credited with the tokens at the destination (can be the user's account or a contract), - * not subject to aliasing. This account, or its alias if it has code in the source chain, will also be able to - * cancel the retryable ticket and receive callvalue refund - * @param _amount Token Amount - * @param _maxGas Max gas deducted from user's balance to cover execution - * @param _gasPriceBid Gas price for execution - * @param _data encoded data from router and user - * @return res abi encoded inbox sequence number + * @notice Fetches the l2 token address from the gateway router for the input l1 token address + * @param _l1Erc20 address of the l1 token. + */ + function calculateL2TokenAddress(address _l1Erc20) external view returns (address); + + /** + * @notice Withdraws a specified amount of an l2 token to an l1 token. + * @param _l1Token address of the token to withdraw on L1. + * @param _to address on L1 which will receive the tokens upon withdrawal. + * @param _amount amount of the token to withdraw. + * @param _data encoded data to send to the gateway router. */ function outboundTransfer( - address _sourceToken, + address _l1Token, address _to, uint256 _amount, - uint256 _maxGas, - uint256 _gasPriceBid, bytes calldata _data ) external payable returns (bytes memory); - - /** - * @notice get ERC20 gateway for token. - * @param _token ERC20 address. - * @return address of ERC20 gateway. - */ - function getGateway(address _token) external view returns (address); }