ETH Price: $1,605.23 (+1.71%)
Gas: 0.76 Gwei

Contract

0x18d0915ADA0d5969db64CA44A42dB1b51D8421aa
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap And Bridge222210722025-04-08 2:03:5919 mins ago1744077839IN
0x18d0915A...51D8421aa
0 ETH0.000172810.9181009
Swap And Bridge222210712025-04-08 2:03:4719 mins ago1744077827IN
0x18d0915A...51D8421aa
0 ETH0.000342121.79368622
Swap And Bridge222210652025-04-08 2:02:3520 mins ago1744077755IN
0x18d0915A...51D8421aa
0 ETH0.000194761.03471124
Swap And Bridge222210422025-04-08 1:57:5925 mins ago1744077479IN
0x18d0915A...51D8421aa
0 ETH0.000152580.8
Swap And Bridge222210422025-04-08 1:57:5925 mins ago1744077479IN
0x18d0915A...51D8421aa
0 ETH0.000215451.12958644
Swap And Bridge222207892025-04-08 1:06:591 hr ago1744074419IN
0x18d0915A...51D8421aa
0 ETH0.000188621.00205943
Swap And Bridge222206382025-04-08 0:36:471 hr ago1744072607IN
0x18d0915A...51D8421aa
0 ETH0.000099190.52696652
Swap And Bridge222206112025-04-08 0:31:111 hr ago1744072271IN
0x18d0915A...51D8421aa
0 ETH0.00015060.8
Swap And Bridge222205452025-04-08 0:17:592 hrs ago1744071479IN
0x18d0915A...51D8421aa
0 ETH0.000131760.7
Swap And Bridge222201872025-04-07 23:05:473 hrs ago1744067147IN
0x18d0915A...51D8421aa
0 ETH0.000092820.49336019
Swap And Bridge222200892025-04-07 22:45:593 hrs ago1744065959IN
0x18d0915A...51D8421aa
0 ETH0.000152580.8
Swap And Bridge222198652025-04-07 22:00:354 hrs ago1744063235IN
0x18d0915A...51D8421aa
0 ETH0.000267031.4
Swap And Bridge222197062025-04-07 21:28:474 hrs ago1744061327IN
0x18d0915A...51D8421aa
0 ETH0.000587433.12125887
Swap And Bridge222196742025-04-07 21:22:235 hrs ago1744060943IN
0x18d0915A...51D8421aa
0 ETH0.000471752.50620306
Swap And Bridge222196622025-04-07 21:19:595 hrs ago1744060799IN
0x18d0915A...51D8421aa
0 ETH0.000277211.45341818
Swap And Bridge222195792025-04-07 21:03:235 hrs ago1744059803IN
0x18d0915A...51D8421aa
0 ETH0.00035771.9006345
Swap And Bridge222194952025-04-07 20:46:355 hrs ago1744058795IN
0x18d0915A...51D8421aa
0 ETH0.000340071.7832362
Swap And Bridge222194782025-04-07 20:43:115 hrs ago1744058591IN
0x18d0915A...51D8421aa
0 ETH0.000408112.1684789
Swap And Bridge222193292025-04-07 20:12:596 hrs ago1744056779IN
0x18d0915A...51D8421aa
0 ETH0.000382512.03212024
Swap And Bridge222191812025-04-07 19:43:116 hrs ago1744054991IN
0x18d0915A...51D8421aa
0 ETH0.000289061.53565755
Swap And Bridge222191642025-04-07 19:39:476 hrs ago1744054787IN
0x18d0915A...51D8421aa
0 ETH0.000426472.26569642
Swap And Bridge222191542025-04-07 19:37:476 hrs ago1744054667IN
0x18d0915A...51D8421aa
0 ETH0.000351781.86972568
Swap And Bridge222191522025-04-07 19:37:236 hrs ago1744054643IN
0x18d0915A...51D8421aa
0 ETH0.000487062.58756675
Swap And Bridge222190812025-04-07 19:22:597 hrs ago1744053779IN
0x18d0915A...51D8421aa
0 ETH0.000322141.68921714
Swap And Bridge222187332025-04-07 18:12:118 hrs ago1744049531IN
0x18d0915A...51D8421aa
0 ETH0.000376462
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x604060c0221513502025-03-29 8:24:239 days ago1743236663  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UniversalSwapAndBridge

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 9 : SwapAndBridge.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "./interfaces/V3SpokePoolInterface.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./Lockable.sol";
import "@uma/core/contracts/common/implementation/MultiCaller.sol";
import "./libraries/AddressConverters.sol";

/**
 * @title SwapAndBridgeBase
 * @notice Base contract for both variants of SwapAndBridge.
 * @custom:security-contact [email protected]
 */
