Sepolia Testnet

Contract

0xB5D83c2436Ad54046d57Cd48c00D619D702F3814

Overview

ETH Balance

288.093349570805518458 ETH

Token Holdings

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Submit Message74929732025-01-14 23:28:362 days ago1736897316IN
0xB5D83c24...D702F3814
0 ETH0.000129453.90334718
Submit Message74903332025-01-14 14:39:002 days ago1736865540IN
0xB5D83c24...D702F3814
0 ETH0.0007859323.69828848
Submit Message74903312025-01-14 14:38:362 days ago1736865516IN
0xB5D83c24...D702F3814
0 ETH0.0007704423.23133857
Submit Message74896232025-01-14 12:16:362 days ago1736856996IN
0xB5D83c24...D702F3814
0 ETH0.0007151121.57859776
Submit Message74541792025-01-09 13:50:007 days ago1736430600IN
0xB5D83c24...D702F3814
0 ETH0.0010728832.58685551
Submit Message74466462025-01-08 12:36:248 days ago1736339784IN
0xB5D83c24...D702F3814
0 ETH0.0006368919.20433799
Submit Message74280612025-01-05 18:32:2411 days ago1736101944IN
0xB5D83c24...D702F3814
0 ETH0.0003943211.89015213
Submit Message74254802025-01-05 9:22:2411 days ago1736068944IN
0xB5D83c24...D702F3814
0 ETH0.000700421.25798958
Submit Message73194972024-12-20 17:50:2427 days ago1734717024IN
0xB5D83c24...D702F3814
0.0001 ETH0.0004248112.89809152
Submit Message72941552024-12-17 0:17:3631 days ago1734394656IN
0xB5D83c24...D702F3814
0 ETH0.000117033.5522567
Submit Message72847582024-12-15 15:04:2432 days ago1734275064IN
0xB5D83c24...D702F3814
0 ETH0.0020315261.65855151
Submit Message72784642024-12-14 16:55:3633 days ago1734195336IN
0xB5D83c24...D702F3814
0 ETH0.0004197912.74590794
Submit Message72722812024-12-13 19:03:4834 days ago1734116628IN
0xB5D83c24...D702F3814
0 ETH0.0003497810.54716386
Submit Message72708612024-12-13 14:03:4834 days ago1734098628IN
0xB5D83c24...D702F3814
0 ETH0.000928427.99422321
Submit Message72621462024-12-12 6:31:1235 days ago1733985072IN
0xB5D83c24...D702F3814
0 ETH0.000108623.29456076
Submit Message72585112024-12-11 17:38:3636 days ago1733938716IN
0xB5D83c24...D702F3814
0 ETH0.000210986.40603491
Submit Message72520682024-12-10 18:54:3637 days ago1733856876IN
0xB5D83c24...D702F3814
0 ETH0.0004717314.22434069
Submit Message72453782024-12-09 19:11:4838 days ago1733771508IN
0xB5D83c24...D702F3814
0 ETH0.000152684.63585599
Submit Message72103662024-12-04 15:11:0043 days ago1733325060IN
0xB5D83c24...D702F3814
0 ETH0.00025897.80688937
Submit Message72057552024-12-03 22:49:4844 days ago1733266188IN
0xB5D83c24...D702F3814
0 ETH0.000049411.50021962
Submit Message72022012024-12-03 10:17:1244 days ago1733221032IN
0xB5D83c24...D702F3814
0 ETH0.000145584.488328
Submit Message71107172024-11-19 18:23:3658 days ago1732040616IN
0xB5D83c24...D702F3814
0 ETH0.000131744
Submit Message71038322024-11-18 17:57:0059 days ago1731952620IN
0xB5D83c24...D702F3814
0 ETH0.000060331.81916664
Submit Message70987512024-11-17 23:51:2460 days ago1731887484IN
0xB5D83c24...D702F3814
0 ETH0.000049741.50000122
Submit Message70811212024-11-15 9:19:4862 days ago1731662388IN
0xB5D83c24...D702F3814
0 ETH0.000128843.88511309
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
60560692024-06-07 5:33:48224 days ago1717738428
0xB5D83c24...D702F3814
0 ETH
60538672024-06-06 22:06:00224 days ago1717711560
0xB5D83c24...D702F3814
0 ETH
60538662024-06-06 22:05:48224 days ago1717711548
0xB5D83c24...D702F3814
0 ETH
60537672024-06-06 21:43:12224 days ago1717710192
0xB5D83c24...D702F3814
0 ETH
60511332024-06-06 12:25:48224 days ago1717676748
0xB5D83c24...D702F3814
0 ETH
60510092024-06-06 11:59:48224 days ago1717675188
0xB5D83c24...D702F3814
0 ETH
58552012024-05-07 13:02:36254 days ago1715086956
0xB5D83c24...D702F3814
0.00372265 ETH
58552012024-05-07 13:02:36254 days ago1715086956
0xB5D83c24...D702F3814
0.0037222 ETH
58552012024-05-07 13:02:36254 days ago1715086956
0xB5D83c24...D702F3814
0.0037222 ETH
58551992024-05-07 13:02:00254 days ago1715086920
0xB5D83c24...D702F3814
0.00427895 ETH
58551982024-05-07 13:01:48254 days ago1715086908
0xB5D83c24...D702F3814
0.00442058 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444673 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444673 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444673 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444673 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444673 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444619 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444619 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444619 ETH
58551942024-05-07 13:01:00254 days ago1715086860
0xB5D83c24...D702F3814
0.00444673 ETH
58551932024-05-07 13:00:36254 days ago1715086836
0xB5D83c24...D702F3814
0.00458246 ETH
58551932024-05-07 13:00:36254 days ago1715086836
0xB5D83c24...D702F3814
0.00458302 ETH
58551932024-05-07 13:00:36254 days ago1715086836
0xB5D83c24...D702F3814
0.00458302 ETH
58551932024-05-07 13:00:36254 days ago1715086836
0xB5D83c24...D702F3814
0.00458302 ETH
58551932024-05-07 13:00:36254 days ago1715086836
0xB5D83c24...D702F3814
0.00458246 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Gateway

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 3 : gateway.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

import "frost-evm/sol/Schnorr.sol";
import "./BranchlessMath.sol";

/**
 * @dev Required interface of an GMP compliant contract
 */
interface IGmpReceiver {
    /**
     * @dev Handles the receipt of a single GMP message.
     * The contract must verify the msg.sender, it must be the Gateway Contract address.
     *
     * @param id The EIP-712 hash of the message payload, used as GMP unique identifier
     * @param network The chain_id of the source chain who send the message
     * @param source The pubkey/address which sent the GMP message
     * @param payload The message payload with no specified format
     * @return 32 byte result which will be stored together with GMP message
     */
    function onGmpReceived(bytes32 id, uint128 network, bytes32 source, bytes calldata payload)
        external
        payable
        returns (bytes32);
}

/**
 * @dev Required interface of an Gateway compliant contract
 */
interface IGateway {
    /**
     * @dev Emitted when `GmpMessage` is executed.
     * - `id` EIP-712 hash of the `GmpPayload`, which is it's unique identifier
     * - `source` sender pubkey/address (the format depends on src chain)
     * - `dest` recipient address
     * - `status` GMP message execution status
     * - `result` GMP result
     */
    event GmpExecuted(bytes32 indexed id, bytes32 indexed source, address indexed dest, uint256 status, bytes32 result);

    /**
     * @dev Emitted when `UpdateShardsMessage` is executed.
     * - `id` EIP-712 hash of the UpdateShardsMessage, zero for sudo
     * - `revoked` shards with keys revoked
     * - `registered` new shards registered
     */
    event KeySetChanged(bytes32 indexed id, TssKey[] revoked, TssKey[] registered);

