ETH Price: $2,952.35 (+0.52%)
 

More Info

Private Name Tags

Multichain Info

1 address found via
Transaction Hash
Method
Block
From
To
New Intent278707882026-01-10 6:55:2314 days ago1768028123IN
0xd0185bfb...fb504540e
0 ETH0.000000040.000121
New Intent277976912026-01-08 11:35:2016 days ago1767872120IN
0xd0185bfb...fb504540e
0 ETH0.000000060.000121
New Intent275536222026-01-02 19:09:2622 days ago1767380966IN
0xd0185bfb...fb504540e
0 ETH0.000000120.000121
New Intent269688982025-12-22 1:43:0533 days ago1766367785IN
0xd0185bfb...fb504540e
0 ETH0.000000040.000121
New Intent269310872025-12-21 8:12:5534 days ago1766304775IN
0xd0185bfb...fb504540e
0 ETH0.000000040.000121
New Intent268163232025-12-19 3:29:3136 days ago1766114971IN
0xd0185bfb...fb504540e
0 ETH0.000001040.004999
New Intent268145812025-12-19 2:58:5436 days ago1766113134IN
0xd0185bfb...fb504540e
0 ETH0.000000940.005049
New Intent268138672025-12-19 2:37:3136 days ago1766111851IN
0xd0185bfb...fb504540e
0 ETH0.000001020.004999
New Intent268138342025-12-19 2:36:4136 days ago1766111801IN
0xd0185bfb...fb504540e
0 ETH0.000001010.004999
New Intent267918922025-12-18 17:45:1237 days ago1766079912IN
0xd0185bfb...fb504540e
0 ETH0.000000210.00012011
New Intent266882812025-12-17 2:27:3838 days ago1765938458IN
0xd0185bfb...fb504540e
0 ETH0.000000040.0001201
New Intent264479602025-12-12 19:12:1943 days ago1765566739IN
0xd0185bfb...fb504540e
0 ETH0.000000020.000121
New Intent263694422025-12-11 11:51:5844 days ago1765453918IN
0xd0185bfb...fb504540e
0 ETH0.000000030.0001201
New Intent263664492025-12-11 10:42:1144 days ago1765449731IN
0xd0185bfb...fb504540e
0 ETH0.000000030.000121
New Intent262982382025-12-10 8:29:3745 days ago1765355377IN
0xd0185bfb...fb504540e
0 ETH0.000001050.004999
New Intent262953412025-12-10 7:12:0245 days ago1765350722IN
0xd0185bfb...fb504540e
0 ETH0.000000040.000121
New Intent262686682025-12-09 18:21:3546 days ago1765304495IN
0xd0185bfb...fb504540e
0 ETH0.000000050.0001201
New Intent261691452025-12-08 1:41:2647 days ago1765158086IN
0xd0185bfb...fb504540e
0 ETH0.000000080.000121

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
246850892025-11-11 14:34:3374 days ago1762871673  Contract Creation0 ETH
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FeeAdapterV2

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 10000 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {Ownable, Ownable2Step} from '@openzeppelin/contracts/access/Ownable2Step.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import {Address} from '@openzeppelin/contracts/utils/Address.sol';
import {ECDSA} from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol';

import {TypeCasts} from 'contracts/common/TypeCasts.sol';

import {IEverclearV2} from 'interfaces/common/IEverclearV2.sol';

import {IPermit2} from 'interfaces/common/IPermit2.sol';
import {IEverclearSpokeV6} from 'interfaces/intent/IEverclearSpokeV6.sol';
import {IFeeAdapterV2} from 'interfaces/intent/IFeeAdapterV2.sol';