abstract contract SwapAndBridgeBase is Lockable, MultiCaller {
    using SafeERC20 for IERC20;
    using AddressToBytes32 for address;

    // This contract performs a low level call with arbirary data to an external contract. This is a large attack
    // surface and we should whitelist which function selectors are allowed to be called on the exchange.
    mapping(bytes4 => bool) public allowedSelectors;

    // Across SpokePool we'll submit deposits to with acrossInputToken as the input token.
    V3SpokePoolInterface public immutable SPOKE_POOL;

    // Exchange address or router where the swapping will happen.
    address public immutable EXCHANGE;

    // Params we'll need caller to pass in to specify an Across Deposit. The input token will be swapped into first
    // before submitting a bridge deposit, which is why we don't include the input token amount as it is not known
    // until after the swap.
    struct DepositData {
        // Token received on destination chain.
        address outputToken;
        // Amount of output token to be received by recipient.
        uint256 outputAmount;
        // The account credited with deposit who can submit speedups to the Across deposit.
        address depositor;
        // The account that will receive the output token on the destination chain. If the output token is
        // wrapped native token, then if this is an EOA then they will receive native token on the destination
        // chain and if this is a contract then they will receive an ERC20.
        address recipient;
        // The destination chain identifier.
        uint256 destinationChainid;
        // The account that can exclusively fill the deposit before the exclusivity deadline.
        address exclusiveRelayer;
        // Timestamp of the deposit used by system to charge fees. Must be within short window of time into the past
        // relative to this chain's current time or deposit will revert.
        uint32 quoteTimestamp;
        // The timestamp on the destination chain after which this deposit can no longer be filled.
        uint32 fillDeadline;
        // The timestamp on the destination chain after which anyone can fill the deposit.
        uint32 exclusivityDeadline;
        // Data that is forwarded to the recipient if the recipient is a contract.
        bytes message;
    }

    event SwapBeforeBridge(
        address exchange,
        address indexed swapToken,
        address indexed acrossInputToken,
        uint256 swapTokenAmount,
        uint256 acrossInputAmount,
        address indexed acrossOutputToken,
        uint256 acrossOutputAmount
    );

    /****************************************
     *                ERRORS                *
     ****************************************/
    error MinimumExpectedInputAmount();
    error LeftoverSrcTokens();
    error InvalidFunctionSelector();

    /**
     * @notice Construct a new SwapAndBridgeBase contract.
     * @param _spokePool Address of the SpokePool contract that we'll submit deposits to.
     * @param _exchange Address of the exchange where tokens will be swapped.
     * @param _allowedSelectors Function selectors that are allowed to be called on the exchange.
     */
    constructor(
        V3SpokePoolInterface _spokePool,
        address _exchange,
        bytes4[] memory _allowedSelectors
    ) {
        SPOKE_POOL = _spokePool;
        EXCHANGE = _exchange;
        for (uint256 i = 0; i < _allowedSelectors.length; i++) {
            allowedSelectors[_allowedSelectors[i]] = true;
        }
    }

    // This contract supports two variants of swap and bridge, one that allows one token and another that allows the caller to pass them in.
    function _swapAndBridge(
        bytes calldata routerCalldata,
        uint256 swapTokenAmount,
        uint256 minExpectedInputTokenAmount,
        DepositData calldata depositData,
        IERC20 _swapToken,
        IERC20 _acrossInputToken
    ) internal {
        // Note: this check should never be impactful, but is here out of an abundance of caution.
        // For example, if the exchange address in the contract is also an ERC20 token that is approved by some
        // user on this contract, a malicious actor could call transferFrom to steal the user's tokens.
        if (!allowedSelectors[bytes4(routerCalldata)]) revert InvalidFunctionSelector();

        // Pull tokens from caller into this contract.
        _swapToken.safeTransferFrom(msg.sender, address(this), swapTokenAmount);
        // Swap and run safety checks.
        uint256 srcBalanceBefore = _swapToken.balanceOf(address(this));
        uint256 dstBalanceBefore = _acrossInputToken.balanceOf(address(this));

        _swapToken.safeIncreaseAllowance(EXCHANGE, swapTokenAmount);
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory result) = EXCHANGE.call(routerCalldata);
        require(success, string(result));

        _checkSwapOutputAndDeposit(
            swapTokenAmount,
            srcBalanceBefore,
            dstBalanceBefore,
            minExpectedInputTokenAmount,
            depositData,
            _swapToken,
            _acrossInputToken
        );
    }

    /**
     * @notice Check that the swap returned enough tokens to submit an Across deposit with and then submit the deposit.
     * @param swapTokenAmount Amount of swapToken to swap for a minimum amount of acrossInputToken.
     * @param swapTokenBalanceBefore Balance of swapToken before swap.
     * @param inputTokenBalanceBefore Amount of Across input token we held before swap
     * @param minExpectedInputTokenAmount Minimum amount of received acrossInputToken that we'll bridge
     **/
    function _checkSwapOutputAndDeposit(
        uint256 swapTokenAmount,
        uint256 swapTokenBalanceBefore,
        uint256 inputTokenBalanceBefore,
        uint256 minExpectedInputTokenAmount,
        DepositData calldata depositData,
        IERC20 _swapToken,
        IERC20 _acrossInputToken
    ) internal {
        // Sanity check that we received as many tokens as we require:
        uint256 returnAmount = _acrossInputToken.balanceOf(address(this)) - inputTokenBalanceBefore;
        // Sanity check that received amount from swap is enough to submit Across deposit with.
        if (returnAmount < minExpectedInputTokenAmount) revert MinimumExpectedInputAmount();
        // Sanity check that we don't have any leftover swap tokens that would be locked in this contract (i.e. check
        // that we weren't partial filled).
        if (swapTokenBalanceBefore - _swapToken.balanceOf(address(this)) != swapTokenAmount) revert LeftoverSrcTokens();

        emit SwapBeforeBridge(
            EXCHANGE,
            address(_swapToken),
            address(_acrossInputToken),
            swapTokenAmount,
            returnAmount,
            depositData.outputToken,
            depositData.outputAmount
        );
        // Deposit the swapped tokens into Across and bridge them using remainder of input params.
        _depositV3(_acrossInputToken, returnAmount, depositData);
    }

    /**
     * @notice Approves the spoke pool and calls `depositV3` function with the specified input parameters.
     * @param _acrossInputToken Token to deposit into the spoke pool.
     * @param _acrossInputAmount Amount of the input token to deposit into the spoke pool.
     * @param depositData Specifies the Across deposit params to use.
     */
    function _depositV3(
        IERC20 _acrossInputToken,
        uint256 _acrossInputAmount,
        DepositData calldata depositData
    ) internal {
        _acrossInputToken.safeIncreaseAllowance(address(SPOKE_POOL), _acrossInputAmount);
        SPOKE_POOL.deposit(
            depositData.depositor.toBytes32(),
            depositData.recipient.toBytes32(),
            address(_acrossInputToken).toBytes32(), // input token
            depositData.outputToken.toBytes32(), // output token
            _acrossInputAmount, // input amount.
            depositData.outputAmount, // output amount
            depositData.destinationChainid,
            depositData.exclusiveRelayer.toBytes32(),
            depositData.quoteTimestamp,
            depositData.fillDeadline,
            depositData.exclusivityDeadline,
            depositData.message
        );
    }
}

/**
 * @title SwapAndBridge
 * @notice Allows caller to swap between two pre-specified tokens on a chain before bridging the received token
 * via Across atomically. Provides safety checks post-swap and before-deposit.
 * @dev This variant primarily exists
 */
