Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x2Ed02372C3efF1F239B22a901ceA8Cf6fbf82d8d
Balance 0 ETH
Nonce 1
Code Size 5656 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

5656 bytes
0x608060405260043610610108575f3560e01c80639562de5911610092578063ed5a97d311610062578063ed5a97d3146102ce578063f2fde38b14610311578063f52cbf0e14610330578063facd743b14610343578063fba9770a14610371575f80fd5b80639562de5914610262578063aca2490b14610275578063db7af85414610288578063e78cea921461029b575f80fd5b80634309b714116100d85780634309b714146101df578063633a8fa9146101f257806369ffa08a1461020657806370502107146102255780638da5cb5b14610244575f80fd5b806301a754ff146101475780632d68efc91461014f578063351bb5491461019f57806336768d3e146101cc575f80fd5b3661014357336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21614610141575f80fd5b005b5f80fd5b6101416103a5565b34801561015a575f80fd5b506101827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101aa575f80fd5b506101be6101b9366004611005565b6103bf565b604051908152602001610196565b6101416101da36600461103b565b6103cf565b6101416101ed36600461109b565b61046d565b3480156101fd575f80fd5b506101be61066f565b348015610211575f80fd5b50610141610220366004611118565b610697565b348015610230575f80fd5b50600254610182906001600160a01b031681565b34801561024f575f80fd5b505f54610182906001600160a01b031681565b61014161027036600461114f565b6106ba565b6101416102833660046111a0565b6106fe565b61014161029636600461123a565b61073d565b3480156102a6575f80fd5b506101827f0000000000000000000000001715a3e4a142d8b698131108995174f37aeba10d81565b3480156102d9575f80fd5b506103017f000000000000000000000000000000000000000000000000000000000000000181565b6040519015158152602001610196565b34801561031c575f80fd5b5061014161032b36600461103b565b610a8a565b61014161033e36600461103b565b610ac0565b34801561034e575f80fd5b5061030161035d36600461103b565b60036020525f908152604090205460ff1681565b34801561037c575f80fd5b5061039061038b3660046112e4565b610adb565b60408051928352602083019190915201610196565b6103bd3360405180602001604052805f815250610b04565b565b5f6103c982610c17565b92915050565b5f546001600160a01b031633146103e4575f80fd5b60405163facd743b60e01b81525f60048201526001600160a01b0382169063facd743b90602401602060405180830381865afa158015610426573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061044a9190611332565b50600280546001600160a01b0319166001600160a01b0392909216919091179055565b60405160200161047c9061134d565b604051602081830303815290604052805190602001206060866001600160a01b0316901b5a6bffffffffffffffffffffffff161760028110156104d257604051632a9ffab760e21b815260040160405180910390fd5b81548290600110156104f7576040516345f5ce8b60e11b815260040160405180910390fd5b81815560025460405163facd743b60e01b81526001600160a01b038a811660048301529091169063facd743b90602401602060405180830381865afa158015610542573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105669190611332565b61058357604051631574f9f360e01b815260040160405180910390fd5b7f0000000000000000000000001715a3e4a142d8b698131108995174f37aeba10d6001600160a01b031663cd5965836040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106039190611384565b6001600160a01b03166323caab49888888886040518563ffffffff1660e01b815260040161063494939291906113c7565b5f604051808303815f87803b15801561064b575f80fd5b505af115801561065d573d5f803e3d5ffd5b50506001909255505050505050505050565b60405160200161067e9061134d565b6040516020818303038152906040528051906020012081565b5f546001600160a01b031633146106ac575f80fd5b6106b68282610c53565b5050565b6106f98383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610b0492505050565b505050565b5f546001600160a01b03163314610713575f80fd5b6001600160a01b03919091165f908152600360205260409020805460ff1916911515919091179055565b600180541115610760576040516345f5ce8b60e11b815260040160405180910390fd5b6002600155336001600160a01b037f0000000000000000000000001715a3e4a142d8b698131108995174f37aeba10d1614610799575f80fd5b6040516370a0823160e01b81523060048201525f906001600160a01b038516906370a0823190602401602060405180830381865afa1580156107dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080191906113f8565b90508281101561080f578092505b81516014036108e3577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316846001600160a01b031614610855575f80fd5b604051632e1a7d4d60e01b8152600481018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156108b4575f80fd5b505af11580156108c6573d5f803e3d5ffd5b505050506108de6108d8836014015190565b84610c87565b610a80565b5f828060200190518101906108f8919061140f565b90505f60ff60fe8360200151901b901c60011480156109485750856001600160a01b03167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316145b905080801561098857507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316866001600160a01b0316145b15610a0357604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156109ec575f80fd5b505af11580156109fe573d5f803e3d5ffd5b505050505b5f610a2f604051602001610a169061134d565b6040516020818303038152906040528051906020012090565b5490505f866001831115610a4f57610a4984898588610cee565b90925090505b8015610a6457610a64848a875f015184610e16565b8115610a7a57610a7a848a606086901c85610e16565b50505050505b5050600180555050565b5f546001600160a01b03163314610a9f575f80fd5b5f80546001600160a01b0319166001600160a01b0392909216919091179055565b610ad88160405180602001604052805f815250610b04565b50565b5f80610af7868686610af23688900388018861145e565b610cee565b9150915094509492505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015610b5d575f80fd5b505af1158015610b6f573d5f803e3d5ffd5b505060405163d740548160e01b81526001600160a01b037f0000000000000000000000001715a3e4a142d8b698131108995174f37aeba10d16935063d74054819250610be691507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2908690349087906004016114ad565b5f604051808303815f87803b158015610bfd575f80fd5b505af1158015610c0f573d5f803e3d5ffd5b505050505050565b5f7f00000000000000000000000000000000000000000000000000000000000000018015610c425750815b610c4c573a6103c9565b4892915050565b806001600160a01b038116610c66575f80fd5b6001600160a01b038316610c7d576106f982610ea6565b6106f98383610eb1565b6040516001600160a01b0383169082156108fc029083905f818181858888f193505050506106b6578082604051610cbd90610fec565b6001600160a01b0390911681526020016040518091039082f0905080158015610ce8573d5f803e3d5ffd5b50505050565b5f8060ff808460200151901b901c600103610d0f5782604001519150610df0565b60ff60fc8460200151901b901c600103610d4d57670de0b6b3a7640000836060015186610d3c9190611530565b610d469190611547565b9150610df0565b5f5a610d67906bffffffffffffffffffffffff8716611566565b90505f610d8260ff60fd8760200151901b901c600114610c17565b9050670de0b6b3a76400008186606001518a610da157620186a0610da5565b61c3505b610db49062ffffff1686611579565b610dbe9190611530565b610dc89190611530565b610dd29190611547565b935084604001518411610de55783610deb565b84604001515b935050505b848211610dfd5781610dff565b845b9150610e0b8286611566565b905094509492505050565b8315610e92575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610e65576040519150601f19603f3d011682016040523d82523d5f602084013e610e6a565b606091505b5050905080610e8c57604051631574f9f360e01b815260040160405180910390fd5b50610ce8565b610ce86001600160a01b0384168383610f2d565b476106b68282610c87565b6040516370a0823160e01b815230600482015282905f906001600160a01b038316906370a0823190602401602060405180830381865afa158015610ef7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f1b91906113f8565b9050610ce86001600160a01b03831684835b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180516001600160e01b031663a9059cbb60e01b17815282516106f993879390925f9283929183919082885af180610f9b576040513d5f823e3d81fd5b50505f513d91508115610fb2578060011415610fbf565b6001600160a01b0384163b155b15610ce857604051635274afe760e01b81526001600160a01b038516600482015260240160405180910390fd5b60568061158d83390190565b8015158114610ad8575f80fd5b5f60208284031215611015575f80fd5b813561102081610ff8565b9392505050565b6001600160a01b0381168114610ad8575f80fd5b5f6020828403121561104b575f80fd5b813561102081611027565b5f8083601f840112611066575f80fd5b50813567ffffffffffffffff81111561107d575f80fd5b602083019150836020828501011115611094575f80fd5b9250929050565b5f805f805f606086880312156110af575f80fd5b85356110ba81611027565b9450602086013567ffffffffffffffff808211156110d6575f80fd5b6110e289838a01611056565b909650945060408801359150808211156110fa575f80fd5b5061110788828901611056565b969995985093965092949392505050565b5f8060408385031215611129575f80fd5b823561113481611027565b9150602083013561114481611027565b809150509250929050565b5f805f60408486031215611161575f80fd5b833561116c81611027565b9250602084013567ffffffffffffffff811115611187575f80fd5b61119386828701611056565b9497909650939450505050565b5f80604083850312156111b1575f80fd5b82356111bc81611027565b9150602083013561114481610ff8565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff81118282101715611203576112036111cc565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611232576112326111cc565b604052919050565b5f805f6060848603121561124c575f80fd5b833561125781611027565b92506020848101359250604085013567ffffffffffffffff8082111561127b575f80fd5b818701915087601f83011261128e575f80fd5b8135818111156112a0576112a06111cc565b6112b2601f8201601f19168501611209565b915080825288848285010111156112c7575f80fd5b80848401858401375f848284010152508093505050509250925092565b5f805f8084860360e08112156112f8575f80fd5b853561130381610ff8565b945060208601359350604086013592506080605f1982011215611324575f80fd5b509295919450926060019150565b5f60208284031215611342575f80fd5b815161102081610ff8565b60208082526017908201527f6f6d6e69627269646765726f757465722e72756e6e6572000000000000000000604082015260600190565b5f60208284031215611394575f80fd5b815161102081611027565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f6113da60408301868861139f565b82810360208401526113ed81858761139f565b979650505050505050565b5f60208284031215611408575f80fd5b5051919050565b5f6080828403121561141f575f80fd5b6114276111e0565b825161143281611027565b808252506020830151602082015260408301516040820152606083015160608201528091505092915050565b5f6080828403121561146e575f80fd5b6114766111e0565b823561148181611027565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b5f60018060a01b0380871683526020818716602085015285604085015260806060850152845191508160808501525f5b828110156114f95785810182015185820160a0015281016114dd565b50505f60a0828501015260a0601f19601f83011684010191505095945050505050565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176103c9576103c961151c565b5f8261156157634e487b7160e01b5f52601260045260245ffd5b500490565b818103818111156103c9576103c961151c565b808201808211156103c9576103c961151c56fe608060405260405160563803806056833981016040819052601e91602a565b806001600160a01b0316ff5b5f602082840312156039575f80fd5b81516001600160a01b0381168114604e575f80fd5b939250505056fea26469706673582212208d79c13cc2914b29dd1028f5b8beabdde677ad1b48f5fb9ee9a2ddae2ede6c8664736f6c63430008180033