    /**
     * @dev New GMP submitted by calling the `submitMessage` method.
     * - `id` EIP-712 hash of the `GmpPayload`, which is it's unique identifier
     * - `sender` sender account, with an extra flag indicating if it is a contract or an EOA
     * - `recipient` address or pubkey, the format depends on the destination network.
     * - `network` recipient network identifier
     * - `gasLimit` maximum gas limit for the GMP call
     * - `salt` salt is equal to the previous message id (EIP-712 hash).
     * - `data` message data with no specified format
     */
    event GmpCreated(
        bytes32 indexed id,
        bytes32 indexed sender,
        address indexed recipient,
        uint16 network,
        uint256 gasLimit,
        uint256 salt,
        bytes data
    );

    function deposit(bytes32 source, uint16 network) external payable;

    /**
     * Returns the deposit of a source against its network id
     */
    function depositOf(bytes32 source, uint16 networkId) external view returns (uint256);

    /**
     * Execute GMP message
     */
    function execute(Signature memory signature, GmpMessage memory message)
        external
        returns (uint8 status, bytes32 result);

    /**
     * Update TSS key set
     */
    function updateKeys(Signature memory signature, UpdateKeysMessage memory message) external;

    function submitMessage(address recipient, uint16 network, uint256 gasLimit, bytes memory data) external payable;
}

/**
 * @dev Tss public key
 */
struct TssKey {
    uint8 yParity; // public key y-coord parity, the contract converts it to 27/28
    uint256 xCoord; // affine x-coordinate
}

/**
 * @dev Message payload used to revoke or/and register new shards
 */
struct UpdateKeysMessage {
    TssKey[] revoke; // Keys to revoke
    TssKey[] register; // Keys to add
}

/**
 * @dev GMP payload, this is what the timechain creates as task payload
 */
struct GmpMessage {
    bytes32 source; // Pubkey/Address of who send the GMP message
    uint16 srcNetwork; // Source chain identifier (for ethereum networks it is the EIP-155 chain id)
    address dest; // Destination/Recipient contract address
    uint16 destNetwork; // Destination chain identifier (it's the EIP-155 chain_id for ethereum networks)
    uint256 gasLimit; // gas limit of the GMP call
    uint256 salt; // Message salt, useful for sending two messages with same content
    bytes data; // message data with no specified format
}

/**
 * @dev this is what must be signed using the schnorr signature,
 * OBS: what is actually signed is: keccak256(abi.encodePacked(R, parity, px, nonce, message))
 * Where `parity` is the public key y coordinate stored in the contract, and `R` is computed from `e` and `s` parameters.
 */
struct Signature {
    uint256 xCoord; // public key x coordinates, y-parity is stored in the contract
    uint256 e; // Schnorr signature e parameter
    uint256 s; // Schnorr signature s parameter
}

/**
 * @dev Shard info stored in the Gateway Contract
 * OBS: the order of the attributes matters! ethereum storage is 256bit aligned, try to keep
 * the shard info below 256 bit, so it can be stored in one single storage slot.
 * reference: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
 *
 */
struct KeyInfo {
    uint216 _gap; // gap, so we can use later for store more information about a shard
    uint8 status; // status, 0 = unregisted, 1 = active, 3 = revoked
    uint32 nonce; // shard nonce
}

/**
 * @dev GMP info stored in the Gateway Contract
 * OBS: the order of the attributes matters! ethereum storage is 256bit aligned, try to keep
 * the attributes 256 bit aligned, ex: nonce, block and status can be read in one storage access.
 * reference: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
 *
 */
struct GmpInfo {
    uint184 _gap; // gap to keep status and blocknumber 256bit aligned
    uint8 status; // message status: NOT_FOUND | PENDING | SUCCESS | REVERT
    uint64 blockNumber; // block in which the message was processed
    bytes32 result; // the result of the GMP message
}

contract SigUtils {
    // EIP-712: Typed structured data hashing and signing
    // https://eips.ethereum.org/EIPS/eip-712
    uint16 internal immutable NETWORK_ID;
    bytes32 internal immutable DOMAIN_SEPARATOR;

    constructor(uint16 networkId, address gateway) {
        NETWORK_ID = networkId;
        DOMAIN_SEPARATOR = computeDomainSeparator(networkId, gateway);
    }

    // Computes the EIP-712 domain separador
    function computeDomainSeparator(uint256 networkId, address addr) private pure returns (bytes32) {
        return keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256("Analog Gateway Contract"),
                keccak256("0.1.0"),
                uint256(networkId),
                address(addr)
            )
        );
    }

    // computes the hash of an array of tss keys
    function _getTssKeyHash(TssKey memory tssKey) private pure returns (bytes32) {
        return keccak256(abi.encode(keccak256("TssKey(uint8 yParity,uint256 xCoord)"), tssKey.yParity, tssKey.xCoord));
    }

    // computes the hash of an array of tss keys
    function _getTssKeyArrayHash(TssKey[] memory tssKeys) private pure returns (bytes32) {
        bytes memory keysHashed = new bytes(tssKeys.length * 32);
        uint256 ptr;
        assembly {
            ptr := keysHashed
        }
        for (uint256 i = 0; i < tssKeys.length; i++) {
            bytes32 hash = _getTssKeyHash(tssKeys[i]);
            assembly {
                ptr := add(ptr, 32)
                mstore(ptr, hash)
            }
        }

        return keccak256(keysHashed);
    }

    // computes the hash of the fully encoded EIP-712 message for the domain, which can be used to recover the signer
    function _getUpdateKeysHash(UpdateKeysMessage memory message) private pure returns (bytes32) {
        return keccak256(
            abi.encode(
                keccak256("UpdateKeysMessage(TssKey[] revoke,TssKey[] register)TssKey(uint8 yParity,uint256 xCoord)"),
                _getTssKeyArrayHash(message.revoke),
                _getTssKeyArrayHash(message.register)
            )
        );
    }

    function getUpdateKeysTypedHash(UpdateKeysMessage memory message) internal view returns (bytes memory) {
        return abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, _getUpdateKeysHash(message));
    }

    // computes the hash of an array of tss keys
    function _getGmpHash(GmpMessage memory gmp) private pure returns (bytes32) {
        return keccak256(
            abi.encode(
                keccak256(
                    "GmpMessage(bytes32 source,uint16 srcNetwork,address dest,uint16 destNetwork,uint256 gasLimit,uint256 salt,bytes data)"
                ),
                gmp.source,
                gmp.srcNetwork,
                gmp.dest,
                gmp.destNetwork,
                gmp.gasLimit,
                gmp.salt,
                keccak256(gmp.data)
            )
        );
    }

    // computes the hash of the fully encoded EIP-712 message for the domain, which can be used to recover the signer
    function getGmpTypedHash(GmpMessage memory message) public view returns (bytes memory) {
        return abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, _getGmpHash(message));
    }
}