contract SwapAndBridge is SwapAndBridgeBase {
    using SafeERC20 for IERC20;

    // This contract simply enables the caller to swap a token on this chain for another specified one
    // and bridge it as the input token via Across. This simplification is made to make the code
    // easier to reason about and solve a specific use case for Across.
    IERC20 public immutable SWAP_TOKEN;

    // The token that will be bridged via Across as the inputToken.
    IERC20 public immutable ACROSS_INPUT_TOKEN;

    /**
     * @notice Construct a new SwapAndBridge contract.
     * @param _spokePool Address of the SpokePool contract that we'll submit deposits to.
     * @param _exchange Address of the exchange where tokens will be swapped.
     * @param _allowedSelectors Function selectors that are allowed to be called on the exchange.
     * @param _swapToken Address of the token that will be swapped for acrossInputToken. Cannot be 0x0
     * @param _acrossInputToken Address of the token that will be bridged via Across as the inputToken.
     */
    constructor(
        V3SpokePoolInterface _spokePool,
        address _exchange,
        bytes4[] memory _allowedSelectors,
        IERC20 _swapToken,
        IERC20 _acrossInputToken
    ) SwapAndBridgeBase(_spokePool, _exchange, _allowedSelectors) {
        SWAP_TOKEN = _swapToken;
        ACROSS_INPUT_TOKEN = _acrossInputToken;
    }

    /**
     * @notice Swaps tokens on this chain via specified router before submitting Across deposit atomically.
     * Caller can specify their slippage tolerance for the swap and Across deposit params.
     * @dev If swapToken or acrossInputToken are the native token for this chain then this function might fail.
     * the assumption is that this function will handle only ERC20 tokens.
     * @param routerCalldata ABI encoded function data to call on router. Should form a swap of swapToken for
     * enough of acrossInputToken, otherwise this function will revert.
     * @param swapTokenAmount Amount of swapToken to swap for a minimum amount of depositData.inputToken.
     * @param minExpectedInputTokenAmount Minimum amount of received depositData.inputToken that we'll submit bridge
     * deposit with.
     * @param depositData Specifies the Across deposit params we'll send after the swap.
     */
    function swapAndBridge(
        bytes calldata routerCalldata,
        uint256 swapTokenAmount,
        uint256 minExpectedInputTokenAmount,
        DepositData calldata depositData
    ) external nonReentrant {
        _swapAndBridge(
            routerCalldata,
            swapTokenAmount,
            minExpectedInputTokenAmount,
            depositData,
            SWAP_TOKEN,
            ACROSS_INPUT_TOKEN
        );
    }
}

/**
 * @title UniversalSwapAndBridge
 * @notice Allows caller to swap between any two tokens specified at runtime on a chain before
 * bridging the received token via Across atomically. Provides safety checks post-swap and before-deposit.
 */
contract UniversalSwapAndBridge is SwapAndBridgeBase {
    /**
     * @notice Construct a new SwapAndBridgeBase contract.
     * @param _spokePool Address of the SpokePool contract that we'll submit deposits to.
     * @param _exchange Address of the exchange where tokens will be swapped.
     * @param _allowedSelectors Function selectors that are allowed to be called on the exchange.
     */
    constructor(
        V3SpokePoolInterface _spokePool,
        address _exchange,
        bytes4[] memory _allowedSelectors
    ) SwapAndBridgeBase(_spokePool, _exchange, _allowedSelectors) {}

    /**
     * @notice Swaps tokens on this chain via specified router before submitting Across deposit atomically.
     * Caller can specify their slippage tolerance for the swap and Across deposit params.
     * @dev If swapToken or acrossInputToken are the native token for this chain then this function might fail.
     * the assumption is that this function will handle only ERC20 tokens.
     * @param swapToken Address of the token that will be swapped for acrossInputToken.
     * @param acrossInputToken Address of the token that will be bridged via Across as the inputToken.
     * @param routerCalldata ABI encoded function data to call on router. Should form a swap of swapToken for
     * enough of acrossInputToken, otherwise this function will revert.
     * @param swapTokenAmount Amount of swapToken to swap for a minimum amount of depositData.inputToken.
     * @param minExpectedInputTokenAmount Minimum amount of received depositData.inputToken that we'll submit bridge
     * deposit with.
     * @param depositData Specifies the Across deposit params we'll send after the swap.
     */
    function swapAndBridge(
        IERC20 swapToken,
        IERC20 acrossInputToken,
        bytes calldata routerCalldata,
        uint256 swapTokenAmount,
        uint256 minExpectedInputTokenAmount,
        DepositData calldata depositData
    ) external nonReentrant {
        _swapAndBridge(
            routerCalldata,
            swapTokenAmount,
            minExpectedInputTokenAmount,
            depositData,
            swapToken,
            acrossInputToken
        );
    }
}

File 2 of 9 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 3 of 9 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount) external returns (bool);
}