Verified Source Code Full Match

Compiler: v0.8.24+commit.e11b9ed9 EVM: cancun Optimization: Yes (200 runs)
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _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 Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(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.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity 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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            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 silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}
Address.sol 150 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, bytes memory returndata) = recipient.call{value: amount}("");
        if (!success) {
            _revert(returndata);
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, 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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}.
     */
    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
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}
Errors.sol 34 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

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

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
StorageSlot.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}
ReentrancyV2.sol 34 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

import { StorageSlot } from "@openzeppelin/contracts/utils/StorageSlot.sol";

abstract contract ReentrancyV2 {
  error ReentrancyGuard();
  error InvalidValue();
  uint256 private constant _ENTERED = 2;
  uint256 private constant _NOT_ENTERED = 1;
  // global reentrant
  uint256 internal reentrant;

  modifier nonReentrant() {
    if (uint256(reentrant) > _NOT_ENTERED) {
      revert ReentrancyGuard();
    }
    reentrant = _ENTERED;
    _;
    reentrant = _NOT_ENTERED;
  }
  modifier nonReentrantUint256(bytes32 key, uint256 value) {
    if (value < _ENTERED) {
      revert InvalidValue();
    }
    StorageSlot.Uint256Slot storage slot = StorageSlot.getUint256Slot(key);
    if (slot.value > _NOT_ENTERED) {
      revert ReentrancyGuard();
    }
    slot.value = value;
    _;
    slot.value = _NOT_ENTERED;
  }
}
TokenOmnibridgeBase.sol 222 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

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

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IBasicAMBMediator} from "../interfaces/IBasicAMBMediator.sol";
import {IBasicForeignAMB} from "../interfaces/IBasicForeignAMB.sol";
import {IBridgeValidators} from "../interfaces/IBridgeValidators.sol";
import {IOmnibridge} from "../interfaces/IOmnibridge.sol";
import {IWETH as IWNative} from "../interfaces/IWETH.sol";