contract FeeAdapterV2 is IFeeAdapterV2, Ownable2Step {
  ////////////////////
  //// Libraries /////
  ////////////////////
  using SafeERC20 for IERC20;
  using TypeCasts for address;
  using TypeCasts for bytes32;

  ////////////////////
  ///// Storage //////
  ////////////////////

  /// @inheritdoc IFeeAdapterV2
  IPermit2 public constant PERMIT2 = IPermit2(0x000000000022D473030F116dDEE9F6B43aC78BA3);

  /// @inheritdoc IFeeAdapterV2
  IEverclearSpokeV6 public immutable spoke;

  // @inheritdoc IFeeAdapterV2
  address public immutable xerc20Module;

  /// @inheritdoc IFeeAdapterV2
  address public feeRecipient;

  /// @inheritdoc IFeeAdapterV2
  address public feeSigner;

  /// @inheritdoc IFeeAdapterV2
  mapping(bytes32 => bool) public txExists;

  ////////////////////
  /// Constructor ////
  ////////////////////
  constructor(
    address _spoke,
    address _feeRecipient,
    address _feeSigner,
    address _xerc20Module,
    address _owner
  ) Ownable(_owner) {
    spoke = IEverclearSpokeV6(_spoke);
    xerc20Module = _xerc20Module;
    _updateFeeRecipient(_feeRecipient);
    _updateFeeSigner(_feeSigner);
  }

  ////////////////////
  ////// Admin ///////
  ////////////////////

  /// @inheritdoc IFeeAdapterV2
  function updateFeeRecipient(
    address _feeRecipient
  ) external onlyOwner {
    _updateFeeRecipient(_feeRecipient);
  }

  /// @inheritdoc IFeeAdapterV2
  function updateFeeSigner(
    address _feeSigner
  ) external onlyOwner {
    _updateFeeSigner(_feeSigner);
  }

  /// @inheritdoc IFeeAdapterV2
  function returnUnsupportedIntent(
    address _asset,
    uint256 _amount,
    address _recipient
  ) external onlyOwner {
    spoke.withdraw(_asset, _amount);
    _pushTokens(_recipient, _asset, _amount);
  }

  ////////////////////
  ///// External /////
  ////////////////////

  /// @inheritdoc IFeeAdapterV2
  function newIntent(
    uint32[] memory _destinations,
    bytes32 _receiver,
    address _inputAsset,
    bytes32 _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    IFeeAdapterV2.FeeParams calldata _feeParams
  ) external payable returns (bytes32 _intentId, IEverclearV2.Intent memory _intent) {
    // Transfer from caller
    _pullTokens(msg.sender, _inputAsset, _amount + _feeParams.fee);

    // Create intent
    (_intentId, _intent) =
      _newIntent(_destinations, _receiver, _inputAsset, _outputAsset, _amount, _amountOutMin, _ttl, _data, _feeParams);
  }

  /// @inheritdoc IFeeAdapterV2
  function newIntent(
    uint32[] memory _destinations,
    address _receiver,
    address _inputAsset,
    address _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    IFeeAdapterV2.FeeParams calldata _feeParams
  ) external payable returns (bytes32 _intentId, IEverclearV2.Intent memory _intent) {
    // Transfer from caller
    _pullTokens(msg.sender, _inputAsset, _amount + _feeParams.fee);

    // Create intent
    (_intentId, _intent) =
      _newIntent(_destinations, _receiver, _inputAsset, _outputAsset, _amount, _amountOutMin, _ttl, _data, _feeParams);
  }

  /// @inheritdoc IFeeAdapterV2
  function newIntent(
    uint32[] memory _destinations,
    address _receiver,
    address _inputAsset,
    address _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    IEverclearSpokeV6.Permit2Params calldata _permit2Params,
    IFeeAdapterV2.FeeParams calldata _feeParams
  ) external payable returns (bytes32 _intentId, IEverclearV2.Intent memory _intent) {
    // Transfer from caller using permit2
    _pullWithPermit2(_inputAsset, _amount + _feeParams.fee, _permit2Params);

    // Call internal helper to create intent
    (_intentId, _intent) =
      _newIntent(_destinations, _receiver, _inputAsset, _outputAsset, _amount, _amountOutMin, _ttl, _data, _feeParams);
  }

  /// @inheritdoc IFeeAdapterV2
  function newOrderSplitEvenly(
    uint32 _numIntents,
    uint256 _fee,
    uint256 _deadline,
    bytes calldata _sig,
    OrderParameters memory _params
  ) external payable returns (bytes32 _orderId, bytes32[] memory _intentIds) {
    // Transfer once from the user
    _pullTokens(msg.sender, _params.inputAsset, _params.amount + _fee);

    // Send fees to recipient
    bytes32 _sigData = keccak256(abi.encode(msg.value, _numIntents, _params, _fee, _deadline));
    _verifySignature(_sigData, _sig);
    _handleFees(_fee, msg.value, _params.inputAsset, _deadline);

    // Approve the spoke contract if needed
    _approveSpokeIfNeeded(_params.inputAsset, _params.amount);

    // Create `_numIntents` intents with the same params and `_amount` divided
    // equally across all created intents.
    uint256 _toSend = _params.amount / _numIntents;

    // Initialising array length
    _intentIds = new bytes32[](_numIntents);

    for (uint256 i; i < _numIntents - 1; i++) {
      // Create new intent
      (bytes32 _intentId,) = spoke.newIntent(
        _params.destinations,
        _params.receiver,
        _params.inputAsset,
        _params.outputAsset,
        _toSend,
        _params.amountOutMin,
        _params.ttl,
        _params.data
      );
      _intentIds[i] = _intentId;
    }

    // Create a final intent here with the remainder of balance
    _toSend = _toSend * (_numIntents - 1);
    (bytes32 _intentId,) = spoke.newIntent(
      _params.destinations,
      _params.receiver,
      _params.inputAsset,
      _params.outputAsset,
      _params.amount - _toSend, // handles remainder gracefully
      _params.amountOutMin,
      _params.ttl,
      _params.data
    );

    // Add to array
    _intentIds[_numIntents - 1] = _intentId;

    // Calculate order id
    _orderId = keccak256(abi.encode(_intentIds));

    // Emit order information event
    emit OrderCreated(_orderId, msg.sender.toBytes32(), _intentIds, _fee, msg.value);
  }

  /// @inheritdoc IFeeAdapterV2
  function newOrder(
    uint256 _fee,
    uint256 _deadline,
    bytes calldata _sig,
    OrderParameters[] memory _params
  ) external payable returns (bytes32 _orderId, bytes32[] memory _intentIds) {
    uint256 _numIntents = _params.length;

    {
      // Get the asset
      address _inputAsset = _params[0].inputAsset;

      // Get the sum of the order amounts
      uint256 _orderSum;
      for (uint256 i; i < _numIntents; i++) {
        _orderSum += _params[i].amount;
        if (_params[i].inputAsset != _inputAsset) {
          revert MultipleOrderAssets();
        }
      }

      // Transfer once from the user
      _pullTokens(msg.sender, _inputAsset, _orderSum + _fee);

      // Approve the spoke contract if needed
      _approveSpokeIfNeeded(_inputAsset, _orderSum);

      // Send fees to recipient
      bytes32 _sigData = keccak256(abi.encode(msg.value, _params, _fee, _deadline));
      _verifySignature(_sigData, _sig);
      _handleFees(_fee, msg.value, _inputAsset, _deadline);
    }

    // Initialising array length
    _intentIds = new bytes32[](_numIntents);
    for (uint256 i; i < _numIntents; i++) {
      // Create new intent
      (bytes32 _intentId,) = spoke.newIntent(
        _params[i].destinations,
        _params[i].receiver,
        _params[i].inputAsset,
        _params[i].outputAsset,
        _params[i].amount,
        _params[i].amountOutMin,
        _params[i].ttl,
        _params[i].data
      );
      _intentIds[i] = _intentId;
    }

    // Calculate order id
    _orderId = keccak256(abi.encode(_intentIds));

    // Emit order event
    emit OrderCreated(_orderId, msg.sender.toBytes32(), _intentIds, _fee, msg.value);
  }

  ////////////////////
  ///// Internal /////
  ////////////////////

  /**
   * @notice Internal function to create a new intent
   * @param _destinations Array of destination chain IDs
   * @param _receiver Address of the receiver on the destination chain
   * @param _inputAsset Address of the input asset
   * @param _outputAsset Address of the output asset
   * @param _amount Amount of input asset to transfer
   * @param _amountOutMin Maximum fee in basis points that can be charged
   * @param _ttl Time-to-live for the intent
   * @param _data Additional data for the intent
   * @param _feeParams Fee parameters including fee amount, deadline, and signature
   * @return _intentId The ID of the created intent
   * @return _intent The created intent object
   */
  function _newIntent(
    uint32[] memory _destinations,
    bytes32 _receiver,
    address _inputAsset,
    bytes32 _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    IFeeAdapterV2.FeeParams calldata _feeParams
  ) internal returns (bytes32 _intentId, IEverclearV2.Intent memory _intent) {
    // Send fees to recipient
    bytes32 _sigData = keccak256(
      abi.encode(
        msg.value,
        _destinations,
        _receiver,
        _inputAsset,
        _outputAsset,
        _amount,
        _amountOutMin,
        _ttl,
        _data,
        _feeParams.fee,
        _feeParams.deadline
      )
    );
    _verifySignature(_sigData, _feeParams.sig);
    _handleFees(_feeParams.fee, msg.value, _inputAsset, _feeParams.deadline);

    // Approve the spoke contract if needed
    _approveSpokeIfNeeded(_inputAsset, _amount);

    // Create new intent
    (_intentId, _intent) =
      spoke.newIntent(_destinations, _receiver, _inputAsset, _outputAsset, _amount, _amountOutMin, _ttl, _data);

    // Emit event
    emit IntentWithFeesAdded(_intentId, msg.sender.toBytes32(), _feeParams.fee, msg.value);
    return (_intentId, _intent);
  }

  /**
   * @notice Internal function to create a new intent
   * @param _destinations Array of destination chain IDs
   * @param _receiver Address of the receiver on the destination chain
   * @param _inputAsset Address of the input asset
   * @param _outputAsset Address of the output asset
   * @param _amount Amount of input asset to transfer
   * @param _amountOutMin Maximum fee in basis points that can be charged
   * @param _ttl Time-to-live for the intent
   * @param _data Additional data for the intent
   * @param _feeParams Fee parameters including fee amount, deadline, and signature
   * @return _intentId The ID of the created intent
   * @return _intent The created intent object
   */
  function _newIntent(
    uint32[] memory _destinations,
    address _receiver,
    address _inputAsset,
    address _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    IFeeAdapterV2.FeeParams calldata _feeParams
  ) internal returns (bytes32 _intentId, IEverclearV2.Intent memory _intent) {
    // Send fees to recipient
    bytes32 _sigData = keccak256(
      abi.encode(
        msg.value,
        _destinations,
        _receiver,
        _inputAsset,
        _outputAsset,
        _amount,
        _amountOutMin,
        _ttl,
        _data,
        _feeParams.fee,
        _feeParams.deadline
      )
    );
    _verifySignature(_sigData, _feeParams.sig);
    _handleFees(_feeParams.fee, msg.value, _inputAsset, _feeParams.deadline);

    // Approve the spoke contract if needed
    _approveSpokeIfNeeded(_inputAsset, _amount);

    // Create new intent
    (_intentId, _intent) =
      spoke.newIntent(_destinations, _receiver, _inputAsset, _outputAsset, _amount, _amountOutMin, _ttl, _data);

    // Emit event
    emit IntentWithFeesAdded(_intentId, msg.sender.toBytes32(), _feeParams.fee, msg.value);
    return (_intentId, _intent);
  }

  /**
   * @notice Updates the fee recipient
   * @param _feeRecipient New recipient
   */
  function _updateFeeRecipient(
    address _feeRecipient
  ) internal {
    emit FeeRecipientUpdated(_feeRecipient, feeRecipient);
    feeRecipient = _feeRecipient;
  }

  /**
   * @notice Updates the fee signer
   * @param _feeSigner New signer
   */
  function _updateFeeSigner(
    address _feeSigner
  ) internal {
    emit FeeSignerUpdated(_feeSigner, feeSigner);
    feeSigner = _feeSigner;
  }

  /**
   * @notice Verifies a signature
   * @param _dataHash The data of the message
   * @param _signature The signature of the message
   */
  function _verifySignature(
    bytes32 _dataHash,
    bytes calldata _signature
  ) internal {
    bytes32 _hash = keccak256(abi.encode(_dataHash, address(this), block.chainid));

    if (txExists[_hash]) revert FeeAdapter_SignatureAlreadyUsed();
    txExists[_hash] = true;

    address _recoveredSigner = ECDSA.recover(MessageHashUtils.toEthSignedMessageHash(_hash), _signature);
    if (_recoveredSigner != feeSigner) {
      revert FeeAdapter_InvalidSignature();
    }
  }

  /**
   * @notice Sends fees to recipient
   * @param _tokenFee Amount in transacting asset to send to recipient
   * @param _nativeFee Amount in native asset to send to recipient
   */
  function _handleFees(
    uint256 _tokenFee,
    uint256 _nativeFee,
    address _inputAsset,
    uint256 _deadline
  ) internal {
    // Verify the ttl is valid
    if (block.timestamp > _deadline) {
      revert FeeAdapter_InvalidDeadline();
    }

    // Handle token fees if exist
    if (_tokenFee > 0) {
      _pushTokens(feeRecipient, _inputAsset, _tokenFee);
    }

    // Handle native tokens
    if (_nativeFee > 0) {
      Address.sendValue(payable(feeRecipient), _nativeFee);
    }
  }

  /**
   * @notice Approves the maximum uint value to the gateway.
   * @dev Approving the max reduces gas for following intents.
   * @param _asset Asset to approve to spoke.
   * @param _minimum Minimum required approval budget.
   */
  function _approveSpokeIfNeeded(
    address _asset,
    uint256 _minimum
  ) internal {
    // Checking if the strategy is default or not
    address spender;
    IEverclearV2.Strategy _strategy = spoke.strategies(_asset);
    if (_strategy == IEverclearV2.Strategy.DEFAULT) spender = address(spoke);
    else spender = xerc20Module;

    // Approve the spoke contract if needed
    IERC20 _token = IERC20(_asset);
    uint256 _current = _token.allowance(address(this), spender);
    if (_current >= _minimum) {
      return;
    }

    // Approve to 0
    if (_current != 0) {
      _token.safeDecreaseAllowance(spender, _current);
    }

    // Approve to max
    _token.safeIncreaseAllowance(spender, type(uint256).max);
  }

  /**
   * @notice Transfers tokens from the caller to this contract using Permit2
   * @dev Uses the Permit2 contract to transfer tokens with a signature
   * @param _asset The token to transfer
   * @param _amount The amount to transfer
   * @param _permit2Params The permit2 parameters including nonce, deadline, and signature
   */
  function _pullWithPermit2(
    address _asset,
    uint256 _amount,
    IEverclearSpokeV6.Permit2Params calldata _permit2Params
  ) internal {
    // Transfer from caller using permit2
    PERMIT2.permitTransferFrom(
      IPermit2.PermitTransferFrom({
        permitted: IPermit2.TokenPermissions({token: IERC20(_asset), amount: _amount}),
        nonce: _permit2Params.nonce,
        deadline: _permit2Params.deadline
      }),
      IPermit2.SignatureTransferDetails({to: address(this), requestedAmount: _amount}),
      msg.sender,
      _permit2Params.signature
    );
  }

  /**
   * @notice Pull tokens from the sender to the contract
   * @param _sender The address of the sender
   * @param _asset The address of the asset
   * @param _amount The amount of the asset
   */
  function _pullTokens(
    address _sender,
    address _asset,
    uint256 _amount
  ) internal {
    IERC20(_asset).safeTransferFrom(_sender, address(this), _amount);
  }

  /**
   * @notice Push tokens from the contract to the recipient
   * @param _recipient The address of the recipient
   * @param _asset The address of the asset
   * @param _amount The amount of the asset
   */
  function _pushTokens(
    address _recipient,
    address _asset,
    uint256 _amount
  ) internal {
    IERC20(_asset).safeTransfer(_recipient, _amount);
  }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {Ownable} from "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 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.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 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 {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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);
        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.
     */
    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.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

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

    /**
     * @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);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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(token).code.length > 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @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 AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @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
     * {FailedInnerCall} 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 AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @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, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @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, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @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 {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // 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 (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @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 {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) 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 FailedInnerCall();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

import {Strings} from "../Strings.sol";

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.25;

/**
 * @title TypeCasts
 * @notice Library for type casts
 */
library TypeCasts {
  // alignment preserving cast
  /**
   * @notice Cast an address to a bytes32
   * @param _addr The address to cast
   */
  function toBytes32(
    address _addr
  ) internal pure returns (bytes32) {
    return bytes32(uint256(uint160(_addr)));
  }

  // alignment preserving cast
  /**
   * @notice Cast a bytes32 to an address
   * @param _buf The bytes32 to cast
   */
  function toAddress(
    bytes32 _buf
  ) internal pure returns (address) {
    return address(uint160(uint256(_buf)));
  }
}

File 9 of 27 : IEverclearV2.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

/**
 * @title IEverclear
 * @notice Common interface for EverclearHub and EverclearSpoke
 */
interface IEverclearV2 {
  /*//////////////////////////////////////////////////////////////
                                ENUMS
    //////////////////////////////////////////////////////////////*/
  /**
   * @notice Enum representing statuses of an intent
   */
  enum IntentStatus {
    NONE, // 0
    ADDED, // 1
    DEPOSIT_PROCESSED, // 2
    FILLED, // 3
    ADDED_AND_FILLED, // 4
    INVOICED, // 5
    SETTLED, // 6
    SETTLED_AND_MANUALLY_EXECUTED, // 7
    UNSUPPORTED, // 8
    UNSUPPORTED_RETURNED // 9
  }

  /**
   * @notice Enum representing asset strategies
   */
  enum Strategy {
    DEFAULT,
    XERC20
  }

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

  /**
   * @notice The structure of an intent
   * @param initiator The address of the intent initiator
   * @param receiver The address of the intent receiver
   * @param inputAsset The address of the intent asset on origin
   * @param outputAsset The address of the intent asset on destination
   * @param origin The origin chain of the intent
   * @param destinations The possible destination chains of the intent
   * @param nonce The nonce of the intent
   * @param timestamp The timestamp of the intent
   * @param ttl The time to live of the intent
   * @param amount The amount of the intent asset normalized to 18 decimals
   * @param amountOutMin The minimum amount of the output asset that the intent solver should return
   * @param data The data of the intent
   */
  struct Intent {
    bytes32 initiator;
    bytes32 receiver;
    bytes32 inputAsset;
    bytes32 outputAsset;
    uint32 origin;
    uint64 nonce;
    uint48 timestamp;
    uint48 ttl;
    uint256 amount;
    uint256 amountOutMin;
    uint32[] destinations;
    bytes data;
  }

  /**
   * @notice The structure of a fill message
   * @param intentId The ID of the intent
   * @param solver The address of the intent solver in bytes32 format
   * @param initiator The address of the intent initiator
   * @param fee The total fee of the expressed in dbps, represents the solver fee plus the sum of protocol fees for the token
   * @param executionTimestamp The execution timestamp of the intent
   */
  struct DeprecatedFillMessage {
    bytes32 intentId;
    bytes32 solver;
    bytes32 initiator;
    uint24 fee;
    uint48 executionTimestamp;
  }

  /**
   * @notice The structure of a fill message
   * @param intentId The ID of the intent
   * @param receiver The address of the intent receiver in bytes32 format
   * @param intentInputAsset The input asset of the intent (i.e. asset the solver will be repaid in)
   * @param intentOrigin The origin chain of the intent
   * @param amountOut The amount being sent to the user by the solver
   * @param destinations The settlement destinations for the fill
   * @param executionTimestamp The execution timestamp of the intent
   */
  struct FillMessage {
    bytes32 intentId;
    bytes32 receiver;
    bytes32 intentInputAsset;
    uint32 intentOrigin;
    uint256 amountOut;
    uint32[] destinations;
    uint48 executionTimestamp;
  }

  /**
   * @notice The structure of a settlement
   * @param intentId The ID of the intent
   * @param amount The amount of the asset
   * @param asset The address of the asset
   * @param recipient The address of the recipient
   * @param updateVirtualBalance If set to true, the settlement will not be transferred to the recipient in spoke domain and the virtual balance will be increased
   */
  struct Settlement {
    bytes32 intentId;
    uint256 amount;
    bytes32 asset;
    bytes32 recipient;
    bool updateVirtualBalance;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

/**
 * @title IPermit2
 * @notice Interface for permit2
 */
interface IPermit2 {
  /*///////////////////////////////////////////////////////////////
                                STRUCTS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Struct for token and amount in a permit message
   * @param token The token to transfer
   * @param amount The amount to transfer
   */
  struct TokenPermissions {
    IERC20 token;
    uint256 amount;
  }

  /**
   * @notice Struct for the permit2 message
   * @param permitted The permitted token and amount
   * @param nonce The unique identifier for this permit
   * @param deadline The expiration for this permit
   */
  struct PermitTransferFrom {
    TokenPermissions permitted;
    uint256 nonce;
    uint256 deadline;
  }

  /**
   * @notice Struct for the transfer details for permitTransferFrom()
   * @param to The recipient of the tokens
   * @param requestedAmount The amount to transfer
   */
  struct SignatureTransferDetails {
    address to;
    uint256 requestedAmount;
  }

  /*///////////////////////////////////////////////////////////////
                                LOGIC
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Consume a permit2 message and transfer tokens
   * @param permit The permit message
   * @param transferDetails The transfer details
   * @param owner The owner of the tokens
   * @param signature The signature of the permit
   */
  function permitTransferFrom(
    PermitTransferFrom calldata permit,
    SignatureTransferDetails calldata transferDetails,
    address owner,
    bytes calldata signature
  ) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IEverclearV2} from 'interfaces/common/IEverclearV2.sol';
import {ISettlementModule} from 'interfaces/common/ISettlementModule.sol';

import {ISpokeStorageV6} from './ISpokeStorageV6.sol';

/**
 * @title IEverclearSpoke
 * @notice Interface for the EverclearSpoke contract
 */
interface IEverclearSpokeV6 is ISpokeStorageV6 {
  /*///////////////////////////////////////////////////////////////
                              STRUCTS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Parameters needed to execute a permit2
   * @param nonce The nonce of the permit
   * @param deadline The deadline of the permit
   * @param signature The signature of the permit
   */
  struct Permit2Params {
    uint256 nonce;
    uint256 deadline;
    bytes signature;
  }
  /*///////////////////////////////////////////////////////////////
                              EVENTS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice emitted when a new intent is added on origin
   * @param _intentId The ID of the intent
   * @param _queueIdx The index of the intent in the IntentQueue
   * @param _intent The intent object
   */
  event IntentAdded(bytes32 indexed _intentId, uint256 _queueIdx, Intent _intent);

  /**
   * @notice emitted when an intent is filled on destination
   * @param _intentId The ID of the intent
   * @param _solver The address of the intent solver
   * @param _receiver The address of the intent receiver
   * @param _amountOut The total amount the user has been transferred
   * @param _queueIdx The index of the FillMessage in the FillQueue
   * @param _intent The full intent object
   */
  event IntentFilled(
    bytes32 indexed _intentId,
    address indexed _solver,
    bytes32 indexed _receiver,
    uint256 _amountOut,
    uint256 _queueIdx,
    Intent _intent
  );

  /**
   * @notice emitted when solver (or anyone) deposits an asset in the EverclearSpoke
   * @param _depositant The address of the depositant
   * @param _asset The address of the deposited asset
   * @param _amount The amount of the deposited asset
   */
  event Deposited(address indexed _depositant, address indexed _asset, uint256 _amount);

  /**
   * @notice emitted when solver (or anyone) withdraws an asset from the EverclearSpoke
   * @param _withdrawer The address of the withdrawer
   * @param _asset The address of the withdrawn asset
   * @param _amount The amount of the withdrawn asset
   */
  event Withdrawn(address indexed _withdrawer, address indexed _asset, uint256 _amount);

  /**
   * @notice Emitted when the intent queue is processed
   * @param _messageId The ID of the message
   * @param _firstIdx The first index of the queue to be processed
   * @param _lastIdx The last index of the queue to be processed
   * @param _quote The quote amount
   */
  event IntentQueueProcessed(bytes32 indexed _messageId, uint256 _firstIdx, uint256 _lastIdx, uint256 _quote);

  /**
   * @notice Emitted when the fill queue is processed
   * @param _messageId The ID of the message
   * @param _firstIdx The first index of the queue to be processed
   * @param _lastIdx The last index of the queue to be processed
   * @param _quote The quote amount
   */
  event FillQueueProcessed(bytes32 indexed _messageId, uint256 _firstIdx, uint256 _lastIdx, uint256 _quote);

  /**
   * @notice Emitted when an external call is executed
   * @param _intentId The ID of the intent
   * @param _returnData The return data of the call
   */
  event ExternalCalldataExecuted(bytes32 indexed _intentId, bytes _returnData);

  /**
   * @notice Emitted when feeAdapter is updated
   * @param _newFeeAdapter The new fee adapter
   */
  event FeeAdapterUpdated(address _newFeeAdapter);

  /**
   * @notice Emitted when fill signer is updated
   * @param _oldFillSigner The old fill signer
   * @param _newFillSigner The new fill signer
   */
  event FillSignerUpdated(address _oldFillSigner, address _newFillSigner);

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

  /**
   * @notice Thrown when the intent is already filled
   * @param _intentId The id of the intent which is being tried to fill
   */
  error EverclearSpoke_FillIntent_InvalidStatus(bytes32 _intentId);

  /**
   * @notice Thrown when trying to fill an expired intent
   * @param _intentId The id of the intent which is being tried to fill
   */
  error EverclearSpoke_FillIntent_IntentExpired(bytes32 _intentId);

  /**
   * @notice Thrown when calling newIntent with invalid intent parameters
   */
  error EverclearSpoke_NewIntent_InvalidIntent();

  /**
   * @notice Thrown when the ttl is non-zero and outputAsset is null
   */
  error EverclearSpoke_NewIntent_OutputAssetNull();

  /**
   * @notice Thrown when the destination array > 1 and outputAsset is not null
   */
  error EverclearSpoke_NewIntent_OutputAssetNotNull();

  /**
   * @notice Thrown when the maxFee is exceeded
   * @param _amountOut The amount sent by the solver
   * @param _amountOutMin The min amount out
   */
  error EverclearSpoke_FillIntent_AmountOutInvalid(uint256 _amountOut, uint256 _amountOutMin);

  /**
   * @notice Thrown when the intent amount is zero
   */
  error EverclearSpoke_NewIntent_ZeroAmount();

  /**
   * @notice Thrown when the solver doesnt have sufficient funds to fill an intent
   * @param _requested The amount of tokens needed to fill the intent
   * @param _available The amount of tokens the solver has deposited in the `EverclearSpoke`
   */
  error EverclearSpoke_FillIntent_InsufficientFunds(uint256 _requested, uint256 _available);

  /**
   * @notice Thrown when the destination array is empty
   */
  error EverclearSpoke_FillIntent_InvalidDestinationArray();

  /**
   * @notice Thrown when the intent calldata exceeds the limit
   */
  error EverclearSpoke_NewIntent_CalldataExceedsLimit();

  /**
   * @notice Thrown when a signature signer does not match the expected address
   */
  error EverclearSpoke_InvalidSignature();

  /**
   * @notice Thrown when the domain does not match the expected domain
   */
  error EverclearSpoke_ProcessFillViaRelayer_WrongDomain();

  /**
   * @notice Thrown when the relayer address does not match the msg.sender
   */
  error EverclearSpoke_ProcessFillViaRelayer_NotRelayer();

  /**
   * @notice Thrown when the TTL of the message has expired
   */
  error EverclearSpoke_ProcessFillViaRelayer_TTLExpired();

  /**
   * @notice Thrown when processing the intent queue and the intent is not found in the position specified in the parameter
   * @param _intentId The id of the intent being processed
   * @param _position The position specified by the queue processor
   */
  error EverclearSpoke_ProcessIntentQueue_NotFound(bytes32 _intentId, uint256 _position);

  /**
   * @notice Thrown when trying to execute the calldata of an intent with invalid status
   * @param _intentId The id of the intent whose calldata is trying to be executed
   */
  error EverclearSpoke_ExecuteIntentCalldata_InvalidStatus(bytes32 _intentId);

  /**
   * @notice Thrown when the external call failed on executeIntentCalldata
   */
  error EverclearSpoke_ExecuteIntentCalldata_ExternalCallFailed();

  /**
   * @notice Thrown when the queues are non-empty
   */
  error EverclearSpoke_Initialize_IntentQueueNotEmpty();

  /**
   * @notice Thrown when the queues are non-empty
   */
  error EverclearSpoke_Initialize_FillQueueNotEmpty();

  /**
   * @notice Thrown when the array length invalid in a batch fill
   */
  error EverclearSpoke_FillIntent_InvalidArrayLengths();

  /**
   * @notice Thrown when the fill signature is invalid
   */
  error EverclearSpoke_InvalidFillSignature();

  /**
   * @notice Thrown when the dynamic gas limit exceeds the maximum gas limit
   * @param _dynamicGasLimit The dynamic gas limit being provided
   */
  error EverclearSpoke_ProcessQueue_ExceedsGasLimit(uint256 _dynamicGasLimit);

  /*///////////////////////////////////////////////////////////////
                              LOGIC
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Pauses the contract
   * @dev only the lighthouse and watchtower can pause the contract
   */
  function pause() external;

  /**
   * @notice Unpauses the contract
   * @dev only the lighthouse and watchtower can unpause the contract
   */
  function unpause() external;

  /**
   * @notice Sets a minting / burning strategy for an asset
   * @param _asset The asset address
   * @param _strategy The strategy id (see `enum Strategy`)
   */
  function setStrategyForAsset(
    address _asset,
    IEverclearV2.Strategy _strategy
  ) external;

  /**
   * @notice Sets a module for a strategy
   * @param _strategy The strategy id (see `enum Strategy`)
   * @param _module The module contract
   */
  function setModuleForStrategy(
    IEverclearV2.Strategy _strategy,
    ISettlementModule _module
  ) external;

  /**
   * @notice Updates the security module
   * @param _newSecurityModule The address of the new security module
   */
  function updateSecurityModule(
    address _newSecurityModule
  ) external;

  /**
   * @notice Update the fee adapter
   * @param _newFeeAdapter The address of the new fee adapter
   */
  function updateFeeAdapter(
    address _newFeeAdapter
  ) external;

  /**
   * @notice Initialize the EverclearSpoke contract
   */
  function initialize(
    address _feeAdapter,
    address _messageReceiver,
    address _fillSigner
  ) external;

  /**
   * @notice Creates a new intent
   * @param _destinations The possible destination chains of the intent
   * @param _receiver The destination address of the intent
   * @param _inputAsset The asset address on origin
   * @param _outputAsset The asset address on destination
   * @param _amount The amount of the asset
   * @param _amountOutMin The minimum amount out the solver should return
   * @param _ttl The time to live of the intent
   * @param _data The data of the intent
   * @return _intentId The ID of the intent
   * @return _intent The intent object
   */
  function newIntent(
    uint32[] memory _destinations,
    bytes32 _receiver,
    address _inputAsset,
    bytes32 _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data
  ) external returns (bytes32 _intentId, Intent memory _intent);

  /**
   * @notice Creates a new intent
   * @param _destinations The possible destination chains of the intent
   * @param _receiver The destination address of the intent
   * @param _inputAsset The asset address on origin
   * @param _outputAsset The asset address on destination
   * @param _amount The amount of the asset
   * @param _amountOutMin The minimum amount out the solver should return
   * @param _ttl The time to live of the intent
   * @param _data The data of the intent
   * @return _intentId The ID of the intent
   * @return _intent The intent object
   */
  function newIntent(
    uint32[] memory _destinations,
    address _receiver,
    address _inputAsset,
    address _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data
  ) external returns (bytes32 _intentId, Intent memory _intent);

  /**
   * @notice Fills a batch of intents
   * @param _intents The intents to fill
   * @param _amountOut The amounts of the assets the solver is sending to the users
   * @param _destinations The destinations for the repayment
   */
  function batchFillIntent(
    Intent[] calldata _intents,
    uint256[] calldata _amountOut,
    bytes32[] calldata _receivers,
    uint32[][] calldata _destinations,
    bytes calldata _signature,
    bool _pullFunds
  ) external returns (FillMessage[] memory _fillMessages);

  /**
   * @notice fills an intent
   * @param _intent The intent structure
   * @param _amountOut The amount of the asset the solver is sending to the user
   * @return _fillMessage The enqueued fill message
   */
  function fillIntent(
    Intent calldata _intent,
    uint256 _amountOut,
    bytes32 _receiver,
    uint32[] memory _destinations,
    bytes calldata _signature,
    bool _pullFunds
  ) external returns (FillMessage memory _fillMessage);

  /**
   * @notice Process the intent queue messages to send a batched message to the transport layer
   * @param _intents The intents to process, must respect the intent queue order
   */
  function processIntentQueue(
    Intent[] calldata _intents,
    uint256 _dynamicGasLimit
  ) external payable;

  /**
   * @notice Process the fill queue messages to send a batched message to the transport layer
   * @param _amount The amount of messages to process and batch
   */
  function processFillQueue(
    uint32 _amount,
    uint256 _dynamicGasLimit
  ) external payable;

  /**
   * @notice Process the intent queue messages to send a batched message to the transport layer (via relayer)
   * @param _domain The domain of the message
   * @param _intents The intents to process, must respect the intent queue order
   * @param _relayer The address of the relayer
   * @param _ttl The time to live of the message
   * @param _nonce The nonce of the signature
   * @param _dynamicGasLimit The dynamic gas limit being provided
   * @param _signature The signature of the data
   */
  function processIntentQueueViaRelayer(
    uint32 _domain,
    Intent[] calldata _intents,
    address _relayer,
    uint256 _ttl,
    uint256 _nonce,
    uint256 _dynamicGasLimit,
    bytes calldata _signature
  ) external;

  /**
   * @notice Process the fill queue messages to send a batched message to the transport layer (via relayer)
   * @param _domain The domain of the message
   * @param _amount The amount of messages to process and batch
   * @param _relayer The address of the relayer
   * @param _ttl The time to live of the message
   * @param _nonce The nonce of the signature
   * @param _dynamicGasLimit The dynamic gas limit being provided
   * @param _signature The signature of the data
   */
  function processFillQueueViaRelayer(
    uint32 _domain,
    uint32 _amount,
    address _relayer,
    uint256 _ttl,
    uint256 _nonce,
    uint256 _dynamicGasLimit,
    bytes calldata _signature
  ) external;

  /**
   * @notice deposits an asset into the EverclearSpoke
   * @dev should be only called by solvers but it is permissionless, the funds will be used by the solvers to execute intents
   * @param _asset The address of the asset
   * @param _amount The amount of the asset
   */
  function deposit(
    address _asset,
    uint256 _amount
  ) external;

  /**
   * @notice withdraws an asset from the EverclearSpoke
   * @dev can be called by solvers or users
   * @param _asset The address of the asset
   * @param _amount The amount of the asset
   */
  function withdraw(
    address _asset,
    uint256 _amount
  ) external;

  /**
   * @notice Updates the gateway
   * @param _newGateway The address of the new gateway
   */
  function updateGateway(
    address _newGateway
  ) external;

  /**
   * @notice Updates the message receiver
   * @param _newMessageReceiver The address of the new message receiver
   */
  function updateMessageReceiver(
    address _newMessageReceiver
  ) external;

  /**
   * @notice Updates the max gas limit used for outgoing messages
   * @param _newGasLimit The new gas limit
   */
  function updateMessageGasLimit(
    uint256 _newGasLimit
  ) external;

  /**
   * @notice Updates the fill signer
   * @param _fillSigner The address of the new fill signer
   */
  function updateFillSigner(
    address _fillSigner
  ) external;

  /**
   * @notice Executes the calldata of an intent
   * @param _intent The intent object
   */
  function executeIntentCalldata(
    Intent calldata _intent
  ) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IEverclearV2} from '../common/IEverclearV2.sol';
import {IEverclearSpokeV6} from './IEverclearSpokeV6.sol';
import {IPermit2} from 'interfaces/common/IPermit2.sol';

interface IFeeAdapterV2 {
  struct OrderParameters {
    uint32[] destinations;
    address receiver;
    address inputAsset;
    address outputAsset;
    uint256 amount;
    uint256 amountOutMin;
    uint48 ttl;
    bytes data;
  }

  struct FeeParams {
    uint256 fee;
    uint256 deadline;
    bytes sig;
  }

  /**
   * @notice Emitted when a new intent is created with fees
   * @param _intentId The ID of the created intent
   * @param _initiator The address of the user who initiated the intent
   * @param _tokenFee The amount of token fees paid
   * @param _nativeFee The amount of native token fees paid
   */
  event IntentWithFeesAdded(
    bytes32 indexed _intentId, bytes32 indexed _initiator, uint256 _tokenFee, uint256 _nativeFee
  );

  /**
   * @notice Emitted when a new order containing multiple intents is created
   * @param _orderId The unique identifier for the created order
   * @param _initiator The address of the user who initiated the order
   * @param _intentIds Array of intent IDs that make up this order
   * @param _tokenFee The amount of token fees paid for the order
   * @param _nativeFee The amount of native token fees paid for the order
   */
  event OrderCreated(
    bytes32 indexed _orderId, bytes32 indexed _initiator, bytes32[] _intentIds, uint256 _tokenFee, uint256 _nativeFee
  );

  /**
   * @notice Emitted when the fee recipient is updated
   * @param _updated The new fee recipient address
   * @param _previous The previous fee recipient address
   */
  event FeeRecipientUpdated(address indexed _updated, address indexed _previous);

  /**
   * @notice Emitted when the fee signer is updated
   * @param _updated The new fee signer address
   * @param _previous The previous fee signer address
   */
  event FeeSignerUpdated(address indexed _updated, address indexed _previous);

  /**
   * @notice Thrown when there are multiple assets included in a single order request.
   */
  error MultipleOrderAssets();

  /**
   * @notice Thrown when the signature is invalid on fees
   */
  error FeeAdapter_InvalidSignature();

  /**
   * @notice Thrown when the deadline has elapsed
   */
  error FeeAdapter_InvalidDeadline();

  /**
   * @notice Thrown when the signature has already been used
   */
  error FeeAdapter_SignatureAlreadyUsed();

  /**
   * @notice Returns the spoke contract address
   * @return The EverclearSpoke contract interface
   */
  function spoke() external view returns (IEverclearSpokeV6);

  /**
   * @notice returns the permit2 contract
   * @return _permit2 The Permit2 singleton address
   */
  function PERMIT2() external view returns (IPermit2 _permit2);

  /**
   * @notice Returns the current fee recipient address
   * @return The address that receives fees
   */
  function feeRecipient() external view returns (address);

  /**
   * @notice Returns the current fee signer address
   * @return The address whose signature is verified
   */
  function feeSigner() external view returns (address);

  /**
   * @notice Returns if the tx exists
   * @return _bool True if the tx exists
   */
  function txExists(
    bytes32 _txHash
  ) external view returns (bool _bool);

  /**
   * @notice Creates a new intent with fees
   * @param _destinations Array of destination domains, preference ordered
   * @param _receiver Address of the receiver on the destination chain
   * @param _inputAsset Address of the input asset
   * @param _outputAsset Address of the output asset
   * @param _amount Amount of input asset to use for the intent
   * @param _amountOutMin Amount expected in the outputAsset
   * @param _ttl Time-to-live for the intent in seconds
   * @param _data Additional data for the intent
   * @param _feeParams Fee parameters including fee amount, deadline, and signature
   * @return _intentId The ID of the created intent
   * @return _intent The created intent object
   */
  function newIntent(
    uint32[] memory _destinations,
    bytes32 _receiver,
    address _inputAsset,
    bytes32 _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    FeeParams calldata _feeParams
  ) external payable returns (bytes32, IEverclearV2.Intent memory);

  /**
   * @notice Creates a new intent with fees
   * @param _destinations Array of destination domains, preference ordered
   * @param _receiver Address of the receiver on the destination chain
   * @param _inputAsset Address of the input asset
   * @param _outputAsset Address of the output asset
   * @param _amount Amount of input asset to use for the intent
   * @param _amountOutMin Amount expected in the outputAsset
   * @param _ttl Time-to-live for the intent in seconds
   * @param _data Additional data for the intent
   * @param _feeParams Fee parameters including fee amount, deadline, and signature
   * @return _intentId The ID of the created intent
   * @return _intent The created intent object
   */
  function newIntent(
    uint32[] memory _destinations,
    address _receiver,
    address _inputAsset,
    address _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    FeeParams calldata _feeParams
  ) external payable returns (bytes32, IEverclearV2.Intent memory);

  /**
   * @notice Creates a new intent with fees using Permit2
   * @dev Users will permit the adapter, which will then approve the spoke and call newIntent
   * @param _destinations Array of destination domains, preference ordered
   * @param _receiver Address of the receiver on the destination chain
   * @param _inputAsset Address of the input asset
   * @param _outputAsset Address of the output asset
   * @param _amount Amount of input asset to use for the intent
   * @param _amountOutMin Amount expected in the outputAsset
   * @param _ttl Time-to-live for the intent in seconds
   * @param _data Additional data for the intent
   * @param _permit2Params Signed Permit2 payload, with adapter as spender
   * @param _feeParams Token fee amount to be sent to the fee recipient
   * @return _intentId The ID of the created intent
   * @return _intent The created intent object
   */
  function newIntent(
    uint32[] memory _destinations,
    address _receiver,
    address _inputAsset,
    address _outputAsset,
    uint256 _amount,
    uint256 _amountOutMin,
    uint48 _ttl,
    bytes calldata _data,
    IEverclearSpokeV6.Permit2Params calldata _permit2Params,
    FeeParams calldata _feeParams
  ) external payable returns (bytes32, IEverclearV2.Intent memory);

  /**
   * @notice Creates multiple intents with the same parameters, splitting the amount evenly
   * @dev Creates _numIntents intents with identical parameters but divides _amount equally among them
   * @param _numIntents Number of intents to create
   * @param _fee Token fee amount to be sent to the fee recipient
   * @param _params Order parameters including destinations, receiver, assets, amount, maxFee, ttl, and data
   * @return _orderId The ID of the created order (hash of all intent IDs)
   * @return _intentIds Array of all created intent IDs
   */
  function newOrderSplitEvenly(
    uint32 _numIntents,
    uint256 _fee,
    uint256 _deadline,
    bytes calldata _sig,
    OrderParameters memory _params
  ) external payable returns (bytes32, bytes32[] memory);

  /**
   * @notice Creates multiple intents with the supplied parameters
   * @param _fee Token fee amount to be sent to the fee recipient
   * @param _params Order parameters including destinations, receiver, assets, amount, maxFee, ttl, and data
   * @return _orderId The ID of the created order (hash of all intent IDs)
   * @return _intentIds Array of all created intent IDs
   */
  function newOrder(
    uint256 _fee,
    uint256 _deadline,
    bytes calldata _sig,
    OrderParameters[] memory _params
  ) external payable returns (bytes32, bytes32[] memory);

  /**
   * @notice Updates the fee recipient address
   * @dev Can only be called by the owner of the contract
   * @param _feeRecipient The new address that will receive fees
   */
  function updateFeeRecipient(
    address _feeRecipient
  ) external;

  /**
   * @notice Updates the fee signer address
   * @dev Can only be called by the owner of the contract
   * @param _feeSigner The new address that will sign for fees
   */
  function updateFeeSigner(
    address _feeSigner
  ) external;

  /**
   * @notice Send virtual balance to the original recipient
   * @param _asset Address of the asset to return
   * @param _amount Amount of the asset to return
   * @param _recipient Address of the recipient
   */
  function returnUnsupportedIntent(
    address _asset,
    uint256 _amount,
    address _recipient
  ) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

/**
 * @title ISettlementModule
 * @notice Interface for the base settlement module
 */
interface ISettlementModule {
  /*///////////////////////////////////////////////////////////////
                              LOGIC
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Handle a mint action for a specific strategy
   * @param _asset The address of the asset to mint
   * @param _recipient The recipient of the minted assets
   * @param _fallbackRecipient The fallback recipient of the minted assets (in case of failure)
   * @param _amount The amount to mint
   * @param _data Extra data needed by some modules
   * @return _success The outcome of the minting strategy
   * @dev In case of failure, the parent module will handle the operation accordingly
   */
  function handleMintStrategy(
    address _asset,
    address _recipient,
    address _fallbackRecipient,
    uint256 _amount,
    bytes calldata _data
  ) external returns (bool _success);

  /**
   * @notice Handle a burn action for a specific strategy
   * @param _asset The address of the asset to burn
   * @param _user The user whose assets are being burned
   * @param _amount The amount to burn
   * @param _data Extra data needed by some modules
   * @dev In case of failure, the `newIntent` flow will revert
   */
  function handleBurnStrategy(
    address _asset,
    address _user,
    uint256 _amount,
    bytes calldata _data
  ) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IEverclearV2} from 'interfaces/common/IEverclearV2.sol';
import {IPermit2} from 'interfaces/common/IPermit2.sol';

import {ISettlementModule} from 'interfaces/common/ISettlementModule.sol';
import {ICallExecutor} from 'interfaces/intent/ICallExecutor.sol';
import {ISpokeGateway} from 'interfaces/intent/ISpokeGateway.sol';

/**
 * @title ISpokeStorageV6
 * @notice Interface for the SpokeStorage contract
 */
interface ISpokeStorageV6 is IEverclearV2 {
  /*///////////////////////////////////////////////////////////////
                              STRUCTS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Parameters needed to initiliaze `EverclearSpoke`
   * @param gateway The local `SpokeGateway`
   * @param callExecutor The local `CallExecutor`
   * @param messageReceiver The address for the `SpokeMessageReceiver` module
   * @param lighthouse The address for the Lighthouse agent
   * @param watchtower The address for the Watchtower agent
   * @param hubDomain The chain id for the Everclear domain
   * @param owner The initial owner of the contract
   */
  struct SpokeInitializationParams {
    ISpokeGateway gateway;
    ICallExecutor callExecutor;
    address messageReceiver;
    address lighthouse;
    address watchtower;
    uint32 hubDomain;
    address owner;
  }

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

  /**
   * @notice emitted when the Gateway address is updated
   * @param _oldGateway The address of the old gateway
   * @param _newGateway The address of the new gateway
   */
  event GatewayUpdated(address _oldGateway, address _newGateway);

  /**
   * @notice emitted when the Lighthouse address is updated
   * @param _oldLightHouse The address of the old lighthouse
   * @param _newLightHouse The address of the new lighthouse
   */
  event LighthouseUpdated(address _oldLightHouse, address _newLightHouse);

  /**
   * @notice emitted when the Watchtower address is updated
   * @param _oldWatchtower The address of the old watchtower
   * @param _newWatchtower The address of the new watchtower
   */
  event WatchtowerUpdated(address _oldWatchtower, address _newWatchtower);

  /**
   * @notice emitted when the MessageReceiver address is updated
   * @param _oldMessageReceiver The address of the old message receiver
   * @param _newMessageReceiver The address of the new message receiver
   */
  event MessageReceiverUpdated(address _oldMessageReceiver, address _newMessageReceiver);

  /**
   * @notice emitted when messageGasLimit is updated
   * @param _oldGasLimit The old gas limit
   * @param _newGasLimit The new gas limit
   */
  event MessageGasLimitUpdated(uint256 _oldGasLimit, uint256 _newGasLimit);

  /**
   * @notice emitted when the protocol is paused (domain-level)
   */
  event Paused();

  /**
   * @notice emitted when the protocol is paused (domain-level)
   */
  event Unpaused();

  /**
   * @notice emitted when a strategy is set for an asset
   * @param _asset The address of the asset being configured
   * @param _strategy The id for the strategy (see `enum Strategy`)
   */
  event StrategySetForAsset(address _asset, IEverclearV2.Strategy _strategy);

  /**
   * @notice emitted when the module is set for a strategy
   * @param _strategy The id for the strategy (see `enum Strategy`)
   * @param _module The settlement module
   */
  event ModuleSetForStrategy(IEverclearV2.Strategy _strategy, ISettlementModule _module);

  /**
   * @notice emitted when the EverclearSpoke processes a settlement
   * @param _intentId The ID of the intent
   * @param _account The address of the account
   * @param _asset The address of the asset
   * @param _amount The amount of the asset
   */
  event Settled(bytes32 indexed _intentId, address _account, address _asset, uint256 _amount);

  /**
   * @notice emitted when `_handleSettlement` fails to transfer tokens to a user (eg. blacklisted recipient)
   * @param _asset The address of the asset
   * @param _recipient The address of the recipient
   * @param _amount The amount of the asset
   */
  event AssetTransferFailed(address indexed _asset, address indexed _recipient, uint256 _amount);

  /**
   * @notice emitted when `_handleSettlement` fails to mint the non-default stategy asset
   * @param _asset The address of the asset
   * @param _recipient The address of the recipient
   * @param _amount The amount of the asset
   * @param _strategy The strategy used for the asset
   */
  event AssetMintFailed(address indexed _asset, address indexed _recipient, uint256 _amount, Strategy _strategy);

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

  /**
   * @notice Thrown when the spoke is receiving a message from an address that is not the authorized gateway, admin or owner
   */
  error EverclearSpoke_Unauthorized();

  /**
   * @notice Thrown when a message is not a valid message type
   */
  error EverclearSpoke_InvalidMessageType();

  /**
   * @notice Thrown when the destination is wrong
   */
  error EverclearSpoke_WrongDestination();

  /**
   * @notice Thrown when a variable update is invalid
   */
  error EverclearSpoke_InvalidVarUpdate();

  /**
   * @notice Thrown when calling to a processQueue method with a zero amount
   */
  error EverclearSpoke_ProcessQueue_ZeroAmount();

  /**
   * @notice Thrown when calling to a processQueue method with an invalid amount
   * @param _first The index of the first element of the queue
   * @param _last The index of the last element of the queue
   * @param _amount The amount of items being tried to process
   */
  error EverclearSpoke_ProcessQueue_InvalidAmount(uint256 _first, uint256 _last, uint256 _amount);

  /**
   * @notice Thrown when calling a function with the zero address
   */
  error EverclearSpoke_ZeroAddress();

  /**
   * @notice Thrown when a function is called when the spoke is paused
   */
  error EverclearSpoke_Paused();

  /**
   * @notice Thrown when the caller is not authorized to pause the spoke
   */
  error EverclearSpoke_Pause_NotAuthorized();

  /**
   * @notice Thrown when the caller is not authorized to pause the spoke
   */
  error EverclearSpoke_FeeAdapter_NotAuthorized();

  /*///////////////////////////////////////////////////////////////
                              VIEWS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice returns the typehash for `fillIntentForSolver`
   * @return _typeHash The `fillIntentForSolver` type hash
   */
  function FILL_INTENT_FOR_SOLVER_TYPEHASH() external view returns (bytes32 _typeHash);

  /**
   * @notice returns the typehash for `processIntentQueueViaRelayer`
   * @return _typeHash The `processIntentQueueViaRelayer` type hash
   */
  function PROCESS_INTENT_QUEUE_VIA_RELAYER_TYPEHASH() external view returns (bytes32 _typeHash);

  /**
   * @notice returns the typehash for `processFillQueueViaRelayer`
   * @return _typeHash The `processFillQueueViaRelayer` type hash
   */
  function PROCESS_FILL_QUEUE_VIA_RELAYER_TYPEHASH() external view returns (bytes32 _typeHash);

  /**
   * @notice returns the typehash for `fillIntentSolver
   * @dev used to verify the destinations array is valid with off-chain API
   * @return _typeHash The `fillIntentSolver` type hash
   */
  function FILL_INTENT_TYPEHASH() external view returns (bytes32 _typeHash);

  /**
   * @notice returns the typehash for `batchFillIntentSolver
   * @dev used to verify the destinations array is valid with off-chain API
   * @return _typeHash The `batchFillIntentSolver` type hash
   */
  function BATCH_FILL_INTENT_TYPEHASH() external view returns (bytes32 _typeHash);

  /**
   * @notice returns the permit2 contract
   * @return _permit2 The Permit2 singleton address
   */
  function PERMIT2() external view returns (IPermit2 _permit2);

  /**
   * @notice returns the domain id for the Everclear rollup
   * @return _domain The id of the Everclear domain
   */
  function EVERCLEAR() external view returns (uint32 _domain);

  /**
   * @notice returns the current domain
   * @return _domain The id of the current domain
   */
  function DOMAIN() external view returns (uint32 _domain);

  /**
   * @notice returns the lighthouse address
   * @return _lighthouse The address of the Lighthouse agent
   */
  function lighthouse() external view returns (address _lighthouse);

  /**
   * @notice returns the watchtower address
   * @return _watchtower The address of the Watchtower agent
   */
  function watchtower() external view returns (address _watchtower);

  /**
   * @notice returns the message receiver address
   * @return _messageReceiver The address of the `SpokeMessageReceiver`
   */
  function messageReceiver() external view returns (address _messageReceiver);

  /**
   * @notice returns the gateway
   * @return _gateway The local `SpokeGateway`
   */
  function gateway() external view returns (ISpokeGateway _gateway);

  /**
   * @notice returns the call executor
   * @return _callExecutor The local `CallExecutor`
   */
  function callExecutor() external view returns (ICallExecutor _callExecutor);

  /**
   * @notice returns the fee adapter
   * @return _feeAdapter The address of the fee adapter
   */
  function feeAdapter() external view returns (address _feeAdapter);

  /**
   * @notice returns the paused status of the spoke
   * @return _paused The boolean indicating if the contract is paused
   */
  function paused() external view returns (bool _paused);

  /**
   * @notice returns the current intent nonce
   * @return _nonce The current nonce
   */
  function nonce() external view returns (uint64 _nonce);

  /**
   * @notice returns the gas limit used for outgoing messages
   * @return _messageGasLimit the max gas limit
   */
  function messageGasLimit() external view returns (uint256 _messageGasLimit);

  /**
   * @notice returns the balance of an asset for a user
   * @param _asset The address of the asset
   * @param _user The address of the user
   * @return _amount The amount of assets locked in the contract
   */
  function balances(
    bytes32 _asset,
    bytes32 _user
  ) external view returns (uint256 _amount);

  /**
   * @notice returns the status of an intent
   * @param _intentId The ID of the intent
   * @return _status The status of the intent
   */
  function status(
    bytes32 _intentId
  ) external view returns (IntentStatus _status);

  /**
   * @notice returns the configured strategy id for an asset
   * @param _asset The address of the asset
   * @return _strategy The strategy for the asset
   */
  function strategies(
    address _asset
  ) external view returns (IEverclearV2.Strategy _strategy);

  /**
   * @notice returns the module address for a strategy
   * @param _strategy The strategy id
   * @return _module The strategy module
   */
  function modules(
    IEverclearV2.Strategy _strategy
  ) external view returns (ISettlementModule _module);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

/**
 * @title ICallExecutor
 * @notice Interface for the CallExecutor contract, executes calls to external contracts
 */
interface ICallExecutor {
  /**
   * @notice Safely call a target contract, use when you _really_ really _really_ don't trust the called
   * contract. This prevents the called contract from causing reversion of the caller in as many ways as we can.
   * @param _target The address to call
   * @param _gas The amount of gas to forward to the remote contract
   * @param _value The value in wei to send to the remote contract
   * @param _maxCopy The maximum number of bytes of returndata to copy to memory
   * @param _calldata The data to send to the remote contract
   * @return _success Whether the call was successful
   * @return _returnData Returndata as `.call()`. Returndata is capped to `_maxCopy` bytes.
   */
  function excessivelySafeCall(
    address _target,
    uint256 _gas,
    uint256 _value,
    uint16 _maxCopy,
    bytes memory _calldata
  ) external returns (bool _success, bytes memory _returnData);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IGateway} from 'interfaces/common/IGateway.sol';

/**
 * @title ISpokeGateway
 * @notice Interface for the SpokeGateway contract, sends and receives messages to and from the transport layer
 */
interface ISpokeGateway is IGateway {
  /*///////////////////////////////////////////////////////////////
                              LOGIC
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Initialize Gateway variables
   * @param _owner The address of the owner
   * @param _mailbox The address of the local mailbox
   * @param _receiver The address of the local message receiver (EverclearSpoke)
   * @param _interchainSecurityModule The address of the chosen interchain security module
   * @param _everclearId The id of the Everclear domain
   * @param _hubGateway The bytes32 representation of the Hub gateway
   * @dev Only called once on initialization
   */
  function initialize(
    address _owner,
    address _mailbox,
    address _receiver,
    address _interchainSecurityModule,
    uint32 _everclearId,
    bytes32 _hubGateway
  ) external;

  /*///////////////////////////////////////////////////////////////
                              VIEWS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Returns the Everclear hub chain id
   * @return _hubChainId The Everclear chain id
   */
  function EVERCLEAR_ID() external view returns (uint32 _hubChainId);

  /**
   * @notice Returns the `HubGateway` gateway address
   * @return _hubGateway The `HubGateway` address
   */
  function EVERCLEAR_GATEWAY() external view returns (bytes32 _hubGateway);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {IMailbox} from '@hyperlane/interfaces/IMailbox.sol';

import {IMessageReceiver} from 'interfaces/common/IMessageReceiver.sol';

interface IGateway {
  /*///////////////////////////////////////////////////////////////
                              EVENTS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Emitted when the mailbox is updated
   * @param _oldMailbox The old mailbox address
   * @param _newMailbox The new mailbox address
   */
  event MailboxUpdated(address _oldMailbox, address _newMailbox);

  /**
   * @notice Emitted when the security module is updated
   * @param _oldSecurityModule The old security module address
   * @param _newSecurityModule The new security module address
   */
  event SecurityModuleUpdated(address _oldSecurityModule, address _newSecurityModule);

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

  /**
   * @notice Thrown when the message origin is invalid
   */
  error Gateway_Handle_InvalidOriginDomain();

  /**
   * @notice Thrown when the sender is not the appropriate remote Gateway
   */
  error Gateway_Handle_InvalidSender();

  /**
   * @notice Thrown when the caller is not the local mailbox
   */
  error Gateway_Handle_NotCalledByMailbox();

  /**
   * @notice Thrown when the GasTank does not have enough native asset to cover the fee
   */
  error Gateway_SendMessage_InsufficientBalance();

  /**
   * @notice Thrown when the message dispatcher is not the local receiver
   */
  error Gateway_SendMessage_UnauthorizedCaller();

  /**
   * @notice Thrown when the call returning the unused fee fails
   */
  error Gateway_SendMessage_UnsuccessfulRebate();

  /**
   * @notice Thrown when an address equals the address zero
   */
  error Gateway_ZeroAddress();

  /*///////////////////////////////////////////////////////////////
                              LOGIC
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Send a message to the transport layer using the gas tank
   * @param _chainId The id of the destination chain
   * @param _message The message to send
   * @param _fee The fee to send the message
   * @param _gasLimit The gas limit to use on destination
   * @return _messageId The id message of the transport layer
   * @return _feeSpent The fee spent to send the message
   * @dev only called by the spoke contract
   */
  function sendMessage(
    uint32 _chainId,
    bytes memory _message,
    uint256 _fee,
    uint256 _gasLimit
  ) external returns (bytes32 _messageId, uint256 _feeSpent);

  /**
   * @notice Send a message to the transport layer
   * @param _chainId The id of the destination chain
   * @param _message The message to send
   * @param _gasLimit The gas limit to use on destination
   * @return _messageId The id message of the transport layer
   * @return _feeSpent The fee spent to send the message
   * @dev only called by the spoke contract
   */
  function sendMessage(
    uint32 _chainId,
    bytes memory _message,
    uint256 _gasLimit
  ) external payable returns (bytes32 _messageId, uint256 _feeSpent);

  /**
   * @notice Updates the mailbox
   * @param _mailbox The new mailbox address
   * @dev only called by the `receiver`
   */
  function updateMailbox(
    address _mailbox
  ) external;

  /**
   * @notice Updates the gateway security module
   * @param _securityModule The address of the new security module
   * @dev only called by the `receiver`
   */
  function updateSecurityModule(
    address _securityModule
  ) external;

  /*///////////////////////////////////////////////////////////////
                              VIEWS
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Returns the transport layer message routing smart contract
   * @dev this is independent of the transport layer used, adopting mailbox name because its descriptive enough
   *      using address instead of specific interface to be independent from HL or any other TL
   * @return _mailbox The mailbox contract
   */
  function mailbox() external view returns (IMailbox _mailbox);

  /**
   * @notice Returns the message receiver for this Gateway (EverclearHub / EverclearSpoke)
   * @return _receiver The message receiver
   */
  function receiver() external view returns (IMessageReceiver _receiver);

  /**
   * @notice Quotes cost of sending a message to the transport layer
   * @param _chainId The id of the destination chain
   * @param _message The message to send
   * @param _gasLimit The gas limit for delivering the message
   * @return _fee The fee to send the message
   */
  function quoteMessage(
    uint32 _chainId,
    bytes memory _message,
    uint256 _gasLimit
  ) external view returns (uint256 _fee);
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

import {IInterchainSecurityModule} from "./IInterchainSecurityModule.sol";
import {IPostDispatchHook} from "./hooks/IPostDispatchHook.sol";

interface IMailbox {
    // ============ Events ============
    /**
     * @notice Emitted when a new message is dispatched via Hyperlane
     * @param sender The address that dispatched the message
     * @param destination The destination domain of the message
     * @param recipient The message recipient address on `destination`
     * @param message Raw bytes of message
     */
    event Dispatch(
        address indexed sender,
        uint32 indexed destination,
        bytes32 indexed recipient,
        bytes message
    );

    /**
     * @notice Emitted when a new message is dispatched via Hyperlane
     * @param messageId The unique message identifier
     */
    event DispatchId(bytes32 indexed messageId);

    /**
     * @notice Emitted when a Hyperlane message is processed
     * @param messageId The unique message identifier
     */
    event ProcessId(bytes32 indexed messageId);

    /**
     * @notice Emitted when a Hyperlane message is delivered
     * @param origin The origin domain of the message
     * @param sender The message sender address on `origin`
     * @param recipient The address that handled the message
     */
    event Process(
        uint32 indexed origin,
        bytes32 indexed sender,
        address indexed recipient
    );

    function localDomain() external view returns (uint32);

    function delivered(bytes32 messageId) external view returns (bool);

    function defaultIsm() external view returns (IInterchainSecurityModule);

    function defaultHook() external view returns (IPostDispatchHook);

    function requiredHook() external view returns (IPostDispatchHook);

    function latestDispatchedId() external view returns (bytes32);

    function dispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody
    ) external payable returns (bytes32 messageId);

    function quoteDispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody
    ) external view returns (uint256 fee);

    function dispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata body,
        bytes calldata defaultHookMetadata
    ) external payable returns (bytes32 messageId);

    function quoteDispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody,
        bytes calldata defaultHookMetadata
    ) external view returns (uint256 fee);

    function dispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata body,
        bytes calldata customHookMetadata,
        IPostDispatchHook customHook
    ) external payable returns (bytes32 messageId);

    function quoteDispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody,
        bytes calldata customHookMetadata,
        IPostDispatchHook customHook
    ) external view returns (uint256 fee);

    function process(
        bytes calldata metadata,
        bytes calldata message
    ) external payable;

    function recipientIsm(
        address recipient
    ) external view returns (IInterchainSecurityModule module);
}

File 25 of 27 : IMessageReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

/**
 * @title IMessageReceiver
 * @notice Interface for the transport layer communication with the message receiver
 */
interface IMessageReceiver {
  /*///////////////////////////////////////////////////////////////
                              LOGIC
  //////////////////////////////////////////////////////////////*/

  /**
   * @notice Receive a message from the transport layer
   * @param _message The message to receive encoded as bytes
   * @dev This function should be called by the the gateway contract
   */
  function receiveMessage(
    bytes calldata _message
  ) external;
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;

interface IInterchainSecurityModule {
    enum Types {
        UNUSED,
        ROUTING,
        AGGREGATION,
        LEGACY_MULTISIG,
        MERKLE_ROOT_MULTISIG,
        MESSAGE_ID_MULTISIG,
        NULL, // used with relayer carrying no metadata
        CCIP_READ
    }

    /**
     * @notice Returns an enum that represents the type of security model
     * encoded by this ISM.
     * @dev Relayers infer how to fetch and format metadata.
     */
    function moduleType() external view returns (uint8);

    /**
     * @notice Defines a security model responsible for verifying interchain
     * messages based on the provided metadata.
     * @param _metadata Off-chain metadata provided by a relayer, specific to
     * the security model encoded by the module (e.g. validator signatures)
     * @param _message Hyperlane encoded interchain message
     * @return True if the message was verified
     */
    function verify(
        bytes calldata _metadata,
        bytes calldata _message
    ) external returns (bool);
}

interface ISpecifiesInterchainSecurityModule {
    function interchainSecurityModule()
        external
        view
        returns (IInterchainSecurityModule);
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

/*@@@@@@@       @@@@@@@@@
 @@@@@@@@@       @@@@@@@@@
  @@@@@@@@@       @@@@@@@@@
   @@@@@@@@@       @@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@
     @@@@@  HYPERLANE  @@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@
   @@@@@@@@@       @@@@@@@@@
  @@@@@@@@@       @@@@@@@@@
 @@@@@@@@@       @@@@@@@@@
@@@@@@@@@       @@@@@@@@*/

interface IPostDispatchHook {
    enum Types {
        UNUSED,
        ROUTING,
        AGGREGATION,
        MERKLE_TREE,
        INTERCHAIN_GAS_PAYMASTER,
        FALLBACK_ROUTING,
        ID_AUTH_ISM,
        PAUSABLE,
        PROTOCOL_FEE,
        LAYER_ZERO_V1
    }

    /**
     * @notice Returns an enum that represents the type of hook
     */
    function hookType() external view returns (uint8);

    /**
     * @notice Returns whether the hook supports metadata
     * @param metadata metadata
     * @return Whether the hook supports metadata
     */
    function supportsMetadata(
        bytes calldata metadata
    ) external view returns (bool);

    /**
     * @notice Post action after a message is dispatched via the Mailbox
     * @param metadata The metadata required for the hook
     * @param message The message passed from the Mailbox.dispatch() call
     */
    function postDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) external payable;

    /**
     * @notice Compute the payment required by the postDispatch call
     * @param metadata The metadata required for the hook
     * @param message The message passed from the Mailbox.dispatch() call
     * @return Quoted payment for the postDispatch call
     */
    function quoteDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) external view returns (uint256);
}

Settings
{
  "remappings": [
    "ds-test/=../../node_modules/ds-test/src/",
    "forge-std/=../../node_modules/forge-std/src/",
    "isolmate/=../../node_modules/isolmate/src/",
    "@hyperlane/=../../node_modules/@hyperlane-xyz/core/contracts/",
    "@openzeppelin/=../../node_modules/@openzeppelin/",
    "@upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "xerc20/=lib/xerc20/solidity/contracts/",
    "contracts/=src/contracts/",
    "interfaces/=src/interfaces/",
    "utils/=script/utils/",
    "@eth-optimism/=../../node_modules/@eth-optimism/",
    "@hyperlane-xyz/=../../node_modules/@hyperlane-xyz/",
    "@layerzerolabs/=../../node_modules/@layerzerolabs/",
    "erc4626-tests/=lib/xerc20/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/xerc20/lib/permit2/lib/forge-gas-snapshot/src/",
    "fx-portal/=../../node_modules/fx-portal/",
    "openzeppelin-contracts/=lib/xerc20/lib/openzeppelin-contracts/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "openzeppelin/=lib/xerc20/lib/openzeppelin-contracts/contracts/",
    "permit2/=lib/xerc20/lib/permit2/",
    "prb-test/=lib/xerc20/lib/prb-test/src/",
    "prb/test/=lib/xerc20/lib/prb-test/src/",
    "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
    "solmate/=lib/xerc20/lib/permit2/lib/solmate/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_spoke","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"address","name":"_feeSigner","type":"address"},{"internalType":"address","name":"_xerc20Module","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeAdapter_InvalidDeadline","type":"error"},{"inputs":[],"name":"FeeAdapter_InvalidSignature","type":"error"},{"inputs":[],"name":"FeeAdapter_SignatureAlreadyUsed","type":"error"},{"inputs":[],"name":"MultipleOrderAssets","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_updated","type":"address"},{"indexed":true,"internalType":"address","name":"_previous","type":"address"}],"name":"FeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_updated","type":"address"},{"indexed":true,"internalType":"address","name":"_previous","type":"address"}],"name":"FeeSignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_intentId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"_initiator","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_tokenFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nativeFee","type":"uint256"}],"name":"IntentWithFeesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"_initiator","type":"bytes32"},{"indexed":false,"internalType":"bytes32[]","name":"_intentIds","type":"bytes32[]"},{"indexed":false,"internalType":"uint256","name":"_tokenFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nativeFee","type":"uint256"}],"name":"OrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"contract IPermit2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_destinations","type":"uint32[]"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_inputAsset","type":"address"},{"internalType":"address","name":"_outputAsset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint48","name":"_ttl","type":"uint48"},{"internalType":"bytes","name":"_data","type":"bytes"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IEverclearSpokeV6.Permit2Params","name":"_permit2Params","type":"tuple"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct IFeeAdapterV2.FeeParams","name":"_feeParams","type":"tuple"}],"name":"newIntent","outputs":[{"internalType":"bytes32","name":"_intentId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"initiator","type":"bytes32"},{"internalType":"bytes32","name":"receiver","type":"bytes32"},{"internalType":"bytes32","name":"inputAsset","type":"bytes32"},{"internalType":"bytes32","name":"outputAsset","type":"bytes32"},{"internalType":"uint32","name":"origin","type":"uint32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint48","name":"timestamp","type":"uint48"},{"internalType":"uint48","name":"ttl","type":"uint48"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint32[]","name":"destinations","type":"uint32[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IEverclearV2.Intent","name":"_intent","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_destinations","type":"uint32[]"},{"internalType":"bytes32","name":"_receiver","type":"bytes32"},{"internalType":"address","name":"_inputAsset","type":"address"},{"internalType":"bytes32","name":"_outputAsset","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint48","name":"_ttl","type":"uint48"},{"internalType":"bytes","name":"_data","type":"bytes"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct IFeeAdapterV2.FeeParams","name":"_feeParams","type":"tuple"}],"name":"newIntent","outputs":[{"internalType":"bytes32","name":"_intentId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"initiator","type":"bytes32"},{"internalType":"bytes32","name":"receiver","type":"bytes32"},{"internalType":"bytes32","name":"inputAsset","type":"bytes32"},{"internalType":"bytes32","name":"outputAsset","type":"bytes32"},{"internalType":"uint32","name":"origin","type":"uint32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint48","name":"timestamp","type":"uint48"},{"internalType":"uint48","name":"ttl","type":"uint48"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint32[]","name":"destinations","type":"uint32[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IEverclearV2.Intent","name":"_intent","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_destinations","type":"uint32[]"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_inputAsset","type":"address"},{"internalType":"address","name":"_outputAsset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint48","name":"_ttl","type":"uint48"},{"internalType":"bytes","name":"_data","type":"bytes"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct IFeeAdapterV2.FeeParams","name":"_feeParams","type":"tuple"}],"name":"newIntent","outputs":[{"internalType":"bytes32","name":"_intentId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"initiator","type":"bytes32"},{"internalType":"bytes32","name":"receiver","type":"bytes32"},{"internalType":"bytes32","name":"inputAsset","type":"bytes32"},{"internalType":"bytes32","name":"outputAsset","type":"bytes32"},{"internalType":"uint32","name":"origin","type":"uint32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint48","name":"timestamp","type":"uint48"},{"internalType":"uint48","name":"ttl","type":"uint48"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint32[]","name":"destinations","type":"uint32[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IEverclearV2.Intent","name":"_intent","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_sig","type":"bytes"},{"components":[{"internalType":"uint32[]","name":"destinations","type":"uint32[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"inputAsset","type":"address"},{"internalType":"address","name":"outputAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint48","name":"ttl","type":"uint48"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IFeeAdapterV2.OrderParameters[]","name":"_params","type":"tuple[]"}],"name":"newOrder","outputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"bytes32[]","name":"_intentIds","type":"bytes32[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_numIntents","type":"uint32"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_sig","type":"bytes"},{"components":[{"internalType":"uint32[]","name":"destinations","type":"uint32[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"inputAsset","type":"address"},{"internalType":"address","name":"outputAsset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint48","name":"ttl","type":"uint48"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IFeeAdapterV2.OrderParameters","name":"_params","type":"tuple"}],"name":"newOrderSplitEvenly","outputs":[{"internalType":"bytes32","name":"_orderId","type":"bytes32"},{"internalType":"bytes32[]","name":"_intentIds","type":"bytes32[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"returnUnsupportedIntent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spoke","outputs":[{"internalType":"contract IEverclearSpokeV6","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"txExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"updateFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeSigner","type":"address"}],"name":"updateFeeSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"xerc20Module","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c060405234801561000f575f80fd5b5060405161347f38038061347f83398101604081905261002e916101d3565b806001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b61006581610095565b506001600160a01b03808616608052821660a052610082846100b1565b61008b8361010d565b5050505050610234565b600180546001600160a01b03191690556100ae81610169565b50565b6002546040516001600160a01b03918216918316907faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d3905f90a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b6003546040516001600160a01b03918216918316907f76bd52e686622d2685524f18ca827265a39b781115ecfee7e344cec952442040905f90a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146101ce575f80fd5b919050565b5f805f805f60a086880312156101e7575f80fd5b6101f0866101b8565b94506101fe602087016101b8565b935061020c604087016101b8565b925061021a606087016101b8565b9150610228608087016101b8565b90509295509295909350565b60805160a0516131eb6102945f395f818161018e015261112a01525f8181610201015281816104bd015281816105bd015281816107700152818161096b0152818161107d0152818161110201528181611463015261162601526131eb5ff3fe60806040526004361061013d575f3560e01c806379ba5097116100bb578063ceb6341c11610071578063e30c397811610057578063e30c397814610361578063f160d3691461037e578063f2fde38b1461039d575f80fd5b8063ceb6341c14610310578063de143b9014610323575f80fd5b8063a7e4d189116100a1578063a7e4d189146102bd578063ae9b2bad146102de578063b0834893146102f1575f80fd5b806379ba50971461028d5780638da5cb5b146102a1575f80fd5b806347bfbcc6116101105780636afdd850116100f65780636afdd85014610244578063715018a61461026657806372aaa1871461027a575f80fd5b806347bfbcc6146101f05780636357360314610223575f80fd5b8063075693391461014157806311eefd541461017d5780632e378bbe146101b057806346904840146101d1575b5f80fd5b34801561014c575f80fd5b50600354610160906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610188575f80fd5b506101607f000000000000000000000000000000000000000000000000000000000000000081565b6101c36101be36600461236e565b6103bc565b604051610174929190612430565b3480156101dc575f80fd5b50600254610160906001600160a01b031681565b3480156101fb575f80fd5b506101607f000000000000000000000000000000000000000000000000000000000000000081565b34801561022e575f80fd5b5061024261023d366004612450565b610729565b005b34801561024f575f80fd5b506101606e22d473030f116ddee9f6b43ac78ba381565b348015610271575f80fd5b506102426107d7565b6101c3610288366004612489565b6107ea565b348015610298575f80fd5b50610242610b8a565b3480156102ac575f80fd5b505f546001600160a01b0316610160565b6102d06102cb366004612586565b610bec565b6040516101749291906126ed565b6102d06102ec3660046127fc565b610c85565b3480156102fc575f80fd5b5061024261030b3660046128ca565b610d18565b6102d061031e3660046128e3565b610d29565b34801561032e575f80fd5b5061035161033d366004612966565b60046020525f908152604090205460ff1681565b6040519015158152602001610174565b34801561036c575f80fd5b506001546001600160a01b0316610160565b348015610389575f80fd5b506102426103983660046128ca565b610da9565b3480156103a8575f80fd5b506102426103b73660046128ca565b610dba565b5f60606103dd3384604001518986608001516103d891906129aa565b610e42565b5f3489858a8a6040516020016103f7959493929190612a49565b60405160208183030381529060405280519060200120905061041a818787610e57565b61042a883486604001518a610fc8565b61043c84604001518560800151611041565b5f8963ffffffff1685608001516104539190612a81565b90508963ffffffff1667ffffffffffffffff811115610474576104746120b9565b60405190808252806020026020018201604052801561049d578160200160208202803683370190505b5092505f5b6104ad60018c612ab9565b63ffffffff1681101561059c575f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638249eb15885f015189602001518a604001518b60600151888d60a001518e60c001518f60e001516040518963ffffffff1660e01b8152600401610530989796959493929190612add565b5f604051808303815f875af115801561054b573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526105729190810190612c2d565b5090508085838151811061058857610588612d4b565b6020908102919091010152506001016104a2565b506105a860018b612ab9565b6105b89063ffffffff1682612d78565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638249eb15875f0151886020015189604001518a60600151878c6080015161060d9190612d8f565b8c60a001518d60c001518e60e001516040518963ffffffff1660e01b815260040161063f989796959493929190612add565b5f604051808303815f875af115801561065a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106819190810190612c2d565b509050808461069160018e612ab9565b63ffffffff16815181106106a7576106a7612d4b565b602002602001018181525050836040516020016106c49190612da2565b60408051601f198184030181529190528051602090910120945033857fc5929cfdbbc98a41855839bee1396d17ee4a149e40d5c324b6f4332655f5cffd868d3460405161071393929190612db4565b60405180910390a3505050965096945050505050565b61073161123e565b6040517ff3fef3a30000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063f3fef3a3906044015f604051808303815f87803b1580156107b1575f80fd5b505af11580156107c3573d5f803e3d5ffd5b505050506107d2818484611283565b505050565b6107df61123e565b6107e85f611297565b565b80515f906060908284818361080157610801612d4b565b60200260200101516040015190505f805b838110156108b55786818151811061082c5761082c612d4b565b6020026020010151608001518261084391906129aa565b9150826001600160a01b031687828151811061086157610861612d4b565b6020026020010151604001516001600160a01b0316146108ad576040517f903d557a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101610812565b506108c533836103d88d856129aa565b6108cf8282611041565b5f34878c8c6040516020016108e79493929190612dd8565b60405160208183030381529060405280519060200120905061090a818a8a610e57565b6109168b34858d610fc8565b5050508067ffffffffffffffff811115610932576109326120b9565b60405190808252806020026020018201604052801561095b578160200160208202803683370190505b5091505f5b81811015610b16575f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638249eb158784815181106109aa576109aa612d4b565b60200260200101515f01518885815181106109c7576109c7612d4b565b6020026020010151602001518986815181106109e5576109e5612d4b565b6020026020010151604001518a8781518110610a0357610a03612d4b565b6020026020010151606001518b8881518110610a2157610a21612d4b565b6020026020010151608001518c8981518110610a3f57610a3f612d4b565b602002602001015160a001518d8a81518110610a5d57610a5d612d4b565b602002602001015160c001518e8b81518110610a7b57610a7b612d4b565b602002602001015160e001516040518963ffffffff1660e01b8152600401610aaa989796959493929190612add565b5f604051808303815f875af1158015610ac5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610aec9190810190612c2d565b50905080848381518110610b0257610b02612d4b565b602090810291909101015250600101610960565b5081604051602001610b289190612da2565b60408051601f198184030181529190528051602090910120925033837fc5929cfdbbc98a41855839bee1396d17ee4a149e40d5c324b6f4332655f5cffd848b34604051610b7793929190612db4565b60405180910390a3509550959350505050565b60015433906001600160a01b03168114610be0576040517f118cdaa70000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b610be981611297565b50565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201819052610160820152610c5f8b610c5985358c6129aa565b866112c8565b610c718d8d8d8d8d8d8d8d8d8c611388565b909e909d509b505050505050505050505050565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201819052610160820152610cf3338b6103d886358c6129aa565b610d058c8c8c8c8c8c8c8c8c8c611550565b909d909c509a5050505050505050505050565b610d2061123e565b610be98161167f565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201819052610160820152610d97338b6103d886358c6129aa565b610d058c8c8c8c8c8c8c8c8c8c611388565b610db161123e565b610be9816116f3565b610dc261123e565b600180546001600160a01b0383167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155610e0a5f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6107d26001600160a01b038316843084611767565b604080516020810185905230918101919091524660608201525f9060800160408051601f1981840301815291815281516020928301205f818152600490935291205490915060ff1615610ed6576040517f417ef34700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260046020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c829052603c8120610f779085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117e392505050565b6003549091506001600160a01b03808316911614610fc1576040517fa85a086900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b80421115611002576040517f634f518f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b831561101f5760025461101f906001600160a01b03168386611283565b821561103b5760025461103b906001600160a01b03168461180d565b50505050565b6040517f39ebf8230000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301525f9182917f000000000000000000000000000000000000000000000000000000000000000016906339ebf82390602401602060405180830381865afa1580156110c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e69190612e6a565b90505f8160018111156110fb576110fb612e88565b03611128577f0000000000000000000000000000000000000000000000000000000000000000915061114c565b7f000000000000000000000000000000000000000000000000000000000000000091505b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03838116602483015285915f9183169063dd62ed3e90604401602060405180830381865afa1580156111b3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111d79190612eb5565b90508481106111e857505050505050565b8015611202576112026001600160a01b03831685836118d2565b6112366001600160a01b038316857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6119be565b505050505050565b5f546001600160a01b031633146107e8576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610bd7565b6107d26001600160a01b0383168483611a5e565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610be981611a8f565b6040805160a0810182526001600160a01b0385166060820190815260808201859052815282356020808301919091528381013582840152825180840184523081529081018590526e22d473030f116ddee9f6b43ac78ba3926330f28b7a929190339061133690870187612ecc565b6040518663ffffffff1660e01b8152600401611356959493929190612f56565b5f604051808303815f87803b15801561136d575f80fd5b505af115801561137f573d5f803e3d5ffd5b50505050505050565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018390526101008201839052610120820183905261014082018190526101608201525f348d8d8d8d8d8d8d8d8d8d5f01358e602001356040516020016114159c9b9a99989796959493929190612fc4565b604051602081830303815290604052805190602001209050611446818580604001906114419190612ecc565b610e57565b6114578435348d6020880135610fc8565b6114618b8a611041565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638249eb158e8e8e8e8e8e8e8e8e6040518a63ffffffff1660e01b81526004016114bd9998979695949392919061304c565b5f604051808303815f875af11580156114d8573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114ff9190810190612c2d565b909350915033604080518635815234602082015285917f4cc03dfa265ccd4670a5059498b2551525947958b26b5e70f6a6dc62a950fd4e910160405180910390a3509a509a98505050505050505050565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018390526101008201839052610120820183905261014082018190526101608201525f348d8d8d8d8d8d8d8d8d8d5f01358e602001356040516020016115dd9c9b9a999897969594939291906130bf565b604051602081830303815290604052805190602001209050611609818580604001906114419190612ecc565b61161a8435348d6020880135610fc8565b6116248b8a611041565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031662c58a2c8e8e8e8e8e8e8e8e8e6040518a63ffffffff1660e01b81526004016114bd99989796959493929190613123565b6003546040516001600160a01b03918216918316907f76bd52e686622d2685524f18ca827265a39b781115ecfee7e344cec952442040905f90a3600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6002546040516001600160a01b03918216918316907faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d3905f90a3600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6040516001600160a01b03848116602483015283811660448301526064820183905261103b9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611af6565b5f805f806117f18686611b70565b9250925092506118018282611bb9565b50909150505b92915050565b80471015611849576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610bd7565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611892576040519150601f19603f3d011682016040523d82523d5f602084013e611897565b606091505b50509050806107d2576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015611938573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061195c9190612eb5565b9050818110156119b1576040517fe570110f0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810182905260448101839052606401610bd7565b61103b8484848403611cc0565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015611a24573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a489190612eb5565b905061103b8484611a5985856129aa565b611cc0565b6040516001600160a01b038381166024830152604482018390526107d291859182169063a9059cbb9060640161179c565b5f80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f611b0a6001600160a01b03841683611d7d565b905080515f14158015611b2e575080806020019051810190611b2c9190613180565b155b156107d2576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610bd7565b5f805f8351604103611ba7576020840151604085015160608601515f1a611b9988828585611d91565b955095509550505050611bb2565b505081515f91506002905b9250925092565b5f826003811115611bcc57611bcc612e88565b03611bd5575050565b6001826003811115611be957611be9612e88565b03611c20576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002826003811115611c3457611c34612e88565b03611c6e576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610bd7565b6003826003811115611c8257611c82612e88565b03611cbc576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610bd7565b5050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052611d3f8482611e59565b61103b576040516001600160a01b0384811660248301525f6044830152611d7391869182169063095ea7b39060640161179c565b61103b8482611af6565b6060611d8a83835f611efa565b9392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115611dca57505f91506003905082611e4f565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015611e1b573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116611e4657505f925060019150829050611e4f565b92505f91508190505b9450945094915050565b5f805f846001600160a01b031684604051611e74919061319f565b5f604051808303815f865af19150503d805f8114611ead576040519150601f19603f3d011682016040523d82523d5f602084013e611eb2565b606091505b5091509150818015611edc575080511580611edc575080806020019051810190611edc9190613180565b8015611ef157505f856001600160a01b03163b115b95945050505050565b606081471015611f38576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610bd7565b5f80856001600160a01b03168486604051611f53919061319f565b5f6040518083038185875af1925050503d805f8114611f8d576040519150601f19603f3d011682016040523d82523d5f602084013e611f92565b606091505b5091509150611fa2868383611fac565b9695505050505050565b606082611fc157611fbc82612021565b611d8a565b8151158015611fd857506001600160a01b0384163b155b1561201a576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610bd7565b5080611d8a565b8051156120315780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff81168114610be9575f80fd5b5f8083601f840112612084575f80fd5b50813567ffffffffffffffff81111561209b575f80fd5b6020830191508360208285010111156120b2575f80fd5b9250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610100810167ffffffffffffffff8111828210171561210a5761210a6120b9565b60405290565b604051610180810167ffffffffffffffff8111828210171561210a5761210a6120b9565b604051601f8201601f1916810167ffffffffffffffff8111828210171561215d5761215d6120b9565b604052919050565b5f67ffffffffffffffff82111561217e5761217e6120b9565b5060051b60200190565b5f82601f830112612197575f80fd5b813560206121ac6121a783612165565b612134565b8083825260208201915060208460051b8701019350868411156121cd575f80fd5b602086015b848110156121f25780356121e581612063565b83529183019183016121d2565b509695505050505050565b80356001600160a01b0381168114612213575f80fd5b919050565b65ffffffffffff81168114610be9575f80fd5b803561221381612218565b5f67ffffffffffffffff82111561224f5761224f6120b9565b50601f01601f191660200190565b5f82601f83011261226c575f80fd5b813561227a6121a782612236565b81815284602083860101111561228e575f80fd5b816020850160208301375f918101602001919091529392505050565b5f61010082840312156122bb575f80fd5b6122c36120e6565b9050813567ffffffffffffffff808211156122dc575f80fd5b6122e885838601612188565b83526122f6602085016121fd565b6020840152612307604085016121fd565b6040840152612318606085016121fd565b60608401526080840135608084015260a084013560a084015261233d60c0850161222b565b60c084015260e0840135915080821115612355575f80fd5b506123628482850161225d565b60e08301525092915050565b5f805f805f8060a08789031215612383575f80fd5b863561238e81612063565b95506020870135945060408701359350606087013567ffffffffffffffff808211156123b8575f80fd5b6123c48a838b01612074565b909550935060808901359150808211156123dc575f80fd5b506123e989828a016122aa565b9150509295509295509295565b5f815180845260208085019450602084015f5b8381101561242557815187529582019590820190600101612409565b509495945050505050565b828152604060208201525f61244860408301846123f6565b949350505050565b5f805f60608486031215612462575f80fd5b61246b846121fd565b925060208401359150612480604085016121fd565b90509250925092565b5f805f805f6080868803121561249d575f80fd5b853594506020808701359450604087013567ffffffffffffffff808211156124c3575f80fd5b6124cf8a838b01612074565b909650945060608901359150808211156124e7575f80fd5b818901915089601f8301126124fa575f80fd5b81356125086121a782612165565b81815260059190911b8301840190848101908c831115612526575f80fd5b8585015b8381101561255c57803585811115612540575f80fd5b61254e8f89838a01016122aa565b84525091860191860161252a565b508096505050505050509295509295909350565b5f60608284031215612580575f80fd5b50919050565b5f805f805f805f805f805f6101408c8e0312156125a1575f80fd5b67ffffffffffffffff808d3511156125b7575f80fd5b6125c48e8e358f01612188565b9b506125d260208e016121fd565b9a506125e060408e016121fd565b99506125ee60608e016121fd565b985060808d0135975060a08d0135965061260a60c08e0161222b565b95508060e08e0135111561261c575f80fd5b61262c8e60e08f01358f01612074565b90955093506101008d0135811015612642575f80fd5b6126538e6101008f01358f01612570565b9250806101208e01351115612666575f80fd5b506126788d6101208e01358e01612570565b90509295989b509295989b9093969950565b5f815180845260208085019450602084015f5b8381101561242557815163ffffffff168752958201959082019060010161269d565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b82815260406020820152815160408201526020820151606082015260408201516080820152606082015160a08201525f608083015161273460c084018263ffffffff169052565b5060a083015167ffffffffffffffff811660e08401525060c08301516101006127668185018365ffffffffffff169052565b60e085015191506101206127838186018465ffffffffffff169052565b9085015161014085810191909152908501516101608086019190915290850151610180808601819052909250906127be6101c086018461268a565b9250808601519150507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101a0850152611fa282826126bf565b5f805f805f805f805f806101208b8d031215612816575f80fd5b8a3567ffffffffffffffff8082111561282d575f80fd5b6128398e838f01612188565b9b5060208d01359a5061284e60408e016121fd565b995060608d0135985060808d0135975060a08d0135965061287160c08e0161222b565b955060e08d0135915080821115612886575f80fd5b6128928e838f01612074565b90955093506101008d01359150808211156128ab575f80fd5b506128b88d828e01612570565b9150509295989b9194979a5092959850565b5f602082840312156128da575f80fd5b611d8a826121fd565b5f805f805f805f805f806101208b8d0312156128fd575f80fd5b8a3567ffffffffffffffff80821115612914575f80fd5b6129208e838f01612188565b9b5061292e60208e016121fd565b9a5061293c60408e016121fd565b995061294a60608e016121fd565b985060808d0135975060a08d0135965061287160c08e0161222b565b5f60208284031215612976575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118075761180761297d565b5f61010082518185526129d28286018261268a565b91505060208301516001600160a01b03808216602087015280604086015116604087015280606086015116606087015250506080830151608085015260a083015160a085015260c0830151612a3160c086018265ffffffffffff169052565b5060e083015184820360e0860152611ef182826126bf565b85815263ffffffff8516602082015260a060408201525f612a6d60a08301866129bd565b606083019490945250608001529392505050565b5f82612ab4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b63ffffffff828116828216039080821115612ad657612ad661297d565b5092915050565b5f610100808352612af08184018c61268a565b90506001600160a01b03808b166020850152808a1660408501528089166060850152508660808401528560a084015265ffffffffffff851660c084015282810360e0840152612b3f81856126bf565b9b9a5050505050505050505050565b805161221381612063565b805167ffffffffffffffff81168114612213575f80fd5b805161221381612218565b5f82601f830112612b8a575f80fd5b81516020612b9a6121a783612165565b8083825260208201915060208460051b870101935086841115612bbb575f80fd5b602086015b848110156121f2578051612bd381612063565b8352918301918301612bc0565b5f82601f830112612bef575f80fd5b8151612bfd6121a782612236565b818152846020838601011115612c11575f80fd5b8160208501602083015e5f918101602001919091529392505050565b5f8060408385031215612c3e575f80fd5b82519150602083015167ffffffffffffffff80821115612c5c575f80fd5b908401906101808287031215612c70575f80fd5b612c78612110565b82518152602083015160208201526040830151604082015260608301516060820152612ca660808401612b4e565b6080820152612cb760a08401612b59565b60a0820152612cc860c08401612b70565b60c0820152612cd960e08401612b70565b60e0820152610100838101519082015261012080840151908201526101408084015183811115612d07575f80fd5b612d1389828701612b7b565b8284015250506101608084015183811115612d2c575f80fd5b612d3889828701612be0565b8284015250508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80820281158282048414176118075761180761297d565b818103818111156118075761180761297d565b602081525f611d8a60208301846123f6565b606081525f612dc660608301866123f6565b60208301949094525060400152919050565b5f6080820186835260206080602085015281875180845260a08601915060a08160051b8701019350602089015f5b82811015612e52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60888703018452612e408683516129bd565b95509284019290840190600101612e06565b50505050506040830194909452506060015292915050565b5f60208284031215612e7a575f80fd5b815160028110611d8a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215612ec5575f80fd5b5051919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612eff575f80fd5b83018035915067ffffffffffffffff821115612f19575f80fd5b6020019150368190038213156120b2575f80fd5b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b5f61010087516001600160a01b038082511685526020820151602086015260208a0151604086015260408a01516060860152808951166080860152602089015160a086015280881660c086015250508060e0840152612fb88184018587612f2d565b98975050505050505050565b5f6101608e8352806020840152612fdd8184018f61268a565b90506001600160a01b03808e166040850152808d166060850152808c166080850152508960a08401528860c084015265ffffffffffff881660e084015282810361010084015261302e818789612f2d565b610120840195909552505061014001529a9950505050505050505050565b5f61010080835261305f8184018d61268a565b90506001600160a01b03808c166020850152808b166040850152808a166060850152508760808401528660a084015265ffffffffffff861660c084015282810360e08401526130af818587612f2d565b9c9b505050505050505050505050565b5f6101608e83528060208401526130d88184018f61268a565b90508c60408401526001600160a01b038c1660608401528a60808401528960a08401528860c084015265ffffffffffff881660e084015282810361010084015261302e818789612f2d565b5f6101008083526131368184018d61268a565b90508a60208401526001600160a01b038a1660408401528860608401528760808401528660a084015265ffffffffffff861660c084015282810360e08401526130af818587612f2d565b5f60208284031215613190575f80fd5b81518015158114611d8a575f80fd5b5f82518060208501845e5f92019182525091905056fea26469706673582212207da41491a2bea2bd323b62d91095bdc2f5ee3f7b50af4d77c6d219e571e8d8e564736f6c63430008190033000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d816000000000000000000000000f20d5277ad2f301e2f18e2948ff3e72ad0a6dff9000000000000000000000000d148c7f37b346a4bd8e14f8c1f181f5f640481c8000000000000000000000000d1daf260951b8d350a4aed5c80d74fd7298c93f4000000000000000000000000f20d5277ad2f301e2f18e2948ff3e72ad0a6dff9

Deployed Bytecode

0x60806040526004361061013d575f3560e01c806379ba5097116100bb578063ceb6341c11610071578063e30c397811610057578063e30c397814610361578063f160d3691461037e578063f2fde38b1461039d575f80fd5b8063ceb6341c14610310578063de143b9014610323575f80fd5b8063a7e4d189116100a1578063a7e4d189146102bd578063ae9b2bad146102de578063b0834893146102f1575f80fd5b806379ba50971461028d5780638da5cb5b146102a1575f80fd5b806347bfbcc6116101105780636afdd850116100f65780636afdd85014610244578063715018a61461026657806372aaa1871461027a575f80fd5b806347bfbcc6146101f05780636357360314610223575f80fd5b8063075693391461014157806311eefd541461017d5780632e378bbe146101b057806346904840146101d1575b5f80fd5b34801561014c575f80fd5b50600354610160906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610188575f80fd5b506101607f000000000000000000000000d1daf260951b8d350a4aed5c80d74fd7298c93f481565b6101c36101be36600461236e565b6103bc565b604051610174929190612430565b3480156101dc575f80fd5b50600254610160906001600160a01b031681565b3480156101fb575f80fd5b506101607f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d81681565b34801561022e575f80fd5b5061024261023d366004612450565b610729565b005b34801561024f575f80fd5b506101606e22d473030f116ddee9f6b43ac78ba381565b348015610271575f80fd5b506102426107d7565b6101c3610288366004612489565b6107ea565b348015610298575f80fd5b50610242610b8a565b3480156102ac575f80fd5b505f546001600160a01b0316610160565b6102d06102cb366004612586565b610bec565b6040516101749291906126ed565b6102d06102ec3660046127fc565b610c85565b3480156102fc575f80fd5b5061024261030b3660046128ca565b610d18565b6102d061031e3660046128e3565b610d29565b34801561032e575f80fd5b5061035161033d366004612966565b60046020525f908152604090205460ff1681565b6040519015158152602001610174565b34801561036c575f80fd5b506001546001600160a01b0316610160565b348015610389575f80fd5b506102426103983660046128ca565b610da9565b3480156103a8575f80fd5b506102426103b73660046128ca565b610dba565b5f60606103dd3384604001518986608001516103d891906129aa565b610e42565b5f3489858a8a6040516020016103f7959493929190612a49565b60405160208183030381529060405280519060200120905061041a818787610e57565b61042a883486604001518a610fc8565b61043c84604001518560800151611041565b5f8963ffffffff1685608001516104539190612a81565b90508963ffffffff1667ffffffffffffffff811115610474576104746120b9565b60405190808252806020026020018201604052801561049d578160200160208202803683370190505b5092505f5b6104ad60018c612ab9565b63ffffffff1681101561059c575f7f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d8166001600160a01b0316638249eb15885f015189602001518a604001518b60600151888d60a001518e60c001518f60e001516040518963ffffffff1660e01b8152600401610530989796959493929190612add565b5f604051808303815f875af115801561054b573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526105729190810190612c2d565b5090508085838151811061058857610588612d4b565b6020908102919091010152506001016104a2565b506105a860018b612ab9565b6105b89063ffffffff1682612d78565b90505f7f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d8166001600160a01b0316638249eb15875f0151886020015189604001518a60600151878c6080015161060d9190612d8f565b8c60a001518d60c001518e60e001516040518963ffffffff1660e01b815260040161063f989796959493929190612add565b5f604051808303815f875af115801561065a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106819190810190612c2d565b509050808461069160018e612ab9565b63ffffffff16815181106106a7576106a7612d4b565b602002602001018181525050836040516020016106c49190612da2565b60408051601f198184030181529190528051602090910120945033857fc5929cfdbbc98a41855839bee1396d17ee4a149e40d5c324b6f4332655f5cffd868d3460405161071393929190612db4565b60405180910390a3505050965096945050505050565b61073161123e565b6040517ff3fef3a30000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490527f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d816169063f3fef3a3906044015f604051808303815f87803b1580156107b1575f80fd5b505af11580156107c3573d5f803e3d5ffd5b505050506107d2818484611283565b505050565b6107df61123e565b6107e85f611297565b565b80515f906060908284818361080157610801612d4b565b60200260200101516040015190505f805b838110156108b55786818151811061082c5761082c612d4b565b6020026020010151608001518261084391906129aa565b9150826001600160a01b031687828151811061086157610861612d4b565b6020026020010151604001516001600160a01b0316146108ad576040517f903d557a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101610812565b506108c533836103d88d856129aa565b6108cf8282611041565b5f34878c8c6040516020016108e79493929190612dd8565b60405160208183030381529060405280519060200120905061090a818a8a610e57565b6109168b34858d610fc8565b5050508067ffffffffffffffff811115610932576109326120b9565b60405190808252806020026020018201604052801561095b578160200160208202803683370190505b5091505f5b81811015610b16575f7f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d8166001600160a01b0316638249eb158784815181106109aa576109aa612d4b565b60200260200101515f01518885815181106109c7576109c7612d4b565b6020026020010151602001518986815181106109e5576109e5612d4b565b6020026020010151604001518a8781518110610a0357610a03612d4b565b6020026020010151606001518b8881518110610a2157610a21612d4b565b6020026020010151608001518c8981518110610a3f57610a3f612d4b565b602002602001015160a001518d8a81518110610a5d57610a5d612d4b565b602002602001015160c001518e8b81518110610a7b57610a7b612d4b565b602002602001015160e001516040518963ffffffff1660e01b8152600401610aaa989796959493929190612add565b5f604051808303815f875af1158015610ac5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610aec9190810190612c2d565b50905080848381518110610b0257610b02612d4b565b602090810291909101015250600101610960565b5081604051602001610b289190612da2565b60408051601f198184030181529190528051602090910120925033837fc5929cfdbbc98a41855839bee1396d17ee4a149e40d5c324b6f4332655f5cffd848b34604051610b7793929190612db4565b60405180910390a3509550959350505050565b60015433906001600160a01b03168114610be0576040517f118cdaa70000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b610be981611297565b50565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201819052610160820152610c5f8b610c5985358c6129aa565b866112c8565b610c718d8d8d8d8d8d8d8d8d8c611388565b909e909d509b505050505050505050505050565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201819052610160820152610cf3338b6103d886358c6129aa565b610d058c8c8c8c8c8c8c8c8c8c611550565b909d909c509a5050505050505050505050565b610d2061123e565b610be98161167f565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201819052610160820152610d97338b6103d886358c6129aa565b610d058c8c8c8c8c8c8c8c8c8c611388565b610db161123e565b610be9816116f3565b610dc261123e565b600180546001600160a01b0383167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155610e0a5f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6107d26001600160a01b038316843084611767565b604080516020810185905230918101919091524660608201525f9060800160408051601f1981840301815291815281516020928301205f818152600490935291205490915060ff1615610ed6576040517f417ef34700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260046020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c829052603c8120610f779085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117e392505050565b6003549091506001600160a01b03808316911614610fc1576040517fa85a086900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b80421115611002576040517f634f518f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b831561101f5760025461101f906001600160a01b03168386611283565b821561103b5760025461103b906001600160a01b03168461180d565b50505050565b6040517f39ebf8230000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301525f9182917f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d81616906339ebf82390602401602060405180830381865afa1580156110c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e69190612e6a565b90505f8160018111156110fb576110fb612e88565b03611128577f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d816915061114c565b7f000000000000000000000000d1daf260951b8d350a4aed5c80d74fd7298c93f491505b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03838116602483015285915f9183169063dd62ed3e90604401602060405180830381865afa1580156111b3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111d79190612eb5565b90508481106111e857505050505050565b8015611202576112026001600160a01b03831685836118d2565b6112366001600160a01b038316857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6119be565b505050505050565b5f546001600160a01b031633146107e8576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610bd7565b6107d26001600160a01b0383168483611a5e565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610be981611a8f565b6040805160a0810182526001600160a01b0385166060820190815260808201859052815282356020808301919091528381013582840152825180840184523081529081018590526e22d473030f116ddee9f6b43ac78ba3926330f28b7a929190339061133690870187612ecc565b6040518663ffffffff1660e01b8152600401611356959493929190612f56565b5f604051808303815f87803b15801561136d575f80fd5b505af115801561137f573d5f803e3d5ffd5b50505050505050565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018390526101008201839052610120820183905261014082018190526101608201525f348d8d8d8d8d8d8d8d8d8d5f01358e602001356040516020016114159c9b9a99989796959493929190612fc4565b604051602081830303815290604052805190602001209050611446818580604001906114419190612ecc565b610e57565b6114578435348d6020880135610fc8565b6114618b8a611041565b7f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d8166001600160a01b0316638249eb158e8e8e8e8e8e8e8e8e6040518a63ffffffff1660e01b81526004016114bd9998979695949392919061304c565b5f604051808303815f875af11580156114d8573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114ff9190810190612c2d565b909350915033604080518635815234602082015285917f4cc03dfa265ccd4670a5059498b2551525947958b26b5e70f6a6dc62a950fd4e910160405180910390a3509a509a98505050505050505050565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018390526101008201839052610120820183905261014082018190526101608201525f348d8d8d8d8d8d8d8d8d8d5f01358e602001356040516020016115dd9c9b9a999897969594939291906130bf565b604051602081830303815290604052805190602001209050611609818580604001906114419190612ecc565b61161a8435348d6020880135610fc8565b6116248b8a611041565b7f000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d8166001600160a01b031662c58a2c8e8e8e8e8e8e8e8e8e6040518a63ffffffff1660e01b81526004016114bd99989796959493929190613123565b6003546040516001600160a01b03918216918316907f76bd52e686622d2685524f18ca827265a39b781115ecfee7e344cec952442040905f90a3600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6002546040516001600160a01b03918216918316907faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d3905f90a3600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6040516001600160a01b03848116602483015283811660448301526064820183905261103b9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611af6565b5f805f806117f18686611b70565b9250925092506118018282611bb9565b50909150505b92915050565b80471015611849576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610bd7565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611892576040519150601f19603f3d011682016040523d82523d5f602084013e611897565b606091505b50509050806107d2576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015611938573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061195c9190612eb5565b9050818110156119b1576040517fe570110f0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810182905260448101839052606401610bd7565b61103b8484848403611cc0565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015611a24573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a489190612eb5565b905061103b8484611a5985856129aa565b611cc0565b6040516001600160a01b038381166024830152604482018390526107d291859182169063a9059cbb9060640161179c565b5f80546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f611b0a6001600160a01b03841683611d7d565b905080515f14158015611b2e575080806020019051810190611b2c9190613180565b155b156107d2576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610bd7565b5f805f8351604103611ba7576020840151604085015160608601515f1a611b9988828585611d91565b955095509550505050611bb2565b505081515f91506002905b9250925092565b5f826003811115611bcc57611bcc612e88565b03611bd5575050565b6001826003811115611be957611be9612e88565b03611c20576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002826003811115611c3457611c34612e88565b03611c6e576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610bd7565b6003826003811115611c8257611c82612e88565b03611cbc576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610bd7565b5050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052611d3f8482611e59565b61103b576040516001600160a01b0384811660248301525f6044830152611d7391869182169063095ea7b39060640161179c565b61103b8482611af6565b6060611d8a83835f611efa565b9392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115611dca57505f91506003905082611e4f565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015611e1b573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116611e4657505f925060019150829050611e4f565b92505f91508190505b9450945094915050565b5f805f846001600160a01b031684604051611e74919061319f565b5f604051808303815f865af19150503d805f8114611ead576040519150601f19603f3d011682016040523d82523d5f602084013e611eb2565b606091505b5091509150818015611edc575080511580611edc575080806020019051810190611edc9190613180565b8015611ef157505f856001600160a01b03163b115b95945050505050565b606081471015611f38576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610bd7565b5f80856001600160a01b03168486604051611f53919061319f565b5f6040518083038185875af1925050503d805f8114611f8d576040519150601f19603f3d011682016040523d82523d5f602084013e611f92565b606091505b5091509150611fa2868383611fac565b9695505050505050565b606082611fc157611fbc82612021565b611d8a565b8151158015611fd857506001600160a01b0384163b155b1561201a576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610bd7565b5080611d8a565b8051156120315780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff81168114610be9575f80fd5b5f8083601f840112612084575f80fd5b50813567ffffffffffffffff81111561209b575f80fd5b6020830191508360208285010111156120b2575f80fd5b9250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610100810167ffffffffffffffff8111828210171561210a5761210a6120b9565b60405290565b604051610180810167ffffffffffffffff8111828210171561210a5761210a6120b9565b604051601f8201601f1916810167ffffffffffffffff8111828210171561215d5761215d6120b9565b604052919050565b5f67ffffffffffffffff82111561217e5761217e6120b9565b5060051b60200190565b5f82601f830112612197575f80fd5b813560206121ac6121a783612165565b612134565b8083825260208201915060208460051b8701019350868411156121cd575f80fd5b602086015b848110156121f25780356121e581612063565b83529183019183016121d2565b509695505050505050565b80356001600160a01b0381168114612213575f80fd5b919050565b65ffffffffffff81168114610be9575f80fd5b803561221381612218565b5f67ffffffffffffffff82111561224f5761224f6120b9565b50601f01601f191660200190565b5f82601f83011261226c575f80fd5b813561227a6121a782612236565b81815284602083860101111561228e575f80fd5b816020850160208301375f918101602001919091529392505050565b5f61010082840312156122bb575f80fd5b6122c36120e6565b9050813567ffffffffffffffff808211156122dc575f80fd5b6122e885838601612188565b83526122f6602085016121fd565b6020840152612307604085016121fd565b6040840152612318606085016121fd565b60608401526080840135608084015260a084013560a084015261233d60c0850161222b565b60c084015260e0840135915080821115612355575f80fd5b506123628482850161225d565b60e08301525092915050565b5f805f805f8060a08789031215612383575f80fd5b863561238e81612063565b95506020870135945060408701359350606087013567ffffffffffffffff808211156123b8575f80fd5b6123c48a838b01612074565b909550935060808901359150808211156123dc575f80fd5b506123e989828a016122aa565b9150509295509295509295565b5f815180845260208085019450602084015f5b8381101561242557815187529582019590820190600101612409565b509495945050505050565b828152604060208201525f61244860408301846123f6565b949350505050565b5f805f60608486031215612462575f80fd5b61246b846121fd565b925060208401359150612480604085016121fd565b90509250925092565b5f805f805f6080868803121561249d575f80fd5b853594506020808701359450604087013567ffffffffffffffff808211156124c3575f80fd5b6124cf8a838b01612074565b909650945060608901359150808211156124e7575f80fd5b818901915089601f8301126124fa575f80fd5b81356125086121a782612165565b81815260059190911b8301840190848101908c831115612526575f80fd5b8585015b8381101561255c57803585811115612540575f80fd5b61254e8f89838a01016122aa565b84525091860191860161252a565b508096505050505050509295509295909350565b5f60608284031215612580575f80fd5b50919050565b5f805f805f805f805f805f6101408c8e0312156125a1575f80fd5b67ffffffffffffffff808d3511156125b7575f80fd5b6125c48e8e358f01612188565b9b506125d260208e016121fd565b9a506125e060408e016121fd565b99506125ee60608e016121fd565b985060808d0135975060a08d0135965061260a60c08e0161222b565b95508060e08e0135111561261c575f80fd5b61262c8e60e08f01358f01612074565b90955093506101008d0135811015612642575f80fd5b6126538e6101008f01358f01612570565b9250806101208e01351115612666575f80fd5b506126788d6101208e01358e01612570565b90509295989b509295989b9093969950565b5f815180845260208085019450602084015f5b8381101561242557815163ffffffff168752958201959082019060010161269d565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b82815260406020820152815160408201526020820151606082015260408201516080820152606082015160a08201525f608083015161273460c084018263ffffffff169052565b5060a083015167ffffffffffffffff811660e08401525060c08301516101006127668185018365ffffffffffff169052565b60e085015191506101206127838186018465ffffffffffff169052565b9085015161014085810191909152908501516101608086019190915290850151610180808601819052909250906127be6101c086018461268a565b9250808601519150507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101a0850152611fa282826126bf565b5f805f805f805f805f806101208b8d031215612816575f80fd5b8a3567ffffffffffffffff8082111561282d575f80fd5b6128398e838f01612188565b9b5060208d01359a5061284e60408e016121fd565b995060608d0135985060808d0135975060a08d0135965061287160c08e0161222b565b955060e08d0135915080821115612886575f80fd5b6128928e838f01612074565b90955093506101008d01359150808211156128ab575f80fd5b506128b88d828e01612570565b9150509295989b9194979a5092959850565b5f602082840312156128da575f80fd5b611d8a826121fd565b5f805f805f805f805f806101208b8d0312156128fd575f80fd5b8a3567ffffffffffffffff80821115612914575f80fd5b6129208e838f01612188565b9b5061292e60208e016121fd565b9a5061293c60408e016121fd565b995061294a60608e016121fd565b985060808d0135975060a08d0135965061287160c08e0161222b565b5f60208284031215612976575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156118075761180761297d565b5f61010082518185526129d28286018261268a565b91505060208301516001600160a01b03808216602087015280604086015116604087015280606086015116606087015250506080830151608085015260a083015160a085015260c0830151612a3160c086018265ffffffffffff169052565b5060e083015184820360e0860152611ef182826126bf565b85815263ffffffff8516602082015260a060408201525f612a6d60a08301866129bd565b606083019490945250608001529392505050565b5f82612ab4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b63ffffffff828116828216039080821115612ad657612ad661297d565b5092915050565b5f610100808352612af08184018c61268a565b90506001600160a01b03808b166020850152808a1660408501528089166060850152508660808401528560a084015265ffffffffffff851660c084015282810360e0840152612b3f81856126bf565b9b9a5050505050505050505050565b805161221381612063565b805167ffffffffffffffff81168114612213575f80fd5b805161221381612218565b5f82601f830112612b8a575f80fd5b81516020612b9a6121a783612165565b8083825260208201915060208460051b870101935086841115612bbb575f80fd5b602086015b848110156121f2578051612bd381612063565b8352918301918301612bc0565b5f82601f830112612bef575f80fd5b8151612bfd6121a782612236565b818152846020838601011115612c11575f80fd5b8160208501602083015e5f918101602001919091529392505050565b5f8060408385031215612c3e575f80fd5b82519150602083015167ffffffffffffffff80821115612c5c575f80fd5b908401906101808287031215612c70575f80fd5b612c78612110565b82518152602083015160208201526040830151604082015260608301516060820152612ca660808401612b4e565b6080820152612cb760a08401612b59565b60a0820152612cc860c08401612b70565b60c0820152612cd960e08401612b70565b60e0820152610100838101519082015261012080840151908201526101408084015183811115612d07575f80fd5b612d1389828701612b7b565b8284015250506101608084015183811115612d2c575f80fd5b612d3889828701612be0565b8284015250508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80820281158282048414176118075761180761297d565b818103818111156118075761180761297d565b602081525f611d8a60208301846123f6565b606081525f612dc660608301866123f6565b60208301949094525060400152919050565b5f6080820186835260206080602085015281875180845260a08601915060a08160051b8701019350602089015f5b82811015612e52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60888703018452612e408683516129bd565b95509284019290840190600101612e06565b50505050506040830194909452506060015292915050565b5f60208284031215612e7a575f80fd5b815160028110611d8a575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215612ec5575f80fd5b5051919050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612eff575f80fd5b83018035915067ffffffffffffffff821115612f19575f80fd5b6020019150368190038213156120b2575f80fd5b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b5f61010087516001600160a01b038082511685526020820151602086015260208a0151604086015260408a01516060860152808951166080860152602089015160a086015280881660c086015250508060e0840152612fb88184018587612f2d565b98975050505050505050565b5f6101608e8352806020840152612fdd8184018f61268a565b90506001600160a01b03808e166040850152808d166060850152808c166080850152508960a08401528860c084015265ffffffffffff881660e084015282810361010084015261302e818789612f2d565b610120840195909552505061014001529a9950505050505050505050565b5f61010080835261305f8184018d61268a565b90506001600160a01b03808c166020850152808b166040850152808a166060850152508760808401528660a084015265ffffffffffff861660c084015282810360e08401526130af818587612f2d565b9c9b505050505050505050505050565b5f6101608e83528060208401526130d88184018f61268a565b90508c60408401526001600160a01b038c1660608401528a60808401528960a08401528860c084015265ffffffffffff881660e084015282810361010084015261302e818789612f2d565b5f6101008083526131368184018d61268a565b90508a60208401526001600160a01b038a1660408401528860608401528760808401528660a084015265ffffffffffff861660c084015282810360e08401526130af818587612f2d565b5f60208284031215613190575f80fd5b81518015158114611d8a575f80fd5b5f82518060208501845e5f92019182525091905056fea26469706673582212207da41491a2bea2bd323b62d91095bdc2f5ee3f7b50af4d77c6d219e571e8d8e564736f6c63430008190033

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

000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d816000000000000000000000000f20d5277ad2f301e2f18e2948ff3e72ad0a6dff9000000000000000000000000d148c7f37b346a4bd8e14f8c1f181f5f640481c8000000000000000000000000d1daf260951b8d350a4aed5c80d74fd7298c93f4000000000000000000000000f20d5277ad2f301e2f18e2948ff3e72ad0a6dff9

-----Decoded View---------------
Arg [0] : _spoke (address): 0xa05A3380889115bf313f1Db9d5f335157Be4D816
Arg [1] : _feeRecipient (address): 0xf20d5277aD2f301E2F18e2948fF3e72Ad0A6dfF9
Arg [2] : _feeSigner (address): 0xd148C7f37b346a4bD8e14f8c1f181f5f640481C8
Arg [3] : _xerc20Module (address): 0xD1daF260951B8d350a4AeD5C80d74Fd7298C93F4
Arg [4] : _owner (address): 0xf20d5277aD2f301E2F18e2948fF3e72Ad0A6dfF9

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000a05a3380889115bf313f1db9d5f335157be4d816
Arg [1] : 000000000000000000000000f20d5277ad2f301e2f18e2948ff3e72ad0a6dff9
Arg [2] : 000000000000000000000000d148c7f37b346a4bd8e14f8c1f181f5f640481c8
Arg [3] : 000000000000000000000000d1daf260951b8d350a4aed5c80d74fd7298c93f4
Arg [4] : 000000000000000000000000f20d5277ad2f301e2f18e2948ff3e72ad0a6dff9


Block Transaction Gas Used Reward
view all blocks sequenced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
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.