File 4 of 9 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/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;

    /**
     * @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 {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @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 {
        _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));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    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");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @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.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    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");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation 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).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // 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 cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

File 5 of 9 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - 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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @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, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * 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.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @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`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 6 of 9 : MultiCaller.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)
// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value
// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.

/// @title MultiCaller
/// @notice Enables calling multiple methods in a single call to the contract
contract MultiCaller {
    function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}

File 7 of 9 : V3SpokePoolInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.
interface V3SpokePoolInterface {
    /**************************************
     *              ENUMS                 *
     **************************************/

    // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.
    enum FillStatus {
        Unfilled,
        RequestedSlowFill,
        Filled
    }
    // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of
    // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.
    enum FillType {
        FastFill,
        // Fast fills are normal fills that do not replace a slow fill request.
        ReplacedSlowFill,
        // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker
        // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used
        // for a slow fill execution.
        SlowFill
    }
    // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing
    // the slow fill is validated.

    /**************************************
     *              STRUCTS               *
     **************************************/

    // This struct represents the data to fully specify a **unique** relay submitted on this chain.
    // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against
    // replay attacks on other chains. If any portion of this data differs, the relay is considered to be
    // completely distinct.
    struct V3RelayData {
        // The bytes32 that made the deposit on the origin chain.
        bytes32 depositor;
        // The recipient bytes32 on the destination chain.
        bytes32 recipient;
        // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.
        bytes32 exclusiveRelayer;
        // Token that is deposited on origin chain by depositor.
        bytes32 inputToken;
        // Token that is received on destination chain by recipient.
        bytes32 outputToken;
        // The amount of input token deposited by depositor.
        uint256 inputAmount;
        // The amount of output token to be received by recipient.
        uint256 outputAmount;
        // Origin chain id.
        uint256 originChainId;
        // The id uniquely identifying this deposit on the origin chain.
        uint256 depositId;
        // The timestamp on the destination chain after which this deposit can no longer be filled.
        uint32 fillDeadline;
        // The timestamp on the destination chain after which any relayer can fill the deposit.
        uint32 exclusivityDeadline;
        // Data that is forwarded to the recipient.
        bytes message;
    }

    // Same as V3RelayData but using addresses instead of bytes32 & depositId is uint32.
    // Will be deprecated in favor of V3RelayData in the future.
    struct V3RelayDataLegacy {
        address depositor;
        address recipient;
        address exclusiveRelayer;
        address inputToken;
        address outputToken;
        uint256 inputAmount;
        uint256 outputAmount;
        uint256 originChainId;
        uint32 depositId;
        uint32 fillDeadline;
        uint32 exclusivityDeadline;
        bytes message;
    }

    // Contains parameters passed in by someone who wants to execute a slow relay leaf.
    struct V3SlowFill {
        V3RelayData relayData;
        uint256 chainId;
        uint256 updatedOutputAmount;
    }

    // Contains information about a relay to be sent along with additional information that is not unique to the
    // relay itself but is required to know how to process the relay. For example, "updatedX" fields can be used
    // by the relayer to modify fields of the relay with the depositor's permission, and "repaymentChainId" is specified
    // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.
    struct V3RelayExecutionParams {
        V3RelayData relay;
        bytes32 relayHash;
        uint256 updatedOutputAmount;
        bytes32 updatedRecipient;
        bytes updatedMessage;
        uint256 repaymentChainId;
    }

    // Packs together parameters emitted in FilledRelay because there are too many emitted otherwise.
    // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being
    // filled so they don't have to be unpacked by all clients.
    struct V3RelayExecutionEventInfo {
        bytes32 updatedRecipient;
        bytes32 updatedMessageHash;
        uint256 updatedOutputAmount;
        FillType fillType;
    }

    // Represents the parameters required for a V3 deposit operation in the SpokePool.
    struct DepositV3Params {
        bytes32 depositor;
        bytes32 recipient;
        bytes32 inputToken;
        bytes32 outputToken;
        uint256 inputAmount;
        uint256 outputAmount;
        uint256 destinationChainId;
        bytes32 exclusiveRelayer;
        uint256 depositId;
        uint32 quoteTimestamp;
        uint32 fillDeadline;
        uint32 exclusivityParameter;
        bytes message;
    }

    /**************************************
     *              EVENTS                *
     **************************************/

    event FundsDeposited(
        bytes32 inputToken,
        bytes32 outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 indexed destinationChainId,
        uint256 indexed depositId,
        uint32 quoteTimestamp,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        bytes32 indexed depositor,
        bytes32 recipient,
        bytes32 exclusiveRelayer,
        bytes message
    );

    event RequestedSpeedUpDeposit(
        uint256 updatedOutputAmount,
        uint256 indexed depositId,
        bytes32 indexed depositor,
        bytes32 updatedRecipient,
        bytes updatedMessage,
        bytes depositorSignature
    );

    event FilledRelay(
        bytes32 inputToken,
        bytes32 outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 repaymentChainId,
        uint256 indexed originChainId,
        uint256 indexed depositId,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        bytes32 exclusiveRelayer,
        bytes32 indexed relayer,
        bytes32 depositor,
        bytes32 recipient,
        bytes32 messageHash,
        V3RelayExecutionEventInfo relayExecutionInfo
    );

    event RequestedSlowFill(
        bytes32 inputToken,
        bytes32 outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 indexed originChainId,
        uint256 indexed depositId,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        bytes32 exclusiveRelayer,
        bytes32 depositor,
        bytes32 recipient,
        bytes32 messageHash
    );

    event ClaimedRelayerRefund(
        bytes32 indexed l2TokenAddress,
        bytes32 indexed refundAddress,
        uint256 amount,
        address indexed caller
    );

    /**************************************
     *              FUNCTIONS             *
     **************************************/

    function deposit(
        bytes32 depositor,
        bytes32 recipient,
        bytes32 inputToken,
        bytes32 outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 destinationChainId,
        bytes32 exclusiveRelayer,
        uint32 quoteTimestamp,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        bytes calldata message
    ) external payable;

    function depositV3(
        address depositor,
        address recipient,
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 destinationChainId,
        address exclusiveRelayer,
        uint32 quoteTimestamp,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        bytes calldata message
    ) external payable;

    function depositNow(
        bytes32 depositor,
        bytes32 recipient,
        bytes32 inputToken,
        bytes32 outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 destinationChainId,
        bytes32 exclusiveRelayer,
        uint32 fillDeadlineOffset,
        uint32 exclusivityDeadline,
        bytes calldata message
    ) external payable;

    function depositV3Now(
        address depositor,
        address recipient,
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 destinationChainId,
        address exclusiveRelayer,
        uint32 fillDeadlineOffset,
        uint32 exclusivityDeadline,
        bytes calldata message
    ) external payable;

    function unsafeDeposit(
        bytes32 depositor,
        bytes32 recipient,
        bytes32 inputToken,
        bytes32 outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 destinationChainId,
        bytes32 exclusiveRelayer,
        uint256 depositNonce,
        uint32 quoteTimestamp,
        uint32 fillDeadline,
        uint32 exclusivityParameter,
        bytes calldata message
    ) external payable;

    function speedUpDeposit(
        bytes32 depositor,
        uint256 depositId,
        uint256 updatedOutputAmount,
        bytes32 updatedRecipient,
        bytes calldata updatedMessage,
        bytes calldata depositorSignature
    ) external;

    function speedUpV3Deposit(
        address depositor,
        uint256 depositId,
        uint256 updatedOutputAmount,
        address updatedRecipient,
        bytes calldata updatedMessage,
        bytes calldata depositorSignature
    ) external;

    function fillRelay(
        V3RelayData calldata relayData,
        uint256 repaymentChainId,
        bytes32 repaymentAddress
    ) external;

    function fillV3Relay(V3RelayDataLegacy calldata relayData, uint256 repaymentChainId) external;

    function fillRelayWithUpdatedDeposit(
        V3RelayData calldata relayData,
        uint256 repaymentChainId,
        bytes32 repaymentAddress,
        uint256 updatedOutputAmount,
        bytes32 updatedRecipient,
        bytes calldata updatedMessage,
        bytes calldata depositorSignature
    ) external;

    function requestSlowFill(V3RelayData calldata relayData) external;

    function executeSlowRelayLeaf(
        V3SlowFill calldata slowFillLeaf,
        uint32 rootBundleId,
        bytes32[] calldata proof
    ) external;

    function claimRelayerRefund(bytes32 l2TokenAddress, bytes32 refundAddress) external;

    /**************************************
     *              ERRORS                *
     **************************************/

    error DisabledRoute();
    error InvalidQuoteTimestamp();
    error InvalidFillDeadline();
    error InvalidExclusiveRelayer();
    error MsgValueDoesNotMatchInputAmount();
    error NotExclusiveRelayer();
    error NoSlowFillsInExclusivityWindow();
    error RelayFilled();
    error InvalidSlowFillRequest();
    error ExpiredFillDeadline();
    error InvalidMerkleProof();
    error InvalidChainId();
    error InvalidMerkleLeaf();
    error ClaimedMerkleLeaf();
    error InvalidPayoutAdjustmentPct();
    error WrongERC7683OrderId();
    error LowLevelCallFailed(bytes data);
    error InsufficientSpokePoolBalanceToExecuteLeaf();
    error NoRelayerRefundToClaim();

    /**************************************
     *             LEGACY EVENTS          *
     **************************************/

    // Note: these events are unused, but included in the ABI for ease of migration.
    event V3FundsDeposited(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 indexed destinationChainId,
        uint32 indexed depositId,
        uint32 quoteTimestamp,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        address indexed depositor,
        address recipient,
        address exclusiveRelayer,
        bytes message
    );

    event RequestedSpeedUpV3Deposit(
        uint256 updatedOutputAmount,
        uint32 indexed depositId,
        address indexed depositor,
        address updatedRecipient,
        bytes updatedMessage,
        bytes depositorSignature
    );

    // Legacy struct only used to preserve the FilledV3Relay event definition.
    struct LegacyV3RelayExecutionEventInfo {
        address updatedRecipient;
        bytes updatedMessage;
        uint256 updatedOutputAmount;
        FillType fillType;
    }

    event FilledV3Relay(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 repaymentChainId,
        uint256 indexed originChainId,
        uint32 indexed depositId,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        address exclusiveRelayer,
        address indexed relayer,
        address depositor,
        address recipient,
        bytes message,
        LegacyV3RelayExecutionEventInfo relayExecutionInfo
    );

    event RequestedV3SlowFill(
        address inputToken,
        address outputToken,
        uint256 inputAmount,
        uint256 outputAmount,
        uint256 indexed originChainId,
        uint32 indexed depositId,
        uint32 fillDeadline,
        uint32 exclusivityDeadline,
        address exclusiveRelayer,
        address depositor,
        address recipient,
        bytes message
    );
}