import {AddressHelper} from "../libraries/AddressHelper.sol";
import {Bytes} from "../libraries/Bytes.sol";

import {OwnableModule} from "../upgradeable_contracts/modules/OwnableModule.sol";
import {Claimable} from "../upgradeable_contracts/Claimable.sol";
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";

/**
 * @title TokenOmnibridgeBase
 * @dev Omnibridge extension for processing tokens that are not otherwise
 * delivered automatically because of foreign omnibridge settings
 */
contract TokenOmnibridgeBase is OwnableModule, Claimable, ReentrancyV2 {
    using SafeERC20 for IERC20;

    bool public immutable EIP1559_ENABLED;
    address public immutable bridge;
    IWNative public immutable wNative;
    address public validatorsFilter;
    mapping(address => bool) public isValidator;

    error NotPayable();

    bytes32 public constant RUNNER_SLOT = keccak256(abi.encode("omnibridgerouter.runner"));

    /**
     * @dev Initializes this contract.
     * @param _bridge address of the HomeOmnibridge/ForeignOmnibridge contract.
     * @param _wNative address of the WNative token used for wrapping/unwrapping native coins (e.g. WETH/WBNB/WXDAI).
     * @param _owner address of the contract owner.
     */
    constructor(address _bridge, IWNative _wNative, address _owner, bool _EIP1559_ENABLED) OwnableModule(_owner) {
        bridge = _bridge;
        wNative = _wNative;
        _wNative.approve(address(_bridge), type(uint256).max);
        validatorsFilter = address(this);
        EIP1559_ENABLED = _EIP1559_ENABLED;
    }

    struct FeeDirector {
        address recipient;
        // a list of up to 256 flags for modifying how the contract handles tokens
        // 0th index is to use the limit as the fee amount
        // 1st index is to unwrap the tokens
        // 2nd is to ask the system to not include the priority fee
        // 3rd is to use the multiplier as a factor of total tokens
        // if a base fee is available it will only use that
        uint256 settings;
        uint256 limit;
        uint256 multiplier;
    }

    /**
     * @dev Bridged callback function used for unwrapping received tokens.
     * Can only be called by the associated Omnibridge contract.
     * @param _token bridged token contract address, should be wNative.
     * @param _value amount of bridged/received tokens.
     * @param _data extra data passed alongside with relayTokensAndCall
     * on the other side of the bridge. Should contain coins receiver address.
     */
    function onTokenBridged(address _token, uint256 _value, bytes memory _data) external payable virtual nonReentrant {
        require(msg.sender == address(bridge));
        uint256 balance = IERC20(_token).balanceOf(address(this));
        if (balance < _value) {
            // this covers the case of tax / reflection tokens
            // where the amount bridged is less than the amount received by this router
            _value = balance;
        }
        if (_data.length == 20) {
            // handling legacy wNative -> Native
            require(_token == address(wNative));
            wNative.withdraw(_value);
            AddressHelper.safeSendValue(payable(Bytes.bytesToAddress(_data)), _value);
        } else {
            FeeDirector memory feeDirector = abi.decode(_data, (FeeDirector));
            // setting at the 0th slot from the right is a signal to unwrap the tokens
            bool toNative = feeDirector.settings << 254 >> 255 == 1 && address(wNative) == _token;
            // handling wNative -> Native
            if (toNative && _token == address(wNative)) {
                wNative.withdraw(_value);
            }
            uint256 runner = StorageSlot.getUint256Slot(RUNNER_SLOT).value;
            uint256 fees;
            uint256 toRecipient = _value;
            if (runner > 1) {
                // setting at the 1st slot from the right is a signal to use the limit as the fixed fee
                (fees, toRecipient) = _feeInfo(toNative, _value, runner, feeDirector);
            }
            if (toRecipient > 0) {
                _distribute(toNative, _token, feeDirector.recipient, toRecipient);
            }
            if (fees > 0) {
                _distribute(toNative, _token, address(uint160(runner >> 96)), fees);
            }
        }
    }

    function _distribute(bool native, address token, address recipient, uint256 amount) internal {
        if (native) {
            (bool success,) = recipient.call{value: amount}("");
            if (!success) {
                revert NotPayable();
            }
        } else {
            IERC20(token).safeTransfer(recipient, amount);
        }
    }

    function _feeInfo(bool toNative, uint256 _value, uint256 runner, FeeDirector memory feeDirector)
        internal
        view
        returns (uint256 fees, uint256 toRecipient)
    {
        // use the limit as the fee
        if (feeDirector.settings << 255 >> 255 == 1) {
            fees = feeDirector.limit;
        } else if (feeDirector.settings << 252 >> 255 == 1) {
            fees = (_value * feeDirector.multiplier) / 1 ether;
        } else {
            // a runner has been named (does not have to match sender)
            uint256 gasUsed = uint256(uint96(runner)) - gasleft();
            // extra 50k added for 2x transfer handling + 10%
            // to cover profit motive + risk compensation
            uint256 baselineFee = _baseFee((feeDirector.settings << 253 >> 255) == 1);
            fees = (
                (
                    gasUsed
                    // this is an unwrap, different costs for tokens vs native
                    + (toNative ? 50_000 : 100_000)
                ) * feeDirector.multiplier * baselineFee
            ) / 1 ether;
            // fees must not be greater than limit
            fees = fees > feeDirector.limit ? feeDirector.limit : fees;
        }
        // fees must not be greater than value
        fees = fees > _value ? _value : fees;
        toRecipient = _value - fees;
    }

    function feeInfo(bool toNative, uint256 _value, uint256 runner, FeeDirector calldata feeDirector)
        external
        view
        returns (uint256, uint256)
    {
        return _feeInfo(toNative, _value, runner, feeDirector);
    }

    function baseFee(bool excludePriority) external view returns (uint256) {
        return _baseFee(excludePriority);
    }

    function _baseFee(bool excludePriority) internal view returns (uint256) {
        return EIP1559_ENABLED && excludePriority ? block.basefee : tx.gasprice;
    }

    /**
     * @dev Claims stuck coins/tokens.
     * Only contract owner can call this method.
     * @param _token address of claimed token contract, address(0) for native coins.
     * @param _to address of tokens receiver
     */
    function claimTokens(address _token, address _to) external onlyOwner {
        claimValues(_token, _to);
    }

    /**
     * @dev Ether receive function.
     * Should be only called from the wNative contract when withdrawing native coins. Will revert otherwise.
     */
    receive() external payable {
        require(msg.sender == address(wNative));
    }
    /**
     * @dev Validates provided signatures and relays a given message. Passes all available gas for the execution.
     * The message is not allowed to fail. The whole tx will be revered if message fails.
     * @param runner the validator you would like to attribute this method call to
     * @param _data bytes to be relayed
     * @param _signatures bytes blob with signatures to be validated
     * @notice that the sender does not matter, so this method could be called via
     * multicall for more efficient gas savings and still attribute tokens to the validator appropriately
     */
    function safeExecuteSignaturesWithAutoGasLimit(address runner, bytes calldata _data, bytes calldata _signatures)
        external
        payable
        nonReentrantUint256(RUNNER_SLOT, uint256(uint96(gasleft())) | (uint256(uint160(runner)) << 96))
    {
        if (!IBridgeValidators(validatorsFilter).isValidator(runner)) {
            revert NotPayable();
        }
        IBasicForeignAMB(address(IBasicAMBMediator(bridge).bridgeContract())).safeExecuteSignaturesWithAutoGasLimit(
            _data, _signatures
        );
    }
    /**
     * updates the filter to any contract.
     * for future use case, this is the bridge's validator contract
     */
    function setValidatorsFilter(address _validatorsFilter) external payable onlyOwner {
        // if this doesn't fail we are at least guaranteed that it has the method
        IBridgeValidators(_validatorsFilter).isValidator(address(0));
        validatorsFilter = _validatorsFilter;
    }
    /**
     * mev protection management
     */
    function setValidatorStatus(address _validator, bool _isValidator) external payable onlyOwner {
        isValidator[_validator] = _isValidator;
    }
}
TokenOmnibridgeRouter.sol 43 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