contract Gateway is IGateway, SigUtils {
    uint8 internal constant GMP_STATUS_NOT_FOUND = 0; // GMP message not processed
    uint8 internal constant GMP_STATUS_SUCCESS = 1; // GMP message executed successfully
    uint8 internal constant GMP_STATUS_REVERTED = 2; // GMP message executed, but reverted
    uint8 internal constant GMP_STATUS_PENDING = 128; // GMP message is pending (used in case of reetrancy)

    uint8 internal constant SHARD_ACTIVE = (1 << 0); // Shard active bitflag
    uint8 internal constant SHARD_Y_PARITY = (1 << 1); // Pubkey y parity bitflag

    uint256 internal constant EXECUTE_GAS_DIFF = 9081; // Measured gas cost difference for `execute`

    // Non-zero value used to initialize the `prevMessageHash` storage
    bytes32 internal constant FIRST_MESSAGE_PLACEHOLDER = bytes32(uint256(2 ** 256 - 1));

    // Shard data, maps the pubkey coordX (which is already collision resistant) to shard info.
    mapping(bytes32 => KeyInfo) _shards;

    // GMP message status
    mapping(bytes32 => GmpInfo) _messages;

    // Source address => Source network => Deposit Amount
    mapping(bytes32 => mapping(uint16 => uint256)) _deposits;

    // Hash of the previous GMP message submitted.
    bytes32 public prevMessageHash;

    constructor(uint16 networkId, TssKey[] memory keys) payable SigUtils(networkId, address(this)) {
        // Initialize the prevMessageHash with a non-zero value to avoid the first GMP to spent more gas,
        // once initialize the storage cost 21k gas, while alter it cost just 2800 gas.
        prevMessageHash = FIRST_MESSAGE_PLACEHOLDER;

        _registerKeys(keys);
        // emit event
        TssKey[] memory revoked = new TssKey[](0);
        emit KeySetChanged(bytes32(0), revoked, keys);
    }

    function gmpInfo(bytes32 id) external view returns (GmpInfo memory) {
        return _messages[id];
    }

    function depositOf(bytes32 source, uint16 networkId) external view returns (uint256) {
        return _deposits[source][networkId];
    }

    function keyInfo(bytes32 id) external view returns (KeyInfo memory) {
        return _shards[id];
    }

    // Check if shard exists, verify TSS signature and increment shard nonce
    function _verifySignature(Signature memory signature, bytes32 message) private view {
        // Load shard from storage
        KeyInfo storage signer = _shards[bytes32(signature.xCoord)];

        // Verify if shard is active
        uint8 status = signer.status;
        require((status & SHARD_ACTIVE) > 0, "shard key revoked or not exists");

        // Load y parity bit, it must be 27 (even), or 28 (odd)
        // ref: https://ethereum.github.io/yellowpaper/paper.pdf
        uint8 yParity;
        if ((status & SHARD_Y_PARITY) > 0) {
            yParity = 28;
        } else {
            yParity = 27;
        }

        // Verify Signature
        require(
            Schnorr.verify(yParity, signature.xCoord, uint256(message), signature.e, signature.s),
            "invalid tss signature"
        );
    }

    // Converts a `TssKey` into an `KeyInfo` unique identifier
    function _tssKeyToShardId(TssKey memory tssKey) private pure returns (bytes32) {
        // The tssKey coord x is already collision resistant
        // if we are unsure about it, we can hash the coord and parity bit
        return bytes32(tssKey.xCoord);
    }

    function _registerKeys(TssKey[] memory keys) private {
        // We don't perform any arithmetic operation, except iterate a loop
        unchecked {
            // Register or activate tss key (revoked keys keep the previous nonce)
            for (uint256 i = 0; i < keys.length; i++) {
                TssKey memory newKey = keys[i];

                // Read shard from storage
                bytes32 shardId = _tssKeyToShardId(newKey);
                KeyInfo storage shard = _shards[shardId];
                uint8 status = shard.status;
                uint32 nonce = shard.nonce;

                // Check if the shard is not active
                require((status & SHARD_ACTIVE) == 0, "already active, cannot register again");

                // Check y-parity
                uint8 yParity = newKey.yParity;
                require(yParity == (yParity & 1), "y parity bit must be 0 or 1, cannot register shard");

                // If nonce is zero, it's a new shard, otherwise it is an existing shard which was previously revoked.
                if (nonce == 0) {
                    // if is a new shard shard, set its initial nonce to 1
                    shard.nonce = 1;
                } else {
                    // If the shard exists, the provided y-parity must match the original one
                    uint8 actualYParity = (status & SHARD_Y_PARITY) > 0 ? 1 : 0;
                    require(
                        actualYParity == yParity,
                        "the provided y-parity doesn't match the existing y-parity, cannot register shard"
                    );
                }

                // store the y-parity in the `KeyInfo`
                if (yParity > 0) {
                    // enable SHARD_Y_PARITY bitflag
                    status |= SHARD_Y_PARITY;
                } else {
                    // disable SHARD_Y_PARITY bitflag
                    status &= ~SHARD_Y_PARITY;
                }

                // enable SHARD_ACTIVE bitflag
                status |= SHARD_ACTIVE;

                // Save new status in the storage
                shard.status = status;
            }
        }
    }

    function _revokeKeys(TssKey[] memory keys) private {
        // We don't perform any arithmetic operation, except iterate a loop
        unchecked {
            // Revoke tss keys
            for (uint256 i = 0; i < keys.length; i++) {
                TssKey memory revokedKey = keys[i];

                // Read shard from storage
                bytes32 shardId = _tssKeyToShardId(revokedKey);
                KeyInfo storage shard = _shards[shardId];

                // Check if the shard exists and is active
                require(shard.nonce > 0, "shard doesn't exists, cannot revoke key");
                require((shard.status & SHARD_ACTIVE) > 0, "cannot revoke a shard key already revoked");

                // Check y-parity
                {
                    uint8 yParity = (shard.status & SHARD_Y_PARITY) > 0 ? 1 : 0;
                    require(yParity == revokedKey.yParity, "invalid y parity bit, cannot revoke key");
                }

                // Disable SHARD_ACTIVE bitflag
                shard.status = shard.status & (~SHARD_ACTIVE); // Disable active flag
            }
        }
    }

    // Register/Revoke TSS keys and emits [`KeySetChanged`] event
    function _updateKeys(bytes32 messageHash, TssKey[] memory keysToRevoke, TssKey[] memory newKeys) private {
        // We don't perform any arithmetic operation, except iterate a loop
        unchecked {
            // Revoke tss keys (revoked keys can be registred again keeping the previous nonce)
            _revokeKeys(keysToRevoke);

            // Register or activate revoked keys
            _registerKeys(newKeys);
        }
        emit KeySetChanged(messageHash, keysToRevoke, newKeys);
    }

    // Register/Revoke TSS keys using shard TSS signature
    function updateKeys(Signature memory signature, UpdateKeysMessage memory message) public {
        bytes memory payload = getUpdateKeysTypedHash(message);
        bytes32 messageHash = keccak256(payload);
        _verifySignature(signature, messageHash);

        // Register shards pubkeys
        _updateKeys(messageHash, message.revoke, message.register);
    }

    // Deposit balance to refund callers of execute
    function deposit(bytes32 source, uint16 network) public payable {
        uint256 depositBefore = _deposits[source][network];
        _deposits[source][network] = depositBefore + msg.value;
    }

    // Execute GMP message
    function _execute(bytes32 payloadHash, GmpMessage memory message) private returns (uint8 status, bytes32 result) {
        // Verify if this GMP message was already executed
        GmpInfo storage gmp = _messages[payloadHash];
        require(gmp.status == GMP_STATUS_NOT_FOUND, "message already executed");

        // Update status to `pending` to prevent reentrancy attacks.
        gmp.status = GMP_STATUS_PENDING;
        gmp.blockNumber = uint64(block.number);

        // The encoded onGmpReceived call
        bytes memory data =
            abi.encodeCall(IGmpReceiver.onGmpReceived, (payloadHash, message.srcNetwork, message.source, message.data));

        // Execute GMP call
        bytes32[1] memory output = [bytes32(0)];
        bool success;
        address dest = message.dest;

        // Cap the GMP gas limit to 80% of the block gas limit
        // OBS: we assume the remaining 20% is enough for the Gateway execution, which is a safe assumption
        // once most EVM blockchains have gas limits above 10M and don't need more than 60k gas for the Gateway execution.
        uint256 maxGasLimit = (block.gaslimit / 5) * 4; // 80% of the block gas limit
        uint256 gasLimit = BranchlessMath.min(message.gasLimit, maxGasLimit);

        // Make sure the gas left is enough to execute the GMP message
        unchecked {
            // Subtract 5000 gas, 2600 (CALL) + 2400 (other instructions with some margin)
            uint256 gasAvailable = BranchlessMath.saturatingSub(gasleft(), 5000);
            // “all but one 64th", reference: https://eips.ethereum.org/EIPS/eip-150
            gasAvailable -= gasAvailable >> 6;
            require(gasAvailable > gasLimit, "gas left below message.gasLimit");
        }
        assembly ("memory-safe") {
            // Using low-level assembly because the GMP is considered executed
            // regardless if the call reverts or not.
            let ptr := add(data, 32)
            let size := mload(data)

            // returns 1 if the call succeed, and 0 if it reverted
            success :=
                call(
                    gasLimit, // call gas limit (defined in the GMP message)
                    dest, // dest address
                    0, // value in wei to transfer (always zero for GMP)
                    ptr, // input memory pointer
                    size, // input size
                    output, // output memory pointer
                    32 // output size (fixed 32 bytes)
                )
        }

        // Get Result
        result = output[0];

        // Update GMP status
        status = uint8(BranchlessMath.choice(success, GMP_STATUS_SUCCESS, GMP_STATUS_REVERTED));

        // Persist result and status on storage
        gmp.result = result;
        gmp.status = status;

        // Emit event
        emit GmpExecuted(payloadHash, message.source, message.dest, status, result);
    }

    // Send GMP message using sudo account
    function execute(
        Signature memory signature, // coordinate x, nonce, e, s
        GmpMessage memory message
    ) public returns (uint8 status, bytes32 result) {
        uint256 initialGas = gasleft();

        // Theoretically we could remove the destination network field
        // and fill it up with the network id of the contract, then the signature will fail.
        require(message.destNetwork == NETWORK_ID, "invalid gmp network");
        bytes memory payload = getGmpTypedHash(message);
        bytes32 messageHash = keccak256(payload);
        _verifySignature(signature, messageHash);
        (status, result) = _execute(messageHash, message);
        uint256 deposited = _deposits[message.source][message.srcNetwork];

        // TODO: we must reimburse the tx base gas cost, we don't have access to it because it
        // is deducted before the contract is executed, currently it is calculated as:
        // base_gas = 21_000 + 4 * zeros + 16 * nonZeros
        uint256 refund = ((initialGas - gasleft()) + EXECUTE_GAS_DIFF) * tx.gasprice;
        require(deposited >= refund, "deposit below max refund");
        _deposits[message.source][message.srcNetwork] = deposited - refund;
        payable(tx.origin).transfer(refund);
    }

    // Submit a new GMP message
    function submitMessage(address recipient, uint16 network, uint256 gasLimit, bytes memory data) external payable {
        // TODO: charge the gas cost of the Gateway execution

        // Check if the msg.sender is a contract or an EOA
        uint256 isContract = BranchlessMath.choice(tx.origin != msg.sender, 1, 0);

        // We use 20 bytes for the address and 1 bit for contract flag
        bytes32 source = bytes32(isContract << 160) | bytes32(uint256(uint160(msg.sender)));

        // Salt is equal to the previous message id (EIP-712 hash), this allows us to establish a sequence and eaily query the message history.
        bytes32 prevHash = prevMessageHash;

        // if the messageHash is the first message, we use a zero salt
        uint256 salt = BranchlessMath.choice(prevHash == FIRST_MESSAGE_PLACEHOLDER, 0, uint256(prevHash));

        // Create GMP message and update prevMessageHash
        {
            GmpMessage memory message = GmpMessage(source, NETWORK_ID, recipient, network, gasLimit, salt, data);
            prevHash = keccak256(getGmpTypedHash(message));
            prevMessageHash = prevHash;
        }

        emit GmpCreated(prevHash, source, recipient, network, gasLimit, salt, data);
    }
}

