Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/tokenbridge/ethereum/gateway/L1OrbitGatewayRouter.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { L1GatewayRouter } from "./L1GatewayRouter.sol";
import { IERC20Inbox } from "../L1ArbitrumMessenger.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20Bridge } from "../../libraries/IERC20Bridge.sol";
/**
* @title Handles deposits from L1 into L2 in ERC20-based rollups where custom token is used to pay for fees. Tokens are routed to their appropriate L1 gateway.
* @notice Router itself also conforms to the Gateway interface. Router also serves as an L1-L2 token address oracle.
*/
contract L1OrbitGatewayRouter is L1GatewayRouter {
using SafeERC20 for IERC20;
/**
* @notice Allows owner to register the default gateway.
* @param newL1DefaultGateway default gateway address
* @param _maxGas max gas for L2 retryable execution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost for L2 retryable ticket
* @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge.
* @return Retryable ticket ID
*/
function setDefaultGateway(
address newL1DefaultGateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
uint256 _feeAmount
) external onlyOwner returns (uint256) {
return
_setDefaultGateway(
newL1DefaultGateway,
_maxGas,
_gasPriceBid,
_maxSubmissionCost,
_feeAmount
);
}
/**
* @notice Allows L1 Token contract to trustlessly register its gateway.
* @dev Other setGateway method allows excess eth recovery from _maxSubmissionCost and is recommended.
* @param _gateway l1 gateway address
* @param _maxGas max gas for L2 retryable execution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost for L2 retryable ticket
* @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge.
* @return Retryable ticket ID
*/
function setGateway(
address _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
uint256 _feeAmount
) external returns (uint256) {
return
setGateway(_gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, msg.sender, _feeAmount);
}
/**
* @notice Allows L1 Token contract to trustlessly register its gateway.
* @dev Other setGateway method allows excess eth recovery from _maxSubmissionCost and is recommended.
* @param _gateway l1 gateway address
* @param _maxGas max gas for L2 retryable execution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost L2 retryable tick3et
* @param _creditBackAddress address for crediting back overpayment of _maxSubmissionCost
* @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge.
* @return Retryable ticket ID
*/
function setGateway(
address _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
address _creditBackAddress,
uint256 _feeAmount
) public returns (uint256) {
return
_setGatewayWithCreditBack(
_gateway,
_maxGas,
_gasPriceBid,
_maxSubmissionCost,
_creditBackAddress,
_feeAmount
);
}
/**
* @notice Allows owner to register gateways for specific tokens.
* @param _token list of L1 token addresses
* @param _gateway list of L1 gateway addresses
* @param _maxGas max gas for L2 retryable execution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost for L2 retryable ticket
* @param _feeAmount total amount of fees in native token to cover for retryable ticket costs. This amount will be transferred from user to bridge.
* @return Retryable ticket ID
*/
function setGateways(
address[] memory _token,
address[] memory _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
uint256 _feeAmount
) external onlyOwner returns (uint256) {
return
_setGateways(
_token,
_gateway,
_maxGas,
_gasPriceBid,
_maxSubmissionCost,
msg.sender,
_feeAmount
);
}
function _createRetryable(
address _inbox,
address _to,
address _refundTo,
address _user,
uint256 _totalFeeAmount,
uint256 _l2CallValue,
uint256 _maxSubmissionCost,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes memory _data
) internal override returns (uint256) {
{
// Transfer native token amount needed to pay for retryable fees to the inbox.
// Fee tokens will be transferred from msg.sender
address nativeFeeToken = IERC20Bridge(address(getBridge(_inbox))).nativeToken();
uint256 inboxNativeTokenBalance = IERC20(nativeFeeToken).balanceOf(_inbox);
if (inboxNativeTokenBalance < _totalFeeAmount) {
uint256 diff = _totalFeeAmount - inboxNativeTokenBalance;
IERC20(nativeFeeToken).safeTransferFrom(msg.sender, _inbox, diff);
}
}
return
IERC20Inbox(_inbox).createRetryableTicket(
_to,
_l2CallValue,
_maxSubmissionCost,
_refundTo,
_user,
_maxGas,
_gasPriceBid,
_totalFeeAmount,
_data
);
}
/**
* @notice Revert 'setGateway' entrypoint which doesn't have total amount of token fees as an argument.
*/
function setGateway(
address,
uint256,
uint256,
uint256,
address
) public payable override returns (uint256) {
revert("NOT_SUPPORTED_IN_ORBIT");
}
/**
* @notice Revert 'setDefaultGateway' entrypoint which doesn't have total amount of token fees as an argument.
*/
function setDefaultGateway(
address,
uint256,
uint256,
uint256
) external payable override onlyOwner returns (uint256) {
revert("NOT_SUPPORTED_IN_ORBIT");
}
/**
* @notice Revert 'setGateway' entrypoint which doesn't have total amount of token fees as an argument.
*/
function setGateway(
address,
uint256,
uint256,
uint256
) external payable override returns (uint256) {
revert("NOT_SUPPORTED_IN_ORBIT");
}
/**
* @notice Revert 'setGateways' entrypoint which doesn't have total amount of token fees as an argument.
*/
function setGateways(
address[] memory,
address[] memory,
uint256,
uint256,
uint256
) external payable override onlyOwner returns (uint256) {
revert("NOT_SUPPORTED_IN_ORBIT");
}
}
"
},
"contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.0;
import "../../libraries/Whitelist.sol";
import { ArbitrumEnabledToken } from "../ICustomToken.sol";
import "../L1ArbitrumMessenger.sol";
import "../../libraries/gateway/GatewayRouter.sol";
import "../../arbitrum/gateway/L2GatewayRouter.sol";
import "../../libraries/ERC165.sol";
import "./IL1GatewayRouter.sol";
import "./IL1ArbitrumGateway.sol";
/**
* @title Handles deposits from Erhereum into Arbitrum. Tokens are routered to their appropriate L1 gateway (Router itself also conforms to the Gateway itnerface).
* @notice Router also serves as an L1-L2 token address oracle.
*/
contract L1GatewayRouter is
WhitelistConsumer,
L1ArbitrumMessenger,
GatewayRouter,
ERC165,
IL1GatewayRouter
{
using Address for address;
address public override owner;
address public override inbox;
modifier onlyOwner() {
require(msg.sender == owner, "ONLY_OWNER");
_;
}
function initialize(
address _owner,
address _defaultGateway,
address, // was _whitelist, now unused
address _counterpartGateway,
address _inbox
) public {
GatewayRouter._initialize(_counterpartGateway, address(0), _defaultGateway);
owner = _owner;
WhitelistConsumer.whitelist = address(0);
inbox = _inbox;
}
function setDefaultGateway(
address newL1DefaultGateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable virtual onlyOwner returns (uint256) {
return
_setDefaultGateway(
newL1DefaultGateway,
_maxGas,
_gasPriceBid,
_maxSubmissionCost,
msg.value
);
}
function _setDefaultGateway(
address newL1DefaultGateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
uint256 feeAmount
) internal returns (uint256) {
defaultGateway = newL1DefaultGateway;
emit DefaultGatewayUpdated(newL1DefaultGateway);
address l2NewDefaultGateway;
if (newL1DefaultGateway != address(0)) {
l2NewDefaultGateway = TokenGateway(newL1DefaultGateway).counterpartGateway();
}
bytes memory data = abi.encodeWithSelector(
L2GatewayRouter.setDefaultGateway.selector,
l2NewDefaultGateway
);
return
sendTxToL2(
inbox,
counterpartGateway,
msg.sender,
feeAmount,
0,
L2GasParams({
_maxSubmissionCost: _maxSubmissionCost,
_maxGas: _maxGas,
_gasPriceBid: _gasPriceBid
}),
data
);
}
function setOwner(address newOwner) external onlyOwner {
require(newOwner != address(0), "INVALID_OWNER");
// set newOwner to address(1) to disable owner and keep `initialize` safe
owner = newOwner;
}
/**
* @notice Allows L1 Token contract to trustlessly register its gateway. (other setGateway method allows excess eth recovery from _maxSubmissionCost and is recommended)
* @param _gateway l1 gateway address
* @param _maxGas max gas for L2 retryable exrecution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost L2 retryable tick3et
* @return Retryable ticket ID
*/
function setGateway(
address _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable virtual override returns (uint256) {
return setGateway(_gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, msg.sender);
}
/**
* @notice Allows L1 Token contract to trustlessly register its gateway.
* @param _gateway l1 gateway address
* @param _maxGas max gas for L2 retryable exrecution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost L2 retryable tick3et
* @param _creditBackAddress address for crediting back overpayment of _maxSubmissionCost
* @return Retryable ticket ID
*/
function setGateway(
address _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
address _creditBackAddress
) public payable virtual override returns (uint256) {
return
_setGatewayWithCreditBack(
_gateway,
_maxGas,
_gasPriceBid,
_maxSubmissionCost,
_creditBackAddress,
msg.value
);
}
function _setGatewayWithCreditBack(
address _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
address _creditBackAddress,
uint256 feeAmount
) internal returns (uint256) {
require(
ArbitrumEnabledToken(msg.sender).isArbitrumEnabled() == uint8(0xb1),
"NOT_ARB_ENABLED"
);
require(_gateway.isContract(), "NOT_TO_CONTRACT");
address currGateway = getGateway(msg.sender);
if (currGateway != address(0) && currGateway != defaultGateway) {
// if gateway is already set to a non-default gateway, don't allow it to set a different gateway
require(currGateway == _gateway, "NO_UPDATE_TO_DIFFERENT_ADDR");
}
address[] memory _tokenArr = new address[](1);
_tokenArr[0] = address(msg.sender);
address[] memory _gatewayArr = new address[](1);
_gatewayArr[0] = _gateway;
return
_setGateways(
_tokenArr,
_gatewayArr,
_maxGas,
_gasPriceBid,
_maxSubmissionCost,
_creditBackAddress,
feeAmount
);
}
function setGateways(
address[] memory _token,
address[] memory _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable virtual onlyOwner returns (uint256) {
// it is assumed that token and gateway are both contracts
// require(_token[i].isContract() && _gateway[i].isContract(), "NOT_CONTRACT");
return
_setGateways(
_token,
_gateway,
_maxGas,
_gasPriceBid,
_maxSubmissionCost,
msg.sender,
msg.value
);
}
function _setGateways(
address[] memory _token,
address[] memory _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
address _creditBackAddress,
uint256 feeAmount
) internal returns (uint256) {
require(_token.length == _gateway.length, "WRONG_LENGTH");
for (uint256 i = 0; i < _token.length; i++) {
l1TokenToGateway[_token[i]] = _gateway[i];
emit GatewaySet(_token[i], _gateway[i]);
// overwrite memory so the L2 router receives the L2 address of each gateway
if (_gateway[i] != address(0) && _gateway[i] != DISABLED) {
// if we are assigning a gateway to the token, the address oracle of the gateway
// must return something other than the 0 address
// this check helps avoid misconfiguring gateways
require(
TokenGateway(_gateway[i]).calculateL2TokenAddress(_token[i]) != address(0),
"TOKEN_NOT_HANDLED_BY_GATEWAY"
);
_gateway[i] = TokenGateway(_gateway[i]).counterpartGateway();
}
}
bytes memory data = abi.encodeWithSelector(
L2GatewayRouter.setGateway.selector,
_token,
_gateway
);
return
sendTxToL2(
inbox,
counterpartGateway,
_creditBackAddress,
feeAmount,
0,
L2GasParams({
_maxSubmissionCost: _maxSubmissionCost,
_maxGas: _maxGas,
_gasPriceBid: _gasPriceBid
}),
data
);
}
function outboundTransfer(
address _token,
address _to,
uint256 _amount,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes calldata _data
) public payable override(GatewayRouter, ITokenGateway) returns (bytes memory) {
return super.outboundTransfer(_token, _to, _amount, _maxGas, _gasPriceBid, _data);
}
/**
* @notice Deposit ERC20 token from Ethereum into Arbitrum using the registered or otherwise default gateway
* @dev Some legacy gateway might not have the outboundTransferCustomRefund method and will revert, in such case use outboundTransfer instead
* L2 address alias will not be applied to the following types of addresses on L1:
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* The msg.sender that calls this method, or its L2 alias if it has code in L1, will be set to the callValueRefundAddress;
* this means it can cancel the retryable ticket if its auto-redeem fails, and also that it receives the l2 callvalue refund.
* @param _token L1 address of ERC20
* @param _refundTo Account, or its L2 alias if it have code in L1, to be credited with excess gas refund in L2
* @param _to Account to be credited with the tokens in the L2 (can be an EOA or a contract), not subject to L2 aliasing.
* @param _amount Token Amount
* @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution
* @param _gasPriceBid Gas price for L2 execution
* @param _data encoded data from router and user
* @return res abi encoded inbox sequence number
*/
function outboundTransferCustomRefund(
address _token,
address _refundTo,
address _to,
uint256 _amount,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes calldata _data
) public payable override returns (bytes memory) {
address gateway = getGateway(_token);
bytes memory gatewayData = GatewayMessageHandler.encodeFromRouterToGateway(
msg.sender,
_data
);
emit TransferRouted(_token, msg.sender, _to, gateway);
// here we use `IL1ArbitrumGateway` since we don't assume all ITokenGateway implements `outboundTransferCustomRefund`
return
IL1ArbitrumGateway(gateway).outboundTransferCustomRefund{ value: msg.value }(
_token,
_refundTo,
_to,
_amount,
_maxGas,
_gasPriceBid,
gatewayData
);
}
modifier onlyCounterpartGateway() override {
// don't expect messages from L2 router
revert("ONLY_COUNTERPART_GATEWAY");
_;
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC165, IERC165)
returns (bool)
{
// registering interfaces that is added after arb-bridge-peripherals >1.0.11
// using function selector instead of single function interfaces to reduce bloat
return
interfaceId == this.outboundTransferCustomRefund.selector ||
super.supportsInterface(interfaceId);
}
}
"
},
"contracts/tokenbridge/ethereum/L1ArbitrumMessenger.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.0;
import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
import "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol";
/// @notice L1 utility contract to assist with L1 <=> L2 interactions
/// @dev this is an abstract contract instead of library so the functions can be easily overriden when testing
abstract contract L1ArbitrumMessenger {
event TxToL2(address indexed _from, address indexed _to, uint256 indexed _seqNum, bytes _data);
struct L2GasParams {
uint256 _maxSubmissionCost;
uint256 _maxGas;
uint256 _gasPriceBid;
}
function sendTxToL2CustomRefund(
address _inbox,
address _to,
address _refundTo,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
L2GasParams memory _l2GasParams,
bytes memory _data
) internal returns (uint256) {
// alternative function entry point when struggling with the stack size
return
sendTxToL2CustomRefund(
_inbox,
_to,
_refundTo,
_user,
_l1CallValue,
_l2CallValue,
_l2GasParams._maxSubmissionCost,
_l2GasParams._maxGas,
_l2GasParams._gasPriceBid,
_data
);
}
function sendTxToL2(
address _inbox,
address _to,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
L2GasParams memory _l2GasParams,
bytes memory _data
) internal returns (uint256) {
// alternative function entry point when struggling with the stack size
return
sendTxToL2(
_inbox,
_to,
_user,
_l1CallValue,
_l2CallValue,
_l2GasParams._maxSubmissionCost,
_l2GasParams._maxGas,
_l2GasParams._gasPriceBid,
_data
);
}
function sendTxToL2CustomRefund(
address _inbox,
address _to,
address _refundTo,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
uint256 _maxSubmissionCost,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes memory _data
) internal returns (uint256) {
uint256 seqNum = _createRetryable(
_inbox,
_to,
_refundTo,
_user,
_l1CallValue,
_l2CallValue,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
_data
);
emit TxToL2(_user, _to, seqNum, _data);
return seqNum;
}
function sendTxToL2(
address _inbox,
address _to,
address _user,
uint256 _l1CallValue,
uint256 _l2CallValue,
uint256 _maxSubmissionCost,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes memory _data
) internal returns (uint256) {
return
sendTxToL2CustomRefund(
_inbox,
_to,
_user,
_user,
_l1CallValue,
_l2CallValue,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
_data
);
}
function getBridge(address _inbox) internal view returns (IBridge) {
return IInbox(_inbox).bridge();
}
/// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
function getL2ToL1Sender(address _inbox) internal view returns (address) {
IOutbox outbox = IOutbox(getBridge(_inbox).activeOutbox());
address l2ToL1Sender = outbox.l2ToL1Sender();
require(l2ToL1Sender != address(0), "NO_SENDER");
return l2ToL1Sender;
}
/**
* @notice Calls inbox to create retryable ticket. Default implementation is for standard Eth-based rollup, but it can be overriden to create retryable in ERC20-based rollup.
* @param _inbox address of the rollup's inbox
* @param _to destination L2 contract address
* @param _refundTo refund address for excess fee
* @param _user refund address for callvalue
* @param _totalFeeAmount amount of fees to pay, in Eth or native token, for retryable's execution
* @param _l2CallValue call value for retryable L2 message
* @param _maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
* @param _maxGas Max gas deducted from user's L2 balance to cover L2 execution
* @param _gasPriceBid price bid for L2 execution
* @param _data ABI encoded data of L2 message
* @return unique message number of the retryable transaction
*/
function _createRetryable(
address _inbox,
address _to,
address _refundTo,
address _user,
uint256 _totalFeeAmount,
uint256 _l2CallValue,
uint256 _maxSubmissionCost,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes memory _data
) internal virtual returns (uint256) {
return
IInbox(_inbox).createRetryableTicket{ value: _totalFeeAmount }(
_to,
_l2CallValue,
_maxSubmissionCost,
_refundTo,
_user,
_maxGas,
_gasPriceBid,
_data
);
}
}
interface IERC20Inbox {
function createRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 tokenTotalFeeAmount,
bytes calldata data
) external returns (uint256);
}"
},
"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
"
},
"node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
"
},
"contracts/tokenbridge/libraries/IERC20Bridge.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
interface IERC20Bridge {
/**
* @dev token that is escrowed in bridge on L1 side and minted on L2 as native currency. Also fees are paid in this token.
*/
function nativeToken() external view returns (address);
}
"
},
"contracts/tokenbridge/libraries/Whitelist.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.0;
abstract contract WhitelistConsumer {
address public whitelist;
event WhitelistSourceUpdated(address newSource);
modifier onlyWhitelisted() {
if (whitelist != address(0)) {
require(Whitelist(whitelist).isAllowed(msg.sender), "NOT_WHITELISTED");
}
_;
}
function updateWhitelistSource(address newSource) external {
require(msg.sender == whitelist, "NOT_FROM_LIST");
whitelist = newSource;
emit WhitelistSourceUpdated(newSource);
}
}
contract Whitelist {
address public owner;
mapping(address => bool) public isAllowed;
event OwnerUpdated(address newOwner);
event WhitelistUpgraded(address newWhitelist, address[] targets);
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "ONLY_OWNER");
_;
}
function setOwner(address newOwner) external onlyOwner {
owner = newOwner;
emit OwnerUpdated(newOwner);
}
function setWhitelist(address[] memory user, bool[] memory val) external onlyOwner {
require(user.length == val.length, "INVALID_INPUT");
for (uint256 i = 0; i < user.length; i++) {
isAllowed[user[i]] = val[i];
}
}
// set new whitelist to address(0) to disable whitelist
function triggerConsumers(address newWhitelist, address[] memory targets) external onlyOwner {
for (uint256 i = 0; i < targets.length; i++) {
WhitelistConsumer(targets[i]).updateWhitelistSource(newWhitelist);
}
emit WhitelistUpgraded(newWhitelist, targets);
}
}
"
},
"contracts/tokenbridge/ethereum/ICustomToken.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
interface ArbitrumEnabledToken {
/// @notice should return `0xb1` if token is enabled for arbitrum gateways
/// @dev Previous implmentation used to return `uint8(0xa4b1)`, however that causes compile time error in Solidity 0.8. due to type mismatch.
/// In current version `uint8(0xb1)` shall be returned, which results in no change as that's the same value as truncated `uint8(0xa4b1)`.
function isArbitrumEnabled() external view returns (uint8);
}
/**
* @title Minimum expected interface for L1 custom token (see TestCustomTokenL1.sol for an example implementation)
*/
interface ICustomToken is ArbitrumEnabledToken {
/**
* @notice Should make an external call to EthERC20Bridge.registerCustomL2Token
*/
function registerTokenOnL2(
address l2CustomTokenAddress,
uint256 maxSubmissionCostForCustomBridge,
uint256 maxSubmissionCostForRouter,
uint256 maxGasForCustomBridge,
uint256 maxGasForRouter,
uint256 gasPriceBid,
uint256 valueForGateway,
uint256 valueForRouter,
address creditBackAddress
) external payable;
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
interface L1MintableToken is ICustomToken {
function bridgeMint(address account, uint256 amount) external;
}
interface L1ReverseToken is L1MintableToken {
function bridgeBurn(address account, uint256 amount) external;
}
"
},
"contracts/tokenbridge/libraries/gateway/GatewayRouter.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.0;
import "../ProxyUtil.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "./TokenGateway.sol";
import "./GatewayMessageHandler.sol";
import "./IGatewayRouter.sol";
/**
* @title Common interface for L1 and L2 Gateway Routers
*/
abstract contract GatewayRouter is TokenGateway, IGatewayRouter {
using Address for address;
address internal constant ZERO_ADDR = address(0);
address internal constant DISABLED = address(1);
mapping(address => address) public l1TokenToGateway;
address public override defaultGateway;
function postUpgradeInit() external {
// it is assumed the L2 Arbitrum Gateway contract is behind a Proxy controlled by a proxy admin
// this function can only be called by the proxy admin contract
address proxyAdmin = ProxyUtil.getProxyAdmin();
require(msg.sender == proxyAdmin, "NOT_FROM_ADMIN");
// this has no other logic since the current upgrade doesn't require this logic
}
function _initialize(
address _counterpartGateway,
address _router,
address _defaultGateway
) internal {
// if you are a router, you can't have a router
require(_router == address(0), "BAD_ROUTER");
TokenGateway._initialize(_counterpartGateway, _router);
// default gateway can have 0 address
defaultGateway = _defaultGateway;
}
function finalizeInboundTransfer(
address, /* _token */
address, /* _from */
address, /* _to */
uint256, /* _amount */
bytes calldata /* _data */
) external payable virtual override {
revert("ONLY_OUTBOUND_ROUTER");
}
function outboundTransfer(
address _token,
address _to,
uint256 _amount,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes calldata _data
) public payable virtual override returns (bytes memory) {
// this function is kept instead of delegating to outboundTransferCustomRefund to allow
// compatibility with older gateways that did not implement outboundTransferCustomRefund
address gateway = getGateway(_token);
bytes memory gatewayData = GatewayMessageHandler.encodeFromRouterToGateway(
msg.sender,
_data
);
emit TransferRouted(_token, msg.sender, _to, gateway);
return
ITokenGateway(gateway).outboundTransfer{ value: msg.value }(
_token,
_to,
_amount,
_maxGas,
_gasPriceBid,
gatewayData
);
}
function getOutboundCalldata(
address _token,
address _from,
address _to,
uint256 _amount,
bytes memory _data
) public view virtual override returns (bytes memory) {
address gateway = getGateway(_token);
return TokenGateway(gateway).getOutboundCalldata(_token, _from, _to, _amount, _data);
}
function getGateway(address _token) public view virtual override returns (address gateway) {
gateway = l1TokenToGateway[_token];
if (gateway == ZERO_ADDR) {
// if no gateway value set, use default gateway
gateway = defaultGateway;
}
if (gateway == DISABLED || !gateway.isContract()) {
// not a valid gateway
return ZERO_ADDR;
}
return gateway;
}
function calculateL2TokenAddress(address l1ERC20)
public
view
virtual
override(TokenGateway, ITokenGateway)
returns (address)
{
address gateway = getGateway(l1ERC20);
if (gateway == ZERO_ADDR) {
return ZERO_ADDR;
}
return TokenGateway(gateway).calculateL2TokenAddress(l1ERC20);
}
}
"
},
"contracts/tokenbridge/arbitrum/gateway/L2GatewayRouter.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.0;
import "../../libraries/gateway/GatewayRouter.sol";
import "../../ethereum/gateway/L1GatewayRouter.sol";
import "../L2ArbitrumMessenger.sol";
import "../../libraries/AddressAliasHelper.sol";
/**
* @title Handles withdrawals from Ethereum into Arbitrum. Tokens are routered to their appropriate L2 gateway (Router itself also conforms to the Gateway interface).
* @notice Router also serves as an L2-L1 token address oracle.
*/
contract L2GatewayRouter is GatewayRouter, L2ArbitrumMessenger {
modifier onlyCounterpartGateway() override {
require(
msg.sender == AddressAliasHelper.applyL1ToL2Alias(counterpartGateway),
"ONLY_COUNTERPART_GATEWAY"
);
_;
}
function initialize(address _counterpartGateway, address _defaultGateway) public {
GatewayRouter._initialize(_counterpartGateway, address(0), _defaultGateway);
}
function setGateway(address[] memory _l1Token, address[] memory _gateway)
external
onlyCounterpartGateway
{
// counterpart gateway (L1 router) should never allow wrong lengths
assert(_l1Token.length == _gateway.length);
for (uint256 i = 0; i < _l1Token.length; i++) {
l1TokenToGateway[_l1Token[i]] = _gateway[i];
emit GatewaySet(_l1Token[i], _gateway[i]);
}
}
function outboundTransfer(
address _l1Token,
address _to,
uint256 _amount,
bytes calldata _data
) public payable returns (bytes memory) {
return outboundTransfer(_l1Token, _to, _amount, 0, 0, _data);
}
function setDefaultGateway(address newL2DefaultGateway) external onlyCounterpartGateway {
defaultGateway = newL2DefaultGateway;
emit DefaultGatewayUpdated(newL2DefaultGateway);
}
}
"
},
"contracts/tokenbridge/libraries/ERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
// With pragma modification to support ^0.6.11
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.6/contracts/utils/introspection/ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
"
},
"contracts/tokenbridge/ethereum/gateway/IL1GatewayRouter.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "../../libraries/gateway/ITokenGateway.sol";
import "../../libraries/IERC165.sol";
/**
* @title Handles deposits from Erhereum into Arbitrum. Tokens are routered to their appropriate L1 gateway (Router itself also conforms to the Gateway itnerface).
* @notice Router also serves as an L1-L2 token address oracle.
*/
interface IL1GatewayRouter is ITokenGateway, IERC165 {
/**
* @notice Deposit ERC20 token from Ethereum into Arbitrum using the registered or otherwise default gateway
* @dev Some legacy gateway might not have the outboundTransferCustomRefund method and will revert, in such case use outboundTransfer instead
* L2 address alias will not be applied to the following types of addresses on L1:
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* @param _token L1 address of ERC20
* @param _refundTo Account, or its L2 alias if it have code in L1, to be credited with excess gas refund in L2
* @param _to Account to be credited with the tokens in the L2 (can be the user's L2 account or a contract), not subject to L2 aliasing
This account, or its L2 alias if it have code in L1, 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 L2 balance to cover L2 execution
* @param _gasPriceBid Gas price for L2 execution
* @param _data encoded data from router and user
* @return res abi encoded inbox sequence number
*/
function outboundTransferCustomRefund(
address _token,
address _refundTo,
address _to,
uint256 _amount,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes calldata _data
) external payable returns (bytes memory);
/**
* @notice Allows L1 Token contract to trustlessly register its gateway.
* @param _gateway l1 gateway address
* @param _maxGas max gas for L2 retryable exrecution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost L2 retryable tick3et
* @param _creditBackAddress address for crediting back overpayment of _maxSubmissionCost
* @return Retryable ticket ID
*/
function setGateway(
address _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost,
address _creditBackAddress
) external payable returns (uint256);
/**
* @notice Allows L1 Token contract to trustlessly register its gateway. (other setGateway method allows excess eth recovery from _maxSubmissionCost and is recommended)
* @param _gateway l1 gateway address
* @param _maxGas max gas for L2 retryable exrecution
* @param _gasPriceBid gas price for L2 retryable ticket
* @param _maxSubmissionCost base submission cost L2 retryable tick3et
* @return Retryable ticket ID
*/
function setGateway(
address _gateway,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable returns (uint256);
function owner() external view returns (address);
function inbox() external view returns (address);
}
"
},
"contracts/tokenbridge/ethereum/gateway/IL1ArbitrumGateway.sol": {
"content": "// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "../../libraries/gateway/ITokenGateway.sol";
import "../../libraries/IERC165.sol";
/**
* @title Common interface for gatways on L1 messaging to Arbitrum.
*/
interface IL1ArbitrumGateway is ITokenGateway, IERC165 {
function inbox() external view returns (address);
/**
* @notice Deposit ERC20 token
Submitted on: 2025-10-10 21:31:41
Comments
Log in to comment.
No comments yet.