import { IOmnibridge } from "../interfaces/IOmnibridge.sol";
import { IWETH as IWNative } from "../interfaces/IWETH.sol";

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

/**
 * @title TokenOmnibridgeRouter
 * @dev Omnibridge extension for processing tokens that are not otherwise
 * delivered automatically because of foreign omnibridge settings
 */
contract TokenOmnibridgeRouter is TokenOmnibridgeBase {
    constructor(address _bridge, IWNative _wNative, address _owner) TokenOmnibridgeBase(_bridge, _wNative, _owner, true) {}
    /**
     * @dev Wraps native assets and relays wrapped ERC20 tokens to the other chain.
     * Call msg.sender will receive assets on the other side of the bridge.
     */
    function wrapAndRelayTokens() external payable {
        _relayTokensAndCall(msg.sender, "");
    }

    /**
     * @dev Wraps native assets and relays wrapped ERC20 tokens to the other chain.
     * @param _receiver bridged assets receiver on the other side of the bridge.
     */
    function wrapAndRelayTokens(address _receiver) external payable {
        _relayTokensAndCall(_receiver, "");
    }
    /**
     * a convenience method for relaying tokens to a corresponding network
     * @param _receiver the receiving contract on the other network
     * @param _data the encoded data that should be passed to `onTokenBridged` on the other network
     */
    function relayTokensAndCall(address _receiver, bytes calldata _data) external payable {
        _relayTokensAndCall(_receiver, _data);
    }
    function _relayTokensAndCall(address _receiver, bytes memory _data) internal {
        wNative.deposit{ value: msg.value }();
        IOmnibridge(bridge).relayTokensAndCall(address(wNative), _receiver, msg.value, _data);
    }
}
IAMB.sol 48 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