File 2 of 3 : Schnorr.sol
//SPDX-License-Identifier: LGPLv3
pragma solidity ^0.8.0;

library Schnorr {
    // secp256k1 group order
    uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;

    // parity := public key y-coord parity (27 or 28)
    // px := public key x-coord
    // message := 32-byte message
    // e := schnorr signature challenge
    // s := schnorr signature
    function verify(uint8 parity, uint256 px, uint256 message, uint256 e, uint256 s) internal pure returns (bool) {
        // ecrecover = (m, v, r, s);
        uint256 sp = Q - mulmod(s, px, Q);
        uint256 ep = Q - mulmod(e, px, Q);

        require(sp != 0);
        // the ecrecover precompile implementation checks that the `r` and `s`
        // inputs are non-zero (in this case, `px` and `ep`), thus we don't need to
        // check if they're zero.
        address R = ecrecover(bytes32(sp), parity, bytes32(px), bytes32(ep));
        require(R != address(0), "ecrecover failed");
        return bytes32(e) == keccak256(abi.encodePacked(R, parity, px, message));
    }
}

File 3 of 3 : BranchlessMath.sol
pragma solidity >=0.7.0 <0.9.0;

/**
 * @dev Utilities for branchless operations, useful when a constant gas cost is required.
 */
library BranchlessMath {
    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 x, uint256 y) internal pure returns (uint256 result) {
        assembly ("memory-safe") {
            // gas efficient branchless min function:
            // min(x,y) = y ^ ((x ^ y) * (x < y))
            // Reference: https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
            result := xor(y, mul(xor(x, y), lt(x, y)))
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 x, uint256 y) internal pure returns (uint256 result) {
        assembly ("memory-safe") {
            // gas efficient branchless max function:
            // max(x,y) = x ^ ((x ^ y) * (x < y))
            // Reference: https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
            result := xor(x, mul(xor(x, y), lt(x, y)))
        }
    }

    /**
     * @dev If `cond` is true, use `x`, otherwise use `y`.
     */
    function choice(bool cond, uint256 x, uint256 y) internal pure returns (uint256 result) {
        assembly ("memory-safe") {
            // gas efficient branchless choice function:
            // choice(c,x,y) = x ^ ((x ^ y) * (c == 0))
            result := xor(x, mul(xor(x, y), iszero(cond)))
        }
    }

    /**
     * @dev Unsigned saturating addition, bounds to UINT256 MAX instead of overflowing.
     * equivalent to:
     * uint256 r = x + y;
     * return r >= x ? r : UINT256_MAX;
     */
    function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 result) {
        assembly ("memory-safe") {
            // add(x,y) = (x + y) | -(y > (x + y))
            x := add(x, y)
            y := sub(0, gt(y, x))
            result := or(x, y)
        }
    }

    /**
     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
     * equivalent to: x > y ? x - y : 0
     */
    function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 result) {
        assembly ("memory-safe") {
            // sub(x,y) = (x - y) * (x > y)
            result := mul(sub(x, y), gt(x, y))
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "frost-evm/=lib/frost-evm/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"uint16","name":"networkId","type":"uint16"},{"components":[{"internalType":"uint8","name":"yParity","type":"uint8"},{"internalType":"uint256","name":"xCoord","type":"uint256"}],"internalType":"struct TssKey[]","name":"keys","type":"tuple[]"}],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"sender","type":"bytes32"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint16","name":"network","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"salt","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"GmpCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"source","type":"bytes32"},{"indexed":true,"internalType":"address","name":"dest","type":"address"},{"indexed":false,"internalType":"uint256","name":"status","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"result","type":"bytes32"}],"name":"GmpExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"components":[{"internalType":"uint8","name":"yParity","type":"uint8"},{"internalType":"uint256","name":"xCoord","type":"uint256"}],"indexed":false,"internalType":"struct TssKey[]","name":"revoked","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"yParity","type":"uint8"},{"internalType":"uint256","name":"xCoord","type":"uint256"}],"indexed":false,"internalType":"struct TssKey[]","name":"registered","type":"tuple[]"}],"name":"KeySetChanged","type":"event"},{"inputs":[{"internalType":"bytes32","name":"source","type":"bytes32"},{"internalType":"uint16","name":"network","type":"uint16"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"source","type":"bytes32"},{"internalType":"uint16","name":"networkId","type":"uint16"}],"name":"depositOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"xCoord","type":"uint256"},{"internalType":"uint256","name":"e","type":"uint256"},{"internalType":"uint256","name":"s","type":"uint256"}],"internalType":"struct Signature","name":"signature","type":"tuple"},{"components":[{"internalType":"bytes32","name":"source","type":"bytes32"},{"internalType":"uint16","name":"srcNetwork","type":"uint16"},{"internalType":"address","name":"dest","type":"address"},{"internalType":"uint16","name":"destNetwork","type":"uint16"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct GmpMessage","name":"message","type":"tuple"}],"name":"execute","outputs":[{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"bytes32","name":"result","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"source","type":"bytes32"},{"internalType":"uint16","name":"srcNetwork","type":"uint16"},{"internalType":"address","name":"dest","type":"address"},{"internalType":"uint16","name":"destNetwork","type":"uint16"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct GmpMessage","name":"message","type":"tuple"}],"name":"getGmpTypedHash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"gmpInfo","outputs":[{"components":[{"internalType":"uint184","name":"_gap","type":"uint184"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint64","name":"blockNumber","type":"uint64"},{"internalType":"bytes32","name":"result","type":"bytes32"}],"internalType":"struct GmpInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"keyInfo","outputs":[{"components":[{"internalType":"uint216","name":"_gap","type":"uint216"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint32","name":"nonce","type":"uint32"}],"internalType":"struct KeyInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prevMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint16","name":"network","type":"uint16"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"submitMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"xCoord","type":"uint256"},{"internalType":"uint256","name":"e","type":"uint256"},{"internalType":"uint256","name":"s","type":"uint256"}],"internalType":"struct Signature","name":"signature","type":"tuple"},{"components":[{"components":[{"internalType":"uint8","name":"yParity","type":"uint8"},{"internalType":"uint256","name":"xCoord","type":"uint256"}],"internalType":"struct TssKey[]","name":"revoke","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"yParity","type":"uint8"},{"internalType":"uint256","name":"xCoord","type":"uint256"}],"internalType":"struct TssKey[]","name":"register","type":"tuple[]"}],"internalType":"struct UpdateKeysMessage","name":"message","type":"tuple"}],"name":"updateKeys","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c0604052604051611eab380380611eab83398101604081905261002291610436565b61ffff82166080818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f9af41c8827b204ef75a7e66226328d17ead3ef661cad3235f0653f0d6fe6ae01828401527faa7cdbe2cce2ec7b606b0e199ddd9b264a6e645e767fb8479a7917dcd1b8693f6060830152928101939093523060a08085019190915281518085038201815260c09094019091528251929091019190912090526000196003556100e281610167565b604080516000808252602082019092528161011f565b60408051808201909152600080825260208201528152602001906001900390816100f85790505b5090506000801b7f08280779918718ff44abb0d69be5f2219690cd1c4155aa887ba7c2423a921e658284604051610157929190610579565b60405180910390a25050506105bd565b60005b81518110156103bd576000828281518110610187576101876105a7565b6020026020010151905060006101a2826103c160201b60201c565b6000818152602081905260409020805491925090600160d81b810460ff811691600160e01b900463ffffffff1690600116156102335760405162461bcd60e51b815260206004820152602560248201527f616c7265616479206163746976652c2063616e6e6f742072656769737465722060448201526430b3b0b4b760d91b60648201526084015b60405180910390fd5b845160ff811660018216146102a55760405162461bcd60e51b815260206004820152603260248201527f792070617269747920626974206d7573742062652030206f7220312c2063616e6044820152711b9bdd081c9959da5cdd195c881cda185c9960721b606482015260840161022a565b8163ffffffff166000036102cb5783546001600160e01b0316600160e01b178455610377565b6000600284166102dc5760006102df565b60015b90508160ff168160ff16146103755760405162461bcd60e51b815260206004820152605060248201527f7468652070726f766964656420792d70617269747920646f65736e2774206d6160448201527f74636820746865206578697374696e6720792d7061726974792c2063616e6e6f60648201526f1d081c9959da5cdd195c881cda185c9960821b608482015260a40161022a565b505b60ff81161561038b57600283179250610393565b600219831692505b5050815460ff60d81b1916600160d81b600192831760ff16021790915592909201915061016a9050565b5050565b6020015190565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715610400576104006103c8565b60405290565b604051601f8201601f191681016001600160401b038111828210171561042e5761042e6103c8565b604052919050565b600080604080848603121561044a57600080fd5b835161ffff8116811461045c57600080fd5b602085810151919450906001600160401b038082111561047b57600080fd5b818701915087601f83011261048f57600080fd5b8151818111156104a1576104a16103c8565b6104af848260051b01610406565b818152848101925060069190911b8301840190898211156104cf57600080fd5b928401925b8184101561051f5785848b0312156104ec5760008081fd5b6104f46103de565b845160ff811681146105065760008081fd5b81528486015186820152835292850192918401916104d4565b8096505050505050509250929050565b60008151808452602080850194506020840160005b8381101561056e578151805160ff1688528301518388015260409096019590820190600101610544565b509495945050505050565b60408152600061058c604083018561052f565b828103602084015261059e818561052f565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b60805160a0516118bb6105f06000396000818161035601526106cb01526000818161045a015261052401526118bb6000f3fe6080604052600436106100865760003560e01c80638d3f97a6116100595780638d3f97a614610124578063a7ef4ebd146101d4578063b9d81984146101e7578063bdfbbea6146102cb578063d67929461461030457600080fd5b80631498212f1461008b5780632a1cf452146100ad5780634e9a2db5146100e357806379e293a814610111575b600080fd5b34801561009757600080fd5b506100ab6100a63660046113b7565b61031a565b005b3480156100b957600080fd5b506100cd6100c8366004611590565b610352565b6040516100da9190611612565b60405180910390f35b3480156100ef57600080fd5b506101036100fe36600461162c565b6103b2565b6040519081526020016100da565b6100ab61011f36600461162c565b6103d7565b34801561013057600080fd5b506101a061013f366004611658565b6040805160608082018352600080835260208084018290529284018190529384528382529282902082519384018352546001600160d81b0381168452600160d81b810460ff1691840191909152600160e01b900463ffffffff169082015290565b6040805182516001600160d81b0316815260208084015160ff16908201529181015163ffffffff16908201526060016100da565b6100ab6101e2366004611671565b610423565b3480156101f357600080fd5b50610283610202366004611658565b60408051608081018252600080825260208201819052918101829052606081019190915250600090815260016020818152604092839020835160808101855281546001600160b81b0381168252600160b81b810460ff1693820193909352600160c01b9092046001600160401b031693820193909352910154606082015290565b6040516100da919081516001600160b81b0316815260208083015160ff16908201526040808301516001600160401b0316908201526060918201519181019190915260800190565b3480156102d757600080fd5b506102eb6102e63660046116d8565b61051a565b6040805160ff90931683526020830191909152016100da565b34801561031057600080fd5b5061010360035481565b6000610325826106c7565b8051602082012090915061033984826106f3565b61034c81846000015185602001516107de565b50505050565b60607f000000000000000000000000000000000000000000000000000000000000000061037e8361082f565b60405161190160f01b6020820152602281019290925260428201526062016040516020818303038152906040529050919050565b600082815260026020908152604080832061ffff851684529091529020545b92915050565b600082815260026020908152604080832061ffff851684529091529020546103ff348261173c565b600093845260026020908152604080862061ffff9095168652939052919092205550565b60006001333214186003549091503360a083901b179060006000198214158202905060006040518060e001604052808581526020017f000000000000000000000000000000000000000000000000000000000000000061ffff1681526020018a6001600160a01b031681526020018961ffff1681526020018881526020018381526020018781525090506104b681610352565b8051906020012092508260038190555050876001600160a01b031683837f0114885f90b5168242aa31b7afb9c2e9f88e90ce329c893d3e6c56021c4c03a58a8a868b604051610508949392919061174f565b60405180910390a45050505050505050565b60008060005a90507f000000000000000000000000000000000000000000000000000000000000000061ffff16846060015161ffff16146105985760405162461bcd60e51b8152602060048201526013602482015272696e76616c696420676d70206e6574776f726b60681b60448201526064015b60405180910390fd5b60006105a385610352565b805160208201209091506105b787826106f3565b6105c181876108f2565b87516000908152600260209081526040808320828c015161ffff1684529091528120549297509095503a6123795a6105f99088611782565b610603919061173c565b61060d9190611795565b90508082101561065f5760405162461bcd60e51b815260206004820152601860248201527f6465706f7369742062656c6f77206d617820726566756e640000000000000000604482015260640161058f565b6106698183611782565b88516000908152600260209081526040808320828d015161ffff168452909152808220929092559051329183156108fc02918491818181858888f193505050501580156106ba573d6000803e3d6000fd5b5050505050509250929050565b60607f000000000000000000000000000000000000000000000000000000000000000061037e83610b19565b815160009081526020819052604090208054600160d81b900460ff8116906001166107605760405162461bcd60e51b815260206004820152601f60248201527f7368617264206b6579207265766f6b6564206f72206e6f742065786973747300604482015260640161058f565b600060028216156107735750601c610777565b50601b5b6107938186600001518660001c88602001518960400151610b75565b6107d75760405162461bcd60e51b8152602060048201526015602482015274696e76616c696420747373207369676e617475726560581b604482015260640161058f565b5050505050565b6107e782610d03565b6107f081610ed4565b827f08280779918718ff44abb0d69be5f2219690cd1c4155aa887ba7c2423a921e6583836040516108229291906117f6565b60405180910390a2505050565b60007feb1e0a6b8c4db87ab3beb15e5ae24e7c880703e1b9ee466077096eaeba83623b826000015183602001518460400151856060015186608001518760a001518860c00151805190602001206040516020016108d5989796959493929190978852602088019690965261ffff94851660408801526001600160a01b039390931660608701529216608085015260a084019190915260c083015260e08201526101000190565b604051602081830303815290604052805190602001209050919050565b60008281526001602052604081208054829190600160b81b900460ff161561095c5760405162461bcd60e51b815260206004820152601860248201527f6d65737361676520616c72656164792065786563757465640000000000000000604482015260640161058f565b80546001600160401b034316600160c01b026001600160b81b0390911617600160bf1b1781556020840151845160c08601516040516000936109a7938a939192909190602401611824565b60408051601f19818403018152918152602080830180516001600160e01b0316630190093760e01b1790528151908101825260008082529188015192935091816109f260054561184d565b6109fd906004611795565b60808a01519091508181189082110281186000610a205a61138880820391110290565b600681901c90039050818111610a785760405162461bcd60e51b815260206004820152601f60248201527f676173206c6566742062656c6f77206d6573736167652e6761734c696d697400604482015260640161058f565b50602086018651602087828460008988f187519a509550506001600386150218905060018801899055875460ff60b81b1916600160b81b60ff831690810291909117895560408c8101518d518251938452602084018d9052939c506001600160a01b031692918e917f29f318d7f9b869de8987630235eb1a1ea9d870133c3092af2510a9fed3e3da21910160405180910390a4505050505050509250929050565b60007f20196ac379740f17512afd999063959b8bfeee674b5db6c6c6f934a8fa3f1074610b498360000151611121565b610b568460200151611121565b60408051602081019490945283019190915260608201526080016108d5565b60008070014551231950b75fc4402da1732fc9bebe19868409610baa9070014551231950b75fc4402da1732fc9bebe19611782565b9050600070014551231950b75fc4402da1732fc9bebe19878609610be09070014551231950b75fc4402da1732fc9bebe19611782565b905081600003610bef57600080fd5b6040805160008082526020820180845285905260ff8b1692820192909252606081018990526080810183905260019060a0016020604051602081039080840390855afa158015610c43573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610c995760405162461bcd60e51b815260206004820152601060248201526f1958dc9958dbdd995c8819985a5b195960821b604482015260640161058f565b6040516bffffffffffffffffffffffff19606083901b1660208201526001600160f81b031960f88b901b1660348201526035810189905260558101889052607501604051602081830303815290604052805190602001208660001b14935050505095945050505050565b60005b8151811015610ed0576000828281518110610d2357610d2361186f565b602002602001015190506000610d3a826020015190565b6000818152602081905260409020805491925090600160e01b900463ffffffff16610db75760405162461bcd60e51b815260206004820152602760248201527f736861726420646f65736e2774206578697374732c2063616e6e6f74207265766044820152666f6b65206b657960c81b606482015260840161058f565b8054600160d81b9004600116610e215760405162461bcd60e51b815260206004820152602960248201527f63616e6e6f74207265766f6b652061207368617264206b657920616c726561646044820152681e481c995d9bdad95960ba1b606482015260840161058f565b8054600090600160d81b9004600216610e3b576000610e3e565b60015b9050836000015160ff168160ff1614610ea95760405162461bcd60e51b815260206004820152602760248201527f696e76616c6964207920706172697479206269742c2063616e6e6f74207265766044820152666f6b65206b657960c81b606482015260840161058f565b50805460ff60d81b198116600160d81b9182900460fe169091021790555050600101610d06565b5050565b60005b8151811015610ed0576000828281518110610ef457610ef461186f565b602002602001015190506000610f0b826020015190565b6000818152602081905260409020805491925090600160d81b810460ff811691600160e01b900463ffffffff169060011615610f975760405162461bcd60e51b815260206004820152602560248201527f616c7265616479206163746976652c2063616e6e6f742072656769737465722060448201526430b3b0b4b760d91b606482015260840161058f565b845160ff811660018216146110095760405162461bcd60e51b815260206004820152603260248201527f792070617269747920626974206d7573742062652030206f7220312c2063616e6044820152711b9bdd081c9959da5cdd195c881cda185c9960721b606482015260840161058f565b8163ffffffff1660000361102f5783546001600160e01b0316600160e01b1784556110db565b600060028416611040576000611043565b60015b90508160ff168160ff16146110d95760405162461bcd60e51b815260206004820152605060248201527f7468652070726f766964656420792d70617269747920646f65736e2774206d6160448201527f74636820746865206578697374696e6720792d7061726974792c2063616e6e6f60648201526f1d081c9959da5cdd195c881cda185c9960821b608482015260a40161058f565b505b60ff8116156110ef576002831792506110f7565b600219831692505b5050815460ff60d81b1916600160d81b600192831760ff160217909155929092019150610ed79050565b600080825160206111329190611795565b6001600160401b0381111561114957611149611219565b6040519080825280601f01601f191660200182016040528015611173576020820181803683370190505b5090508060005b84518110156111b95760006111a786838151811061119a5761119a61186f565b60200260200101516111c9565b6020939093019283525060010161117a565b5050805160209091012092915050565b80516020808301516040516000936108d5937f811c696df5f31d44fda354b9ceaa10237015e73b631a3eb69dbca953eac4a5009391920192835260ff919091166020830152604082015260600190565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561125157611251611219565b60405290565b60405160e081016001600160401b038111828210171561125157611251611219565b604051601f8201601f191681016001600160401b03811182821017156112a1576112a1611219565b604052919050565b6000606082840312156112bb57600080fd5b604051606081018181106001600160401b03821117156112dd576112dd611219565b80604052508091508235815260208301356020820152604083013560408201525092915050565b600082601f83011261131557600080fd5b813560206001600160401b0382111561133057611330611219565b61133e818360051b01611279565b82815260069290921b8401810191818101908684111561135d57600080fd5b8286015b848110156113ac576040818903121561137a5760008081fd5b61138261122f565b813560ff811681146113945760008081fd5b81528185013585820152835291830191604001611361565b509695505050505050565b600080608083850312156113ca57600080fd5b6113d484846112a9565b915060608301356001600160401b03808211156113f057600080fd5b908401906040828703121561140457600080fd5b61140c61122f565b82358281111561141b57600080fd5b61142788828601611304565b82525060208301358281111561143c57600080fd5b61144888828601611304565b6020830152508093505050509250929050565b803561ffff8116811461146d57600080fd5b919050565b80356001600160a01b038116811461146d57600080fd5b600082601f83011261149a57600080fd5b81356001600160401b038111156114b3576114b3611219565b6114c6601f8201601f1916602001611279565b8181528460208386010111156114db57600080fd5b816020850160208301376000918101602001919091529392505050565b600060e0828403121561150a57600080fd5b611512611257565b9050813581526115246020830161145b565b602082015261153560408301611472565b60408201526115466060830161145b565b60608201526080820135608082015260a082013560a082015260c08201356001600160401b0381111561157857600080fd5b61158484828501611489565b60c08301525092915050565b6000602082840312156115a257600080fd5b81356001600160401b038111156115b857600080fd5b6115c4848285016114f8565b949350505050565b6000815180845260005b818110156115f2576020818501810151868301820152016115d6565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061162560208301846115cc565b9392505050565b6000806040838503121561163f57600080fd5b8235915061164f6020840161145b565b90509250929050565b60006020828403121561166a57600080fd5b5035919050565b6000806000806080858703121561168757600080fd5b61169085611472565b935061169e6020860161145b565b92506040850135915060608501356001600160401b038111156116c057600080fd5b6116cc87828801611489565b91505092959194509250565b600080608083850312156116eb57600080fd5b6116f584846112a9565b915060608301356001600160401b0381111561171057600080fd5b61171c858286016114f8565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103d1576103d1611726565b61ffff8516815283602082015282604082015260806060820152600061177860808301846115cc565b9695505050505050565b818103818111156103d1576103d1611726565b80820281158282048414176103d1576103d1611726565b60008151808452602080850194506020840160005b838110156117eb578151805160ff16885283015183880152604090960195908201906001016117c1565b509495945050505050565b60408152600061180960408301856117ac565b828103602084015261181b81856117ac565b95945050505050565b84815261ffff8416602082015282604082015260806060820152600061177860808301846115cc565b60008261186a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220e597ea991356b942c3027ae1235720bad340395d40fe5e7a2cb48a74f6436b5564736f6c634300081900330000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ea799c7abe5e749b5e7c180ea319eee79c36cc89cae50ba26aeae11d2f1ce54d

