HYPE Price: $26.91 (+8.14%)
 

Overview

HYPE Balance

HyperEVM LogoHyperEVM LogoHyperEVM Logo0 HYPE

HYPE Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Add Supported To...256442802026-01-27 1:37:004 hrs ago1769477820IN
0x861E1270...9e007d195
0 HYPE0.000472045.16300213
Deposit To Hyper...250913562026-01-20 18:31:116 days ago1768933871IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...249777192026-01-19 11:28:177 days ago1768822097IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...249475252026-01-19 3:13:188 days ago1768792398IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...246875462026-01-16 4:09:5911 days ago1768536599IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...246370572026-01-15 14:22:1711 days ago1768486937IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...242947862026-01-11 16:51:1715 days ago1768150277IN
0x861E1270...9e007d195
0 HYPE0.000012750.10495703
Deposit To Hyper...240718132026-01-09 3:56:0018 days ago1767930960IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...237409062026-01-05 9:31:1721 days ago1767605477IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...237404522026-01-05 9:23:5121 days ago1767605031IN
0x861E1270...9e007d195
0 HYPE0.000012140.1
Deposit To Hyper...222597092025-12-19 12:46:3538 days ago1766148395IN
0x861E1270...9e007d195
0 HYPE0.000012450.1
Deposit To Hyper...221251132025-12-18 0:00:0540 days ago1766016005IN
0x861E1270...9e007d195
0 HYPE0.000012450.1
Deposit To Hyper...220963922025-12-17 16:09:1540 days ago1765987755IN
0x861E1270...9e007d195
0 HYPE0.000127321.02238803
Deposit To Hyper...219052032025-12-15 11:55:0042 days ago1765799700IN
0x861E1270...9e007d195
0 HYPE0.000012450.1
Deposit To Hyper...219005062025-12-15 10:38:0042 days ago1765795080IN
0x861E1270...9e007d195
0 HYPE0.000116881.849
Deposit To Hyper...219003842025-12-15 10:36:0042 days ago1765794960IN
0x861E1270...9e007d195
0 HYPE0.000119360.9585
Sweep Donation B...212988612025-12-08 14:14:5949 days ago1765203299IN
0x861E1270...9e007d195
0 HYPE0.000139331.6
Sweep Core Funds...209521762025-12-04 15:30:1453 days ago1764862214IN
0x861E1270...9e007d195
0 HYPE0.000003240.10099611
Sweep Core Funds...209521382025-12-04 15:29:3753 days ago1764862177IN
0x861E1270...9e007d195
0 HYPE0.000013330.4152199
Add Supported To...203016792025-11-27 5:45:0061 days ago1764222300IN
0x861E1270...9e007d195
0 HYPE0.000054850.6

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
203016792025-11-27 5:45:0061 days ago1764222300
0x861E1270...9e007d195
 Contract Creation0 HYPE
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
HyperliquidDepositHandler

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 800 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;

import "../interfaces/SpokePoolMessageHandler.sol";
import "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts-v4/security/ReentrancyGuard.sol";
import { HyperCoreLib } from "../libraries/HyperCoreLib.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { DonationBox } from "../chain-adapters/DonationBox.sol";

/**
 * @title Allows caller to bridge tokens from HyperEVM to Hypercore and send them to an end user's account
 * on Hypercore.
 * @dev This contract should only be deployed on HyperEVM.
 * @dev This contract can replace a MulticallHandler on HyperEVM if the intent only wants to deposit tokens into
 * Hypercore and bypass the other complex arbitrary calldata logic.
 * @dev This contract can also be called directly to deposit tokens into Hypercore on behalf of an end user.
 */