interface IAMB {
    event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData);
    event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData);
    event AffirmationCompleted(
        address indexed sender,
        address indexed executor,
        bytes32 indexed messageId,
        bool status
    );
    event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status);

    function messageSender() external view returns (address);

    function maxGasPerTx() external view returns (uint256);

    function transactionHash() external view returns (bytes32);

    function messageId() external view returns (bytes32);

    function messageSourceChainId() external view returns (bytes32);

    function messageCallStatus(bytes32 _messageId) external view returns (bool);

    function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32);

    function failedMessageReceiver(bytes32 _messageId) external view returns (address);

    function failedMessageSender(bytes32 _messageId) external view returns (address);

    function requireToPassMessage(
        address _contract,
        bytes calldata _data,
        uint256 _gas
    ) external returns (bytes32);

    function requireToConfirmMessage(
        address _contract,
        bytes calldata _data,
        uint256 _gas
    ) external returns (bytes32);

    function sourceChainId() external view returns (uint256);

    function destinationChainId() external view returns (uint256);
}
IBasicAMBMediator.sol 8 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

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

interface IBasicAMBMediator {
  function bridgeContract() external view returns (IAMB);
}
IBasicForeignAMB.sol 12 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

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

interface IBasicForeignAMB {
    function safeExecuteSignaturesWithAutoGasLimit(bytes calldata _data, bytes calldata _signatures) external;