File 8 of 9 : AddressConverters.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

library Bytes32ToAddress {
    /**************************************
     *              ERRORS                *
     **************************************/
    error InvalidBytes32();

    function toAddress(bytes32 _bytes32) internal pure returns (address) {
        checkAddress(_bytes32);
        return address(uint160(uint256(_bytes32)));
    }

    function toAddressUnchecked(bytes32 _bytes32) internal pure returns (address) {
        return address(uint160(uint256(_bytes32)));
    }

    function checkAddress(bytes32 _bytes32) internal pure {
        if (uint256(_bytes32) >> 160 != 0) {
            revert InvalidBytes32();
        }
    }
}

library AddressToBytes32 {
    function toBytes32(address _address) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(_address)));
    }
}

File 9 of 9 : Lockable.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

/**
 * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract
 * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol
 * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.
 * @dev The reason why we use this local contract instead of importing from uma/contracts is because of the addition
 * of the internal method `functionCallStackOriginatesFromOutsideThisContract` which doesn't exist in the one exported
 * by uma/contracts.
 * @custom:security-contact [email protected]
 */
contract Lockable {
    bool internal _notEntered;

    constructor() {
        // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every
        // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full
        // refund coming into effect.
        _notEntered = true;
    }

    /**
     * @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 state modification.
     */
    modifier nonReentrant() {
        _preEntranceCheck();
        _preEntranceSet();
        _;
        _postEntranceReset();
    }

    /**
     * @dev Designed to prevent a view-only method from being re-entered during a call to a nonReentrant() state-changing method.
     */
    modifier nonReentrantView() {
        _preEntranceCheck();
        _;
    }

    /**
     * @dev Returns true if the contract is currently in a non-entered state, meaning that the origination of the call
     * came from outside the contract. This is relevant with fallback/receive methods to see if the call came from ETH
     * being dropped onto the contract externally or due to ETH dropped on the contract from within a method in this
     * contract, such as unwrapping WETH to ETH within the contract.
     */
    function functionCallStackOriginatesFromOutsideThisContract() internal view returns (bool) {
        return _notEntered;
    }

    // Internal methods are used to avoid copying the require statement's bytecode to every nonReentrant() method.
    // On entry into a function, _preEntranceCheck() should always be called to check if the function is being
    // re-entered. Then, if the function modifies state, it should call _postEntranceSet(), perform its logic, and
    // then call _postEntranceReset().
    // View-only methods can simply call _preEntranceCheck() to make sure that it is not being re-entered.
    function _preEntranceCheck() internal view {
        // On the first call to nonReentrant, _notEntered will be true
        require(_notEntered, "ReentrancyGuard: reentrant call");
    }

    function _preEntranceSet() internal {
        // Any calls to nonReentrant after this point will fail
        _notEntered = false;
    }

    function _postEntranceReset() internal {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _notEntered = true;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "viaIR": true,
  "debug": {
    "revertStrings": "strip"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract V3SpokePoolInterface","name":"_spokePool","type":"address"},{"internalType":"address","name":"_exchange","type":"address"},{"internalType":"bytes4[]","name":"_allowedSelectors","type":"bytes4[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidFunctionSelector","type":"error"},{"inputs":[],"name":"LeftoverSrcTokens","type":"error"},{"inputs":[],"name":"MinimumExpectedInputAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"exchange","type":"address"},{"indexed":true,"internalType":"address","name":"swapToken","type":"address"},{"indexed":true,"internalType":"address","name":"acrossInputToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"swapTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"acrossInputAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"acrossOutputToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"acrossOutputAmount","type":"uint256"}],"name":"SwapBeforeBridge","type":"event"},{"inputs":[],"name":"EXCHANGE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPOKE_POOL","outputs":[{"internalType":"contract V3SpokePoolInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"allowedSelectors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"swapToken","type":"address"},{"internalType":"contract IERC20","name":"acrossInputToken","type":"address"},{"internalType":"bytes","name":"routerCalldata","type":"bytes"},{"internalType":"uint256","name":"swapTokenAmount","type":"uint256"},{"internalType":"uint256","name":"minExpectedInputTokenAmount","type":"uint256"},{"components":[{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"address","name":"depositor","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"destinationChainid","type":"uint256"},{"internalType":"address","name":"exclusiveRelayer","type":"address"},{"internalType":"uint32","name":"quoteTimestamp","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"uint32","name":"exclusivityDeadline","type":"uint32"},{"internalType":"bytes","name":"message","type":"bytes"}],"internalType":"struct SwapAndBridgeBase.DepositData","name":"depositData","type":"tuple"}],"name":"swapAndBridge","outputs":[],"stateMutability":"nonpayable","type":"function"}]