contract HyperliquidDepositHandler is AcrossMessageHandler, ReentrancyGuard, Ownable {
    using SafeERC20 for IERC20;
    struct TokenInfo {
        // HyperEVM token address.
        address evmAddress;
        // Hypercore token index.
        uint64 tokenId;
        // Activation fee in EVM units. e.g. 1000000 ($1) for USDH.
        uint256 activationFeeEvm;
        // coreDecimals - evmDecimals. e.g. -2 for USDH.
        int8 decimalDiff;
    }

    // Stores hardcoded Hypercore configurations for tokens that this handler supports.
    mapping(address => TokenInfo) public supportedTokens;

    // Donation box contract to store funds for account activation fees.
    DonationBox public immutable donationBox;

    error InsufficientEvmAmountForActivation();
    error TokenNotSupported();

    event UserAccountActivated(address user, address indexed token, uint256 amountRequiredToActivate);

    /**
     * @notice Constructor.
     * @dev Creates a new donation box contract owned by this contract.
     */
    constructor() Ownable(msg.sender) {
        donationBox = new DonationBox();
    }

    /**
     * @notice Adds a new token to the supported tokens list.
     * @dev Caller must be owner of this contract.
     * @param evmAddress The address of the EVM token.
     * @param tokenId The index of the Hypercore token.
     * @param activationFeeEvm The activation fee in EVM units.
     * @param decimalDiff The difference in decimals between the EVM and Hypercore tokens.
     */
    function addSupportedToken(
        address evmAddress,
        uint64 tokenId,
        uint256 activationFeeEvm,
        int8 decimalDiff
    ) external onlyOwner {
        supportedTokens[evmAddress] = TokenInfo({
            evmAddress: evmAddress,
            tokenId: tokenId,
            activationFeeEvm: activationFeeEvm,
            decimalDiff: decimalDiff
        });
    }

    /**
     * @notice Bridges tokens from HyperEVM to Hypercore and sends them to the end user's account on Hypercore.
     * @dev Requires msg.sender to have approved this contract to spend the tokens.
     * @param token The address of the token to deposit.
     * @param amount The amount of tokens on HyperEVM to deposit.
     * @param user The address of the user on Hypercore to send the tokens to.
     */
    function depositToHypercore(address token, uint256 amount, address user) external nonReentrant {
        IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
        _depositToHypercore(token, amount, user);
    }

    /**
     * @notice Entrypoint function if this contract is called by the SpokePool contract following an intent fill.
     * @dev Deposits tokens into Hypercore and sends them to the end user's account on Hypercore.
     * @param token The address of the token sent.
     * @param amount The amount of tokens received by this contract.
     * @param message Encoded end user address.
     */
    function handleV3AcrossMessage(
        address token,
        uint256 amount,
        address /* relayer */,
        bytes memory message
    ) external nonReentrant {
        address user = abi.decode(message, (address));
        _depositToHypercore(token, amount, user);
    }

    /**
     * @notice Send Hypercore funds to a user from this contract's Hypercore account
     * @dev The coreAmount parameter is specified in Hypercore units which often differs from the EVM units for the
     * same token.
     * @param token The token address
     * @param coreAmount The amount of tokens on Hypercore to sweep
     * @param user The address of the user to send the tokens to
     */
    function sweepCoreFundsToUser(address token, uint64 coreAmount, address user) external onlyOwner nonReentrant {
        uint64 tokenIndex = _getTokenInfo(token).tokenId;
        HyperCoreLib.transferERC20CoreToCore(tokenIndex, user, coreAmount);
    }

    /**
     * @notice Send donation box funds to a user from this contract's address on HyperEVM
     * @param token The token address
     * @param amount The amount of tokens to sweep
     * @param user The address of the user to send the tokens to
     */
    function sweepDonationBoxFundsToUser(address token, uint256 amount, address user) external onlyOwner nonReentrant {
        donationBox.withdraw(IERC20(token), amount);
        IERC20(token).safeTransfer(user, amount);
    }

    /**
     * @notice Send ERC20 tokens to a user from this contract's address on HyperEVM
     * @param token The token address
     * @param evmAmount The amount of tokens to sweep
     * @param user The address of the user to send the tokens to
     */
    function sweepERC20ToUser(address token, uint256 evmAmount, address user) external onlyOwner nonReentrant {
        IERC20(token).safeTransfer(user, evmAmount);
    }

    function _depositToHypercore(address token, uint256 evmAmount, address user) internal {
        TokenInfo memory tokenInfo = _getTokenInfo(token);
        uint64 tokenIndex = tokenInfo.tokenId;
        int8 decimalDiff = tokenInfo.decimalDiff;

        bool userExists = HyperCoreLib.coreUserExists(user);
        if (!userExists) {
            // To activate an account, we must pay the activation fee from this contract's core account and then send 1
            // wei to the user's account, so we pull the activation fee + 1 wei from the donation box. This contract
            // does not allow the end user subtracting part of their received amount to use for the activation fee.
            uint256 activationFee = tokenInfo.activationFeeEvm;
            uint256 amountRequiredToActivate = activationFee + 1;
            donationBox.withdraw(IERC20(token), amountRequiredToActivate);
            // Deposit the activation fee + 1 wei into this contract's core account to pay for the user's
            // account activation.
            HyperCoreLib.transferERC20EVMToSelfOnCore(token, tokenIndex, amountRequiredToActivate, decimalDiff);
            HyperCoreLib.transferERC20CoreToCore(tokenIndex, user, 1);
            emit UserAccountActivated(user, token, amountRequiredToActivate);
        }

        HyperCoreLib.transferERC20EVMToCore(token, tokenIndex, user, evmAmount, decimalDiff);
    }

    function _getTokenInfo(address evmAddress) internal view returns (TokenInfo memory) {
        if (supportedTokens[evmAddress].evmAddress == address(0)) {
            revert TokenNotSupported();
        }
        return supportedTokens[evmAddress];
    }

    // Native tokens are not supported by this contract, so there is no fallback function.
}