    function validatorContract() external view returns (IBridgeValidators);

    function relayTokens(address _receiver, uint256 _amount) external;
}
IBridgeValidators.sol 14 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

interface IBridgeValidators {
    function isValidator(address _validator) external view returns (bool);

    function F_ADDR() external view returns (address);

    function getNextValidator(address _address) external view returns (address);

    function validatorCount() external view returns (uint256);

    function validatorList() external view returns(address[] memory);
}
IOmnibridge.sol 32 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

interface IOmnibridge {
    function relayTokens(
        address _token,
        address _receiver,
        uint256 _value
    ) external;
    function relayTokensAndCall(
        address _token,
        address _receiver,
        uint256 _value,
        bytes calldata _data
    ) external;
}

interface IOmnibridgeExtra {
    function relayTokens(
        address _token,
        address _receiver,
        uint256 _value,
        address senderOrigin
    ) external;
    function relayTokensAndCall(
        address _token,
        address _receiver,
        uint256 _value,
        bytes calldata _data,
        address senderOrigin
    ) external;
}
IWETH.sol 10 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 _value) external;

    function approve(address _to, uint256 _value) external;
}
AddressHelper.sol 21 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

import "../upgradeable_contracts/Sacrifice.sol";

/**
 * @title AddressHelper
 * @dev Helper methods for Address type.
 */
library AddressHelper {
    /**
     * @dev Try to send native tokens to the address. If it fails, it will force the transfer by creating a selfdestruct contract
     * @param _receiver address that will receive the native tokens
     * @param _value the amount of native tokens to send
     */
    function safeSendValue(address payable _receiver, uint256 _value) internal {
        if (!(_receiver).send(_value)) {
            new Sacrifice{ value: _value }(_receiver);
        }
    }
}
Bytes.sol 23 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

/**
 * @title Bytes
 * @dev Helper methods to transform bytes to other solidity types.
 */