Deployed Bytecode

0x6080604052600436106100865760003560e01c80638d3f97a6116100595780638d3f97a614610124578063a7ef4ebd146101d4578063b9d81984146101e7578063bdfbbea6146102cb578063d67929461461030457600080fd5b80631498212f1461008b5780632a1cf452146100ad5780634e9a2db5146100e357806379e293a814610111575b600080fd5b34801561009757600080fd5b506100ab6100a63660046113b7565b61031a565b005b3480156100b957600080fd5b506100cd6100c8366004611590565b610352565b6040516100da9190611612565b60405180910390f35b3480156100ef57600080fd5b506101036100fe36600461162c565b6103b2565b6040519081526020016100da565b6100ab61011f36600461162c565b6103d7565b34801561013057600080fd5b506101a061013f366004611658565b6040805160608082018352600080835260208084018290529284018190529384528382529282902082519384018352546001600160d81b0381168452600160d81b810460ff1691840191909152600160e01b900463ffffffff169082015290565b6040805182516001600160d81b0316815260208084015160ff16908201529181015163ffffffff16908201526060016100da565b6100ab6101e2366004611671565b610423565b3480156101f357600080fd5b50610283610202366004611658565b60408051608081018252600080825260208201819052918101829052606081019190915250600090815260016020818152604092839020835160808101855281546001600160b81b0381168252600160b81b810460ff1693820193909352600160c01b9092046001600160401b031693820193909352910154606082015290565b6040516100da919081516001600160b81b0316815260208083015160ff16908201526040808301516001600160401b0316908201526060918201519181019190915260800190565b3480156102d757600080fd5b506102eb6102e63660046116d8565b61051a565b6040805160ff90931683526020830191909152016100da565b34801561031057600080fd5b5061010360035481565b6000610325826106c7565b8051602082012090915061033984826106f3565b61034c81846000015185602001516107de565b50505050565b60607f42487e60b8430b462aaec984dbc48065224b826d2de7f497b18c3fd5578fe77761037e8361082f565b60405161190160f01b6020820152602281019290925260428201526062016040516020818303038152906040529050919050565b600082815260026020908152604080832061ffff851684529091529020545b92915050565b600082815260026020908152604080832061ffff851684529091529020546103ff348261173c565b600093845260026020908152604080862061ffff9095168652939052919092205550565b60006001333214186003549091503360a083901b179060006000198214158202905060006040518060e001604052808581526020017f000000000000000000000000000000000000000000000000000000000000000561ffff1681526020018a6001600160a01b031681526020018961ffff1681526020018881526020018381526020018781525090506104b681610352565b8051906020012092508260038190555050876001600160a01b031683837f0114885f90b5168242aa31b7afb9c2e9f88e90ce329c893d3e6c56021c4c03a58a8a868b604051610508949392919061174f565b60405180910390a45050505050505050565b60008060005a90507f000000000000000000000000000000000000000000000000000000000000000561ffff16846060015161ffff16146105985760405162461bcd60e51b8152602060048201526013602482015272696e76616c696420676d70206e6574776f726b60681b60448201526064015b60405180910390fd5b60006105a385610352565b805160208201209091506105b787826106f3565b6105c181876108f2565b87516000908152600260209081526040808320828c015161ffff1684529091528120549297509095503a6123795a6105f99088611782565b610603919061173c565b61060d9190611795565b90508082101561065f5760405162461bcd60e51b815260206004820152601860248201527f6465706f7369742062656c6f77206d617820726566756e640000000000000000604482015260640161058f565b6106698183611782565b88516000908152600260209081526040808320828d015161ffff168452909152808220929092559051329183156108fc02918491818181858888f193505050501580156106ba573d6000803e3d6000fd5b5050505050509250929050565b60607f42487e60b8430b462aaec984dbc48065224b826d2de7f497b18c3fd5578fe77761037e83610b19565b815160009081526020819052604090208054600160d81b900460ff8116906001166107605760405162461bcd60e51b815260206004820152601f60248201527f7368617264206b6579207265766f6b6564206f72206e6f742065786973747300604482015260640161058f565b600060028216156107735750601c610777565b50601b5b6107938186600001518660001c88602001518960400151610b75565b6107d75760405162461bcd60e51b8152602060048201526015602482015274696e76616c696420747373207369676e617475726560581b604482015260640161058f565b5050505050565b6107e782610d03565b6107f081610ed4565b827f08280779918718ff44abb0d69be5f2219690cd1c4155aa887ba7c2423a921e6583836040516108229291906117f6565b60405180910390a2505050565b60007feb1e0a6b8c4db87ab3beb15e5ae24e7c880703e1b9ee466077096eaeba83623b826000015183602001518460400151856060015186608001518760a001518860c00151805190602001206040516020016108d5989796959493929190978852602088019690965261ffff94851660408801526001600160a01b039390931660608701529216608085015260a084019190915260c083015260e08201526101000190565b604051602081830303815290604052805190602001209050919050565b60008281526001602052604081208054829190600160b81b900460ff161561095c5760405162461bcd60e51b815260206004820152601860248201527f6d65737361676520616c72656164792065786563757465640000000000000000604482015260640161058f565b80546001600160401b034316600160c01b026001600160b81b0390911617600160bf1b1781556020840151845160c08601516040516000936109a7938a939192909190602401611824565b60408051601f19818403018152918152602080830180516001600160e01b0316630190093760e01b1790528151908101825260008082529188015192935091816109f260054561184d565b6109fd906004611795565b60808a01519091508181189082110281186000610a205a61138880820391110290565b600681901c90039050818111610a785760405162461bcd60e51b815260206004820152601f60248201527f676173206c6566742062656c6f77206d6573736167652e6761734c696d697400604482015260640161058f565b50602086018651602087828460008988f187519a509550506001600386150218905060018801899055875460ff60b81b1916600160b81b60ff831690810291909117895560408c8101518d518251938452602084018d9052939c506001600160a01b031692918e917f29f318d7f9b869de8987630235eb1a1ea9d870133c3092af2510a9fed3e3da21910160405180910390a4505050505050509250929050565b60007f20196ac379740f17512afd999063959b8bfeee674b5db6c6c6f934a8fa3f1074610b498360000151611121565b610b568460200151611121565b60408051602081019490945283019190915260608201526080016108d5565b60008070014551231950b75fc4402da1732fc9bebe19868409610baa9070014551231950b75fc4402da1732fc9bebe19611782565b9050600070014551231950b75fc4402da1732fc9bebe19878609610be09070014551231950b75fc4402da1732fc9bebe19611782565b905081600003610bef57600080fd5b6040805160008082526020820180845285905260ff8b1692820192909252606081018990526080810183905260019060a0016020604051602081039080840390855afa158015610c43573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610c995760405162461bcd60e51b815260206004820152601060248201526f1958dc9958dbdd995c8819985a5b195960821b604482015260640161058f565b6040516bffffffffffffffffffffffff19606083901b1660208201526001600160f81b031960f88b901b1660348201526035810189905260558101889052607501604051602081830303815290604052805190602001208660001b14935050505095945050505050565b60005b8151811015610ed0576000828281518110610d2357610d2361186f565b602002602001015190506000610d3a826020015190565b6000818152602081905260409020805491925090600160e01b900463ffffffff16610db75760405162461bcd60e51b815260206004820152602760248201527f736861726420646f65736e2774206578697374732c2063616e6e6f74207265766044820152666f6b65206b657960c81b606482015260840161058f565b8054600160d81b9004600116610e215760405162461bcd60e51b815260206004820152602960248201527f63616e6e6f74207265766f6b652061207368617264206b657920616c726561646044820152681e481c995d9bdad95960ba1b606482015260840161058f565b8054600090600160d81b9004600216610e3b576000610e3e565b60015b9050836000015160ff168160ff1614610ea95760405162461bcd60e51b815260206004820152602760248201527f696e76616c6964207920706172697479206269742c2063616e6e6f74207265766044820152666f6b65206b657960c81b606482015260840161058f565b50805460ff60d81b198116600160d81b9182900460fe169091021790555050600101610d06565b5050565b60005b8151811015610ed0576000828281518110610ef457610ef461186f565b602002602001015190506000610f0b826020015190565b6000818152602081905260409020805491925090600160d81b810460ff811691600160e01b900463ffffffff169060011615610f975760405162461bcd60e51b815260206004820152602560248201527f616c7265616479206163746976652c2063616e6e6f742072656769737465722060448201526430b3b0b4b760d91b606482015260840161058f565b845160ff811660018216146110095760405162461bcd60e51b815260206004820152603260248201527f792070617269747920626974206d7573742062652030206f7220312c2063616e6044820152711b9bdd081c9959da5cdd195c881cda185c9960721b606482015260840161058f565b8163ffffffff1660000361102f5783546001600160e01b0316600160e01b1784556110db565b600060028416611040576000611043565b60015b90508160ff168160ff16146110d95760405162461bcd60e51b815260206004820152605060248201527f7468652070726f766964656420792d70617269747920646f65736e2774206d6160448201527f74636820746865206578697374696e6720792d7061726974792c2063616e6e6f60648201526f1d081c9959da5cdd195c881cda185c9960821b608482015260a40161058f565b505b60ff8116156110ef576002831792506110f7565b600219831692505b5050815460ff60d81b1916600160d81b600192831760ff160217909155929092019150610ed79050565b600080825160206111329190611795565b6001600160401b0381111561114957611149611219565b6040519080825280601f01601f191660200182016040528015611173576020820181803683370190505b5090508060005b84518110156111b95760006111a786838151811061119a5761119a61186f565b60200260200101516111c9565b6020939093019283525060010161117a565b5050805160209091012092915050565b80516020808301516040516000936108d5937f811c696df5f31d44fda354b9ceaa10237015e73b631a3eb69dbca953eac4a5009391920192835260ff919091166020830152604082015260600190565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561125157611251611219565b60405290565b60405160e081016001600160401b038111828210171561125157611251611219565b604051601f8201601f191681016001600160401b03811182821017156112a1576112a1611219565b604052919050565b6000606082840312156112bb57600080fd5b604051606081018181106001600160401b03821117156112dd576112dd611219565b80604052508091508235815260208301356020820152604083013560408201525092915050565b600082601f83011261131557600080fd5b813560206001600160401b0382111561133057611330611219565b61133e818360051b01611279565b82815260069290921b8401810191818101908684111561135d57600080fd5b8286015b848110156113ac576040818903121561137a5760008081fd5b61138261122f565b813560ff811681146113945760008081fd5b81528185013585820152835291830191604001611361565b509695505050505050565b600080608083850312156113ca57600080fd5b6113d484846112a9565b915060608301356001600160401b03808211156113f057600080fd5b908401906040828703121561140457600080fd5b61140c61122f565b82358281111561141b57600080fd5b61142788828601611304565b82525060208301358281111561143c57600080fd5b61144888828601611304565b6020830152508093505050509250929050565b803561ffff8116811461146d57600080fd5b919050565b80356001600160a01b038116811461146d57600080fd5b600082601f83011261149a57600080fd5b81356001600160401b038111156114b3576114b3611219565b6114c6601f8201601f1916602001611279565b8181528460208386010111156114db57600080fd5b816020850160208301376000918101602001919091529392505050565b600060e0828403121561150a57600080fd5b611512611257565b9050813581526115246020830161145b565b602082015261153560408301611472565b60408201526115466060830161145b565b60608201526080820135608082015260a082013560a082015260c08201356001600160401b0381111561157857600080fd5b61158484828501611489565b60c08301525092915050565b6000602082840312156115a257600080fd5b81356001600160401b038111156115b857600080fd5b6115c4848285016114f8565b949350505050565b6000815180845260005b818110156115f2576020818501810151868301820152016115d6565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061162560208301846115cc565b9392505050565b6000806040838503121561163f57600080fd5b8235915061164f6020840161145b565b90509250929050565b60006020828403121561166a57600080fd5b5035919050565b6000806000806080858703121561168757600080fd5b61169085611472565b935061169e6020860161145b565b92506040850135915060608501356001600160401b038111156116c057600080fd5b6116cc87828801611489565b91505092959194509250565b600080608083850312156116eb57600080fd5b6116f584846112a9565b915060608301356001600160401b0381111561171057600080fd5b61171c858286016114f8565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b808201808211156103d1576103d1611726565b61ffff8516815283602082015282604082015260806060820152600061177860808301846115cc565b9695505050505050565b818103818111156103d1576103d1611726565b80820281158282048414176103d1576103d1611726565b60008151808452602080850194506020840160005b838110156117eb578151805160ff16885283015183880152604090960195908201906001016117c1565b509495945050505050565b60408152600061180960408301856117ac565b828103602084015261181b81856117ac565b95945050505050565b84815261ffff8416602082015282604082015260806060820152600061177860808301846115cc565b60008261186a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220e597ea991356b942c3027ae1235720bad340395d40fe5e7a2cb48a74f6436b5564736f6c63430008190033

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

0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ea799c7abe5e749b5e7c180ea319eee79c36cc89cae50ba26aeae11d2f1ce54d

-----Decoded View---------------
Arg [0] : networkId (uint16): 5
Arg [1] : keys (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : ea799c7abe5e749b5e7c180ea319eee79c36cc89cae50ba26aeae11d2f1ce54d


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.