File 2 of 13 : SpokePoolMessageHandler.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// This interface is expected to be implemented by any contract that expects to receive messages from the SpokePool.
interface AcrossMessageHandler {
    function handleV3AcrossMessage(
        address tokenSent,
        uint256 amount,
        address relayer,
        bytes memory message
    ) external;
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

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

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

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

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

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

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

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

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

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

import { IERC20 } from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol";

interface ICoreWriter {
    function sendRawAction(bytes calldata data) external;
}

library HyperCoreLib {
    using SafeERC20 for IERC20;

    // Time-in-Force order types
    enum Tif {
        None, // invalid
        ALO, // Add Liquidity Only
        GTC, // Good-Till-Cancel
        IOC // Immediate-or-Cancel
    }

    struct SpotBalance {
        uint64 total;
        uint64 hold; // Unused in this implementation
        uint64 entryNtl; // Unused in this implementation
    }

    struct TokenInfo {
        string name;
        uint64[] spots;
        uint64 deployerTradingFeeShare;
        address deployer;
        address evmContract;
        uint8 szDecimals;
        uint8 weiDecimals;
        int8 evmExtraWeiDecimals;
    }

    struct CoreUserExists {
        bool exists;
    }

    // Base asset bridge addresses
    address public constant BASE_ASSET_BRIDGE_ADDRESS = 0x2000000000000000000000000000000000000000;
    uint256 public constant BASE_ASSET_BRIDGE_ADDRESS_UINT256 = uint256(uint160(BASE_ASSET_BRIDGE_ADDRESS));

    // Precompile addresses
    address public constant SPOT_BALANCE_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000801;
    address public constant SPOT_PX_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000808;
    address public constant CORE_USER_EXISTS_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000810;
    address public constant TOKEN_INFO_PRECOMPILE_ADDRESS = 0x000000000000000000000000000000000000080C;
    address public constant CORE_WRITER_PRECOMPILE_ADDRESS = 0x3333333333333333333333333333333333333333;

    // CoreWriter action headers
    bytes4 public constant LIMIT_ORDER_HEADER = 0x01000001; // version=1, action=1
    bytes4 public constant SPOT_SEND_HEADER = 0x01000006; // version=1, action=6
    bytes4 public constant CANCEL_BY_CLOID_HEADER = 0x0100000B; // version=1, action=11

    // Errors
    error LimitPxIsZero();
    error OrderSizeIsZero();
    error InvalidTif();
    error CoreUserAlreadyExists();
    error InsufficientCoreBalanceToActivateAccount();
    error InsufficientEvmBalanceToActivateAccount();
    error SpotBalancePrecompileCallFailed();
    error CoreUserExistsPrecompileCallFailed();
    error TokenInfoPrecompileCallFailed();
    error SpotPxPrecompileCallFailed();

    /**
     * @notice Transfer `amountEVM` from HyperEVM to `to` on HyperCore.
     * @dev Returns the amount credited on Core in Core units (post conversion).
     * @param erc20EVMAddress The address of the ERC20 token on HyperEVM
     * @param erc20CoreIndex The HyperCore index id of the token to transfer
     * @param to The address to receive tokens on HyperCore
     * @param amountEVM The amount to transfer on HyperEVM
     * @param decimalDiff The decimal difference of evmDecimals - coreDecimals
     * @return amountEVMSent The amount sent on HyperEVM
     * @return amountCoreToReceive The amount credited on Core in Core units (post conversion)
     */
    function transferERC20EVMToCore(
        address erc20EVMAddress,
        uint64 erc20CoreIndex,
        address to,
        uint256 amountEVM,
        int8 decimalDiff
    ) internal returns (uint256 amountEVMSent, uint64 amountCoreToReceive) {
        // if the transfer amount exceeds the bridge balance, this wil revert
        (uint256 _amountEVMToSend, uint64 _amountCoreToReceive) = maximumEVMSendAmountToAmounts(amountEVM, decimalDiff);

        if (_amountEVMToSend != 0) {
            // Transfer the tokens to this contract's address on HyperCore
            IERC20(erc20EVMAddress).safeTransfer(toAssetBridgeAddress(erc20CoreIndex), _amountEVMToSend);

            // Transfer the tokens from this contract on HyperCore to the `to` address on HyperCore
            transferERC20CoreToCore(erc20CoreIndex, to, _amountCoreToReceive);
        }

        return (_amountEVMToSend, _amountCoreToReceive);
    }

    /**
     * @notice Bridges `amountEVM` of `erc20` from this address on HyperEVM to this address on HyperCore.
     * @dev Returns the amount credited on Core in Core units (post conversion).
     * @dev The decimal difference is evmDecimals - coreDecimals
     * @param erc20EVMAddress The address of the ERC20 token on HyperEVM
     * @param erc20CoreIndex The HyperCore index id of the token to transfer
     * @param amountEVM The amount to transfer on HyperEVM
     * @param decimalDiff The decimal difference of evmDecimals - coreDecimals
     * @return amountEVMSent The amount sent on HyperEVM
     * @return amountCoreToReceive The amount credited on Core in Core units (post conversion)
     */
    function transferERC20EVMToSelfOnCore(
        address erc20EVMAddress,
        uint64 erc20CoreIndex,
        uint256 amountEVM,
        int8 decimalDiff
    ) internal returns (uint256 amountEVMSent, uint64 amountCoreToReceive) {
        (uint256 _amountEVMToSend, uint64 _amountCoreToReceive) = maximumEVMSendAmountToAmounts(amountEVM, decimalDiff);

        if (_amountEVMToSend != 0) {
            // Transfer the tokens to this contract's address on HyperCore
            IERC20(erc20EVMAddress).safeTransfer(toAssetBridgeAddress(erc20CoreIndex), _amountEVMToSend);
        }

        return (_amountEVMToSend, _amountCoreToReceive);
    }

    /**
     * @notice Transfers tokens from this contract on HyperCore to the `to` address on HyperCore
     * @param erc20CoreIndex The HyperCore index id of the token
     * @param to The address to receive tokens on HyperCore
     * @param amountCore The amount to transfer on HyperCore
     */
    function transferERC20CoreToCore(uint64 erc20CoreIndex, address to, uint64 amountCore) internal {
        bytes memory action = abi.encode(to, erc20CoreIndex, amountCore);
        bytes memory payload = abi.encodePacked(SPOT_SEND_HEADER, action);

        ICoreWriter(CORE_WRITER_PRECOMPILE_ADDRESS).sendRawAction(payload);
    }

    /**
     * @notice Submit a limit order on HyperCore.
     * @dev Expects price & size already scaled by 1e8 per HyperCore spec.
     * @param asset The asset index of the order
     * @param isBuy Whether the order is a buy order
     * @param limitPriceX1e8 The limit price of the order scaled by 1e8
     * @param sizeX1e8 The size of the order scaled by 1e8
     * @param reduceOnly If true, only reduce existing position rather than opening a new opposing order
     * @param tif Time-in-Force: ALO, GTC, IOC (None invalid)
     * @param cloid The client order id of the order, 0 means no cloid
     */
    function submitLimitOrder(
        uint32 asset,
        bool isBuy,
        uint64 limitPriceX1e8,
        uint64 sizeX1e8,
        bool reduceOnly,
        Tif tif,
        uint128 cloid
    ) internal {
        // Basic sanity checks
        if (limitPriceX1e8 == 0) revert LimitPxIsZero();
        if (sizeX1e8 == 0) revert OrderSizeIsZero();
        if (tif == Tif.None || uint8(tif) > uint8(type(Tif).max)) revert InvalidTif();

        // Encode the action
        bytes memory encodedAction = abi.encode(asset, isBuy, limitPriceX1e8, sizeX1e8, reduceOnly, uint8(tif), cloid);

        // Prefix with the limit-order header
        bytes memory data = abi.encodePacked(LIMIT_ORDER_HEADER, encodedAction);

        // Enqueue limit order to HyperCore via CoreWriter precompile
        ICoreWriter(CORE_WRITER_PRECOMPILE_ADDRESS).sendRawAction(data);
    }

    /**
     * @notice Enqueue a cancel-order-by-CLOID for a given asset.
     * @param asset The asset index of the order
     * @param cloid The client order id of the order
     */
    function cancelOrderByCloid(uint32 asset, uint128 cloid) internal {
        // Encode the action
        bytes memory encodedAction = abi.encode(asset, cloid);

        // Prefix with the cancel-by-cloid header
        bytes memory data = abi.encodePacked(CANCEL_BY_CLOID_HEADER, encodedAction);

        // Enqueue cancel order by CLOID to HyperCore via CoreWriter precompile
        ICoreWriter(CORE_WRITER_PRECOMPILE_ADDRESS).sendRawAction(data);
    }

    /**
     * @notice Get the balance of the specified ERC20 for `account` on HyperCore.
     * @param account The address of the account to get the balance of
     * @param token The token to get the balance of
     * @return balance The balance of the specified ERC20 for `account` on HyperCore
     */
    function spotBalance(address account, uint64 token) internal view returns (uint64 balance) {
        (bool success, bytes memory result) = SPOT_BALANCE_PRECOMPILE_ADDRESS.staticcall(abi.encode(account, token));
        if (!success) revert SpotBalancePrecompileCallFailed();
        SpotBalance memory _spotBalance = abi.decode(result, (SpotBalance));
        return _spotBalance.total;
    }

    /**
     * @notice Checks if the user exists / has been activated on HyperCore.
     * @param user The address of the user to check if they exist on HyperCore
     * @return exists True if the user exists on HyperCore, false otherwise
     */
    function coreUserExists(address user) internal view returns (bool) {
        (bool success, bytes memory result) = CORE_USER_EXISTS_PRECOMPILE_ADDRESS.staticcall(abi.encode(user));
        if (!success) revert CoreUserExistsPrecompileCallFailed();
        CoreUserExists memory _coreUserExists = abi.decode(result, (CoreUserExists));
        return _coreUserExists.exists;
    }

    /**
     * @notice Get the spot price of the specified asset on HyperCore.
     * @param index The asset index to get the spot price of
     * @return spotPx The spot price of the specified asset on HyperCore scaled by 1e8
     */
    function spotPx(uint32 index) internal view returns (uint64) {
        (bool success, bytes memory result) = SPOT_PX_PRECOMPILE_ADDRESS.staticcall(abi.encode(index));
        if (!success) revert SpotPxPrecompileCallFailed();
        return abi.decode(result, (uint64));
    }

    /**
     * @notice Get the info of the specified token on HyperCore.
     * @param erc20CoreIndex The token to get the info of
     * @return tokenInfo The info of the specified token on HyperCore
     */
    function tokenInfo(uint32 erc20CoreIndex) internal view returns (TokenInfo memory) {
        (bool success, bytes memory result) = TOKEN_INFO_PRECOMPILE_ADDRESS.staticcall(abi.encode(erc20CoreIndex));
        if (!success) revert TokenInfoPrecompileCallFailed();
        TokenInfo memory _tokenInfo = abi.decode(result, (TokenInfo));
        return _tokenInfo;
    }

    /**
     * @notice Checks if an amount is safe to bridge from HyperEVM to HyperCore
     * @dev Verifies that the asset bridge has sufficient balance to cover the amount plus a buffer
     * @param erc20CoreIndex The HyperCore index id of the token
     * @param coreAmount The amount that the bridging should result in on HyperCore
     * @param coreBufferAmount The minimum buffer amount that should remain on HyperCore after bridging
     * @return True if the bridge has enough balance to safely bridge the amount, false otherwise
     */
    function isCoreAmountSafeToBridge(
        uint64 erc20CoreIndex,
        uint64 coreAmount,
        uint64 coreBufferAmount
    ) internal view returns (bool) {
        address bridgeAddress = toAssetBridgeAddress(erc20CoreIndex);
        uint64 currentBridgeBalance = spotBalance(bridgeAddress, erc20CoreIndex);

        // Return true if currentBridgeBalance >= coreAmount + coreBufferAmount
        return currentBridgeBalance >= coreAmount + coreBufferAmount;
    }

    /**
     * @notice Converts a core index id to an asset bridge address
     * @param erc20CoreIndex The core token index id to convert
     * @return assetBridgeAddress The asset bridge address
     */
    function toAssetBridgeAddress(uint64 erc20CoreIndex) internal pure returns (address) {
        return address(uint160(BASE_ASSET_BRIDGE_ADDRESS_UINT256 + erc20CoreIndex));
    }

    /**
     * @notice Converts an asset bridge address to a core index id
     * @param assetBridgeAddress The asset bridge address to convert
     * @return erc20CoreIndex The core token index id
     */
    function toTokenId(address assetBridgeAddress) internal pure returns (uint64) {
        return uint64(uint160(assetBridgeAddress) - BASE_ASSET_BRIDGE_ADDRESS_UINT256);
    }

    /**
     * @notice Returns an amount to send on HyperEVM to receive AT LEAST the minimumCoreReceiveAmount on HyperCore
     * @param minimumCoreReceiveAmount The minimum amount desired to receive on HyperCore
     * @param decimalDiff The decimal difference of evmDecimals - coreDecimals
     * @return amountEVMToSend The amount to send on HyperEVM to receive at least minimumCoreReceiveAmount on HyperCore
     * @return amountCoreToReceive The amount that will be received on core if the amountEVMToSend is sent from HyperEVM
     */
    function minimumCoreReceiveAmountToAmounts(
        uint64 minimumCoreReceiveAmount,
        int8 decimalDiff
    ) internal pure returns (uint256 amountEVMToSend, uint64 amountCoreToReceive) {
        if (decimalDiff == 0) {
            // Same decimals between HyperEVM and HyperCore
            amountEVMToSend = uint256(minimumCoreReceiveAmount);
            amountCoreToReceive = minimumCoreReceiveAmount;
        } else if (decimalDiff > 0) {
            // EVM token has more decimals than Core
            // Scale up to represent the same value in higher-precision EVM units
            amountEVMToSend = uint256(minimumCoreReceiveAmount) * (10 ** uint8(decimalDiff));
            amountCoreToReceive = minimumCoreReceiveAmount;
        } else {
            // Core token has more decimals than EVM
            // Scale down, rounding UP to avoid shortfall on Core
            uint256 scaleDivisor = 10 ** uint8(-decimalDiff);
            amountEVMToSend = (uint256(minimumCoreReceiveAmount) + scaleDivisor - 1) / scaleDivisor; // ceil division
            amountCoreToReceive = uint64(amountEVMToSend * scaleDivisor);
        }
    }

    /**
     * @notice Converts a maximum EVM amount to send into an EVM amount to send to avoid loss to dust,
     * @notice and the corresponding amount that will be recieved on Core.
     * @param maximumEVMSendAmount The maximum amount to send on HyperEVM
     * @param decimalDiff The decimal difference of evmDecimals - coreDecimals
     * @return amountEVMToSend The amount to send on HyperEVM
     * @return amountCoreToReceive The amount that will be received on HyperCore if the amountEVMToSend is sent
     */
    function maximumEVMSendAmountToAmounts(
        uint256 maximumEVMSendAmount,
        int8 decimalDiff
    ) internal pure returns (uint256 amountEVMToSend, uint64 amountCoreToReceive) {
        /// @dev HyperLiquid decimal conversion: Scale EVM (u256,evmDecimals) -> Core (u64,coreDecimals)
        /// @dev Core amount is guaranteed to be within u64 range.
        if (decimalDiff == 0) {
            amountEVMToSend = maximumEVMSendAmount;
            amountCoreToReceive = uint64(amountEVMToSend);
        } else if (decimalDiff > 0) {
            // EVM token has more decimals than Core
            uint256 scale = 10 ** uint8(decimalDiff);
            amountEVMToSend = maximumEVMSendAmount - (maximumEVMSendAmount % scale); // Safe: dustAmount = maximumEVMSendAmount % scale, so dust <= maximumEVMSendAmount

            /// @dev Safe: Guaranteed to be in the range of [0, u64.max] because it is upperbounded by uint64 maxAmt
            amountCoreToReceive = uint64(amountEVMToSend / scale);
        } else {
            // Core token has more decimals than EVM
            uint256 scale = 10 ** uint8(-1 * decimalDiff);
            amountEVMToSend = maximumEVMSendAmount;

            /// @dev Safe: Guaranteed to be in the range of [0, u64.max] because it is upperbounded by uint64 maxAmt
            amountCoreToReceive = uint64(amountEVMToSend * scale);
        }
    }

    function convertCoreDecimalsSimple(
        uint64 amountDecimalsFrom,
        uint8 decimalsFrom,
        uint8 decimalsTo
    ) internal pure returns (uint64) {
        if (decimalsFrom == decimalsTo) {
            return amountDecimalsFrom;
        } else if (decimalsFrom < decimalsTo) {
            return uint64(amountDecimalsFrom * 10 ** (decimalsTo - decimalsFrom));
        } else {
            // round down
            return uint64(amountDecimalsFrom / 10 ** (decimalsFrom - decimalsTo));
        }
    }
}

// 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
pragma solidity ^0.8.0;

import { Ownable } from "@openzeppelin/contracts-v4/access/Ownable.sol";
import { IERC20 } from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol";

/**
 * @notice Users can donate tokens to this contract that only the owner can withdraw.
 * @dev This contract is designed to be used as a convenience for the owner to store funds to pay for
 * future transactions, such as donating custom gas tokens to pay for future retryable ticket messages
 * to be sent via the Arbitrum_Adapter.
 * @custom:security-contact [email protected]
 */
contract DonationBox is Ownable {
    using SafeERC20 for IERC20;

    /**
     * @notice Withdraw tokens from the contract.
     * @dev Only callable by owner, which should be set to the HubPool
     * so that it can use these funds to pay for relaying messages to
     * an Arbitrum L2 that uses custom gas tokens as the L1 payment currency,
     * via the Arbitrum_CustomGasToken_Adapter.
     * @param token Token to withdraw.
     * @param amount Amount of tokens to withdraw.
     */
    function withdraw(IERC20 token, uint256 amount) external onlyOwner {
        token.safeTransfer(msg.sender, amount);
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

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

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

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

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

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

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

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

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

// 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 v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../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.
 *
 * By default, the owner account will be the one that deploys the contract. 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;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @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 {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _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 v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;

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

Settings
{
  "remappings": [
    "@across-protocol/=node_modules/@across-protocol/",
    "@ensdomains/=node_modules/@ensdomains/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@gnosis.pm/=node_modules/@gnosis.pm/",
    "@maticnetwork/=node_modules/@maticnetwork/",
    "@matterlabs/=node_modules/@matterlabs/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@scroll-tech/=node_modules/@scroll-tech/",
    "@uniswap/=node_modules/@uniswap/",
    "arb-bridge-eth/=node_modules/arb-bridge-eth/",
    "arb-bridge-peripherals/=node_modules/arb-bridge-peripherals/",
    "arbos-precompiles/=node_modules/arbos-precompiles/",
    "base64-sol/=node_modules/base64-sol/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "@uma/=node_modules/@uma/",
    "forge-std/=lib/forge-std/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "metadata": {
    "useLiteralContent": true,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "debug": {
    "revertStrings": "strip"
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CoreUserExistsPrecompileCallFailed","type":"error"},{"inputs":[],"name":"InsufficientEvmAmountForActivation","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":[],"name":"TokenNotSupported","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountRequiredToActivate","type":"uint256"}],"name":"UserAccountActivated","type":"event"},{"inputs":[{"internalType":"address","name":"evmAddress","type":"address"},{"internalType":"uint64","name":"tokenId","type":"uint64"},{"internalType":"uint256","name":"activationFeeEvm","type":"uint256"},{"internalType":"int8","name":"decimalDiff","type":"int8"}],"name":"addSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"depositToHypercore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"donationBox","outputs":[{"internalType":"contract DonationBox","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"handleV3AcrossMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"address","name":"evmAddress","type":"address"},{"internalType":"uint64","name":"tokenId","type":"uint64"},{"internalType":"uint256","name":"activationFeeEvm","type":"uint256"},{"internalType":"int8","name":"decimalDiff","type":"int8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"coreAmount","type":"uint64"},{"internalType":"address","name":"user","type":"address"}],"name":"sweepCoreFundsToUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"sweepDonationBoxFundsToUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"evmAmount","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"sweepERC20ToUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a080604052346100e15760015f5533156100cc5760018054336001600160a01b03198216811790925560405191906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a36103a38181016001600160401b038111838210176100b8578291610ed2833903905ff080156100ad57608052604051610dec90816100e682396080518181816101b70152818161026a01526108080152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b631e4fbdf760e01b81525f6004820152602490fd5b5f80fdfe6040608081526004361015610012575f80fd5b5f905f3560e01c80633a5be8cb146105275780633eda20c61461045757806368c4ac26146103f2578063715018a61461038c5780637826a16e146102fa5780637bce887a146102385780638da5cb5b146102115780639b61d2d8146101db578063a4b672b614610198578063c48919d61461012c5763f2fde38b14610095575f80fd5b34610128576020366003190112610128576100ae6105df565b6100b66109f6565b6001600160a01b0380911691821561011157506001548273ffffffffffffffffffffffffffffffffffffffff19821617600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a380f35b51631e4fbdf760e01b815260048101849052602490fd5b5080fd5b8234610195576060366003190112610195576101466105df565b61014e610695565b6101566105f5565b61015e6109f6565b60025f54146101915767ffffffffffffffff602061018261018a9560025f55610a65565b015116610b1d565b6001815580f35b5f80fd5b80fd5b5034610128578160031936011261012857602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b8234610195576101ea366106ac565b6101f26109f6565b60025f5414610191576001600160a01b0361018a9360025f5516610a22565b50346101285781600319360112610128576020906001600160a01b03600154169051908152f35b50903461019157610248366106ac565b90916102526109f6565b60025f54146101915760025f556001600160a01b03807f000000000000000000000000000000000000000000000000000000000000000016911694813b1561019157805163f3fef3a360e01b81526001600160a01b038716600482015260248101859052915f908390604490829084905af19081156102f157506102dc575b5061018a9293610a22565b61018a93506102ea90610627565b5f926102d1565b513d5f823e3d90fd5b503461019157610309366106ac565b9160025f54146101915760025f5583516323b872dd60e01b60208201523360248201523060448201526064808201849052815260a08101949067ffffffffffffffff861181871017610378576103729561036d92526001600160a01b038316610c49565b610716565b60015f55005b634e487b7160e01b5f52604160045260245ffd5b34610191575f366003190112610191576103a46109f6565b5f6001600160a01b0360015473ffffffffffffffffffffffffffffffffffffffff198116600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b5034610191576020366003190112610191576080906001600160a01b0390816104196105df565b165f526002602052805f2080549167ffffffffffffffff600260018401549301545f0b938251958116865260a01c1660208501528301526060820152f35b5034610191576080366003190112610191576104716105df565b610479610695565b9060643592835f0b809403610191576002926104936109f6565b81519261049f8461060b565b6001600160a01b038091169283855267ffffffffffffffff6020860193168352808501936044358552606086019788525f52856020525f209351167bffffffffffffffff00000000000000000000000000000000000000008454925160a01b169163ffffffff60e01b161717825551600182015501905160ff198254169060ff161790555f80f35b5034610191576080366003190112610191576105416105df565b9061054a6105f5565b506064359067ffffffffffffffff8211610191573660238301121561019157816004013561058361057a82610679565b92519283610657565b8082526020820192366024838301011161019157815f9260246020930186378301015260025f54146101915760209060025f5580518101031261019157516001600160a01b038116809103610191576103729160243590610716565b600435906001600160a01b038216820361019157565b604435906001600160a01b038216820361019157565b6080810190811067ffffffffffffffff82111761037857604052565b67ffffffffffffffff811161037857604052565b6040810190811067ffffffffffffffff82111761037857604052565b90601f8019910116810190811067ffffffffffffffff82111761037857604052565b67ffffffffffffffff811161037857601f01601f191660200190565b6024359067ffffffffffffffff8216820361019157565b6060906003190112610191576001600160a01b03600435818116810361019157916024359160443590811681036101915790565b9073200000000000000000000000000000000000000091820180921161070257565b634e487b7160e01b5f52601160045260245ffd5b9161072083610a65565b67ffffffffffffffff926020908482840151169260608101515f0b926040805192828401985f806001600160a01b039b8c8c16978882528781526107638161063b565b51906108105afa610772610c0d565b90156109e557848180518101031261019157835191858301908111838210176103785784526107a2908501610c3c565b809152156107f3575b50505050906107b991610cef565b9390806107c9575b505050505050565b6107e895826107e3936107db866106e0565b169116610a22565b610b1d565b5f80808080806107c1565b810151916001830180931161070257898916937f00000000000000000000000000000000000000000000000000000000000000008a16803b1561019157835163f3fef3a360e01b81526001600160a01b038716600482015260248101869052905f908290604490829084905af180156109db576109cc575b506108768785610cef565b50806109b1575b50825191808301918252888484015260016060840152606083526108a08361060b565b6108d56024855180946108c5858301976280000360e11b895251809285850190610afc565b8101036004810185520183610657565b733333333333333333333333333333333333333333803b15610191575f92836044610924948851978896879586936317938e1360e01b8552600485015251809281602486015285850190610afc565b601f01601f191681010301925af180156109a757927f45b9d2d602535b50313ef0fa849df42dd31d8610fc42876e005a5b6806d3e8809261098b926107b998979695610998575b50516001600160a01b038a16815260208101919091529081906040820190565b0390a290915f80806107ab565b6109a190610627565b5f61096b565b82513d5f823e3d90fd5b6109c6908b6109bf8b6106e0565b1687610a22565b5f61087d565b6109d590610627565b5f61086b565b84513d5f823e3d90fd5b83516313dd7ccd60e31b8152600490fd5b6001600160a01b03600154163303610a0a57565b60405163118cdaa760e01b8152336004820152602490fd5b60405163a9059cbb60e01b60208201526001600160a01b03929092166024830152604480830193909352918152610a6391610a5e606483610657565b610c49565b565b60405f60608251610a758161060b565b828152826020820152828482015201526001600160a01b03809216805f52600260205282825f20541615610aeb57906002915f5281602052805f209067ffffffffffffffff815194610ac68661060b565b8354908116865260a01c16602085015260018201549084015201545f0b606082015290565b8151633dd1b30560e01b8152600490fd5b5f5b838110610b0d5750505f910152565b8181015183820152602001610afe565b604051926001600160a01b03602085019316835267ffffffffffffffff809216604085015216606083015260608252610b558261060b565b610b8c60246040518093610b7c60208301966280000360e11b885251809285850190610afc565b8101036004810184520182610657565b73333333333333333333333333333333333333333390813b15610191575f91610bde918360446040518097819682956317938e1360e01b84526020600485015251809281602486015285850190610afc565b601f01601f191681010301925af18015610c0257610bf95750565b610a6390610627565b6040513d5f823e3d90fd5b3d15610c37573d90610c1e82610679565b91610c2c6040519384610657565b82523d5f602084013e565b606090565b5190811515820361019157565b905f806001600160a01b03610ca69416927f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020604051610c898161063b565b818152015260208151910182855af1610ca0610c0d565b91610d8d565b8051908115918215610cbc575b50501561019157565b8192509060209181010312610191576020610cd79101610c3c565b5f80610cb3565b60ff16604d811161070257600a0a90565b9190805f0b9081155f14610d0d57505067ffffffffffffffff821690565b5f821315610d5757610d22915060ff16610cde565b8015610d4357808306830392831161070257820467ffffffffffffffff1690565b634e487b7160e01b5f52601260045260245ffd5b505f0380805f0b0361070257610d6f9060ff16610cde565b828181029181830414901517156107025767ffffffffffffffff1690565b9015610da757815115610d9e575090565b3b156101915790565b50805190811561019157602001fdfea2646970667358221220c0cba36db139425c71e4049e05ab727a287009647e4f3ca742370867c5d7d0ff64736f6c634300081800336080806040523461005a575f8054336001600160a01b0319821681178355916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3610344908161005f8239f35b5f80fdfe608060409080825260049081361015610016575f80fd5b5f3560e01c908163715018a61461026e5781638da5cb5b1461024c57508063f2fde38b146101d45763f3fef3a31461004c575f80fd5b346101545781600319360112610154578035916001600160a01b0383168093036101545760249261007b6102d2565b8151916020830163a9059cbb60e01b815233868501528535604485015260448452608084019367ffffffffffffffff94818110868211176101c25760c08201818110878211176101b0578452602090527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460a0820152515f9182919082865af1923d1561019f573d9181831161018d57805195601f8401601f19908116603f011687019283118784101761017b575052835261013e93503d5f602085013e6102e5565b8051908115918215610158575b50501561015457005b5f80fd5b819250906020918101031261015457602001518015158103610154575f8061014b565b60418891634e487b7160e01b5f52525ffd5b86604187634e487b7160e01b5f52525ffd5b5050915061013e92506060916102e5565b88604189634e487b7160e01b5f52525ffd5b87604188634e487b7160e01b5f52525ffd5b503461015457602036600319011261015457356001600160a01b03808216809203610154576102016102d2565b8115610154575f548273ffffffffffffffffffffffffffffffffffffffff198216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b34610154575f366003190112610154576020906001600160a01b035f54168152f35b34610154575f366003190112610154576102866102d2565b5f6001600160a01b03815473ffffffffffffffffffffffffffffffffffffffff1981168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b6001600160a01b035f5416330361015457565b90156102ff578151156102f6575090565b3b156101545790565b50805190811561015457602001fdfea2646970667358221220c55691de465342d56d68c31160f5d7d661422ef39ebccaa5223872c823ad6d6964736f6c63430008180033

Deployed Bytecode

0x6040608081526004361015610012575f80fd5b5f905f3560e01c80633a5be8cb146105275780633eda20c61461045757806368c4ac26146103f2578063715018a61461038c5780637826a16e146102fa5780637bce887a146102385780638da5cb5b146102115780639b61d2d8146101db578063a4b672b614610198578063c48919d61461012c5763f2fde38b14610095575f80fd5b34610128576020366003190112610128576100ae6105df565b6100b66109f6565b6001600160a01b0380911691821561011157506001548273ffffffffffffffffffffffffffffffffffffffff19821617600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a380f35b51631e4fbdf760e01b815260048101849052602490fd5b5080fd5b8234610195576060366003190112610195576101466105df565b61014e610695565b6101566105f5565b61015e6109f6565b60025f54146101915767ffffffffffffffff602061018261018a9560025f55610a65565b015116610b1d565b6001815580f35b5f80fd5b80fd5b5034610128578160031936011261012857602090516001600160a01b037f00000000000000000000000059ee1342867c200fa8ac052faa5f3df8eef21a67168152f35b8234610195576101ea366106ac565b6101f26109f6565b60025f5414610191576001600160a01b0361018a9360025f5516610a22565b50346101285781600319360112610128576020906001600160a01b03600154169051908152f35b50903461019157610248366106ac565b90916102526109f6565b60025f54146101915760025f556001600160a01b03807f00000000000000000000000059ee1342867c200fa8ac052faa5f3df8eef21a6716911694813b1561019157805163f3fef3a360e01b81526001600160a01b038716600482015260248101859052915f908390604490829084905af19081156102f157506102dc575b5061018a9293610a22565b61018a93506102ea90610627565b5f926102d1565b513d5f823e3d90fd5b503461019157610309366106ac565b9160025f54146101915760025f5583516323b872dd60e01b60208201523360248201523060448201526064808201849052815260a08101949067ffffffffffffffff861181871017610378576103729561036d92526001600160a01b038316610c49565b610716565b60015f55005b634e487b7160e01b5f52604160045260245ffd5b34610191575f366003190112610191576103a46109f6565b5f6001600160a01b0360015473ffffffffffffffffffffffffffffffffffffffff198116600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b5034610191576020366003190112610191576080906001600160a01b0390816104196105df565b165f526002602052805f2080549167ffffffffffffffff600260018401549301545f0b938251958116865260a01c1660208501528301526060820152f35b5034610191576080366003190112610191576104716105df565b610479610695565b9060643592835f0b809403610191576002926104936109f6565b81519261049f8461060b565b6001600160a01b038091169283855267ffffffffffffffff6020860193168352808501936044358552606086019788525f52856020525f209351167bffffffffffffffff00000000000000000000000000000000000000008454925160a01b169163ffffffff60e01b161717825551600182015501905160ff198254169060ff161790555f80f35b5034610191576080366003190112610191576105416105df565b9061054a6105f5565b506064359067ffffffffffffffff8211610191573660238301121561019157816004013561058361057a82610679565b92519283610657565b8082526020820192366024838301011161019157815f9260246020930186378301015260025f54146101915760209060025f5580518101031261019157516001600160a01b038116809103610191576103729160243590610716565b600435906001600160a01b038216820361019157565b604435906001600160a01b038216820361019157565b6080810190811067ffffffffffffffff82111761037857604052565b67ffffffffffffffff811161037857604052565b6040810190811067ffffffffffffffff82111761037857604052565b90601f8019910116810190811067ffffffffffffffff82111761037857604052565b67ffffffffffffffff811161037857601f01601f191660200190565b6024359067ffffffffffffffff8216820361019157565b6060906003190112610191576001600160a01b03600435818116810361019157916024359160443590811681036101915790565b9073200000000000000000000000000000000000000091820180921161070257565b634e487b7160e01b5f52601160045260245ffd5b9161072083610a65565b67ffffffffffffffff926020908482840151169260608101515f0b926040805192828401985f806001600160a01b039b8c8c16978882528781526107638161063b565b51906108105afa610772610c0d565b90156109e557848180518101031261019157835191858301908111838210176103785784526107a2908501610c3c565b809152156107f3575b50505050906107b991610cef565b9390806107c9575b505050505050565b6107e895826107e3936107db866106e0565b169116610a22565b610b1d565b5f80808080806107c1565b810151916001830180931161070257898916937f00000000000000000000000059ee1342867c200fa8ac052faa5f3df8eef21a678a16803b1561019157835163f3fef3a360e01b81526001600160a01b038716600482015260248101869052905f908290604490829084905af180156109db576109cc575b506108768785610cef565b50806109b1575b50825191808301918252888484015260016060840152606083526108a08361060b565b6108d56024855180946108c5858301976280000360e11b895251809285850190610afc565b8101036004810185520183610657565b733333333333333333333333333333333333333333803b15610191575f92836044610924948851978896879586936317938e1360e01b8552600485015251809281602486015285850190610afc565b601f01601f191681010301925af180156109a757927f45b9d2d602535b50313ef0fa849df42dd31d8610fc42876e005a5b6806d3e8809261098b926107b998979695610998575b50516001600160a01b038a16815260208101919091529081906040820190565b0390a290915f80806107ab565b6109a190610627565b5f61096b565b82513d5f823e3d90fd5b6109c6908b6109bf8b6106e0565b1687610a22565b5f61087d565b6109d590610627565b5f61086b565b84513d5f823e3d90fd5b83516313dd7ccd60e31b8152600490fd5b6001600160a01b03600154163303610a0a57565b60405163118cdaa760e01b8152336004820152602490fd5b60405163a9059cbb60e01b60208201526001600160a01b03929092166024830152604480830193909352918152610a6391610a5e606483610657565b610c49565b565b60405f60608251610a758161060b565b828152826020820152828482015201526001600160a01b03809216805f52600260205282825f20541615610aeb57906002915f5281602052805f209067ffffffffffffffff815194610ac68661060b565b8354908116865260a01c16602085015260018201549084015201545f0b606082015290565b8151633dd1b30560e01b8152600490fd5b5f5b838110610b0d5750505f910152565b8181015183820152602001610afe565b604051926001600160a01b03602085019316835267ffffffffffffffff809216604085015216606083015260608252610b558261060b565b610b8c60246040518093610b7c60208301966280000360e11b885251809285850190610afc565b8101036004810184520182610657565b73333333333333333333333333333333333333333390813b15610191575f91610bde918360446040518097819682956317938e1360e01b84526020600485015251809281602486015285850190610afc565b601f01601f191681010301925af18015610c0257610bf95750565b610a6390610627565b6040513d5f823e3d90fd5b3d15610c37573d90610c1e82610679565b91610c2c6040519384610657565b82523d5f602084013e565b606090565b5190811515820361019157565b905f806001600160a01b03610ca69416927f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020604051610c898161063b565b818152015260208151910182855af1610ca0610c0d565b91610d8d565b8051908115918215610cbc575b50501561019157565b8192509060209181010312610191576020610cd79101610c3c565b5f80610cb3565b60ff16604d811161070257600a0a90565b9190805f0b9081155f14610d0d57505067ffffffffffffffff821690565b5f821315610d5757610d22915060ff16610cde565b8015610d4357808306830392831161070257820467ffffffffffffffff1690565b634e487b7160e01b5f52601260045260245ffd5b505f0380805f0b0361070257610d6f9060ff16610cde565b828181029181830414901517156107025767ffffffffffffffff1690565b9015610da757815115610d9e575090565b3b156101915790565b50805190811561019157602001fdfea2646970667358221220c0cba36db139425c71e4049e05ab727a287009647e4f3ca742370867c5d7d0ff64736f6c63430008180033

Block Transaction Gas Used Reward
view all blocks ##produced##

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.