library Bytes {
    /**
     * @dev Truncate bytes array if its size is more than 20 bytes.
     * NOTE: This function does not perform any checks on the received parameter.
     * Make sure that the _bytes argument has a correct length, not less than 20 bytes.
     * A case when _bytes has length less than 20 will lead to the undefined behaviour,
     * since assembly will read data from memory that is not related to the _bytes argument.
     * @param _bytes to be converted to address type
     * @return addr address included in the firsts 20 bytes of the bytes array in parameter.
     */
    function bytesToAddress(bytes memory _bytes) internal pure returns (address addr) {
        assembly {
            addr := mload(add(_bytes, 20))
        }
    }
}
Claimable.sol 55 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../libraries/AddressHelper.sol";

/**
 * @title Claimable
 * @dev Implementation of the claiming utils that can be useful for withdrawing accidentally sent tokens that are not used in bridge operations.
 */
contract Claimable {
    using SafeERC20 for IERC20;

    /**
     * Throws if a given address is equal to address(0)
     */
    modifier validAddress(address _to) {
        require(_to != address(0));
        _;
    }

    /**
     * @dev Withdraws the erc20 tokens or native coins from this contract.
     * Caller should additionally check that the claimed token is not a part of bridge operations (i.e. that token != erc20token()).
     * @param _token address of the claimed token or address(0) for native coins.
     * @param _to address of the tokens/coins receiver.
     */
    function claimValues(address _token, address _to) internal validAddress(_to) {
        if (_token == address(0)) {
            claimNativeCoins(_to);
        } else {
            claimErc20Tokens(_token, _to);
        }
    }

    /**
     * @dev Internal function for withdrawing all native coins from the contract.
     * @param _to address of the coins receiver.
     */
    function claimNativeCoins(address _to) internal virtual {
        uint256 value = address(this).balance;
        AddressHelper.safeSendValue(payable(_to), value);
    }

    /**
     * @dev Internal function for withdrawing all tokens of some particular ERC20 contract from this contract.
     * @param _token address of the claimed ERC20 token.
     * @param _to address of the tokens receiver.
     */
    function claimErc20Tokens(address _token, address _to) internal virtual {
        IERC20 token = IERC20(_token);
        uint256 balance = token.balanceOf(address(this));
        token.safeTransfer(_to, balance);
    }
}
OwnableModule.sol 36 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

import "@openzeppelin/contracts/utils/Address.sol";

/**
 * @title OwnableModule
 * @dev Common functionality for multi-token extension non-upgradeable module.
 */
contract OwnableModule {
    address public owner;

    /**
     * @dev Initializes this contract.
     * @param _owner address of the owner that is allowed to perform additional actions on the particular module.
     */
    constructor(address _owner) {
        owner = _owner;
    }

    /**
     * @dev Throws if sender is not the owner of this contract.
     */
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    /**
     * @dev Changes the owner of this contract.
     * @param _newOwner address of the new owner.
     */
    function transferOwnership(address _newOwner) external onlyOwner {
        owner = _newOwner;
    }
}
Sacrifice.sol 8 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.24;

contract Sacrifice {
    constructor(address payable _recipient) payable {
        selfdestruct(_recipient);
    }
}

Read Contract

EIP1559_ENABLED 0xed5a97d3 → bool
RUNNER_SLOT 0x633a8fa9 → bytes32
baseFee 0x351bb549 → uint256
bridge 0xe78cea92 → address
feeInfo 0x52ed42f5 → uint256, uint256
isValidator 0xfacd743b → bool
owner 0x8da5cb5b → address
validatorsFilter 0x70502107 → address
wNative 0x2d68efc9 → address

Write Contract 9 functions

These functions modify contract state and require a wallet transaction to execute.

claimTokens 0x69ffa08a
address _token
address _to
onTokenBridged 0xdb7af854
address _token
uint256 _value
bytes _data
relayTokensAndCall 0x9562de59
address _receiver
bytes _data
safeExecuteSignaturesWithAutoGasLimit 0x4309b714
address runner
bytes _data
bytes _signatures
setValidatorStatus 0xaca2490b
address _validator
bool _isValidator
setValidatorsFilter 0x36768d3e
address _validatorsFilter
transferOwnership 0xf2fde38b
address _newOwner
wrapAndRelayTokens 0x01a754ff
No parameters
wrapAndRelayTokens 0xf52cbf0e
address _receiver

Recent Transactions

No transactions found for this address