604060c060405234620001745762001201908138038062000020816200018c565b9384398201606083820312620001745782516001600160a01b039290919083831683036200017457602094858101519485168503620001745760408101516001600160401b03918282116200017457019280601f850112156200017457835191821162000178576005938260051b9088806200009e8185016200018c565b80968152019282010192831162000174578801905b8282106200015257505050600195869560ff19956001875f5416175f5560805260a0525f955b62000116575b60405161104e9081620001b3823960805181818161011f0152610ec1015260a0518181816102f9015281816108420152610c5f0152f35b81518610156200014c5786809663ffffffff60e01b8382881b86010151165f52818352845f2082888254161790550195620000d9565b620000df565b81516001600160e01b03198116810362000174578152908801908801620000b3565b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b6040519190601f01601f191682016001600160401b03811183821017620001785760405256fe60806040526004361015610011575f80fd5b5f3560e01c80638021fef7146100da57806385f168eb1461005f578063ac9650d81461005a578063b50e44b8146100555763c51e5eb914610050575f80fd5b61034a565b6102af565b610227565b346100d65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036100d6575f526001602052602060ff60405f2054166040519015158152f35b5f80fd5b346100d6575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d65773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660805260206080f35b5f9103126100d657565b5f5b8381106101635750505f910152565b8181015183820152602001610154565b602080820190808352835180925260408301928160408460051b8301019501935f915b8483106101a65750505050505090565b909192939495848080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8c5161021381518092818752878088019101610152565b011601019801930193019194939290610196565b346100d65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d65767ffffffffffffffff6004358181116100d657366023820112156100d65780600401359182116100d6573660248360051b830101116100d6576102ab91602461029f9201610621565b60405191829182610173565b0390f35b346100d6575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d657602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b73ffffffffffffffffffffffffffffffffffffffff8116036100d657565b90816101409103126100d65790565b346100d65760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d6576004356103858161031d565b602435906103928261031d565b67ffffffffffffffff916044358381116100d657366023820112156100d65780600401358481116100d65736602482840101116100d65760a4359485116100d6576103e46103f695369060040161033b565b93608435936024606435940191610708565b005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b67ffffffffffffffff811161043957604052565b6103f8565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761043957604052565b67ffffffffffffffff81116104395760051b60200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156100d6570180359067ffffffffffffffff82116100d6576020019181360383136100d657565b908210156105305761052c9160051b8101906104c4565b9091565b610497565b908092918237015f815290565b67ffffffffffffffff811161043957601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d156105a6573d9061058d82610542565b9161059b604051938461043e565b82523d5f602084013e565b606090565b6020818303126100d65780519067ffffffffffffffff82116100d6570181601f820112156100d65780516105de81610542565b926105ec604051948561043e565b818452602082840101116100d65761060a9160208085019101610152565b90565b80518210156105305760209160051b010190565b91909161062d8361047f565b90604061063d604051938461043e565b8483527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061066a8661047f565b015f5b8181106106f757505082945f5b818110610688575050505050565b5f80610695838588610515565b906106a4875180938193610535565b0390305af46106b161057c565b90156106d757906001916106c5828861060d565b526106d0818761060d565b500161067a565b60448151106100d6578060046100d69201516024809183010191016105ab565b80606060208093880101520161066d565b9395929491909460ff5f5416156100d6576107447fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f54165f55565b61079261078e6107876107578486610955565b7fffffffff00000000000000000000000000000000000000000000000000000000165f52600160205260405f2090565b5460ff1690565b1590565b610924576107a2873033886109b3565b6040517f70a082310000000000000000000000000000000000000000000000000000000080825230600483015273ffffffffffffffffffffffffffffffffffffffff98919260209182856024818c8f165afa9485156108fe575f95610903575b506040519081523060048201529982908b9060249082908d165afa9485156108fe5761088e9a89935f976108be575b5050610889925f92838093610868887f00000000000000000000000000000000000000000000000000000000000000008096610a5c565b61087760405180948193610535565b03925af161088361057c565b5061094e565b610b70565b6108bc60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5416175f55565b565b5f809491819499506108899693816108ea92903d106108f7575b6108e2818361043e565b810190610999565b9893505092819450610831565b503d6108d8565b6109a8565b8391955061091d90823d84116108f7576108e2818361043e565b9490610802565b60046040517f42868c9b000000000000000000000000000000000000000000000000000000008152fd5b156100d657565b7fffffffff00000000000000000000000000000000000000000000000000000000903581811693926004811061098a57505050565b60040360031b82901b16169150565b908160209103126100d6575190565b6040513d5f823e3d90fd5b9290604051927f23b872dd00000000000000000000000000000000000000000000000000000000602085015273ffffffffffffffffffffffffffffffffffffffff809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117610439576108bc92604052610d49565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60449192602073ffffffffffffffffffffffffffffffffffffffff604051948580927fdd62ed3e000000000000000000000000000000000000000000000000000000008252306004830152808916602483015286165afa9283156108fe575f93610b38575b508201809211610b33576040517f095ea7b300000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff9390931660248401526044808401929092529082526108bc9190610b2e60648361043e565b610d49565b610a2f565b610b5291935060203d6020116108f7576108e2818361043e565b915f610ac1565b91908203918211610b3357565b3561060a8161031d565b6040517f70a082310000000000000000000000000000000000000000000000000000000080825230600483015273ffffffffffffffffffffffffffffffffffffffff989697959695602095878b16959294939087826024818a5afa80156108fe57610be2925f91610d2c575b50610b59565b978810610d02576040519384523060048501528916928581602481875afa80156108fe578392610c18925f92610ce35750610b59565b03610cb9576108bc977f646284e396b68ff4b4f34e0aa97bcdb9c100f5b44a20da5c475f62703985384191610cb1610c4f8a610b66565b918960405194859416988c0135917f0000000000000000000000000000000000000000000000000000000000000000859094939260609273ffffffffffffffffffffffffffffffffffffffff6080840197168352602083015260408201520152565b0390a4610ea8565b60046040517fd6cf42f0000000000000000000000000000000000000000000000000000000008152fd5b610cfb919250883d8a116108f7576108e2818361043e565b905f610bdc565b60046040517f0492ff87000000000000000000000000000000000000000000000000000000008152fd5b610d439150893d8b116108f7576108e2818361043e565b5f610bdc565b73ffffffffffffffffffffffffffffffffffffffff166040516040810181811067ffffffffffffffff82111761043957610dc4937f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460205f948594604052818152015260208151910182855af1610dbe61057c565b91610fef565b8051908115918215610dda575b5050156100d657565b81925090602091810103126100d6576020015180151581036100d6575f80610dd1565b3563ffffffff811681036100d65790565b9b9c9893947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09b9560608e8c9b96601f9e9a959b966101809c835260208301526040820152015260808d015260a08c015260c08b015260e08a015263ffffffff92838092166101008b0152166101208901521661014087015280610160870152850152806101a095868601375f8582860101520116010190565b9073ffffffffffffffffffffffffffffffffffffffff807f00000000000000000000000000000000000000000000000000000000000000001692610eed838583610a5c565b610f15610efc60408701610b66565b73ffffffffffffffffffffffffffffffffffffffff1690565b90610f25610efc60608801610b66565b93610f32610efc88610b66565b96610f42610efc60a08301610b66565b610f4e60c08301610dfd565b610f5a60e08401610dfd565b91610f686101008501610dfd565b93610f776101208201826104c4565b9790968c3b156100d6576040519d8e809d819d7fad5425c6000000000000000000000000000000000000000000000000000000008352608087013596602001359516916004019c610fc79d610e0e565b03815a5f948591f180156108fe57610fdc5750565b80610fe96108bc92610425565b80610148565b901561100957815115611000575090565b3b156100d65790565b5080519081156100d657602001fdfea264697066735822122039395153a8bad7f55c9c734e8e21320cad4336b943bc43774b20f8d68e8033c164736f6c634300081700330000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c50000000000000000000000001ff1dc3cb9eedbc6eb2d99c03b30a05ca625fb5a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000003205c28780000000000000000000000000000000000000000000000000000000023b872dd000000000000000000000000000000000000000000000000000000002f4f21e200000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c80638021fef7146100da57806385f168eb1461005f578063ac9650d81461005a578063b50e44b8146100555763c51e5eb914610050575f80fd5b61034a565b6102af565b610227565b346100d65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036100d6575f526001602052602060ff60405f2054166040519015158152f35b5f80fd5b346100d6575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d65773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c51660805260206080f35b5f9103126100d657565b5f5b8381106101635750505f910152565b8181015183820152602001610154565b602080820190808352835180925260408301928160408460051b8301019501935f915b8483106101a65750505050505090565b909192939495848080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8c5161021381518092818752878088019101610152565b011601019801930193019194939290610196565b346100d65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d65767ffffffffffffffff6004358181116100d657366023820112156100d65780600401359182116100d6573660248360051b830101116100d6576102ab91602461029f9201610621565b60405191829182610173565b0390f35b346100d6575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d657602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001ff1dc3cb9eedbc6eb2d99c03b30a05ca625fb5a168152f35b73ffffffffffffffffffffffffffffffffffffffff8116036100d657565b90816101409103126100d65790565b346100d65760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d6576004356103858161031d565b602435906103928261031d565b67ffffffffffffffff916044358381116100d657366023820112156100d65780600401358481116100d65736602482840101116100d65760a4359485116100d6576103e46103f695369060040161033b565b93608435936024606435940191610708565b005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b67ffffffffffffffff811161043957604052565b6103f8565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761043957604052565b67ffffffffffffffff81116104395760051b60200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156100d6570180359067ffffffffffffffff82116100d6576020019181360383136100d657565b908210156105305761052c9160051b8101906104c4565b9091565b610497565b908092918237015f815290565b67ffffffffffffffff811161043957601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d156105a6573d9061058d82610542565b9161059b604051938461043e565b82523d5f602084013e565b606090565b6020818303126100d65780519067ffffffffffffffff82116100d6570181601f820112156100d65780516105de81610542565b926105ec604051948561043e565b818452602082840101116100d65761060a9160208085019101610152565b90565b80518210156105305760209160051b010190565b91909161062d8361047f565b90604061063d604051938461043e565b8483527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061066a8661047f565b015f5b8181106106f757505082945f5b818110610688575050505050565b5f80610695838588610515565b906106a4875180938193610535565b0390305af46106b161057c565b90156106d757906001916106c5828861060d565b526106d0818761060d565b500161067a565b60448151106100d6578060046100d69201516024809183010191016105ab565b80606060208093880101520161066d565b9395929491909460ff5f5416156100d6576107447fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f54165f55565b61079261078e6107876107578486610955565b7fffffffff00000000000000000000000000000000000000000000000000000000165f52600160205260405f2090565b5460ff1690565b1590565b610924576107a2873033886109b3565b6040517f70a082310000000000000000000000000000000000000000000000000000000080825230600483015273ffffffffffffffffffffffffffffffffffffffff98919260209182856024818c8f165afa9485156108fe575f95610903575b506040519081523060048201529982908b9060249082908d165afa9485156108fe5761088e9a89935f976108be575b5050610889925f92838093610868887f0000000000000000000000001ff1dc3cb9eedbc6eb2d99c03b30a05ca625fb5a8096610a5c565b61087760405180948193610535565b03925af161088361057c565b5061094e565b610b70565b6108bc60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5416175f55565b565b5f809491819499506108899693816108ea92903d106108f7575b6108e2818361043e565b810190610999565b9893505092819450610831565b503d6108d8565b6109a8565b8391955061091d90823d84116108f7576108e2818361043e565b9490610802565b60046040517f42868c9b000000000000000000000000000000000000000000000000000000008152fd5b156100d657565b7fffffffff00000000000000000000000000000000000000000000000000000000903581811693926004811061098a57505050565b60040360031b82901b16169150565b908160209103126100d6575190565b6040513d5f823e3d90fd5b9290604051927f23b872dd00000000000000000000000000000000000000000000000000000000602085015273ffffffffffffffffffffffffffffffffffffffff809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117610439576108bc92604052610d49565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60449192602073ffffffffffffffffffffffffffffffffffffffff604051948580927fdd62ed3e000000000000000000000000000000000000000000000000000000008252306004830152808916602483015286165afa9283156108fe575f93610b38575b508201809211610b33576040517f095ea7b300000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff9390931660248401526044808401929092529082526108bc9190610b2e60648361043e565b610d49565b610a2f565b610b5291935060203d6020116108f7576108e2818361043e565b915f610ac1565b91908203918211610b3357565b3561060a8161031d565b6040517f70a082310000000000000000000000000000000000000000000000000000000080825230600483015273ffffffffffffffffffffffffffffffffffffffff989697959695602095878b16959294939087826024818a5afa80156108fe57610be2925f91610d2c575b50610b59565b978810610d02576040519384523060048501528916928581602481875afa80156108fe578392610c18925f92610ce35750610b59565b03610cb9576108bc977f646284e396b68ff4b4f34e0aa97bcdb9c100f5b44a20da5c475f62703985384191610cb1610c4f8a610b66565b918960405194859416988c0135917f0000000000000000000000001ff1dc3cb9eedbc6eb2d99c03b30a05ca625fb5a859094939260609273ffffffffffffffffffffffffffffffffffffffff6080840197168352602083015260408201520152565b0390a4610ea8565b60046040517fd6cf42f0000000000000000000000000000000000000000000000000000000008152fd5b610cfb919250883d8a116108f7576108e2818361043e565b905f610bdc565b60046040517f0492ff87000000000000000000000000000000000000000000000000000000008152fd5b610d439150893d8b116108f7576108e2818361043e565b5f610bdc565b73ffffffffffffffffffffffffffffffffffffffff166040516040810181811067ffffffffffffffff82111761043957610dc4937f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460205f948594604052818152015260208151910182855af1610dbe61057c565b91610fef565b8051908115918215610dda575b5050156100d657565b81925090602091810103126100d6576020015180151581036100d6575f80610dd1565b3563ffffffff811681036100d65790565b9b9c9893947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09b9560608e8c9b96601f9e9a959b966101809c835260208301526040820152015260808d015260a08c015260c08b015260e08a015263ffffffff92838092166101008b0152166101208901521661014087015280610160870152850152806101a095868601375f8582860101520116010190565b9073ffffffffffffffffffffffffffffffffffffffff807f0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c51692610eed838583610a5c565b610f15610efc60408701610b66565b73ffffffffffffffffffffffffffffffffffffffff1690565b90610f25610efc60608801610b66565b93610f32610efc88610b66565b96610f42610efc60a08301610b66565b610f4e60c08301610dfd565b610f5a60e08401610dfd565b91610f686101008501610dfd565b93610f776101208201826104c4565b9790968c3b156100d6576040519d8e809d819d7fad5425c6000000000000000000000000000000000000000000000000000000008352608087013596602001359516916004019c610fc79d610e0e565b03815a5f948591f180156108fe57610fdc5750565b80610fe96108bc92610425565b80610148565b901561100957815115611000575090565b3b156100d65790565b5080519081156100d657602001fdfea264697066735822122039395153a8bad7f55c9c734e8e21320cad4336b943bc43774b20f8d68e8033c164736f6c63430008170033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c50000000000000000000000001ff1dc3cb9eedbc6eb2d99c03b30a05ca625fb5a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000003205c28780000000000000000000000000000000000000000000000000000000023b872dd000000000000000000000000000000000000000000000000000000002f4f21e200000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _spokePool (address): 0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5
Arg [1] : _exchange (address): 0x1ff1dC3cB9eeDbC6Eb2d99C03b30A05cA625fB5a
Arg [2] : _allowedSelectors (bytes4[]): System.Byte[],System.Byte[],System.Byte[]

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c5
Arg [1] : 0000000000000000000000001ff1dc3cb9eedbc6eb2d99c03b30a05ca625fb5a
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [4] : 205c287800000000000000000000000000000000000000000000000000000000
Arg [5] : 23b872dd00000000000000000000000000000000000000000000000000000000
Arg [6] : 2f4f21e200000000000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.