Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60e06040 | 23734244 | 92 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Passage
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
No with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.26;
import {PassagePermit2} from "./PassagePermit2.sol";
import {UsesPermit2} from "../UsesPermit2.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol";
import {ReentrancyGuardTransient} from "openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sol";
/// @notice A contract deployed to Host chain that allows tokens to enter the rollup.
contract Passage is PassagePermit2, ReentrancyGuardTransient {
using SafeERC20 for IERC20;
using Address for address payable;
/// @notice The chainId of rollup that Ether will be sent to by default when entering the rollup via fallback() or receive().
uint256 public immutable defaultRollupChainId;
/// @notice The address that is allowed to withdraw funds from the contract.
address public immutable tokenAdmin;
/// @notice tokenAddress => whether new EnterToken events are currently allowed for that token.
mapping(address => bool) public canEnter;
/// @notice Thrown when attempting to call admin functions if not the token admin.
error OnlyTokenAdmin();
/// @notice Thrown when attempting to enter the rollup with an ERC20 token that is not currently allowed.
error DisallowedEnter(address token);
/// @notice Emitted when Ether enters the rollup.
/// @param rollupChainId - The chainId of the destination rollup.
/// @param rollupRecipient - The recipient of Ether on the rollup.
/// @param amount - The amount of Ether entering the rollup.
event Enter(uint256 indexed rollupChainId, address indexed rollupRecipient, uint256 amount);
/// @notice Emitted when ERC20 tokens enter the rollup.
/// @param rollupChainId - The chainId of the destination rollup.
/// @param rollupRecipient - The recipient of tokens on the rollup.
/// @param token - The host chain address of the token entering the rollup.
/// @param amount - The amount of tokens entering the rollup.
event EnterToken(
uint256 indexed rollupChainId, address indexed rollupRecipient, address indexed token, uint256 amount
);
/// @notice Emitted when the admin withdraws tokens from the contract.
event Withdrawal(address indexed token, address indexed recipient, uint256 amount);
/// @notice Emitted when the admin allow/disallow ERC20 Enters for a given token.
event EnterConfigured(address indexed token, bool indexed canEnter);
/// @param _defaultRollupChainId - the chainId of the rollup that Ether will be sent to by default
/// when entering the rollup via fallback() or receive() fns.
constructor(
uint256 _defaultRollupChainId,
address _tokenAdmin,
address[] memory initialEnterTokens,
address _permit2
) UsesPermit2(_permit2) {
defaultRollupChainId = _defaultRollupChainId;
tokenAdmin = _tokenAdmin;
for (uint256 i; i < initialEnterTokens.length; i++) {
_configureEnter(initialEnterTokens[i], true);
}
}
/// @notice Allows native Ether to enter the rollup by being sent directly to the contract.
fallback() external payable {
enter(defaultRollupChainId, msg.sender);
}
/// @notice Allows native Ether to enter the rollup by being sent directly to the contract.
receive() external payable {
enter(defaultRollupChainId, msg.sender);
}
/// @notice Allows native Ether to enter the rollup.
/// @param rollupChainId - The rollup chain to enter.
/// @param rollupRecipient - The recipient of the Ether on the rollup.
/// @custom:emits Enter indicating the amount of Ether to mint on the rollup & its recipient.
function enter(uint256 rollupChainId, address rollupRecipient) public payable {
if (msg.value == 0) return;
emit Enter(rollupChainId, rollupRecipient, msg.value);
}
/// @notice Allows native Ether to enter the default rollup.
/// @dev see `enter` for docs.
function enter(address rollupRecipient) external payable {
enter(defaultRollupChainId, rollupRecipient);
}
/// @notice Allows ERC20 tokens to enter the rollup.
/// @param rollupChainId - The rollup chain to enter.
/// @param rollupRecipient - The recipient of tokens on the rollup.
/// @param token - The host chain address of the token entering the rollup.
/// @param amount - The amount of tokens entering the rollup.
function enterToken(uint256 rollupChainId, address rollupRecipient, address token, uint256 amount)
public
nonReentrant
{
// transfer tokens to this contract
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
// check and emit
_enterToken(rollupChainId, rollupRecipient, token, amount);
}
/// @notice Allows ERC20 tokens to enter the default rollup.
/// @dev see `enterToken` for docs.
function enterToken(address rollupRecipient, address token, uint256 amount) external {
enterToken(defaultRollupChainId, rollupRecipient, token, amount);
}
/// @notice Allows ERC20 tokens to enter the rollup.
/// @param rollupChainId - The rollup chain to enter.
/// @param rollupRecipient - The recipient of tokens on the rollup.
/// @param permit2 - The Permit2 information, including token & amount.
function enterTokenPermit2(uint256 rollupChainId, address rollupRecipient, PassagePermit2.Permit2 calldata permit2)
external
nonReentrant
{
// transfer tokens to this contract via permit2
_permitWitnessTransferFrom(enterWitness(rollupChainId, rollupRecipient), permit2);
// check and emit
_enterToken(rollupChainId, rollupRecipient, permit2.permit.permitted.token, permit2.permit.permitted.amount);
}
/// @notice Alow/Disallow a given ERC20 token to enter the rollup.
function configureEnter(address token, bool _canEnter) external {
if (msg.sender != tokenAdmin) revert OnlyTokenAdmin();
if (canEnter[token] != _canEnter) _configureEnter(token, _canEnter);
}
/// @notice Allows the admin to withdraw ETH or ERC20 tokens from the contract.
/// @dev Only the admin can call this function.
function withdraw(address token, address recipient, uint256 amount) external nonReentrant {
if (msg.sender != tokenAdmin) revert OnlyTokenAdmin();
if (token == address(0)) {
payable(recipient).sendValue(amount);
} else {
IERC20(token).safeTransfer(recipient, amount);
}
emit Withdrawal(token, recipient, amount);
}
/// @notice Shared functionality for tokens entering rollup.
function _enterToken(uint256 rollupChainId, address rollupRecipient, address token, uint256 amount) internal {
if (amount == 0) return;
if (!canEnter[token]) revert DisallowedEnter(token);
emit EnterToken(rollupChainId, rollupRecipient, token, amount);
}
/// @notice Helper to configure ERC20 enters on deploy & via admin function
function _configureEnter(address token, bool _canEnter) internal {
canEnter[token] = _canEnter;
emit EnterConfigured(token, _canEnter);
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.26;
import {UsesPermit2} from "../UsesPermit2.sol";
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
abstract contract PassagePermit2 is UsesPermit2 {
string constant _ENTER_WITNESS_TYPESTRING =
"EnterWitness witness)EnterWitness(uint256 rollupChainId,address rollupRecipient)TokenPermissions(address token,uint256 amount)";
bytes32 constant _ENTER_WITNESS_TYPEHASH = keccak256("EnterWitness(uint256 rollupChainId,address rollupRecipient)");
string constant _EXIT_WITNESS_TYPESTRING =
"ExitWitness witness)ExitWitness(address hostRecipient)TokenPermissions(address token,uint256 amount)";
bytes32 constant _EXIT_WITNESS_TYPEHASH = keccak256("ExitWitness(address hostRecipient)");
/// @notice Struct to hash Enter witness data into a 32-byte witness field, in an EIP-712 compliant way.
struct EnterWitness {
uint256 rollupChainId;
address rollupRecipient;
}
/// @notice Struct to hash Exit witness data into a 32-byte witness field, in an EIP-712 compliant way.
struct ExitWitness {
address hostRecipient;
}
/// @notice Encode & hash the rollupChainId and rollupRecipient for use as a permit2 witness.
/// @return _witness - the hashed witness and its typestring.
function enterWitness(uint256 rollupChainId, address rollupRecipient)
public
pure
returns (Witness memory _witness)
{
_witness.witnessHash =
keccak256(abi.encode(_ENTER_WITNESS_TYPEHASH, EnterWitness(rollupChainId, rollupRecipient)));
_witness.witnessTypeString = _ENTER_WITNESS_TYPESTRING;
}
/// @notice Hash the hostRecipient for use as a permit2 witness.
/// @return _witness - the hashed witness and its typestring.
function exitWitness(address hostRecipient) public pure returns (Witness memory _witness) {
_witness.witnessHash = keccak256(abi.encode(_EXIT_WITNESS_TYPEHASH, ExitWitness(hostRecipient)));
_witness.witnessTypeString = _EXIT_WITNESS_TYPESTRING;
}
/// @notice Transfer tokens using permit2.
/// @param _witness - the hashed witness and its typestring.
/// @param permit2 - the Permit2 information.
function _permitWitnessTransferFrom(Witness memory _witness, Permit2 calldata permit2) internal {
ISignatureTransfer(permit2Contract).permitWitnessTransferFrom(
permit2.permit,
_selfTransferDetails(permit2.permit.permitted.amount),
permit2.owner,
_witness.witnessHash,
_witness.witnessTypeString,
permit2.signature
);
}
/// @notice Construct TransferDetails transferring a balance to this contract, for passing to permit2.
/// @dev always transfers the full amount to address(this).
/// @param amount - the amount to transfer to this contract.
/// @return transferDetails - the SignatureTransferDetails generated.
function _selfTransferDetails(uint256 amount)
internal
view
returns (ISignatureTransfer.SignatureTransferDetails memory transferDetails)
{
transferDetails.to = address(this);
transferDetails.requestedAmount = amount;
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.26;
import {IOrders} from "./orders/IOrders.sol";
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
abstract contract UsesPermit2 {
/// @param permit - the permit2 single token transfer details. includes a `deadline` and an unordered `nonce`.
/// @param signer - the signer of the permit2 info; the owner of the tokens.
/// @param signature - the signature over the permit + witness.
struct Permit2 {
ISignatureTransfer.PermitTransferFrom permit;
address owner;
bytes signature;
}
/// @param permit - the permit2 batch token transfer details. includes a `deadline` and an unordered `nonce`.
/// @param signer - the signer of the permit2 info; the owner of the tokens.
/// @param signature - the signature over the permit + witness.
struct Permit2Batch {
ISignatureTransfer.PermitBatchTransferFrom permit;
address owner;
bytes signature;
}
/// @notice Struct to hold the pre-hashed witness field and the witness type string.
struct Witness {
bytes32 witnessHash;
string witnessTypeString;
}
/// @notice The Permit2 contract address.
address immutable permit2Contract;
constructor(address _permit2) {
permit2Contract = _permit2;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 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 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
if (!_safeTransfer(token, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
if (!_safeTransferFrom(token, from, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _safeTransfer(token, to, value, false);
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _safeTransferFrom(token, from, to, value, false);
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
if (!_safeApprove(token, spender, value, false)) {
if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Oppositely, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity `token.transfer(to, value)` call, 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 to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.transfer.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(to, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
/**
* @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, 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 from The sender of the tokens
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.transferFrom.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(from, shr(96, not(0))))
mstore(0x24, and(to, shr(96, not(0))))
mstore(0x44, value)
success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
mstore(0x60, 0)
}
}
/**
* @dev Imitates a Solidity `token.approve(spender, value)` call, 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 spender The spender of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.approve.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(spender, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
import {LowLevelCall} from "./LowLevelCall.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
if (LowLevelCall.callNoReturn(recipient, amount, "")) {
// call successful, nothing to do
return;
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
bool success = LowLevelCall.callNoReturn(target, value, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
bool success = LowLevelCall.staticcallNoReturn(target, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
bool success = LowLevelCall.delegatecallNoReturn(target, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*
* NOTE: This function is DEPRECATED and may be removed in the next major release.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (success && (returndata.length > 0 || target.code.length > 0)) {
return returndata;
} else if (success) {
revert AddressEmptyCode(target);
} else if (returndata.length > 0) {
LowLevelCall.bubbleRevert(returndata);
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else if (returndata.length > 0) {
LowLevelCall.bubbleRevert(returndata);
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/ReentrancyGuardTransient.sol)
pragma solidity ^0.8.24;
import {TransientSlot} from "./TransientSlot.sol";
/**
* @dev Variant of {ReentrancyGuard} that uses transient storage.
*
* NOTE: This variant only works on networks where EIP-1153 is available.
*
* _Available since v5.1._
*
* @custom:stateless
*/
abstract contract ReentrancyGuardTransient {
using TransientSlot for *;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
/**
* @dev A `view` only version of {nonReentrant}. Use to block view functions
* from being called, preventing reading from inconsistent contract state.
*
* CAUTION: This is a "view" modifier and does not change the reentrancy
* status. Use it only on view functions. For payable or non-payable functions,
* use the standard {nonReentrant} modifier instead.
*/
modifier nonReentrantView() {
_nonReentrantBeforeView();
_;
}
function _nonReentrantBeforeView() private view {
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false
_nonReentrantBeforeView();
// Any calls to nonReentrant after this point will fail
_reentrancyGuardStorageSlot().asBoolean().tstore(true);
}
function _nonReentrantAfter() private {
_reentrancyGuardStorageSlot().asBoolean().tstore(false);
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _reentrancyGuardStorageSlot().asBoolean().tload();
}
function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
return REENTRANCY_GUARD_STORAGE;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IEIP712} from "./IEIP712.sol";
/// @title SignatureTransfer
/// @notice Handles ERC20 token transfers through signature based actions
/// @dev Requires user's token approval on the Permit2 contract
interface ISignatureTransfer is IEIP712 {
/// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount
/// @param maxAmount The maximum amount a spender can request to transfer
error InvalidAmount(uint256 maxAmount);
/// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred
/// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred
error LengthMismatch();
/// @notice Emits an event when the owner successfully invalidates an unordered nonce.
event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);
/// @notice The token and amount details for a transfer signed in the permit transfer signature
struct TokenPermissions {
// ERC20 token address
address token;
// the maximum amount that can be spent
uint256 amount;
}
/// @notice The signed permit message for a single token transfer
struct PermitTransferFrom {
TokenPermissions permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice Specifies the recipient address and amount for batched transfers.
/// @dev Recipients and amounts correspond to the index of the signed token permissions array.
/// @dev Reverts if the requested amount is greater than the permitted signed amount.
struct SignatureTransferDetails {
// recipient address
address to;
// spender requested amount
uint256 requestedAmount;
}
/// @notice Used to reconstruct the signed permit message for multiple token transfers
/// @dev Do not need to pass in spender address as it is required that it is msg.sender
/// @dev Note that a user still signs over a spender address
struct PermitBatchTransferFrom {
// the tokens and corresponding amounts permitted for a transfer
TokenPermissions[] permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection
/// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order
/// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce
/// @dev It returns a uint256 bitmap
/// @dev The index, or wordPosition is capped at type(uint248).max
function nonceBitmap(address, uint256) external view returns (uint256);
/// @notice Transfers a token using a signed permit message
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param signature The signature to verify
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers a token using a signed permit message
/// @notice Includes extra data provided by the caller to verify signature over
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param signature The signature to verify
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @notice Includes extra data provided by the caller to verify signature over
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Invalidates the bits specified in mask for the bitmap at the word position
/// @dev The wordPos is maxed at type(uint248).max
/// @param wordPos A number to index the nonceBitmap at
/// @param mask A bitmap masked against msg.sender's current bitmap at the word position
function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.26;
interface IOrders {
/// @notice Tokens sent by the swapper as inputs to the order
/// @dev From ERC-7683
struct Input {
/// @dev The address of the ERC20 token on the origin chain
address token;
/// @dev The amount of the token to be sent
uint256 amount;
}
/// @notice Tokens that must be receive for a valid order fulfillment
/// @dev From ERC-7683
struct Output {
/// @dev The address of the ERC20 token on the destination chain
/// @dev address(0) used as a sentinel for the native token
address token;
/// @dev The amount of the token to be sent
uint256 amount;
/// @dev The address to receive the output tokens
address recipient;
/// @dev When emitted on the origin chain, the destination chain for the Output.
/// When emitted on the destination chain, the origin chain for the Order containing the Output.
uint32 chainId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Library of low level call functions that implement different calling strategies to deal with the return data.
*
* WARNING: Using this library requires an advanced understanding of Solidity and how the EVM works. It is recommended
* to use the {Address} library instead.
*/
library LowLevelCall {
/// @dev Performs a Solidity function call using a low level `call` and ignoring the return data.
function callNoReturn(address target, bytes memory data) internal returns (bool success) {
return callNoReturn(target, 0, data);
}
/// @dev Same as {callNoReturn}, but allows to specify the value to be sent in the call.
function callNoReturn(address target, uint256 value, bytes memory data) internal returns (bool success) {
assembly ("memory-safe") {
success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `call` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function callReturn64Bytes(
address target,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
return callReturn64Bytes(target, 0, data);
}
/// @dev Same as {callReturnBytes32Pair}, but allows to specify the value to be sent in the call.
function callReturn64Bytes(
address target,
uint256 value,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Performs a Solidity function call using a low level `staticcall` and ignoring the return data.
function staticcallNoReturn(address target, bytes memory data) internal view returns (bool success) {
assembly ("memory-safe") {
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `staticcall` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function staticcallReturn64Bytes(
address target,
bytes memory data
) internal view returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Performs a Solidity function call using a low level `delegatecall` and ignoring the return data.
function delegatecallNoReturn(address target, bytes memory data) internal returns (bool success) {
assembly ("memory-safe") {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `delegatecall` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function delegatecallReturn64Bytes(
address target,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Returns the size of the return data buffer.
function returnDataSize() internal pure returns (uint256 size) {
assembly ("memory-safe") {
size := returndatasize()
}
}
/// @dev Returns a buffer containing the return data from the last call.
function returnData() internal pure returns (bytes memory result) {
assembly ("memory-safe") {
result := mload(0x40)
mstore(result, returndatasize())
returndatacopy(add(result, 0x20), 0x00, returndatasize())
mstore(0x40, add(result, add(0x20, returndatasize())))
}
}
/// @dev Revert with the return data from the last call.
function bubbleRevert() internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
}
function bubbleRevert(bytes memory returndata) internal pure {
assembly ("memory-safe") {
revert(add(returndata, 0x20), mload(returndata))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.
pragma solidity ^0.8.24;
/**
* @dev Library for reading and writing value-types to specific transient storage slots.
*
* Transient slots are often used to store temporary values that are removed after the current transaction.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* * Example reading and writing values using transient storage:
* ```solidity
* contract Lock {
* using TransientSlot for *;
*
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
*
* modifier locked() {
* require(!_LOCK_SLOT.asBoolean().tload());
*
* _LOCK_SLOT.asBoolean().tstore(true);
* _;
* _LOCK_SLOT.asBoolean().tstore(false);
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library TransientSlot {
/**
* @dev UDVT that represents a slot holding an address.
*/
type AddressSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a AddressSlot.
*/
function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
return AddressSlot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a bool.
*/
type BooleanSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a BooleanSlot.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
return BooleanSlot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a bytes32.
*/
type Bytes32Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Bytes32Slot.
*/
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
return Bytes32Slot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a uint256.
*/
type Uint256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Uint256Slot.
*/
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
return Uint256Slot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a int256.
*/
type Int256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Int256Slot.
*/
function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
return Int256Slot.wrap(slot);
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(AddressSlot slot) internal view returns (address value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(AddressSlot slot, address value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlot slot) internal view returns (bool value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlot slot, bool value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Bytes32Slot slot, bytes32 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Uint256Slot slot) internal view returns (uint256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Uint256Slot slot, uint256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Int256Slot slot) internal view returns (int256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Int256Slot slot, int256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IEIP712 {
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@openzeppelin/=lib/stablecoin-evm/node_modules/@openzeppelin/",
"ds-test/=lib/permit2/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-gas-snapshot/=lib/permit2/lib/forge-gas-snapshot/src/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"permit2/=lib/permit2/",
"safe-smart-account/=lib/safe-smart-account/",
"simple-erc20/=lib/simple-erc20/src/",
"solmate/=lib/permit2/lib/solmate/",
"stablecoin-evm/=lib/stablecoin-evm/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"_defaultRollupChainId","type":"uint256"},{"internalType":"address","name":"_tokenAdmin","type":"address"},{"internalType":"address[]","name":"initialEnterTokens","type":"address[]"},{"internalType":"address","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"DisallowedEnter","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"OnlyTokenAdmin","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"rollupRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Enter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bool","name":"canEnter","type":"bool"}],"name":"EnterConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"rollupRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EnterToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"canEnter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"_canEnter","type":"bool"}],"name":"configureEnter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultRollupChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rollupRecipient","type":"address"}],"name":"enter","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rollupChainId","type":"uint256"},{"internalType":"address","name":"rollupRecipient","type":"address"}],"name":"enter","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rollupChainId","type":"uint256"},{"internalType":"address","name":"rollupRecipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"enterToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rollupRecipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"enterToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rollupChainId","type":"uint256"},{"internalType":"address","name":"rollupRecipient","type":"address"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ISignatureTransfer.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ISignatureTransfer.PermitTransferFrom","name":"permit","type":"tuple"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UsesPermit2.Permit2","name":"permit2","type":"tuple"}],"name":"enterTokenPermit2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rollupChainId","type":"uint256"},{"internalType":"address","name":"rollupRecipient","type":"address"}],"name":"enterWitness","outputs":[{"components":[{"internalType":"bytes32","name":"witnessHash","type":"bytes32"},{"internalType":"string","name":"witnessTypeString","type":"string"}],"internalType":"struct UsesPermit2.Witness","name":"_witness","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"hostRecipient","type":"address"}],"name":"exitWitness","outputs":[{"components":[{"internalType":"bytes32","name":"witnessHash","type":"bytes32"},{"internalType":"string","name":"witnessTypeString","type":"string"}],"internalType":"struct UsesPermit2.Witness","name":"_witness","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"tokenAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e060405234801561000f575f80fd5b50604051611bcf380380611bcf8339818101604052810190610031919061037b565b808073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050508360a081815250508273ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505f5b82518110156100e6576100d98382815181106100c4576100c36103fb565b5b602002602001015160016100f060201b60201c565b80806001019150506100a5565b5050505050610428565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508015158273ffffffffffffffffffffffffffffffffffffffff167f2f8601534249821eb3b2cf9f1d88960ce5b7feb89b9e4a117d2ac7725c56539360405160405180910390a35050565b5f604051905090565b5f80fd5b5f80fd5b5f819050919050565b6101b08161019e565b81146101ba575f80fd5b50565b5f815190506101cb816101a7565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6101fa826101d1565b9050919050565b61020a816101f0565b8114610214575f80fd5b50565b5f8151905061022581610201565b92915050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6102758261022f565b810181811067ffffffffffffffff821117156102945761029361023f565b5b80604052505050565b5f6102a661018d565b90506102b2828261026c565b919050565b5f67ffffffffffffffff8211156102d1576102d061023f565b5b602082029050602081019050919050565b5f80fd5b5f6102f86102f3846102b7565b61029d565b9050808382526020820190506020840283018581111561031b5761031a6102e2565b5b835b8181101561034457806103308882610217565b84526020840193505060208101905061031d565b5050509392505050565b5f82601f8301126103625761036161022b565b5b81516103728482602086016102e6565b91505092915050565b5f805f806080858703121561039357610392610196565b5b5f6103a0878288016101bd565b94505060206103b187828801610217565b935050604085015167ffffffffffffffff8111156103d2576103d161019a565b5b6103de8782880161034e565b92505060606103ef87828801610217565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60805160a05160c05161175561047a5f395f81816105280152818161060f015261066801525f818160b40152818160e00152818161046901528181610504015261063601525f610a3401526117555ff3fe6080604052600436106100aa575f3560e01c8063b32ed95e11610063578063b32ed95e14610221578063b7e1917c14610249578063d014c01f14610273578063d9caed121461028f578063ea3b9ba1146102b7578063eba1f981146102d3576100db565b806322ac3885146101075780633930e3911461012f578063416ef5a81461016b5780634f8b4a3c14610193578063942c39db146101cf57806395577b72146101f7576100db565b366100db576100d97f00000000000000000000000000000000000000000000000000000000000000003361030f565b005b6101057f00000000000000000000000000000000000000000000000000000000000000003361030f565b005b348015610112575f80fd5b5061012d60048036038101906101289190610f72565b61036b565b005b34801561013a575f80fd5b5061015560048036038101906101509190610fd6565b6103ba565b60405161016291906110d6565b60405180910390f35b348015610176575f80fd5b50610191600480360381019061018c91906110f6565b610464565b005b34801561019e575f80fd5b506101b960048036038101906101b49190611146565b610495565b6040516101c6919061118b565b60405180910390f35b3480156101da575f80fd5b506101f560048036038101906101f091906111c6565b6104b1565b005b348015610202575f80fd5b5061020b610502565b6040516102189190611241565b60405180910390f35b34801561022c575f80fd5b5061024760048036038101906102429190611284565b610526565b005b348015610254575f80fd5b5061025d61060d565b60405161026a91906112d1565b60405180910390f35b61028d60048036038101906102889190611146565b610631565b005b34801561029a575f80fd5b506102b560048036038101906102b091906110f6565b61065e565b005b6102d160048036038101906102cc9190610fd6565b61030f565b005b3480156102de575f80fd5b506102f960048036038101906102f49190611146565b6107ea565b60405161030691906110d6565b60405180910390f35b5f340315610367578073ffffffffffffffffffffffffffffffffffffffff16827f5f67e0a44fbb8ec0f3794c6687c657244a50a7da2411d14707aa219d86b854923460405161035e9190611241565b60405180910390a35b5050565b61037361088d565b6103a03330838573ffffffffffffffffffffffffffffffffffffffff166108ba909392919063ffffffff16565b6103ac8484848461090f565b6103b4610a0e565b50505050565b6103c2610e93565b7fc5d03356b54a64d088070694ab907941e70a5ea4ae772ff6df7f162d054037b660405180604001604052808581526020018473ffffffffffffffffffffffffffffffffffffffff1681525060405160200161041f929190611344565b60405160208183030381529060405280519060200120815f0181815250506040518060a00160405280607e815260200161163e607e9139816020018190525092915050565b6104907f000000000000000000000000000000000000000000000000000000000000000084848461036b565b505050565b5f602052805f5260405f205f915054906101000a900460ff1681565b6104b961088d565b6104cc6104c684846103ba565b82610a32565b6104f58383835f015f015f0160208101906104e79190611146565b845f015f016020013561090f565b6104fd610a0e565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146105ab576040517f21dba17e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015155f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16151514610609576106088282610b01565b5b5050565b7f000000000000000000000000000000000000000000000000000000000000000081565b61065b7f00000000000000000000000000000000000000000000000000000000000000008261030f565b50565b61066661088d565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106eb576040517f21dba17e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361074c57610747818373ffffffffffffffffffffffffffffffffffffffff16610b9e90919063ffffffff16565b610778565b61077782828573ffffffffffffffffffffffffffffffffffffffff16610c559092919063ffffffff16565b5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398836040516107d59190611241565b60405180910390a36107e5610a0e565b505050565b6107f2610e93565b7fa91a2bac0243280e19cfd0a3ae9d7639a15fa41d49eab3e0bf320c8485cc66a960405180602001604052808473ffffffffffffffffffffffffffffffffffffffff16815250604051602001610849929190611385565b60405160208183030381529060405280519060200120815f0181815250506040518060a00160405280606481526020016116bc606491398160200181905250919050565b610895610ca8565b6108b860016108aa6108a5610ce9565b610d12565b610d1b90919063ffffffff16565b565b6108c8848484846001610d22565b61090957836040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161090091906112d1565b60405180910390fd5b50505050565b5f810315610a08575f808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166109a157816040517f087fe76b00000000000000000000000000000000000000000000000000000000815260040161099891906112d1565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f918d96675770fc73e96feacdd04b31ed125e0e5e0223938cd0043a42228a49e4846040516109ff9190611241565b60405180910390a45b50505050565b610a305f610a22610a1d610ce9565b610d12565b610d1b90919063ffffffff16565b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663137c29fe825f01610a82845f015f0160200135610d93565b846080016020810190610a959190611146565b865f01518760200151878060a00190610aae91906113b8565b6040518863ffffffff1660e01b8152600401610ad097969594939291906115a4565b5f604051808303815f87803b158015610ae7575f80fd5b505af1158015610af9573d5f803e3d5ffd5b505050505050565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508015158273ffffffffffffffffffffffffffffffffffffffff167f2f8601534249821eb3b2cf9f1d88960ce5b7feb89b9e4a117d2ac7725c56539360405160405180910390a35050565b80471015610be55747816040517fcf479181000000000000000000000000000000000000000000000000000000008152600401610bdc929190611616565b60405180910390fd5b610bfe828260405180602001604052805f815250610de1565b610c51575f610c0b610df7565b1115610c1e57610c19610dfe565b610c50565b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b5050565b610c628383836001610e09565b610ca357826040517f5274afe7000000000000000000000000000000000000000000000000000000008152600401610c9a91906112d1565b60405180910390fd5b505050565b610cb0610e6b565b15610ce7576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005f1b905090565b5f819050919050565b80825d5050565b5f806323b872dd60e01b9050604051815f525f1960601c87166004525f1960601c86166024528460445260205f60645f808c5af1925060015f51148316610d80578383151615610d74573d5f823e3d81fd5b5f883b113d1516831692505b806040525f606052505095945050505050565b610d9b610eaf565b30815f019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081816020018181525050919050565b5f805f83516020850186885af190509392505050565b5f3d905090565b6040513d5f823e3d81fd5b5f8063a9059cbb60e01b9050604051815f525f1960601c86166004528460245260205f60445f808b5af1925060015f51148316610e5d578383151615610e51573d5f823e3d81fd5b5f873b113d1516831692505b806040525050949350505050565b5f610e84610e7f610e7a610ce9565b610d12565b610e89565b905090565b5f815c9050919050565b60405180604001604052805f8019168152602001606081525090565b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81525090565b5f80fd5b5f80fd5b5f819050919050565b610ef781610ee5565b8114610f01575f80fd5b50565b5f81359050610f1281610eee565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610f4182610f18565b9050919050565b610f5181610f37565b8114610f5b575f80fd5b50565b5f81359050610f6c81610f48565b92915050565b5f805f8060808587031215610f8a57610f89610edd565b5b5f610f9787828801610f04565b9450506020610fa887828801610f5e565b9350506040610fb987828801610f5e565b9250506060610fca87828801610f04565b91505092959194509250565b5f8060408385031215610fec57610feb610edd565b5b5f610ff985828601610f04565b925050602061100a85828601610f5e565b9150509250929050565b5f819050919050565b61102681611014565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61106e8261102c565b6110788185611036565b9350611088818560208601611046565b61109181611054565b840191505092915050565b5f604083015f8301516110b15f86018261101d565b50602083015184820360208601526110c98282611064565b9150508091505092915050565b5f6020820190508181035f8301526110ee818461109c565b905092915050565b5f805f6060848603121561110d5761110c610edd565b5b5f61111a86828701610f5e565b935050602061112b86828701610f5e565b925050604061113c86828701610f04565b9150509250925092565b5f6020828403121561115b5761115a610edd565b5b5f61116884828501610f5e565b91505092915050565b5f8115159050919050565b61118581611171565b82525050565b5f60208201905061119e5f83018461117c565b92915050565b5f80fd5b5f60c082840312156111bd576111bc6111a4565b5b81905092915050565b5f805f606084860312156111dd576111dc610edd565b5b5f6111ea86828701610f04565b93505060206111fb86828701610f5e565b925050604084013567ffffffffffffffff81111561121c5761121b610ee1565b5b611228868287016111a8565b9150509250925092565b61123b81610ee5565b82525050565b5f6020820190506112545f830184611232565b92915050565b61126381611171565b811461126d575f80fd5b50565b5f8135905061127e8161125a565b92915050565b5f806040838503121561129a57611299610edd565b5b5f6112a785828601610f5e565b92505060206112b885828601611270565b9150509250929050565b6112cb81610f37565b82525050565b5f6020820190506112e45f8301846112c2565b92915050565b6112f381611014565b82525050565b61130281610ee5565b82525050565b61131181610f37565b82525050565b604082015f82015161132b5f8501826112f9565b50602082015161133e6020850182611308565b50505050565b5f6060820190506113575f8301856112ea565b6113646020830184611317565b9392505050565b602082015f82015161137f5f850182611308565b50505050565b5f6040820190506113985f8301856112ea565b6113a5602083018461136b565b9392505050565b5f80fd5b5f80fd5b5f80fd5b5f80833560016020038436030381126113d4576113d36113ac565b5b80840192508235915067ffffffffffffffff8211156113f6576113f56113b0565b5b602083019250600182023603831315611412576114116113b4565b5b509250929050565b5f82905092915050565b5f6114326020840184610f5e565b905092915050565b5f6114486020840184610f04565b905092915050565b604082016114605f830183611424565b61146c5f850182611308565b5061147a602083018361143a565b61148760208501826112f9565b50505050565b6080820161149d5f83018361141a565b6114a95f850182611450565b506114b7604083018361143a565b6114c460408501826112f9565b506114d2606083018361143a565b6114df60608501826112f9565b50505050565b604082015f8201516114f95f850182611308565b50602082015161150c60208501826112f9565b50505050565b5f82825260208201905092915050565b5f61152c8261102c565b6115368185611512565b9350611546818560208601611046565b61154f81611054565b840191505092915050565b5f82825260208201905092915050565b828183375f83830152505050565b5f611583838561155a565b935061159083858461156a565b61159983611054565b840190509392505050565b5f610140820190506115b85f83018a61148d565b6115c560808301896114e5565b6115d260c08301886112c2565b6115df60e08301876112ea565b8181036101008301526115f28186611522565b9050818103610120830152611608818486611578565b905098975050505050505050565b5f6040820190506116295f830185611232565b6116366020830184611232565b939250505056fe456e7465725769746e657373207769746e65737329456e7465725769746e6573732875696e7432353620726f6c6c7570436861696e49642c6164647265737320726f6c6c7570526563697069656e7429546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429457869745769746e657373207769746e65737329457869745769746e657373286164647265737320686f7374526563697069656e7429546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a2646970667358221220a157bcb9385794d213fbb8872b67d58e9b0bc081338a211cce080e2c2c2f80d864736f6c634300081a00330000000000000000000000000000000000000000000000000000000000000207000000000000000000000000fa963e3d8dfd6817aaf70140c1fbaea094090fa00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000000000000000000000040000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Deployed Bytecode
0x6080604052600436106100aa575f3560e01c8063b32ed95e11610063578063b32ed95e14610221578063b7e1917c14610249578063d014c01f14610273578063d9caed121461028f578063ea3b9ba1146102b7578063eba1f981146102d3576100db565b806322ac3885146101075780633930e3911461012f578063416ef5a81461016b5780634f8b4a3c14610193578063942c39db146101cf57806395577b72146101f7576100db565b366100db576100d97f00000000000000000000000000000000000000000000000000000000000002073361030f565b005b6101057f00000000000000000000000000000000000000000000000000000000000002073361030f565b005b348015610112575f80fd5b5061012d60048036038101906101289190610f72565b61036b565b005b34801561013a575f80fd5b5061015560048036038101906101509190610fd6565b6103ba565b60405161016291906110d6565b60405180910390f35b348015610176575f80fd5b50610191600480360381019061018c91906110f6565b610464565b005b34801561019e575f80fd5b506101b960048036038101906101b49190611146565b610495565b6040516101c6919061118b565b60405180910390f35b3480156101da575f80fd5b506101f560048036038101906101f091906111c6565b6104b1565b005b348015610202575f80fd5b5061020b610502565b6040516102189190611241565b60405180910390f35b34801561022c575f80fd5b5061024760048036038101906102429190611284565b610526565b005b348015610254575f80fd5b5061025d61060d565b60405161026a91906112d1565b60405180910390f35b61028d60048036038101906102889190611146565b610631565b005b34801561029a575f80fd5b506102b560048036038101906102b091906110f6565b61065e565b005b6102d160048036038101906102cc9190610fd6565b61030f565b005b3480156102de575f80fd5b506102f960048036038101906102f49190611146565b6107ea565b60405161030691906110d6565b60405180910390f35b5f340315610367578073ffffffffffffffffffffffffffffffffffffffff16827f5f67e0a44fbb8ec0f3794c6687c657244a50a7da2411d14707aa219d86b854923460405161035e9190611241565b60405180910390a35b5050565b61037361088d565b6103a03330838573ffffffffffffffffffffffffffffffffffffffff166108ba909392919063ffffffff16565b6103ac8484848461090f565b6103b4610a0e565b50505050565b6103c2610e93565b7fc5d03356b54a64d088070694ab907941e70a5ea4ae772ff6df7f162d054037b660405180604001604052808581526020018473ffffffffffffffffffffffffffffffffffffffff1681525060405160200161041f929190611344565b60405160208183030381529060405280519060200120815f0181815250506040518060a00160405280607e815260200161163e607e9139816020018190525092915050565b6104907f000000000000000000000000000000000000000000000000000000000000020784848461036b565b505050565b5f602052805f5260405f205f915054906101000a900460ff1681565b6104b961088d565b6104cc6104c684846103ba565b82610a32565b6104f58383835f015f015f0160208101906104e79190611146565b845f015f016020013561090f565b6104fd610a0e565b505050565b7f000000000000000000000000000000000000000000000000000000000000020781565b7f000000000000000000000000fa963e3d8dfd6817aaf70140c1fbaea094090fa073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146105ab576040517f21dba17e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015155f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16151514610609576106088282610b01565b5b5050565b7f000000000000000000000000fa963e3d8dfd6817aaf70140c1fbaea094090fa081565b61065b7f00000000000000000000000000000000000000000000000000000000000002078261030f565b50565b61066661088d565b7f000000000000000000000000fa963e3d8dfd6817aaf70140c1fbaea094090fa073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106eb576040517f21dba17e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361074c57610747818373ffffffffffffffffffffffffffffffffffffffff16610b9e90919063ffffffff16565b610778565b61077782828573ffffffffffffffffffffffffffffffffffffffff16610c559092919063ffffffff16565b5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398836040516107d59190611241565b60405180910390a36107e5610a0e565b505050565b6107f2610e93565b7fa91a2bac0243280e19cfd0a3ae9d7639a15fa41d49eab3e0bf320c8485cc66a960405180602001604052808473ffffffffffffffffffffffffffffffffffffffff16815250604051602001610849929190611385565b60405160208183030381529060405280519060200120815f0181815250506040518060a00160405280606481526020016116bc606491398160200181905250919050565b610895610ca8565b6108b860016108aa6108a5610ce9565b610d12565b610d1b90919063ffffffff16565b565b6108c8848484846001610d22565b61090957836040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161090091906112d1565b60405180910390fd5b50505050565b5f810315610a08575f808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff166109a157816040517f087fe76b00000000000000000000000000000000000000000000000000000000815260040161099891906112d1565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f918d96675770fc73e96feacdd04b31ed125e0e5e0223938cd0043a42228a49e4846040516109ff9190611241565b60405180910390a45b50505050565b610a305f610a22610a1d610ce9565b610d12565b610d1b90919063ffffffff16565b565b7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba373ffffffffffffffffffffffffffffffffffffffff1663137c29fe825f01610a82845f015f0160200135610d93565b846080016020810190610a959190611146565b865f01518760200151878060a00190610aae91906113b8565b6040518863ffffffff1660e01b8152600401610ad097969594939291906115a4565b5f604051808303815f87803b158015610ae7575f80fd5b505af1158015610af9573d5f803e3d5ffd5b505050505050565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508015158273ffffffffffffffffffffffffffffffffffffffff167f2f8601534249821eb3b2cf9f1d88960ce5b7feb89b9e4a117d2ac7725c56539360405160405180910390a35050565b80471015610be55747816040517fcf479181000000000000000000000000000000000000000000000000000000008152600401610bdc929190611616565b60405180910390fd5b610bfe828260405180602001604052805f815250610de1565b610c51575f610c0b610df7565b1115610c1e57610c19610dfe565b610c50565b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b5050565b610c628383836001610e09565b610ca357826040517f5274afe7000000000000000000000000000000000000000000000000000000008152600401610c9a91906112d1565b60405180910390fd5b505050565b610cb0610e6b565b15610ce7576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005f1b905090565b5f819050919050565b80825d5050565b5f806323b872dd60e01b9050604051815f525f1960601c87166004525f1960601c86166024528460445260205f60645f808c5af1925060015f51148316610d80578383151615610d74573d5f823e3d81fd5b5f883b113d1516831692505b806040525f606052505095945050505050565b610d9b610eaf565b30815f019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081816020018181525050919050565b5f805f83516020850186885af190509392505050565b5f3d905090565b6040513d5f823e3d81fd5b5f8063a9059cbb60e01b9050604051815f525f1960601c86166004528460245260205f60445f808b5af1925060015f51148316610e5d578383151615610e51573d5f823e3d81fd5b5f873b113d1516831692505b806040525050949350505050565b5f610e84610e7f610e7a610ce9565b610d12565b610e89565b905090565b5f815c9050919050565b60405180604001604052805f8019168152602001606081525090565b60405180604001604052805f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81525090565b5f80fd5b5f80fd5b5f819050919050565b610ef781610ee5565b8114610f01575f80fd5b50565b5f81359050610f1281610eee565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610f4182610f18565b9050919050565b610f5181610f37565b8114610f5b575f80fd5b50565b5f81359050610f6c81610f48565b92915050565b5f805f8060808587031215610f8a57610f89610edd565b5b5f610f9787828801610f04565b9450506020610fa887828801610f5e565b9350506040610fb987828801610f5e565b9250506060610fca87828801610f04565b91505092959194509250565b5f8060408385031215610fec57610feb610edd565b5b5f610ff985828601610f04565b925050602061100a85828601610f5e565b9150509250929050565b5f819050919050565b61102681611014565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61106e8261102c565b6110788185611036565b9350611088818560208601611046565b61109181611054565b840191505092915050565b5f604083015f8301516110b15f86018261101d565b50602083015184820360208601526110c98282611064565b9150508091505092915050565b5f6020820190508181035f8301526110ee818461109c565b905092915050565b5f805f6060848603121561110d5761110c610edd565b5b5f61111a86828701610f5e565b935050602061112b86828701610f5e565b925050604061113c86828701610f04565b9150509250925092565b5f6020828403121561115b5761115a610edd565b5b5f61116884828501610f5e565b91505092915050565b5f8115159050919050565b61118581611171565b82525050565b5f60208201905061119e5f83018461117c565b92915050565b5f80fd5b5f60c082840312156111bd576111bc6111a4565b5b81905092915050565b5f805f606084860312156111dd576111dc610edd565b5b5f6111ea86828701610f04565b93505060206111fb86828701610f5e565b925050604084013567ffffffffffffffff81111561121c5761121b610ee1565b5b611228868287016111a8565b9150509250925092565b61123b81610ee5565b82525050565b5f6020820190506112545f830184611232565b92915050565b61126381611171565b811461126d575f80fd5b50565b5f8135905061127e8161125a565b92915050565b5f806040838503121561129a57611299610edd565b5b5f6112a785828601610f5e565b92505060206112b885828601611270565b9150509250929050565b6112cb81610f37565b82525050565b5f6020820190506112e45f8301846112c2565b92915050565b6112f381611014565b82525050565b61130281610ee5565b82525050565b61131181610f37565b82525050565b604082015f82015161132b5f8501826112f9565b50602082015161133e6020850182611308565b50505050565b5f6060820190506113575f8301856112ea565b6113646020830184611317565b9392505050565b602082015f82015161137f5f850182611308565b50505050565b5f6040820190506113985f8301856112ea565b6113a5602083018461136b565b9392505050565b5f80fd5b5f80fd5b5f80fd5b5f80833560016020038436030381126113d4576113d36113ac565b5b80840192508235915067ffffffffffffffff8211156113f6576113f56113b0565b5b602083019250600182023603831315611412576114116113b4565b5b509250929050565b5f82905092915050565b5f6114326020840184610f5e565b905092915050565b5f6114486020840184610f04565b905092915050565b604082016114605f830183611424565b61146c5f850182611308565b5061147a602083018361143a565b61148760208501826112f9565b50505050565b6080820161149d5f83018361141a565b6114a95f850182611450565b506114b7604083018361143a565b6114c460408501826112f9565b506114d2606083018361143a565b6114df60608501826112f9565b50505050565b604082015f8201516114f95f850182611308565b50602082015161150c60208501826112f9565b50505050565b5f82825260208201905092915050565b5f61152c8261102c565b6115368185611512565b9350611546818560208601611046565b61154f81611054565b840191505092915050565b5f82825260208201905092915050565b828183375f83830152505050565b5f611583838561155a565b935061159083858461156a565b61159983611054565b840190509392505050565b5f610140820190506115b85f83018a61148d565b6115c560808301896114e5565b6115d260c08301886112c2565b6115df60e08301876112ea565b8181036101008301526115f28186611522565b9050818103610120830152611608818486611578565b905098975050505050505050565b5f6040820190506116295f830185611232565b6116366020830184611232565b939250505056fe456e7465725769746e657373207769746e65737329456e7465725769746e6573732875696e7432353620726f6c6c7570436861696e49642c6164647265737320726f6c6c7570526563697069656e7429546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429457869745769746e657373207769746e65737329457869745769746e657373286164647265737320686f7374526563697069656e7429546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a2646970667358221220a157bcb9385794d213fbb8872b67d58e9b0bc081338a211cce080e2c2c2f80d864736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000207000000000000000000000000fa963e3d8dfd6817aaf70140c1fbaea094090fa00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000000000000000000000040000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
-----Decoded View---------------
Arg [0] : _defaultRollupChainId (uint256): 519
Arg [1] : _tokenAdmin (address): 0xfa963E3D8dfD6817aAF70140C1fbAEA094090Fa0
Arg [2] : initialEnterTokens (address[]): 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599,0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0xdAC17F958D2ee523a2206206994597C13D831ec7
Arg [3] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000207
Arg [1] : 000000000000000000000000fa963e3d8dfd6817aaf70140c1fbaea094090fa0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [5] : 0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599
Arg [6] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [7] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [8] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.