Contract 0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c 3

 
Txn Hash Method
Block
From
To
Value
0x24455536c1fba7f2053b44c74549acb0236af716e040493b918167dbe157491dDeliver Compute133532312024-04-19 3:03:292 secs ago0x9b87c21f9d8ab20a806a7576dfc15f30986f7c3d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000024011340.077544911
0xdedf6ff0e167e6eb9ccf40d60183e87572768ea678b6d09c10714ce692d9b17bDeliver Compute133532312024-04-19 3:03:292 secs ago0xbc23b4da3e1d8a54f41cebd88e075e5c91692bf4 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000024011340.077544911
0x0cd13809676077e3ffeb90d0891f526b4ab88ee4742ba3af0f08bb6b85256b96Deliver Compute133532312024-04-19 3:03:292 secs ago0x166a51b5961d73d770fab908abba47eb10fccf1d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000024007070.077544911
0x6ec69cfda898f20d864e9a69eba299432a32bffc4ee3a02c294b26e881d274d3Deliver Compute133532312024-04-19 3:03:292 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000024011340.077544911
0x165ac67873557f1bb23c07121c3234e42119c8e27fdf6cb22f84b01e9fa8491eDeliver Compute133532312024-04-19 3:03:292 secs ago0x84188a8a8e5726aeb5c74877ab538ca81bbf053f IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000024007070.077544911
0xa3ea57d6cd69d180231637c48b28a6f20d5417bfd23111fa085efdd5343e9820Deliver Compute133532292024-04-19 3:03:256 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023851570.077457612
0x1ba716a1bd654195b339da4ddfbccf2dbb425e4553f0ef8266baf7e545f43d4aDeliver Compute133532282024-04-19 3:03:238 secs ago0x84188a8a8e5726aeb5c74877ab538ca81bbf053f IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023883030.077577493
0x4305d1e8f0c7e288f5e626d851602281ae8e78dd4d74b1c53308c24a7b4269a1Deliver Compute133532272024-04-19 3:03:2110 secs ago0x166a51b5961d73d770fab908abba47eb10fccf1d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023899120.077641862
0x372c07adda3d350c63eec87becc723e96dbb6933480d4fd03796510b0570efd0Deliver Compute133532272024-04-19 3:03:2110 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023902910.077641862
0x9cffdb242d0cf26835345c23853c20a779a9762af4fa0d648ef406d6b2712e98Deliver Compute133532262024-04-19 3:03:1912 secs ago0x9b87c21f9d8ab20a806a7576dfc15f30986f7c3d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023888740.077584019
0xd767b5665aa777b10adb01a79ef3d721668605b0de3be524a48a5185b47c6ab9Deliver Compute133532262024-04-19 3:03:1912 secs ago0xbc23b4da3e1d8a54f41cebd88e075e5c91692bf4 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.000002388590.077584019
0x2015fcf5d7191c70ce99c2186184f2068bd3eabcfbecb361f926c49fb255a6aeDeliver Compute133532262024-04-19 3:03:1912 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023884950.077584019
0x9ec00cba27b390fe20c24764f527722a9df6a79b4697176011cd09be8488f5f3Deliver Compute133532262024-04-19 3:03:1912 secs ago0x84188a8a8e5726aeb5c74877ab538ca81bbf053f IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023882110.077584019
0x37291b7e007ed466ba185b3b6505a0660ff7707b5c04ff463f13483cdd9d4db9Deliver Compute133532262024-04-19 3:03:1912 secs ago0x166a51b5961d73d770fab908abba47eb10fccf1d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023884950.077584019
0x170810600e99e9137d3121da6b974c82ed438a7802211cfcf67bd66333cc91d7Deliver Compute133532242024-04-19 3:03:1516 secs ago0x166a51b5961d73d770fab908abba47eb10fccf1d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023823140.077383485
0xe9c3a0d22df03b686169565238916d038ebbdffc4fd5bd36315b3ffb458ccc19Deliver Compute133532242024-04-19 3:03:1516 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023820290.077383485
0x2389a89ca40d02d0e2c9cd32c7c7c6269ab50e17331ca1873bd8687a2bb90a2fDeliver Compute133532232024-04-19 3:03:1318 secs ago0x84188a8a8e5726aeb5c74877ab538ca81bbf053f IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023896670.077526045
0xf3a2cfd744450d6b75bd976c25494dfbc13662ba28cbc8a0f9548834e46db3f4Deliver Compute133532222024-04-19 3:03:1120 secs ago0x166a51b5961d73d770fab908abba47eb10fccf1d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023929980.077629358
0xd7e5f1ddc58212f09ae21259cc46a8b9b62b4a84e16dac0f5c3aee2d2171234eDeliver Compute133532222024-04-19 3:03:1120 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023927050.077629358
0x864593349d597c30aae25e7d5234fdb0487cfe7be402e90e6b83bef8b84ed469Deliver Compute133532222024-04-19 3:03:1120 secs ago0xbc23b4da3e1d8a54f41cebd88e075e5c91692bf4 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023933880.077629358
0x52d8512d1a54dd39fea74d4e3d58dc290db59f0b5765626a83a2166625f747c5Deliver Compute133532212024-04-19 3:03:0922 secs ago0x9b87c21f9d8ab20a806a7576dfc15f30986f7c3d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023922980.077592274
0x015331ff0aeb0d7b4e3c9b6435371f92dd149b7ab60884d079c0fb23a3b3d3e9Deliver Compute133532212024-04-19 3:03:0922 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023916150.077592274
0x3c3cd13402ef2e3d7bacd8ede5abb539e66c1e233f858267432552b90f76d67dDeliver Compute133532212024-04-19 3:03:0922 secs ago0x84188a8a8e5726aeb5c74877ab538ca81bbf053f IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023919080.077592274
0x3b60ae5daa998d8e7f89f23c63ab64962c81a00353bac4007f5ad21472993206Deliver Compute133532212024-04-19 3:03:0922 secs ago0x166a51b5961d73d770fab908abba47eb10fccf1d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023919080.077592274
0xe02168c7d462fa2a789548d47bebfb6264549f103f912ec7f7f9d82821598bc5Deliver Compute133532192024-04-19 3:03:0526 secs ago0x48524fada7402c2f0f9b64715302fdc133ae2818 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000023932540.077638061
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EIP712Coordinator

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion, GNU GPLv3 license
File 1 of 7 : EIP712Coordinator.sol
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.4;

import {ECDSA} from "solady/utils/ECDSA.sol";
import {Coordinator} from "./Coordinator.sol";
import {EIP712} from "solady/utils/EIP712.sol";
import {Delegator} from "./pattern/Delegator.sol";

/// @title EIP712Coordinator
/// @notice Coordinator enhanced with ability to created subscriptions via off-chain EIP-712 signature
/// @dev Allows creating a subscription on behalf of a contract via delegatee EOA signature
/// @dev Allows nodes to atomically create subscriptions and deliver compute responses
contract EIP712Coordinator is EIP712, Coordinator {
    /*//////////////////////////////////////////////////////////////
                               CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /// @notice EIP-712 signing domain major version
    string public constant EIP712_VERSION = "1";

    /// @notice EIP-712 signing domain name
    string public constant EIP712_NAME = "InfernetCoordinator";

    /// @notice Gas overhead in wei to retrieve cached subscriptionId for existing delegatee-created subscription
    /// @dev A uint16 is sufficient but increases control plane costs. While we can pack this and the subsequent uint24
    ///      in contract storage to save data plane costs, we prioritize control plane and instead simply use a uint256
    uint256 public constant DELEGATEE_OVERHEAD_CACHED_WEI = 600 wei;

    /// @notice Gas overhead in wei to create a new subscription via delegatee signature
    /// @dev Make note that this does not account for gas costs of dynamic inputs (containerId, inputs), just base overhead
    /// @dev Can fit within uint24, see comment for `DELEGATEE_OVERHEAD_CACHED_WEI` for details
    uint256 public constant DELEGATEE_OVERHEAD_CREATE_WEI = 91_200 wei;

    /// @notice EIP-712 struct(Subscription) typeHash
    bytes32 private constant EIP712_SUBSCRIPTION_TYPEHASH = keccak256(
        "Subscription(address owner,uint32 activeAt,uint32 period,uint32 frequency,uint16 redundancy,uint48 maxGasPrice,uint32 maxGasLimit,string containerId,bytes inputs)"
    );

    /// @notice EIP-712 struct(DelegateSubscription) typeHash
    /// @dev struct(DelegateSubscription) == { uint32 nonce, uint32 expiry, Subscription sub }
    /// @dev The `nonce` represents the nonce of the subscribing contract (sub-owner); prevents signature replay
    /// @dev The `expiry` is when the delegated subscription signature expires and can no longer be used
    bytes32 private constant EIP712_DELEGATE_SUBSCRIPTION_TYPEHASH = keccak256(
        "DelegateSubscription(uint32 nonce,uint32 expiry,Subscription sub)Subscription(address owner,uint32 activeAt,uint32 period,uint32 frequency,uint16 redundancy,uint48 maxGasPrice,uint32 maxGasLimit,string containerId,bytes inputs)"
    );

    /*//////////////////////////////////////////////////////////////
                                MUTABLE
    //////////////////////////////////////////////////////////////*/

    /// @notice Subscribing contract => maximum seen nonce
    /// @dev The nonce is a uint32 size(4.2B) which would take > 100 years of incrementing nonce per second to overflow
    mapping(address => uint32) public maxSubscriberNonce;

    /// @notice hash(subscribing contract, nonce) => subscriptionId
    /// @notice Allows lookup between a delegated subscription creation (unique(subscriber, nonce)) and subscriptionId
    mapping(bytes32 => uint32) public delegateCreatedIds;

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

    /// @notice Thrown by `createSubscriptionDelegatee()` if subscription signature does not match contract delegatee
    /// @dev 4-byte signature: `0x10c74b03`
    error SignerMismatch();

    /// @notice Thrown by `createSubscriptionDelegatee()` if signature for delegated subscription has expired
    /// @dev 4-byte signature: `0x0819bdcd`
    error SignatureExpired();

    /*//////////////////////////////////////////////////////////////
                           OVERRIDE FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Overrides Solady.EIP712._domainNameAndVersion to return EIP712-compatible domain name, version
    function _domainNameAndVersion() internal pure override returns (string memory, string memory) {
        return (EIP712_NAME, EIP712_VERSION);
    }

    /// @notice Overrides Solady.EIP712._domainNameAndVersionMayChange to always return false since the domain params are not updateable
    function _domainNameAndVersionMayChange() internal pure override returns (bool) {
        return false;
    }

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

    /// @notice Allows a delegatee to create a subscription on behalf of a subscribing contract (sub.owner)
    /// @dev Unlike `Coordinator.createSubscription()`, offers maximum flexibility to set subscription parameters
    /// @param nonce subscribing contract nonce (included in signature)
    /// @param expiry delegated subscription signature expiry (included in signature)
    /// @param sub subscription to create
    /// @param v ECDSA recovery id
    /// @param r ECDSA signature output (r)
    /// @param s ECDSA signature output (s)
    /// @return 0: subscriptionId (if subscription exists, returns existing ID, else returns new ID),
    ///         1: exists (true if returning existing subscription, else false)
    function createSubscriptionDelegatee(
        uint32 nonce,
        uint32 expiry,
        Subscription calldata sub,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public returns (uint32, bool) {
        // Check if subscription already exists via delegate-created lookup table
        bytes32 key = keccak256(abi.encode(sub.owner, nonce));
        uint32 subscriptionId = delegateCreatedIds[key];

        // If subscription exists, return existing subscriptionId
        // This implicitly prevents nonce replay because if the nonce was already used, a subscription would exist
        if (subscriptionId != 0) {
            return (subscriptionId, true);
        }

        // Else, if subscription does not exist
        // First, verify that signature has not expired
        if (uint32(block.timestamp) >= expiry) {
            revert SignatureExpired();
        }

        // Generate EIP-712 data
        bytes32 digest = _hashTypedData(
            keccak256(
                // Encode(DelegateSubscription, nonce, expiry, sub)
                abi.encode(
                    EIP712_DELEGATE_SUBSCRIPTION_TYPEHASH,
                    nonce,
                    expiry,
                    // Encode(Subscription, sub)
                    keccak256(
                        abi.encode(
                            EIP712_SUBSCRIPTION_TYPEHASH,
                            sub.owner,
                            sub.activeAt,
                            sub.period,
                            sub.frequency,
                            sub.redundancy,
                            sub.maxGasPrice,
                            sub.maxGasLimit,
                            // Hash dynamic values
                            keccak256(bytes(sub.containerId)),
                            keccak256(sub.inputs)
                        )
                    )
                )
            )
        );

        // Get recovered signer from data
        // Throws `InvalidSignature()` (4-byte signature: `0x8baa579f`) if can't recover signer
        address recoveredSigner = ECDSA.recover(digest, v, r, s);

        // Collect delegated signer from subscribing contract
        address delegatedSigner = Delegator(sub.owner).signer();

        // Verify signatures (recoveredSigner should equal delegatedSigner)
        if (recoveredSigner != delegatedSigner) {
            revert SignerMismatch();
        }

        // By this point, the signer is verified and a net-new subscription can be created
        // Assign new subscription id
        // Unlikely this will ever overflow so we can toss in unchecked
        unchecked {
            subscriptionId = id++;
        }

        // Store provided subscription as-is
        subscriptions[subscriptionId] = sub;

        // Update delegate-created ID lookup table
        delegateCreatedIds[key] = subscriptionId;

        // Emit new subscription
        emit SubscriptionCreated(subscriptionId);

        // Update max known subscriber nonce (useful for off-chain signing utilities to prevent nonce-collision)
        if (nonce > maxSubscriberNonce[sub.owner]) {
            maxSubscriberNonce[sub.owner] = nonce;
        }

        // Explicitly return subscriptionId
        return (subscriptionId, false);
    }

    /// @notice Allows active nodes to (1) atomically create or collect subscription via signed EIP-712 message,
    ///         (2) deliver container compute responses for created or collected subscription
    /// @param nonce subscribing contract nonce (included in signature)
    /// @param expiry delegated subscription signature expiry (included in signature)
    /// @param sub subscription to create
    /// @param v ECDSA recovery id
    /// @param r ECDSA signature output (r)
    /// @param s ECDSA signature output (s)
    /// @param deliveryInterval subscription `interval`
    /// @param input optional off-chain input recorded by Infernet node (empty, hashed input, processed input, or both)
    /// @param output optional off-chain container output (empty, hashed output, processed output, both, or fallback: all encodeable data)
    /// @param proof optional container execution proof (or arbitrary metadata)
    function deliverComputeDelegatee(
        uint32 nonce,
        uint32 expiry,
        Subscription calldata sub,
        uint8 v,
        bytes32 r,
        bytes32 s,
        uint32 deliveryInterval,
        bytes calldata input,
        bytes calldata output,
        bytes calldata proof
    ) external onlyActiveNode {
        // Create subscriptionId via delegatee creation + or collect if subscription already exists
        (uint32 subscriptionId, bool cached) = createSubscriptionDelegatee(nonce, expiry, sub, v, r, s);

        // Calculate additional gas overhead imposed from delivering container compute response via delegatee function
        uint256 overhead;
        if (cached) {
            // Subscription exists, cost to retrieve subscriptionId
            overhead = DELEGATEE_OVERHEAD_CACHED_WEI;
        } else {
            // Subscription does not exist, cost to create subscription w/ delegatee signature
            overhead = DELEGATEE_OVERHEAD_CREATE_WEI;
        }

        // Deliver subscription response
        _deliverComputeWithOverhead(subscriptionId, deliveryInterval, input, output, proof, overhead);
    }
}

File 2 of 7 : ECDSA.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
///
/// WARNING! Do NOT use signatures as unique identifiers.
/// Please use EIP712 with a nonce included in the digest to prevent replay attacks.
/// This implementation does NOT check if a signature is non-malleable.
library ECDSA {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The signature is invalid.
    error InvalidSignature();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    RECOVERY OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: as of Solady version 0.0.68, these functions will
    // revert upon recovery failure for more safety by default.

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            let signatureLength := mload(signature)
            mstore(0x00, hash)
            mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
            mstore(0x40, mload(add(signature, 0x20))) // `r`.
            mstore(0x60, mload(add(signature, 0x40))) // `s`.
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        eq(signatureLength, 65), // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function recoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
            calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        eq(signature.length, 65), // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    ///
    /// This function only accepts EIP-2098 short form signatures.
    /// See: https://eips.ethereum.org/EIPS/eip-2098
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   TRY-RECOVER OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // WARNING!
    // These functions will NOT revert upon recovery failure.
    // Instead, they will return the zero address upon recovery failure.
    // It is critical that the returned address is NEVER compared against
    // a zero address (e.g. an uninitialized address variable).

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function tryRecover(bytes32 hash, bytes memory signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            let signatureLength := mload(signature)
            mstore(0x00, hash)
            mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
            mstore(0x40, mload(add(signature, 0x20))) // `r`.
            mstore(0x60, mload(add(signature, 0x40))) // `s`.
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    eq(signatureLength, 65), // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
            calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    eq(signature.length, 65), // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    ///
    /// This function only accepts EIP-2098 short form signatures.
    /// See: https://eips.ethereum.org/EIPS/eip-2098
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    1, // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    1, // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

File 3 of 7 : Coordinator.sol
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.4;

import {Manager} from "./Manager.sol";
import {BaseConsumer} from "./consumer/Base.sol";

/// @title Coordinator
/// @notice Coordination layer between consuming smart contracts and off-chain Infernet nodes
/// @dev Allows creating and deleting `Subscription`(s)
/// @dev Allows nodes with `Manager.NodeStatus.Active` to deliver subscription outputs via off-chain container compute
contract Coordinator is Manager {
    /*//////////////////////////////////////////////////////////////
                                STRUCTS
    //////////////////////////////////////////////////////////////*/

    /// @notice A subscription is the fundamental unit of Infernet
    /// @dev A subscription represents some request configuration for off-chain compute via containers on Infernet nodes
    /// @dev A subscription with `frequency == 1` is a one-time subscription (a callback)
    /// @dev A subscription with `frequency > 1` is a recurring subscription (many callbacks)
    /// @dev Tightly-packed struct:
    ///      - [owner, activeAt, period, frequency]: [32, 160, 32, 32] = 256
    ///      - [redundancy, maxGasPrice, maxGasLimit]: [16, 48, 32] = 96
    struct Subscription {
        /// @notice Subscription owner + recipient
        /// @dev This is the address called to fulfill a subscription request and must inherit `BaseConsumer`
        /// @dev Default initializes to `address(0)`
        address owner;
        /// @notice Timestamp when subscription is first active and an off-chain Infernet node can respond
        /// @dev When `period == 0`, the subscription is immediately active
        /// @dev When `period > 0`, subscription is active at `createdAt + period`
        uint32 activeAt;
        /// @notice Time, in seconds, between each subscription interval
        /// @dev At worst, assuming subscription occurs once/year << uint32
        uint32 period;
        /// @notice Number of times a subscription is processed
        /// @dev At worst, assuming 30 req/min * 60 min * 24 hours * 365 days * 10 years << uint32
        uint32 frequency;
        /// @notice Number of unique nodes that can fulfill a subscription at each `interval`
        /// @dev uint16 allows for >255 nodes (uint8) but <65,535
        uint16 redundancy;
        /// @notice Max gas price in wei paid by an Infernet node when fulfilling callback
        /// @dev uint40 caps out at ~1099 gwei, uint48 allows up to ~281K gwei
        uint48 maxGasPrice;
        /// @notice Max gas limit in wei used by an Infernet node when fulfilling callback
        /// @dev Must be at least equal to the gas limit of your receiving function execution + DELIVERY_OVERHEAD_WEI
        /// @dev uint24 is too small at ~16.7M (<30M mainnet gas limit), but uint32 is more than enough (~4.2B wei)
        uint32 maxGasLimit;
        /// @notice Container identifier used by off-chain Infernet nodes to determine which container is used to fulfill a subscription
        /// @dev Can be used to specify a linear DAG of containers by seperating container names with a "," delimiter ("A,B,C")
        /// @dev Better represented by a string[] type but constrained to string to keep struct and functions simple
        string containerId;
        /// @notice Optional container input parameters
        /// @dev If left empty, off-chain Infernet nodes call public view fn: `BaseConsumer(owner).getContainerInputs()`
        bytes inputs;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /// @notice Gas overhead in wei to deliver container compute responses
    /// @dev This is the additional cost of any validation checks performed within the `Coordinator`
    ///      before delivering responses to consumer contracts
    /// @dev A uint16 is sufficient but we are not packing variables so control plane cost is higher because of type
    ///      casting during operations. Thus, we can just stick to uint256
    uint256 public constant DELIVERY_OVERHEAD_WEI = 56_600 wei;

    /*//////////////////////////////////////////////////////////////
                                MUTABLE
    //////////////////////////////////////////////////////////////*/

    /// @notice Current highest subscription ID
    /// @dev 1-indexed to allow using id as a mapping value (prevent 0-indexed default from being misused)
    /// @dev uint32 size(4.2B) should be sufficiently large
    uint32 public id = 1;

    /// @notice hash(subscriptionId, interval, caller) => has caller responded for (sub, interval)?
    mapping(bytes32 => bool) public nodeResponded;

    /// @notice hash(subscriptionId, interval) => Number of responses for (sub, interval)?
    /// @dev Limited to type(Subscription.redundancy) == uint16
    /// @dev Technically, this is not required and we can save an SLOAD if we simply add a uint48 to the subscription
    ///      struct that represents 32 bits of the interval -> 16 bits of redundancy count, reset each interval change
    ///      But, this is a little over the optimization:redability line and would make Subscriptions harder to grok
    mapping(bytes32 => uint16) public redundancyCount;

    /// @notice subscriptionID => Subscription
    /// @dev 1-indexed, 0th-subscription is empty
    mapping(uint32 => Subscription) public subscriptions;

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

    /// @notice Emitted when a new subscription is created
    /// @param id subscription ID
    event SubscriptionCreated(uint32 indexed id);

    /// @notice Emitted when a subscription is cancelled
    /// @param id subscription ID
    event SubscriptionCancelled(uint32 indexed id);

    /// @notice Emitted when a subscription is fulfilled
    /// @param id subscription ID
    /// @param node address of fulfilling node
    event SubscriptionFulfilled(uint32 indexed id, address indexed node);

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

    /// @notice Thrown by `deliverComputeWithOverhead()` if delivering tx with gasPrice > subscription maxGasPrice
    /// @dev E.g. submitting tx with gas price `10 gwei` when network basefee is `11 gwei`
    /// @dev 4-byte signature: `0x682bad5a`
    error GasPriceExceeded();

    /// @notice Thrown by `deliverComputeWithOverhead()` if delivering tx with consumed gas > subscription maxGasLimit
    /// @dev E.g. submitting tx with gas consumed `200_000 wei` when max allowed by subscription is `175_000 wei`
    /// @dev 4-byte signature: `0xbe9179a6`
    error GasLimitExceeded();

    /// @notice Thrown by `deliverComputeWithOverhead()` if attempting to deliver container compute response for non-current interval
    /// @dev E.g submitting tx for `interval` < current (period elapsed) or `interval` > current (too early to submit)
    /// @dev 4-byte signature: `0x4db310c3`
    error IntervalMismatch();

    /// @notice Thrown by `deliverComputeWithOverhead()` if `redundancy` has been met for current `interval`
    /// @dev E.g submitting 4th output tx for a subscription with `redundancy == 3`
    /// @dev 4-byte signature: `0x2f4ca85b`
    error IntervalCompleted();

    /// @notice Thrown by `deliverComputeWithOverhead()` if `node` has already responded this `interval`
    /// @dev 4-byte signature: `0x88a21e4f`
    error NodeRespondedAlready();

    /// @notice Thrown by `deliverComputeWithOverhead()` if attempting to access a subscription that does not exist
    /// @dev 4-byte signature: `0x1a00354f`
    error SubscriptionNotFound();

    /// @notice Thrown by `cancelSubscription()` if attempting to modify a subscription not owned by caller
    /// @dev 4-byte signature: `0xa7fba711`
    error NotSubscriptionOwner();

    /// @notice Thrown by `deliverComputeWithOverhead()` if attempting to deliver a completed subscription
    /// @dev 4-byte signature: `0xae6704a7`
    error SubscriptionCompleted();

    /// @notice Thrown by `deliverComputeWithOverhead()` if attempting to deliver a subscription before `activeAt`
    /// @dev 4-byte signature: `0xefb74efe`
    error SubscriptionNotActive();

    /*//////////////////////////////////////////////////////////////
                           INTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Internal counterpart to `deliverCompute()` w/ ability to set custom gas overhead allowance
    /// @dev When called by `deliverCompute()`, `callingOverheadWei == 0` because no additional overhead imposed
    /// @dev When called by `deliverComputeDelegatee()`, `DELEGATEE_OVERHEAD_*_WEI` is imposed
    /// @param subscriptionId subscription ID to deliver
    /// @param deliveryInterval subscription `interval` to deliver
    /// @param input optional off-chain input recorded by Infernet node (empty, hashed input, processed input, or both)
    /// @param output optional off-chain container output (empty, hashed output, processed output, both, or fallback: all encodeable data)
    /// @param proof optional container execution proof (or arbitrary metadata)
    /// @param callingOverheadWei additional overhead gas used for delivery
    function _deliverComputeWithOverhead(
        uint32 subscriptionId,
        uint32 deliveryInterval,
        bytes calldata input,
        bytes calldata output,
        bytes calldata proof,
        uint256 callingOverheadWei
    ) internal {
        // Naively, one would think that loading a subscription into memory via
        // `Subscription memory subscription = subscriptions[subscriptionId]`
        // would be cost-effective and most readable.

        // Unfortunately, this is not the case. This function makes no use of
        // `subscription.containerId` or `subscription.inputs`. Because these
        // are dynamic types, we are forced to pay to load into memory the length
        // + content of these parameters. In some cases (say, container input being
        // 100 uint256's), we are forced to pay 2 SLOAD (length slot containerId, inputs)
        // + N SLOAD (containerId + inputs byte length / word size) (for example, 100
        // SLOAD's in the case of 100 uint256's) + N MSTORE (copying into memory)
        // + memory expansion costs.

        // To avoid this, we can first access memory parameters selectively, copying
        // just the fixed size params (uint16, etc.) into memory by accessing state via
        // `subscriptions[subscriptionId].activeAt` syntax.

        // But, with this syntax, while we avoid the significant overhead of copying
        // from storage, into memory, the unnecessary dynamic parameters, we are now
        // forced to pay 100 gas for each non-first storage slot read (hot SLOAD).

        // For example, even if accessing two tightly-packed variables in slot 0, we must
        // pay COLD SLOAD + HOT SLOAD, rather than just COLD SLOAD + MLOAD.

        // To avoid this, we can drop down to assembly and:
        //      1. Manually SLOAD tightly-packed struct slots
        //      2. Unpack and MSTORE variables to avoid the hot SLOAD penalty since we
        //         only copy from storage into memory once (rather than for each variable)

        // Setup parameters in first slot
        // Note, we could load these variables right before they are used but the MSTORE is cheap and this is cleaner
        address subOwner;
        uint32 subActiveAt;
        uint32 subPeriod;
        uint32 subFrequency;

        // Store slot identifier for subscriptions[subscriptionId][slot 0]
        bytes32 storageSlot;
        assembly ("memory-safe") {
            // Load address of free-memory pointer
            let m := mload(0x40)

            // Store subscription ID to first free slot
            // uint32 automatically consumes full word
            mstore(m, subscriptionId)
            // Store subscriptions mapping storage slot (4) to 32 byte (1 word) offset
            mstore(add(m, 0x20), 4)

            // At this point, memory layout [0 -> 0x20 == subscriptionId, 0x20 -> 0x40 == 4]
            // Calculate mapping storage slot — hash(key, mapping slot)
            // Hash data from 0 -> 0x40 (2 words)
            storageSlot := keccak256(m, 0x40)

            // SLOAD struct data
            let data := sload(storageSlot)

            // Solidity packs structs right to left (least-significant bits a la little-endian)
            // MSTORE'ing tightly-packed variables from storage slot data
            // Erase first 96 bits via AND, grab last 160
            subOwner := and(data, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
            // Grab first 32 bits preceeding owner
            subActiveAt := and(shr(160, data), 0xFFFFFFFF)
            // Grab first 32 bits preceeding activeAt
            subPeriod := and(shr(192, data), 0xFFFFFFFF)
            // Grab first 32 bits from left
            subFrequency := shr(224, data)
        }

        // Revert if subscription does not exist
        if (subOwner == address(0)) {
            revert SubscriptionNotFound();
        }

        // Revert if subscription is not yet active
        if (block.timestamp < subActiveAt) {
            revert SubscriptionNotActive();
        }

        // Calculate subscription interval
        uint32 interval = getSubscriptionInterval(subActiveAt, subPeriod);

        // Revert if not processing curent interval
        if (interval != deliveryInterval) {
            revert IntervalMismatch();
        }

        // Revert if interval > frequency
        if (interval > subFrequency) {
            revert SubscriptionCompleted();
        }

        // Setup parameters in second slot
        uint16 subRedundancy;
        uint48 subMaxGasPrice;
        uint32 subMaxGasLimit;

        assembly ("memory-safe") {
            // SLOAD struct data
            // Second slot is simply offset from first by 1
            let data := sload(add(storageSlot, 1))

            // MSTORE'ing tightly-packed variables from storage slot data
            // Grab last 16 bits
            subRedundancy := and(data, 0xFFFF)
            // Grab first 48 bits preceeding redundancy
            subMaxGasPrice := and(shr(16, data), 0xFFFFFFFFFFFF)
            // Grab first 32 bits from left
            subMaxGasLimit := and(shr(64, data), 0xFFFFFFFF)
        }

        // Revert if tx gas price > max subscription allowed
        if (tx.gasprice > subMaxGasPrice) {
            revert GasPriceExceeded();
        }

        // Revert if redundancy requirements for this interval have been met
        bytes32 key = keccak256(abi.encode(subscriptionId, interval));
        uint16 numRedundantDeliveries = redundancyCount[key];
        if (numRedundantDeliveries == subRedundancy) {
            revert IntervalCompleted();
        }
        // Highly unlikely to overflow given incrementing by 1/node
        unchecked {
            redundancyCount[key] = numRedundantDeliveries + 1;
        }

        // Revert if node has already responded this interval
        key = keccak256(abi.encode(subscriptionId, interval, msg.sender));
        if (nodeResponded[key]) {
            revert NodeRespondedAlready();
        }
        nodeResponded[key] = true;

        // Deliver container compute output to contract (measuring execution cost)
        uint256 startingGas = gasleft();
        BaseConsumer(subOwner).rawReceiveCompute(
            subscriptionId, interval, numRedundantDeliveries + 1, msg.sender, input, output, proof
        );
        uint256 endingGas = gasleft();

        // Revert if gas used > allowed, we can make unchecked:
        // Gas limit in most networks is usually much below uint256 max, and by this point a decent amount is spent
        // `callingOverheadWei`, `DELIVERY_OVERHEAD_WEI` both fit in under uint24's
        // Thus, this operation is unlikely to ever overflow ((uint256 - uint256) + (uint16 + uint24))
        // Unless the bounds are along the lines of: {startingGas: UINT256_MAX, endingGas: << (callingOverheadWei + DELIVERY_OVERHEAD_WEI)}
        uint256 executionCost;
        unchecked {
            executionCost = startingGas - endingGas + callingOverheadWei + DELIVERY_OVERHEAD_WEI;
        }
        if (executionCost > subMaxGasLimit) {
            revert GasLimitExceeded();
        }

        // Emit successful delivery
        emit SubscriptionFulfilled(subscriptionId, msg.sender);
    }

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

    /// @notice Creates new subscription
    /// @param containerId compute container identifier used by off-chain Infernet node
    /// @param inputs optional container inputs
    /// @param maxGasPrice max gas price in wei paid by an Infernet node when fulfilling callback
    /// @param maxGasLimit max gas limit in wei paid by an Infernet node in callback tx
    /// @param frequency max number of times to process subscription (i.e, `frequency == 1` is a one-time request)
    /// @param period period, in seconds, at which to progress each responding `interval`
    /// @param redundancy number of unique responding Infernet nodes
    /// @return subscription ID
    function createSubscription(
        string memory containerId,
        bytes calldata inputs,
        uint48 maxGasPrice,
        uint32 maxGasLimit,
        uint32 frequency,
        uint32 period,
        uint16 redundancy
    ) external returns (uint32) {
        // Get subscription id and increment
        // Unlikely this will ever overflow so we can toss in unchecked
        uint32 subscriptionId;
        unchecked {
            subscriptionId = id++;
        }

        // Store new subscription
        subscriptions[subscriptionId] = Subscription({
            // If period is = 0 (one-time), active immediately
            // Else, next active at first period mark
            // Probably reasonable to keep the overflow protection here given adding 2 uint32's into a uint32
            activeAt: uint32(block.timestamp) + period,
            owner: msg.sender,
            maxGasPrice: maxGasPrice,
            redundancy: redundancy,
            maxGasLimit: maxGasLimit,
            frequency: frequency,
            period: period,
            containerId: containerId,
            inputs: inputs
        });

        // Emit new subscription
        emit SubscriptionCreated(subscriptionId);

        // Explicitly return subscriptionId
        return subscriptionId;
    }

    /// @notice Cancel a subscription
    /// @dev Must be called by `subscriptions[subscriptionId].owner`
    /// @param subscriptionId subscription ID to cancel
    function cancelSubscription(uint32 subscriptionId) external {
        // Throw if owner of subscription is not caller
        if (subscriptions[subscriptionId].owner != msg.sender) {
            revert NotSubscriptionOwner();
        }

        // Nullify subscription
        delete subscriptions[subscriptionId];

        // Emit cancellation
        emit SubscriptionCancelled(subscriptionId);
    }

    /// @notice Calculates subscription `interval` based on `activeAt` and `period`
    /// @param activeAt when does a subscription start accepting callback responses
    /// @param period time, in seconds, between each subscription response `interval`
    /// @return current subscription interval
    function getSubscriptionInterval(uint32 activeAt, uint32 period) public view returns (uint32) {
        // If period is 0, we're always at interval 1
        if (period == 0) {
            return 1;
        }

        // Else, interval = ((block.timestamp - activeAt) / period) + 1
        // This is only called after validating block.timestamp >= activeAt so timestamp can't underflow
        // We also short-circuit above if period is zero so no need for division by zero checks
        unchecked {
            return ((uint32(block.timestamp) - activeAt) / period) + 1;
        }
    }

    /// @notice Allows nodes with `Manager.NodeStatus.Active` to deliver container compute responses for a subscription
    /// @dev Re-entering does not work because only active nodes (max 1 response) can call `deliverCompute`
    /// @dev Re-entering and delivering via a seperate node `msg.sender` works but is ignored in favor of explicit `maxGasLimit`
    /// @dev For containers without succinctly-verifiable proofs, the `proof` field can be repurposed for arbitrary metadata
    /// @dev Enforces an overhead delivery cost of `DELIVERY_OVERHEAD_WEI` and `0` additional overhead
    /// @param subscriptionId subscription ID to deliver
    /// @param deliveryInterval subscription `interval` to deliver
    /// @param input optional off-chain container input recorded by Infernet node (empty, hashed input, processed input, or both)
    /// @param output optional off-chain container output (empty, hashed output, processed output, both, or fallback: all encodeable data)
    /// @param proof optional off-chain container execution proof (or arbitrary metadata)
    function deliverCompute(
        uint32 subscriptionId,
        uint32 deliveryInterval,
        bytes calldata input,
        bytes calldata output,
        bytes calldata proof
    ) external onlyActiveNode {
        _deliverComputeWithOverhead(subscriptionId, deliveryInterval, input, output, proof, 0);
    }
}

File 4 of 7 : EIP712.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Contract for EIP-712 typed structured data hashing and signing.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol)
/// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol)
///
/// @dev Note, this implementation:
/// - Uses `address(this)` for the `verifyingContract` field.
/// - Does NOT use the optional EIP-712 salt.
/// - Does NOT use any EIP-712 extensions.
/// This is for simplicity and to save gas.
/// If you need to customize, please fork / modify accordingly.
abstract contract EIP712 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  CONSTANTS AND IMMUTABLES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 internal constant _DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    address private immutable _cachedThis;
    uint256 private immutable _cachedChainId;
    bytes32 private immutable _cachedNameHash;
    bytes32 private immutable _cachedVersionHash;
    bytes32 private immutable _cachedDomainSeparator;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CONSTRUCTOR                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Cache the hashes for cheaper runtime gas costs.
    /// In the case of upgradeable contracts (i.e. proxies),
    /// or if the chain id changes due to a hard fork,
    /// the domain separator will be seamlessly calculated on-the-fly.
    constructor() {
        _cachedThis = address(this);
        _cachedChainId = block.chainid;

        string memory name;
        string memory version;
        if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion();
        bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name));
        bytes32 versionHash =
            _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version));
        _cachedNameHash = nameHash;
        _cachedVersionHash = versionHash;

        bytes32 separator;
        if (!_domainNameAndVersionMayChange()) {
            /// @solidity memory-safe-assembly
            assembly {
                let m := mload(0x40) // Load the free memory pointer.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), nameHash)
                mstore(add(m, 0x40), versionHash)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())
                separator := keccak256(m, 0xa0)
            }
        }
        _cachedDomainSeparator = separator;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   FUNCTIONS TO OVERRIDE                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Please override this function to return the domain name and version.
    /// ```
    ///     function _domainNameAndVersion()
    ///         internal
    ///         pure
    ///         virtual
    ///         returns (string memory name, string memory version)
    ///     {
    ///         name = "Solady";
    ///         version = "1";
    ///     }
    /// ```
    ///
    /// Note: If the returned result may change after the contract has been deployed,
    /// you must override `_domainNameAndVersionMayChange()` to return true.
    function _domainNameAndVersion()
        internal
        view
        virtual
        returns (string memory name, string memory version);

    /// @dev Returns if `_domainNameAndVersion()` may change
    /// after the contract has been deployed (i.e. after the constructor).
    /// Default: false.
    function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {}

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _domainSeparator() internal view virtual returns (bytes32 separator) {
        if (_domainNameAndVersionMayChange()) {
            separator = _buildDomainSeparator();
        } else {
            separator = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
        }
    }

    /// @dev Returns the hash of the fully encoded EIP-712 message for this domain,
    /// given `structHash`, as defined in
    /// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
    ///
    /// The hash can be used together with {ECDSA-recover} to obtain the signer of a message:
    /// ```
    ///     bytes32 digest = _hashTypedData(keccak256(abi.encode(
    ///         keccak256("Mail(address to,string contents)"),
    ///         mailTo,
    ///         keccak256(bytes(mailContents))
    ///     )));
    ///     address signer = ECDSA.recover(digest, signature);
    /// ```
    function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) {
        bytes32 separator;
        if (_domainNameAndVersionMayChange()) {
            separator = _buildDomainSeparator();
        } else {
            separator = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the digest.
            mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
            mstore(0x1a, separator) // Store the domain separator.
            mstore(0x3a, structHash) // Store the struct hash.
            digest := keccak256(0x18, 0x42)
            // Restore the part of the free memory slot that was overwritten.
            mstore(0x3a, 0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    EIP-5267 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev See: https://eips.ethereum.org/EIPS/eip-5267
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        fields = hex"0f"; // `0b01111`.
        (name, version) = _domainNameAndVersion();
        chainId = block.chainid;
        verifyingContract = address(this);
        salt = salt; // `bytes32(0)`.
        extensions = extensions; // `new uint256[](0)`.
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _buildDomainSeparator() private view returns (bytes32 separator) {
        bytes32 nameHash;
        bytes32 versionHash;
        if (_domainNameAndVersionMayChange()) {
            (string memory name, string memory version) = _domainNameAndVersion();
            nameHash = keccak256(bytes(name));
            versionHash = keccak256(bytes(version));
        } else {
            nameHash = _cachedNameHash;
            versionHash = _cachedVersionHash;
        }
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), nameHash)
            mstore(add(m, 0x40), versionHash)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            separator := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns if the cached domain separator has been invalidated.
    function _cachedDomainSeparatorInvalidated() private view returns (bool result) {
        uint256 cachedChainId = _cachedChainId;
        address cachedThis = _cachedThis;
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis)))
        }
    }
}

File 5 of 7 : Delegator.sol
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.4;

/// @title Delegator
/// @notice Exposes a `signer` address that allows an authorized EOA to sign off on actions on behalf of a contract
/// @dev Allows developers to create Coordinator subscriptions off-chain, on behalf of a contract, by signing a
///      `DelegateSubscription` from `signer` and submitting to `EIP712Coordinator.createSubscriptionDelegatee()`
abstract contract Delegator {
    /*//////////////////////////////////////////////////////////////
                                MUTABLE
    //////////////////////////////////////////////////////////////*/

    /// @notice Authorized address with signing privileges
    /// @dev Recommended to use an EOA so that it can sign EIP-712 messages
    /// @dev Visibility is `public` to automatically generate and expose a getter
    address public signer;

    /*//////////////////////////////////////////////////////////////
                              CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /// @notice Initialize new Delegator
    /// @param signer_ authorized address
    constructor(address signer_) {
        signer = signer_;
    }

    /*//////////////////////////////////////////////////////////////
                           INTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Update delegated signer
    /// @dev No event is emitted given contract is meant to be inherited
    /// @param newSigner new delegated signer address
    function _updateSigner(address newSigner) internal {
        signer = newSigner;
    }
}

File 6 of 7 : Manager.sol
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.4;

/// @title Manager
/// @notice Manages node lifecycle (registration, activation, deactivation)
/// @dev Allows anyone to register to become an active node
/// @dev Allows registered nodes to become active after a `cooldown` seconds waiting period
/// @dev Allows any node to deactivate itself and return to an inactive state
/// @dev Exposes an `onlyActiveNode()` modifier used to restrict functions to being called by only active nodes
/// @dev Restricts addresses to 1 of 3 states: `Inactive`, `Registered`, `Active`
abstract contract Manager {
    /*//////////////////////////////////////////////////////////////
                                STRUCTS
    //////////////////////////////////////////////////////////////*/

    /// @notice Packed information about a node (status, cooldown start)
    /// @dev Cheaper to use a struct to store `status` + `cooldownStart` rather than SSTORE 2 independent mappings
    /// @dev Technically, could bitshift pack uint40 of data into single uint256 but readability penalty not worth it
    /// @dev Tightly-packed (well under 32-byte slot): [uint8, uint32] = 40 bits = 5 bytes
    struct NodeInfo {
        /// @notice Node status
        NodeStatus status;
        /// @notice Cooldown start timestamp in seconds
        /// @dev Default initializes to `0`; no cooldown active to start
        /// @dev Equal to `0` if `status != NodeStatus.Registered`, else equal to cooldown start time
        /// @dev Is modified by `registerNode()` to initiate `cooldown` holding period
        /// @dev uint32 allows for a timestamp up to year ~2106, likely far beyond lifecycle of this contract
        uint32 cooldownStart;
    }

    /*//////////////////////////////////////////////////////////////
                                 ENUMS
    //////////////////////////////////////////////////////////////*/

    /// @notice Possible node statuses
    /// @dev Enums in Solidity are unsigned integers capped at 256 members, so Inactive is the 0-initialized default
    /// @dev Inactive (0): Default status is inactive; no status
    /// @dev Registered (1): Node has registered to become active, initiating a period of `cooldown`
    /// @dev Active (2): Node is active, able to fulfill subscriptions, and is part of `modifier(onlyActiveNode)`
    enum NodeStatus {
        Inactive,
        Registered,
        Active
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /// @notice Cooldown period, in seconds, before a node with `NodeStatus.Registered` can call `activateNode()`
    /// @dev type(uint32) is sufficient but we are not packing variables so control plane costs are higher because we
    ///      need to cast the 32-bit type into the 256-bit type anyways. Thus, we use type(uint256).
    uint256 public constant cooldown = 1 hours;

    /*//////////////////////////////////////////////////////////////
                                MUTABLE
    //////////////////////////////////////////////////////////////*/

    /// @dev Node address => node information
    mapping(address => NodeInfo) public nodeInfo;

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

    /// @notice Emitted when a node moves from `NodeStatus.Inactive` to `NodeStatus.Registered`
    /// @dev It's actually slightly more expensive (~6 gas) to emit the uint32 given the explicit conversion needed
    ///      but this is necessary to have better readability and uniformity across the type (not casting in event)
    /// @param node newly-registered node address
    /// @param registerer optional proxy address registering on behalf of node (is equal to node when self-registering)
    /// @param cooldownStart start timestamp of registration cooldown
    event NodeRegistered(address indexed node, address indexed registerer, uint32 cooldownStart);

    /// @notice Emitted when a node moves from `NodeStatus.Registered` to `NodeStatus.Active`
    /// @param node newly-activated node address
    event NodeActivated(address indexed node);

    /// @notice Emitted when a node moves from any status to `NodeStatus.Inactive`
    /// @param node newly-deactivated node address
    event NodeDeactivated(address indexed node);

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

    /// @notice Thrown if attempting to call function that requires a node to have status `NodeStatus.Active`
    /// @dev Only used by `modifier(onlyActiveNode)`
    /// @dev 4-byte signature: `0x8741cbb8`
    error NodeNotActive();

    /// @notice Thrown by `registerNode()` if attempting to register node with status that is not `NodeStatus.Inactive`
    /// @dev 4-byte signature: `0x5acfd518`
    /// @param node address of node attempting to register
    /// @param status current status of node failing registration
    error NodeNotRegisterable(address node, NodeStatus status);

    /// @notice Thrown by `activateNode()` if `cooldown` has not elapsed since node was registered
    /// @dev Like `NodeRegistered`, slightly more expensive to use uint32 over uint256 (~6 gas) but better readability
    /// @dev 4-byte signature: `0xc84b5bdd`
    /// @param cooldownStart start timestamp of node cooldown
    error CooldownActive(uint32 cooldownStart);

    /// @notice Thrown by `activateNode()` if attempting to active node with status that is not `NodeStatus.Registered`
    /// @dev 4-byte signature: `0x33daa7f9`
    /// @param status current status of node failing activation
    error NodeNotActivateable(NodeStatus status);

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /// @notice Allow only callers that are active nodes
    modifier onlyActiveNode() {
        if (nodeInfo[msg.sender].status != NodeStatus.Active) {
            revert NodeNotActive();
        }
        _;
    }

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

    /// @notice Allows registering a node for activation
    /// @dev First-step of two-step process (followed by `activateNode()`)
    /// @dev Can call on behalf of other nodes as a proxy registerer
    /// @dev Node must have `NodeStatus.Inactive` to begin registration
    /// @param node node address to register
    function registerNode(address node) external {
        // SLOAD node info
        NodeInfo storage info = nodeInfo[node];

        // Ensure node is registerable
        // Current status must be `NodeStatus.Inactive`
        if (info.status != NodeStatus.Inactive) {
            revert NodeNotRegisterable(node, info.status);
        }

        // Update node status to Registered
        info.status = NodeStatus.Registered;
        // Update cooldown start timestamp to now
        info.cooldownStart = uint32(block.timestamp);

        // Emit new registration event
        emit NodeRegistered(node, msg.sender, uint32(block.timestamp));
    }

    /// @notice Allows activating a registered node after `cooldown` has elapsed
    /// @dev Second-step of two-step process (preceeded by `registerNode()`)
    /// @dev Must be called by node accepting a pending registration (`msg.sender == node`)
    /// @dev Must be called at least `cooldown` seconds after `registerNode()`
    function activateNode() external {
        // SLOAD node info
        NodeInfo storage info = nodeInfo[msg.sender];

        // Ensure node is already registered
        // Technically this check is not needed since the next check would fail anyways, but it provides a useful error
        if (info.status != NodeStatus.Registered) {
            revert NodeNotActivateable(info.status);
        }

        // Ensure node has elapsed required cooldown
        // Adding a uint32 to a uint32-bounded uint256 and upcasting to a uint256, so can't overflow
        uint256 cooldownEnd;
        unchecked {
            cooldownEnd = info.cooldownStart + cooldown;
        }
        if (block.timestamp < cooldownEnd) {
            revert CooldownActive(info.cooldownStart);
        }

        // Toggle node status to Active
        info.status = NodeStatus.Active;
        // Reset cooldown start timestamp
        info.cooldownStart = 0;

        // Emit activation event
        emit NodeActivated(msg.sender);
    }

    /// @notice Allows deactivating a node
    /// @dev Can be called to set the status of any node back to `NodeStatus.Inactive` with no cooldown
    /// @dev Must be called by the node deactivating itself (`msg.sender == node`)
    function deactivateNode() external {
        delete nodeInfo[msg.sender];

        // Emit deactivation event
        emit NodeDeactivated(msg.sender);
    }
}

File 7 of 7 : Base.sol
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.4;

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

/// @title BaseConsumer
/// @notice Handles receiving container compute responses from Infernet coordinator
/// @dev Contains a single public entrypoint `rawReceiveCompute` callable by only the Infernet coordinator. Once
///      call origin is verified, parameters are proxied to internal function `_receiveCompute`
abstract contract BaseConsumer {
    /*//////////////////////////////////////////////////////////////
                               IMMUTABLE
    //////////////////////////////////////////////////////////////*/

    /// @notice Infernet Coordinator
    /// @dev Internal visibility since COORDINATOR is consumed by inheriting contracts
    Coordinator internal immutable COORDINATOR;

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

    /// @notice Thrown if attempting to call `rawReceiveCompute` from a `msg.sender != address(COORDINATOR)`
    /// @dev 4-byte signature: `0x9ec853e6`
    error NotCoordinator();

    /*//////////////////////////////////////////////////////////////
                              CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /// @notice Initialize new BaseConsumer
    /// @param coordinator coordinator address
    constructor(address coordinator) {
        // Setup Coordinator
        COORDINATOR = Coordinator(coordinator);
    }

    /*//////////////////////////////////////////////////////////////
                           VIRTUAL FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Callback entrypoint to receive container compute responses from validated Coordinator source
    /// @dev Called by `rawReceiveCompute` once validated that `msg.sender == address(COORDINATOR)`
    /// @dev Same function parameters as `rawReceiveCompute`
    /// @param subscriptionId id of subscription being responded to
    /// @param interval subscription interval
    /// @param redundancy after this call succeeds, how many nodes will have delivered a response for this interval
    /// @param node address of responding Infernet node
    /// @param input optional off-chain container input recorded by Infernet node (empty, hashed input, processed input, or both)
    /// @param output optional off-chain container output (empty, hashed output, processed output, both, or fallback: all encodeable data)
    /// @param proof optional off-chain container execution proof (or arbitrary metadata)
    function _receiveCompute(
        uint32 subscriptionId,
        uint32 interval,
        uint16 redundancy,
        address node,
        bytes calldata input,
        bytes calldata output,
        bytes calldata proof
    ) internal virtual {}

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

    /// @notice Callback entrypoint called by Infernet Coordinator to return container compute responses
    /// @dev Callable only by `address(COORDINATOR)`, else throws `NotCoordinator()` error
    /// @param subscriptionId id of subscription being responded to
    /// @param interval subscription interval
    /// @param redundancy after this call succeeds, how many nodes will have delivered a response for this interval
    /// @param node address of responding Infernet node
    /// @param input optional off-chain container input recorded by Infernet node (empty, hashed input, processed input, or both)
    /// @param output optional off-chain container output (empty, hashed output, processed output, both, or fallback: all encodeable data)
    /// @param proof optional off-chain container execution proof (or arbitrary metadata)
    function rawReceiveCompute(
        uint32 subscriptionId,
        uint32 interval,
        uint16 redundancy,
        address node,
        bytes calldata input,
        bytes calldata output,
        bytes calldata proof
    ) external {
        // Ensure caller is coordinator
        if (msg.sender != address(COORDINATOR)) {
            revert NotCoordinator();
        }

        // Call internal receive function, since caller is validated
        _receiveCompute(subscriptionId, interval, redundancy, node, input, output, proof);
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint32","name":"cooldownStart","type":"uint32"}],"name":"CooldownActive","type":"error"},{"inputs":[],"name":"GasLimitExceeded","type":"error"},{"inputs":[],"name":"GasPriceExceeded","type":"error"},{"inputs":[],"name":"IntervalCompleted","type":"error"},{"inputs":[],"name":"IntervalMismatch","type":"error"},{"inputs":[{"internalType":"enum Manager.NodeStatus","name":"status","type":"uint8"}],"name":"NodeNotActivateable","type":"error"},{"inputs":[],"name":"NodeNotActive","type":"error"},{"inputs":[{"internalType":"address","name":"node","type":"address"},{"internalType":"enum Manager.NodeStatus","name":"status","type":"uint8"}],"name":"NodeNotRegisterable","type":"error"},{"inputs":[],"name":"NodeRespondedAlready","type":"error"},{"inputs":[],"name":"NotSubscriptionOwner","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"SignerMismatch","type":"error"},{"inputs":[],"name":"SubscriptionCompleted","type":"error"},{"inputs":[],"name":"SubscriptionNotActive","type":"error"},{"inputs":[],"name":"SubscriptionNotFound","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"node","type":"address"}],"name":"NodeActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"node","type":"address"}],"name":"NodeDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"node","type":"address"},{"indexed":true,"internalType":"address","name":"registerer","type":"address"},{"indexed":false,"internalType":"uint32","name":"cooldownStart","type":"uint32"}],"name":"NodeRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"id","type":"uint32"}],"name":"SubscriptionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"id","type":"uint32"}],"name":"SubscriptionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":true,"internalType":"address","name":"node","type":"address"}],"name":"SubscriptionFulfilled","type":"event"},{"inputs":[],"name":"DELEGATEE_OVERHEAD_CACHED_WEI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATEE_OVERHEAD_CREATE_WEI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELIVERY_OVERHEAD_WEI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activateNode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"subscriptionId","type":"uint32"}],"name":"cancelSubscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"containerId","type":"string"},{"internalType":"bytes","name":"inputs","type":"bytes"},{"internalType":"uint48","name":"maxGasPrice","type":"uint48"},{"internalType":"uint32","name":"maxGasLimit","type":"uint32"},{"internalType":"uint32","name":"frequency","type":"uint32"},{"internalType":"uint32","name":"period","type":"uint32"},{"internalType":"uint16","name":"redundancy","type":"uint16"}],"name":"createSubscription","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint32","name":"expiry","type":"uint32"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"activeAt","type":"uint32"},{"internalType":"uint32","name":"period","type":"uint32"},{"internalType":"uint32","name":"frequency","type":"uint32"},{"internalType":"uint16","name":"redundancy","type":"uint16"},{"internalType":"uint48","name":"maxGasPrice","type":"uint48"},{"internalType":"uint32","name":"maxGasLimit","type":"uint32"},{"internalType":"string","name":"containerId","type":"string"},{"internalType":"bytes","name":"inputs","type":"bytes"}],"internalType":"struct Coordinator.Subscription","name":"sub","type":"tuple"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"createSubscriptionDelegatee","outputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deactivateNode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"delegateCreatedIds","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"subscriptionId","type":"uint32"},{"internalType":"uint32","name":"deliveryInterval","type":"uint32"},{"internalType":"bytes","name":"input","type":"bytes"},{"internalType":"bytes","name":"output","type":"bytes"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"deliverCompute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint32","name":"expiry","type":"uint32"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"activeAt","type":"uint32"},{"internalType":"uint32","name":"period","type":"uint32"},{"internalType":"uint32","name":"frequency","type":"uint32"},{"internalType":"uint16","name":"redundancy","type":"uint16"},{"internalType":"uint48","name":"maxGasPrice","type":"uint48"},{"internalType":"uint32","name":"maxGasLimit","type":"uint32"},{"internalType":"string","name":"containerId","type":"string"},{"internalType":"bytes","name":"inputs","type":"bytes"}],"internalType":"struct Coordinator.Subscription","name":"sub","type":"tuple"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint32","name":"deliveryInterval","type":"uint32"},{"internalType":"bytes","name":"input","type":"bytes"},{"internalType":"bytes","name":"output","type":"bytes"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"deliverComputeDelegatee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"activeAt","type":"uint32"},{"internalType":"uint32","name":"period","type":"uint32"}],"name":"getSubscriptionInterval","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"id","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxSubscriberNonce","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nodeInfo","outputs":[{"internalType":"enum Manager.NodeStatus","name":"status","type":"uint8"},{"internalType":"uint32","name":"cooldownStart","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nodeResponded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"redundancyCount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"node","type":"address"}],"name":"registerNode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"subscriptions","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"activeAt","type":"uint32"},{"internalType":"uint32","name":"period","type":"uint32"},{"internalType":"uint32","name":"frequency","type":"uint32"},{"internalType":"uint16","name":"redundancy","type":"uint16"},{"internalType":"uint48","name":"maxGasPrice","type":"uint48"},{"internalType":"uint32","name":"maxGasLimit","type":"uint32"},{"internalType":"string","name":"containerId","type":"string"},{"internalType":"bytes","name":"inputs","type":"bytes"}],"stateMutability":"view","type":"function"}]

6101203461012b57306080524660a0526040906001600160401b03908083018281118282101761011557835260138152602081017f496e6665726e6574436f6f7264696e61746f72000000000000000000000000008152835190848201938285109085111761011557602060019260a09587528381520192603160f81b845251902091208160c0528060e0528351917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f83526020830152838201524660608201523060808201522090610100918252600163ffffffff198154161760015551612baf918261013183396080518261233a015260a0518261235d015260c05182612adf015260e05182612b06015251816123180152f35b634e487b7160e01b600052604160045260246000fd5b600080fdfe608080604052600436101561001357600080fd5b60003560e01c908163105ddd1d14611ae65750806323c2e2bc14611a67578063298f7bdc14611a1857806331e451a91461189e5780633b2fb7a81461186457806341770e9a146117cf57806341cf2b7f146117945780634d9bf22f1461112957806360ed0f61146110d9578063642012c714610c8d578063672d7a0d14610b715780636e021332146105d057806373fb5c3a146104c4578063787a08a6146104895780637fb61b271461041b578063836a6cc9146103c357806384b0196e146102e157806390b04c15146102a657806396ef592e1461023f578063af640d0f146101fd578063bc85694f146101af578063e7cab346146101735763eccec5a81461011c57600080fd5b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5761016a610156611f22565b604051918291602083526020830190611d19565b0390f35b600080fd5b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576020604051620164408152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576004356000526003602052602061ffff60406000205416604051908152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57602063ffffffff60015416604051908152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5733600052600060205260006040812055337fd9957750e6343405c319eb99a4ec67fa11cfd66969318cbc71aa2d45fa53a349600080a2005b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57602060405161dd188152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5761037161031b611ce0565b610323611f22565b906040519283927f0f00000000000000000000000000000000000000000000000000000000000000845261036360209360e08587015260e0860190611d19565b908482036040860152611d19565b90466060840152306080840152600060a084015282820360c08401528060605192838152019160809160005b8281106103ac57505050500390f35b83518552869550938101939281019260010161039d565b3461016e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57602061040d6103ff611c11565b610407611c24565b90611fb9565b63ffffffff60405191168152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043573ffffffffffffffffffffffffffffffffffffffff811680910361016e576000526005602052602063ffffffff60406000205416604051908152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576020604051610e108152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5763ffffffff80610501611c11565b166000526004602052604060002061016a60036105c183549360018101549561054f6040519261053f846105388160028501611e6d565b0385611c9f565b6105386040518097819301611e6d565b604051968673ffffffffffffffffffffffffffffffffffffffff8998168852828160a01c166020890152828160c01c16604089015260e01c606088015261ffff8116608088015265ffffffffffff8160101c1660a088015260401c1660c08601526101208060e0870152850190611d19565b90838203610100850152611d19565b3461016e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57610607611c11565b61060f611c24565b67ffffffffffffffff9060443582811161016e57610631903690600401611dec565b92909160643582811161016e5761064c903690600401611dec565b91909260843590811161016e57610667903690600401611dec565b91909533600052600060205260ff604060002054166003811015610b4257600203610b1857600096604080518a815260046020820152209384549473ffffffffffffffffffffffffffffffffffffffff861615610aee5763ffffffff8660a01c16804210610ac45763ffffffff6106e58192828a60c01c1690611fb9565b1695168503610a9a578560e01c8511610a7057600101549665ffffffffffff8860101c163a11610a4657604051602081019063ffffffff8d1682528660408201526040815261073381611c4b565b5190209687600052600360205261ffff604060002054169761ffff8a168914610a1c576000526003602052604060002061ffff60018a01167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00008254161790558b60405163ffffffff6020820192168252876040820152336060820152606081526107bc81611c67565b51902080600052600260205260ff604060002054166109f2576000526002602052604060002060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555a9961ffff60018a01116109c35773ffffffffffffffffffffffffffffffffffffffff88163b1561016e578c95604051998a9889987ff8eb7fbd000000000000000000000000000000000000000000000000000000008a5263ffffffff1660048a0152602489015260010161ffff1660448801523360648801526084870160e0905260e487019061089b92611fde565b908582037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160a48701526108cf92611fde565b908382037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160c485015261090392611fde565b039173ffffffffffffffffffffffffffffffffffffffff1691815a6000948591f180156109b75761099f575b5063ffffffff61dd189160401c16915a90030111610975577fc68fb0ae5cea2793405d29014d881bcda18f67122e0bcd7d0a577e118b64e4c863ffffffff3393169180a3005b60046040517fbe9179a6000000000000000000000000000000000000000000000000000000008152fd5b6109aa919350611c37565b60009163ffffffff61092f565b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60046040517f88a21e4f000000000000000000000000000000000000000000000000000000008152fd5b60046040517f2f4ca85b000000000000000000000000000000000000000000000000000000008152fd5b60046040517f682bad5a000000000000000000000000000000000000000000000000000000008152fd5b60046040517fae6704a7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f4db310c3000000000000000000000000000000000000000000000000000000008152fd5b60046040517fefb74efe000000000000000000000000000000000000000000000000000000008152fd5b60046040517f1a00354f000000000000000000000000000000000000000000000000000000008152fd5b60046040517f8741cbb8000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043573ffffffffffffffffffffffffffffffffffffffff811680910361016e578060005260006020526040600020805460ff81166003811015610b425780610c4e57506001907fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000064ffffffff004260081b169116171790556040519063ffffffff421682527fb73af334a40cdaaad72e06d597bdeed270fc94d45415863afec219108096d2e860203393a3005b83610c8b604492604051927f5acfd51800000000000000000000000000000000000000000000000000000000845260048401526024830190611c04565bfd5b3461016e576101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57610cc5611c11565b610ccd611c24565b67ffffffffffffffff91826044351161016e576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6044353603011261016e57610d17611d77565b60c4359363ffffffff8516850361016e5760e43581811161016e57610d40903690600401611dec565b9290936101043583811161016e57610d5c903690600401611dec565b9290936101243590811161016e57610d78903690600401611dec565b92909733600052600060205260ff604060002054166003811015610b4257600203610b1857610db59260a4359260843592604435600401916120c2565b909790156110cf57610258945b604080518a815260046020820152209788549360009973ffffffffffffffffffffffffffffffffffffffff861615610aee5763ffffffff8660a01c16804210610ac45763ffffffff610e1b8192828a60c01c1690611fb9565b1695168503610a9a578560e01c8511610a7057600101549665ffffffffffff8860101c163a11610a465760405163ffffffff8d16602082015285604082015260408152610e6781611c4b565b602081519101209687600052600360205261ffff604060002054169761ffff8a168914610a1c576000526003602052604060002061ffff60018a01167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00008254161790558c60405163ffffffff602082019216825287604082015233606082015260608152610ef481611c67565b51902080600052600260205260ff604060002054166109f2576000526002602052604060002060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555a9a61ffff60018a01116109c35773ffffffffffffffffffffffffffffffffffffffff88163b1561016e578d95604051998a9889987ff8eb7fbd000000000000000000000000000000000000000000000000000000008a5263ffffffff1660048a0152602489015260010161ffff1660448801523360648801526084870160e0905260e4870190610fd392611fde565b908582037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160a487015261100792611fde565b908382037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160c485015261103b92611fde565b039173ffffffffffffffffffffffffffffffffffffffff1691815a6000948591f180156109b7576110af575b509063ffffffff61dd189260401c16925a9003010111610975577fc68fb0ae5cea2793405d29014d881bcda18f67122e0bcd7d0a577e118b64e4c863ffffffff3393169180a3005b61dd18929194506110bf90611c37565b63ffffffff600094919250611067565b6201644094610dc2565b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576004356000526006602052602063ffffffff60406000205416604051908152f35b3461016e5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043567ffffffffffffffff811161016e573660238201121561016e57611189903690602481600401359101611d87565b60243567ffffffffffffffff811161016e576111a9903690600401611dec565b90916044359265ffffffffffff8416840361016e576064359263ffffffff8416840361016e576084359263ffffffff8416840361016e5760a4359463ffffffff8616860361016e5760c4359061ffff8216820361016e576001549663ffffffff6001818a1601167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000089161760015563ffffffff80821681421601116109c357604051988961012081011067ffffffffffffffff6101208c0111176116b05761ffff63ffffffff94856112c19a8d60408365ffffffffffff98610120840183523384528180821681421601166020850152169101521660608d01521660808b01521660a08901521660c087015260e08601523691611d87565b61010083015263ffffffff81166000526004602052604060002073ffffffffffffffffffffffffffffffffffffffff8351167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617815561137263ffffffff60208501511682907fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff77ffffffff000000000000000000000000000000000000000083549260a01b169116179055565b604083015181547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7bffffffff00000000000000000000000000000000000000000000000016178155606083015181547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09190911b7fffffffff00000000000000000000000000000000000000000000000000000000161781556114d56001820161ffff6080860151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000082541617815561149365ffffffffffff60a08701511682907fffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffff67ffffffffffff000083549260101b169116179055565b60c085015181547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1660409190911b6bffffffff000000000000000016179055565b6002810160e084015180519067ffffffffffffffff82116116b057611504826114fe8554611e1a565b85611f72565b602090601f83116001146116ea5791806003949261010096946000926116df575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b92861b1c19161790555b019201519081519267ffffffffffffffff84116116b0578361158460209561157e8454611e1a565b84611f72565b8493601f8211600114611611579381929394600092611606575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b63ffffffff604051918181167f04344ed7a67fec80c444d56ee1cee242f3f75b91fecc8dbce8890069c82eb48e600080a2168152f35b01519050858061159e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169483600052866000209160005b878110611699575083600195969710611662575b505050811b0190556115d0565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c19169055858080611655565b919288600181928685015181550194019201611641565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b015190508880611525565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316918460005260206000209260005b81811061177c575092600192859261010098966003989610611746575b505050811b019055611556565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f884891b161c19169055888080611739565b9293602060018192878601518155019501930161171c565b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760206040516102588152f35b3461016e577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60c08136011261016e57611807611c11565b61180f611c24565b6044359267ffffffffffffffff841161016e5761012090843603011261016e576040926118509261183e611d77565b9060a4359360843593600401916120c2565b63ffffffff83519216825215156020820152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5761016a610156611ce0565b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5763ffffffff6118da611c11565b1680600052600460205273ffffffffffffffffffffffffffffffffffffffff6040600020541633036119ee578060005260046020526003604060002060008155600060018201556002810161192f8154611e1a565b90816119b0575b5050016119438154611e1a565b9081611972575b827ff4126e31c182db4c4109605c6d50470fc7e8ca90d62d44fd25cbe049fb9cac3e600080a2005b81601f6000931160011461198a5750555b818061194a565b9080839182526119a9601f60208420940160051c840160018501611f5b565b5555611983565b81601f600093116001146119c85750555b8380611936565b9080839182526119e7601f60208420940160051c840160018501611f5b565b55556119c1565b60046040517fa7fba711000000000000000000000000000000000000000000000000000000008152fd5b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576004356000526002602052602060ff604060002054166040519015158152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043573ffffffffffffffffffffffffffffffffffffffff811680910361016e5760005260006020526040806000205463ffffffff825191611adb8360ff8316611c04565b60081c166020820152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5733600052600060205260406000209081549060ff82166003811015610b425760018103611bd457505063ffffffff8160081c16610e1081014210611ba357507fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000166002179055337f7dc8b937d2916b130743c447af3d771fa55e66b7393105150e2e635ac3e87260600080a2005b602490604051907fc84b5bdd0000000000000000000000000000000000000000000000000000000082526004820152fd5b90610c8b6024927f33daa7f900000000000000000000000000000000000000000000000000000000835260048301905b906003821015610b425752565b6004359063ffffffff8216820361016e57565b6024359063ffffffff8216820361016e57565b67ffffffffffffffff81116116b057604052565b6060810190811067ffffffffffffffff8211176116b057604052565b6080810190811067ffffffffffffffff8211176116b057604052565b6040810190811067ffffffffffffffff8211176116b057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176116b057604052565b60405190611ced82611c83565b601382527f496e6665726e6574436f6f7264696e61746f72000000000000000000000000006020830152565b919082519283825260005b848110611d635750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b602081830181015184830182015201611d24565b6064359060ff8216820361016e57565b92919267ffffffffffffffff82116116b05760405191611dcf60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611c9f565b82948184528183011161016e578281602093846000960137010152565b9181601f8401121561016e5782359167ffffffffffffffff831161016e576020838186019501011161016e57565b90600182811c92168015611e63575b6020831014611e3457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611e29565b9060009291805491611e7e83611e1a565b918282526001938481169081600014611ee05750600114611ea0575b50505050565b90919394506000526020928360002092846000945b838610611ecc575050505001019038808080611e9a565b805485870183015294019385908201611eb5565b91505060209495507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009193501683830152151560051b01019038808080611e9a565b60405190611f2f82611c83565b600182527f31000000000000000000000000000000000000000000000000000000000000006020830152565b818110611f66575050565b60008155600101611f5b565b9190601f8111611f8157505050565b611fad926000526020600020906020601f840160051c83019310611faf575b601f0160051c0190611f5b565b565b9091508190611fa0565b63ffffffff8092168015611fd65782600192814216031604011690565b505050600190565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b3573ffffffffffffffffffffffffffffffffffffffff8116810361016e5790565b3563ffffffff8116810361016e5790565b3561ffff8116810361016e5790565b3565ffffffffffff8116810361016e5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561016e570180359067ffffffffffffffff821161016e5760200191813603831361016e57565b929193959490956120d28561201d565b60405173ffffffffffffffffffffffffffffffffffffffff602082019216825263ffffffff861660408201526040815261210b81611c4b565b5190209687600052600660205263ffffffff6040600020541680612b6b575063ffffffff811663ffffffff42161015612b41576121478661201d565b906121546020880161203e565b6121606040890161203e565b61216c60608a0161203e565b61217860808b0161204f565b61218460a08c0161205e565b9061219160c08d0161203e565b9261219f60e08e018e612071565b36906121aa92611d87565b80519060200120948d61010081016121c191612071565b36906121cc92611d87565b80519060200120966040519960208b017f2b24aa047bbff05c807b5ba16020ac01534fdb34947d5608264ac56133753190905273ffffffffffffffffffffffffffffffffffffffff1660408b015263ffffffff1660608a015263ffffffff16608089015263ffffffff1660a088015261ffff1660c087015265ffffffffffff1660e086015263ffffffff166101008501526101208401526101409081840152825281610160810110610160830167ffffffffffffffff10176116b057610160820160405263ffffffff82516020840120917f1950b0dfc42b437b752641a63d09bd2a7d858914bdd31db6ef0dc3e5b2bf544e6101808501528188166101a0850152166101c08301526101e08201526080610160820152610160810161020082011067ffffffffffffffff610200830111176116b0576102008101604052610160810151610180820120907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000030147f000000000000000000000000000000000000000000000000000000000000000046141615612ab0575b50671901000000000000600052601a52603a5260ff6042601820936000603a5260405194600052166020526040526060526020600160806000825afa51903d15612aa25760006060528060405260208160048173ffffffffffffffffffffffffffffffffffffffff6123f68961201d565b167f238ac9330000000000000000000000000000000000000000000000000000000082525afa9081156109b757600091612a3f575b5073ffffffffffffffffffffffffffffffffffffffff809116911603612a15576001549163ffffffff600181851601167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000084161760015563ffffffff83166000526004602052604060002073ffffffffffffffffffffffffffffffffffffffff6124b48361201d565b167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781556125346124eb6020840161203e565b82547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b77ffffffff000000000000000000000000000000000000000016178255565b6125906125436040840161203e565b82547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7bffffffff00000000000000000000000000000000000000000000000016178255565b6125ec61259f6060840161203e565b82547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09190911b7fffffffff0000000000000000000000000000000000000000000000000000000016178255565b6126ba6001820161ffff6126026080860161204f565b167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000082541617815561267261263960a0860161205e565b82547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffff1660109190911b67ffffffffffff000016178255565b61267e60c0850161203e565b7fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff6bffffffff000000000000000083549260401b169116179055565b6126c760e0830183612071565b67ffffffffffffffff81116116b05760028301916126e9826114fe8554611e1a565b600090601f831160011461296f5760039493929160009183612964575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b92861b1c19161790555b0194612747610100830183612071565b67ffffffffffffffff81989298116116b0576127678161157e8454611e1a565b6000601f82116001146128ba57819063ffffffff98996000926128af575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b600052600660205260406000208484167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008254161790558383167f04344ed7a67fec80c444d56ee1cee242f3f75b91fecc8dbce8890069c82eb48e600080a273ffffffffffffffffffffffffffffffffffffffff6128348261201d565b166000526005602052836040600020541684831611612857575b50501690600090565b61287573ffffffffffffffffffffffffffffffffffffffff9161201d565b1660005282604060002091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000825416179055388061284e565b013590503880612785565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08216908360005260206000209160005b81811061294c57509983929160019463ffffffff9b9c10612914575b505050811b0190556127b7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88560031b161c19910135169055388080612907565b9192602060018192868f0135815501940192016128eb565b013590503880612706565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316918460005260206000209260005b8181106129fd5750916001939185600398979694106129c7575b505050811b019055612737565b01357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83881b60f8161c191690553880806129ba565b919360206001819287870135815501950192016129a0565b60046040517f10c74b03000000000000000000000000000000000000000000000000000000008152fd5b90506020813d602011612a9a575b81612a5a60209383611c9f565b8101031261016e575173ffffffffffffffffffffffffffffffffffffffff8116810361016e5773ffffffffffffffffffffffffffffffffffffffff61242b565b3d9150612a4d565b638baa579f6000526004601cfd5b60a09150807f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610200809301527f00000000000000000000000000000000000000000000000000000000000000006102208201527f00000000000000000000000000000000000000000000000000000000000000006102408201524661026082015230610280820152012038612385565b60046040517f0819bdcd000000000000000000000000000000000000000000000000000000008152fd5b97506001969550505050505056fea264697066735822122095589eb4b5ab0766de415e6daf4ff18a4ce5190aac1c3052b77c63cb77e91b7464736f6c63430008130033

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c908163105ddd1d14611ae65750806323c2e2bc14611a67578063298f7bdc14611a1857806331e451a91461189e5780633b2fb7a81461186457806341770e9a146117cf57806341cf2b7f146117945780634d9bf22f1461112957806360ed0f61146110d9578063642012c714610c8d578063672d7a0d14610b715780636e021332146105d057806373fb5c3a146104c4578063787a08a6146104895780637fb61b271461041b578063836a6cc9146103c357806384b0196e146102e157806390b04c15146102a657806396ef592e1461023f578063af640d0f146101fd578063bc85694f146101af578063e7cab346146101735763eccec5a81461011c57600080fd5b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5761016a610156611f22565b604051918291602083526020830190611d19565b0390f35b600080fd5b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576020604051620164408152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576004356000526003602052602061ffff60406000205416604051908152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57602063ffffffff60015416604051908152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5733600052600060205260006040812055337fd9957750e6343405c319eb99a4ec67fa11cfd66969318cbc71aa2d45fa53a349600080a2005b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57602060405161dd188152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5761037161031b611ce0565b610323611f22565b906040519283927f0f00000000000000000000000000000000000000000000000000000000000000845261036360209360e08587015260e0860190611d19565b908482036040860152611d19565b90466060840152306080840152600060a084015282820360c08401528060605192838152019160809160005b8281106103ac57505050500390f35b83518552869550938101939281019260010161039d565b3461016e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57602061040d6103ff611c11565b610407611c24565b90611fb9565b63ffffffff60405191168152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043573ffffffffffffffffffffffffffffffffffffffff811680910361016e576000526005602052602063ffffffff60406000205416604051908152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576020604051610e108152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5763ffffffff80610501611c11565b166000526004602052604060002061016a60036105c183549360018101549561054f6040519261053f846105388160028501611e6d565b0385611c9f565b6105386040518097819301611e6d565b604051968673ffffffffffffffffffffffffffffffffffffffff8998168852828160a01c166020890152828160c01c16604089015260e01c606088015261ffff8116608088015265ffffffffffff8160101c1660a088015260401c1660c08601526101208060e0870152850190611d19565b90838203610100850152611d19565b3461016e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57610607611c11565b61060f611c24565b67ffffffffffffffff9060443582811161016e57610631903690600401611dec565b92909160643582811161016e5761064c903690600401611dec565b91909260843590811161016e57610667903690600401611dec565b91909533600052600060205260ff604060002054166003811015610b4257600203610b1857600096604080518a815260046020820152209384549473ffffffffffffffffffffffffffffffffffffffff861615610aee5763ffffffff8660a01c16804210610ac45763ffffffff6106e58192828a60c01c1690611fb9565b1695168503610a9a578560e01c8511610a7057600101549665ffffffffffff8860101c163a11610a4657604051602081019063ffffffff8d1682528660408201526040815261073381611c4b565b5190209687600052600360205261ffff604060002054169761ffff8a168914610a1c576000526003602052604060002061ffff60018a01167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00008254161790558b60405163ffffffff6020820192168252876040820152336060820152606081526107bc81611c67565b51902080600052600260205260ff604060002054166109f2576000526002602052604060002060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555a9961ffff60018a01116109c35773ffffffffffffffffffffffffffffffffffffffff88163b1561016e578c95604051998a9889987ff8eb7fbd000000000000000000000000000000000000000000000000000000008a5263ffffffff1660048a0152602489015260010161ffff1660448801523360648801526084870160e0905260e487019061089b92611fde565b908582037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160a48701526108cf92611fde565b908382037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160c485015261090392611fde565b039173ffffffffffffffffffffffffffffffffffffffff1691815a6000948591f180156109b75761099f575b5063ffffffff61dd189160401c16915a90030111610975577fc68fb0ae5cea2793405d29014d881bcda18f67122e0bcd7d0a577e118b64e4c863ffffffff3393169180a3005b60046040517fbe9179a6000000000000000000000000000000000000000000000000000000008152fd5b6109aa919350611c37565b60009163ffffffff61092f565b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60046040517f88a21e4f000000000000000000000000000000000000000000000000000000008152fd5b60046040517f2f4ca85b000000000000000000000000000000000000000000000000000000008152fd5b60046040517f682bad5a000000000000000000000000000000000000000000000000000000008152fd5b60046040517fae6704a7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f4db310c3000000000000000000000000000000000000000000000000000000008152fd5b60046040517fefb74efe000000000000000000000000000000000000000000000000000000008152fd5b60046040517f1a00354f000000000000000000000000000000000000000000000000000000008152fd5b60046040517f8741cbb8000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043573ffffffffffffffffffffffffffffffffffffffff811680910361016e578060005260006020526040600020805460ff81166003811015610b425780610c4e57506001907fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000064ffffffff004260081b169116171790556040519063ffffffff421682527fb73af334a40cdaaad72e06d597bdeed270fc94d45415863afec219108096d2e860203393a3005b83610c8b604492604051927f5acfd51800000000000000000000000000000000000000000000000000000000845260048401526024830190611c04565bfd5b3461016e576101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e57610cc5611c11565b610ccd611c24565b67ffffffffffffffff91826044351161016e576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6044353603011261016e57610d17611d77565b60c4359363ffffffff8516850361016e5760e43581811161016e57610d40903690600401611dec565b9290936101043583811161016e57610d5c903690600401611dec565b9290936101243590811161016e57610d78903690600401611dec565b92909733600052600060205260ff604060002054166003811015610b4257600203610b1857610db59260a4359260843592604435600401916120c2565b909790156110cf57610258945b604080518a815260046020820152209788549360009973ffffffffffffffffffffffffffffffffffffffff861615610aee5763ffffffff8660a01c16804210610ac45763ffffffff610e1b8192828a60c01c1690611fb9565b1695168503610a9a578560e01c8511610a7057600101549665ffffffffffff8860101c163a11610a465760405163ffffffff8d16602082015285604082015260408152610e6781611c4b565b602081519101209687600052600360205261ffff604060002054169761ffff8a168914610a1c576000526003602052604060002061ffff60018a01167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00008254161790558c60405163ffffffff602082019216825287604082015233606082015260608152610ef481611c67565b51902080600052600260205260ff604060002054166109f2576000526002602052604060002060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790555a9a61ffff60018a01116109c35773ffffffffffffffffffffffffffffffffffffffff88163b1561016e578d95604051998a9889987ff8eb7fbd000000000000000000000000000000000000000000000000000000008a5263ffffffff1660048a0152602489015260010161ffff1660448801523360648801526084870160e0905260e4870190610fd392611fde565b908582037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160a487015261100792611fde565b908382037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160c485015261103b92611fde565b039173ffffffffffffffffffffffffffffffffffffffff1691815a6000948591f180156109b7576110af575b509063ffffffff61dd189260401c16925a9003010111610975577fc68fb0ae5cea2793405d29014d881bcda18f67122e0bcd7d0a577e118b64e4c863ffffffff3393169180a3005b61dd18929194506110bf90611c37565b63ffffffff600094919250611067565b6201644094610dc2565b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576004356000526006602052602063ffffffff60406000205416604051908152f35b3461016e5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043567ffffffffffffffff811161016e573660238201121561016e57611189903690602481600401359101611d87565b60243567ffffffffffffffff811161016e576111a9903690600401611dec565b90916044359265ffffffffffff8416840361016e576064359263ffffffff8416840361016e576084359263ffffffff8416840361016e5760a4359463ffffffff8616860361016e5760c4359061ffff8216820361016e576001549663ffffffff6001818a1601167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000089161760015563ffffffff80821681421601116109c357604051988961012081011067ffffffffffffffff6101208c0111176116b05761ffff63ffffffff94856112c19a8d60408365ffffffffffff98610120840183523384528180821681421601166020850152169101521660608d01521660808b01521660a08901521660c087015260e08601523691611d87565b61010083015263ffffffff81166000526004602052604060002073ffffffffffffffffffffffffffffffffffffffff8351167fffffffffffffffffffffffff000000000000000000000000000000000000000082541617815561137263ffffffff60208501511682907fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff77ffffffff000000000000000000000000000000000000000083549260a01b169116179055565b604083015181547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7bffffffff00000000000000000000000000000000000000000000000016178155606083015181547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09190911b7fffffffff00000000000000000000000000000000000000000000000000000000161781556114d56001820161ffff6080860151167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000082541617815561149365ffffffffffff60a08701511682907fffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffff67ffffffffffff000083549260101b169116179055565b60c085015181547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1660409190911b6bffffffff000000000000000016179055565b6002810160e084015180519067ffffffffffffffff82116116b057611504826114fe8554611e1a565b85611f72565b602090601f83116001146116ea5791806003949261010096946000926116df575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b92861b1c19161790555b019201519081519267ffffffffffffffff84116116b0578361158460209561157e8454611e1a565b84611f72565b8493601f8211600114611611579381929394600092611606575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b63ffffffff604051918181167f04344ed7a67fec80c444d56ee1cee242f3f75b91fecc8dbce8890069c82eb48e600080a2168152f35b01519050858061159e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169483600052866000209160005b878110611699575083600195969710611662575b505050811b0190556115d0565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c19169055858080611655565b919288600181928685015181550194019201611641565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b015190508880611525565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316918460005260206000209260005b81811061177c575092600192859261010098966003989610611746575b505050811b019055611556565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f884891b161c19169055888080611739565b9293602060018192878601518155019501930161171c565b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760206040516102588152f35b3461016e577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60c08136011261016e57611807611c11565b61180f611c24565b6044359267ffffffffffffffff841161016e5761012090843603011261016e576040926118509261183e611d77565b9060a4359360843593600401916120c2565b63ffffffff83519216825215156020820152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5761016a610156611ce0565b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5763ffffffff6118da611c11565b1680600052600460205273ffffffffffffffffffffffffffffffffffffffff6040600020541633036119ee578060005260046020526003604060002060008155600060018201556002810161192f8154611e1a565b90816119b0575b5050016119438154611e1a565b9081611972575b827ff4126e31c182db4c4109605c6d50470fc7e8ca90d62d44fd25cbe049fb9cac3e600080a2005b81601f6000931160011461198a5750555b818061194a565b9080839182526119a9601f60208420940160051c840160018501611f5b565b5555611983565b81601f600093116001146119c85750555b8380611936565b9080839182526119e7601f60208420940160051c840160018501611f5b565b55556119c1565b60046040517fa7fba711000000000000000000000000000000000000000000000000000000008152fd5b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e576004356000526002602052602060ff604060002054166040519015158152f35b3461016e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5760043573ffffffffffffffffffffffffffffffffffffffff811680910361016e5760005260006020526040806000205463ffffffff825191611adb8360ff8316611c04565b60081c166020820152f35b3461016e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261016e5733600052600060205260406000209081549060ff82166003811015610b425760018103611bd457505063ffffffff8160081c16610e1081014210611ba357507fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000166002179055337f7dc8b937d2916b130743c447af3d771fa55e66b7393105150e2e635ac3e87260600080a2005b602490604051907fc84b5bdd0000000000000000000000000000000000000000000000000000000082526004820152fd5b90610c8b6024927f33daa7f900000000000000000000000000000000000000000000000000000000835260048301905b906003821015610b425752565b6004359063ffffffff8216820361016e57565b6024359063ffffffff8216820361016e57565b67ffffffffffffffff81116116b057604052565b6060810190811067ffffffffffffffff8211176116b057604052565b6080810190811067ffffffffffffffff8211176116b057604052565b6040810190811067ffffffffffffffff8211176116b057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176116b057604052565b60405190611ced82611c83565b601382527f496e6665726e6574436f6f7264696e61746f72000000000000000000000000006020830152565b919082519283825260005b848110611d635750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b602081830181015184830182015201611d24565b6064359060ff8216820361016e57565b92919267ffffffffffffffff82116116b05760405191611dcf60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611c9f565b82948184528183011161016e578281602093846000960137010152565b9181601f8401121561016e5782359167ffffffffffffffff831161016e576020838186019501011161016e57565b90600182811c92168015611e63575b6020831014611e3457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691611e29565b9060009291805491611e7e83611e1a565b918282526001938481169081600014611ee05750600114611ea0575b50505050565b90919394506000526020928360002092846000945b838610611ecc575050505001019038808080611e9a565b805485870183015294019385908201611eb5565b91505060209495507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009193501683830152151560051b01019038808080611e9a565b60405190611f2f82611c83565b600182527f31000000000000000000000000000000000000000000000000000000000000006020830152565b818110611f66575050565b60008155600101611f5b565b9190601f8111611f8157505050565b611fad926000526020600020906020601f840160051c83019310611faf575b601f0160051c0190611f5b565b565b9091508190611fa0565b63ffffffff8092168015611fd65782600192814216031604011690565b505050600190565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b3573ffffffffffffffffffffffffffffffffffffffff8116810361016e5790565b3563ffffffff8116810361016e5790565b3561ffff8116810361016e5790565b3565ffffffffffff8116810361016e5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561016e570180359067ffffffffffffffff821161016e5760200191813603831361016e57565b929193959490956120d28561201d565b60405173ffffffffffffffffffffffffffffffffffffffff602082019216825263ffffffff861660408201526040815261210b81611c4b565b5190209687600052600660205263ffffffff6040600020541680612b6b575063ffffffff811663ffffffff42161015612b41576121478661201d565b906121546020880161203e565b6121606040890161203e565b61216c60608a0161203e565b61217860808b0161204f565b61218460a08c0161205e565b9061219160c08d0161203e565b9261219f60e08e018e612071565b36906121aa92611d87565b80519060200120948d61010081016121c191612071565b36906121cc92611d87565b80519060200120966040519960208b017f2b24aa047bbff05c807b5ba16020ac01534fdb34947d5608264ac56133753190905273ffffffffffffffffffffffffffffffffffffffff1660408b015263ffffffff1660608a015263ffffffff16608089015263ffffffff1660a088015261ffff1660c087015265ffffffffffff1660e086015263ffffffff166101008501526101208401526101409081840152825281610160810110610160830167ffffffffffffffff10176116b057610160820160405263ffffffff82516020840120917f1950b0dfc42b437b752641a63d09bd2a7d858914bdd31db6ef0dc3e5b2bf544e6101808501528188166101a0850152166101c08301526101e08201526080610160820152610160810161020082011067ffffffffffffffff610200830111176116b0576102008101604052610160810151610180820120907f4bdffc2f7bddf42b258c51d780c4f8e7b01dc4545bb76c1d6095e138a1df4c9b907f0000000000000000000000008d871ef2826ac9001fb2e33fdd6379b6aabf449c30147f000000000000000000000000000000000000000000000000000000000000210546141615612ab0575b50671901000000000000600052601a52603a5260ff6042601820936000603a5260405194600052166020526040526060526020600160806000825afa51903d15612aa25760006060528060405260208160048173ffffffffffffffffffffffffffffffffffffffff6123f68961201d565b167f238ac9330000000000000000000000000000000000000000000000000000000082525afa9081156109b757600091612a3f575b5073ffffffffffffffffffffffffffffffffffffffff809116911603612a15576001549163ffffffff600181851601167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000084161760015563ffffffff83166000526004602052604060002073ffffffffffffffffffffffffffffffffffffffff6124b48361201d565b167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161781556125346124eb6020840161203e565b82547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b77ffffffff000000000000000000000000000000000000000016178255565b6125906125436040840161203e565b82547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7bffffffff00000000000000000000000000000000000000000000000016178255565b6125ec61259f6060840161203e565b82547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09190911b7fffffffff0000000000000000000000000000000000000000000000000000000016178255565b6126ba6001820161ffff6126026080860161204f565b167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000082541617815561267261263960a0860161205e565b82547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffff1660109190911b67ffffffffffff000016178255565b61267e60c0850161203e565b7fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff6bffffffff000000000000000083549260401b169116179055565b6126c760e0830183612071565b67ffffffffffffffff81116116b05760028301916126e9826114fe8554611e1a565b600090601f831160011461296f5760039493929160009183612964575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b92861b1c19161790555b0194612747610100830183612071565b67ffffffffffffffff81989298116116b0576127678161157e8454611e1a565b6000601f82116001146128ba57819063ffffffff98996000926128af575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790555b600052600660205260406000208484167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008254161790558383167f04344ed7a67fec80c444d56ee1cee242f3f75b91fecc8dbce8890069c82eb48e600080a273ffffffffffffffffffffffffffffffffffffffff6128348261201d565b166000526005602052836040600020541684831611612857575b50501690600090565b61287573ffffffffffffffffffffffffffffffffffffffff9161201d565b1660005282604060002091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000825416179055388061284e565b013590503880612785565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08216908360005260206000209160005b81811061294c57509983929160019463ffffffff9b9c10612914575b505050811b0190556127b7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88560031b161c19910135169055388080612907565b9192602060018192868f0135815501940192016128eb565b013590503880612706565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08316918460005260206000209260005b8181106129fd5750916001939185600398979694106129c7575b505050811b019055612737565b01357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83881b60f8161c191690553880806129ba565b919360206001819287870135815501950192016129a0565b60046040517f10c74b03000000000000000000000000000000000000000000000000000000008152fd5b90506020813d602011612a9a575b81612a5a60209383611c9f565b8101031261016e575173ffffffffffffffffffffffffffffffffffffffff8116810361016e5773ffffffffffffffffffffffffffffffffffffffff61242b565b3d9150612a4d565b638baa579f6000526004601cfd5b60a09150807f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610200809301527fe7f0b77df5c5e5c7a7bc3e252dd153438c3d764ef75b93d0f9e5658cfd0afde36102208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66102408201524661026082015230610280820152012038612385565b60046040517f0819bdcd000000000000000000000000000000000000000000000000000000008152fd5b97506001969550505050505056fea264697066735822122095589eb4b5ab0766de415e6daf4ff18a4ce5190aac1c3052b77c63cb77e91b7464736f6c63430008130033

Deployed ByteCode Sourcemap

576:10455:3:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;1813:10;576:10455;;;;;;;;;;;;;;;;;;5256:49:2;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;4568:20:2;576:10455:3;;;;;;;;;;;;;;;;;;;9108:10:4;576:10455:3;;;;;;;;;;9108:10:4;9170:27;576:10455:3;9170:27:4;;576:10455:3;;;;;;;;;;;;;;;4157:10:2;576:10455:3;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;7365:13:1;;576:10455:3;;;;7416:4:1;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3195:52;576:10455;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2989:7:4;576:10455:3;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;5409:52:2;576:10455:3;;;5409:52:2;;;;576:10455:3;;;;;5409:52:2;576:10455:3;5409:52:2;576:10455:3;5409:52:2;;;;576:10455:3;:::i;:::-;;;;:::i;:::-;;;;5409:52:2;;;;;576:10455:3;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;6206:10:4;;;;576:10455:3;;;;;;;;;;;;;;;;;6228:17:4;6197:48;6193:101;;576:10455:3;11914:1349:2;576:10455:3;11914:1349:2;;;;;576:10455:3;;11914:1349:2;;;;;;;;;;;13326:22;13322:82;;11914:1349;;576:10455:3;11914:1349:2;;13470:15;;:29;13466:90;;11914:1349;13627:47;11914:1349;;;;;;;13627:47;;:::i;:::-;576:10455:3;;;13741:28:2;;13737:84;;11914:1349;576:10455:3;11914:1349:2;13877:23;;13873:84;;14103:561;;;;;;;;;14739:11;:28;14735:84;;576:10455:3;;;14930:36:2;;576:10455:3;11914:1349:2;576:10455:3;;;;;;;;;;14930:36:2;;;;;:::i;:::-;576:10455:3;14920:47:2;;576:10455:3;;;;;;;14103:561:2;576:10455:3;;;;;14103:561:2;;;;15043:39;;15039:96;;576:10455:3;;;;;;;;14103:561:2;;576:10455:3;;;;;;;;;;;;;11914:1349:2;576:10455:3;15384:48:2;;576:10455:3;;;;;;;;;6206:10:4;576:10455:3;;;;;15384:48:2;;;;;:::i;:::-;576:10455:3;15374:59:2;;576:10455:3;;;6228:17:4;576:10455:3;;;;;;;;15443:78:2;;576:10455:3;;6228:17:4;576:10455:3;;;;;14103:561:2;576:10455:3;;;;;;;15671:9:2;576:10455:3;14103:561:2;;576:10455:3;;;;;11914:1349:2;;;15690:150;;;;576:10455:3;;;;15690:150:2;;;;;576:10455:3;15690:150:2;;11914:1349;576:10455:3;;15690:150:2;;576:10455:3;;;;;14103:561:2;576:10455:3;14103:561:2;576:10455:3;;;;;6206:10:4;576:10455:3;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;15690:150:2;11914:1349;;;15690:150;;;576:10455:3;15690:150:2;;;;;;;;;;576:10455:3;14103:561:2;11914:1349;4157:10;14103:561;576:10455:3;14103:561:2;;15870:9;;576:10455:3;;;16560:30:2;16556:86;;16693:49;11914:1349;6206:10:4;576:10455:3;;16693:49:2;;;576:10455:3;16556:86:2;576:10455:3;;;16613:18:2;;;;15690:150;;;;;;:::i;:::-;576:10455:3;;11914:1349:2;15690:150;;;576:10455:3;;;;;;;;;;;;;;;;;;;15443:78:2;576:10455:3;;;15488:22:2;;;;15039:96;576:10455:3;;;15105:19:2;;;;14735:84;576:10455:3;;;14790:18:2;;;;13873:84;576:10455:3;;;13923:23:2;;;;13737:84;576:10455:3;;;13792:18:2;;;;13466:90;576:10455:3;;;13522:23:2;;;;13322:82;576:10455:3;;;13371:22:2;;;;6193:101:4;576:10455:3;;;6268:15:4;;;;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7045:34:4;7041:110;;7328:15;7219:21;7328:15;576:10455:3;;7328:15:4;576:10455:3;;;;;;;;;;;7328:15:4;576:10455:3;7328:15:4;576:10455:3;;;7399:57:4;576:10455:3;7420:10:4;7399:57;;576:10455:3;7041:110:4;576:10455:3;;;;;;7102:38:4;;;;576:10455:3;7102:38:4;;576:10455:3;;;;;;:::i;:::-;7102:38:4;576:10455:3;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;6206:10:4;;;;576:10455:3;;;;;;;;;;;;;;;;;6228:17:4;6197:48;6193:101;;10355:56:3;576:10455;;;;;;;;;;;10355:56;;:::i;:::-;10541:16;;;10567:311;;;1434:7;10567:311;;576:10455;11914:1349:2;;;;;576:10455:3;;11914:1349:2;;;;;;;-1:-1:-1;576:10455:3;11914:1349:2;;;;13326:22;13322:82;;576:10455:3;11914:1349:2;;;;13470:15;;:29;13466:90;;576:10455:3;13627:47:2;11914:1349;;;;;;;13627:47;;:::i;:::-;576:10455:3;;;13741:28:2;;13737:84;;11914:1349;576:10455:3;11914:1349:2;13877:23;;13873:84;;14103:561;;;;;;;;;14739:11;:28;14735:84;;576:10455:3;;;;;;14930:36:2;;576:10455:3;;;;;;;14930:36:2;;;;;:::i;:::-;576:10455:3;;;14930:36:2;;14920:47;576:10455:3;;;;;;;14103:561:2;576:10455:3;;;;;14103:561:2;;;;15043:39;;15039:96;;576:10455:3;;;;;;;;14103:561:2;;576:10455:3;;;;;;;;;;;;;;;15384:48:2;;576:10455:3;;;;;;;;;6206:10:4;576:10455:3;;;;;15384:48:2;;;;;:::i;:::-;576:10455:3;15374:59:2;;576:10455:3;;;6228:17:4;576:10455:3;;;;;;;;15443:78:2;;576:10455:3;;6228:17:4;576:10455:3;;;;;14103:561:2;576:10455:3;;;;;;;15671:9:2;576:10455:3;14103:561:2;;576:10455:3;;;;;11914:1349:2;;;15690:150;;;;576:10455:3;;;;15690:150:2;;;;;576:10455:3;15690:150:2;;576:10455:3;;;15690:150:2;;576:10455:3;;;;;14103:561:2;576:10455:3;14103:561:2;576:10455:3;;;;;6206:10:4;576:10455:3;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;15690:150:2;11914:1349;;;15690:150;;;576:10455:3;15690:150:2;;;;;;;;;;10567:311:3;14103:561:2;;576:10455:3;4157:10:2;14103:561;576:10455:3;14103:561:2;;15870:9;;576:10455:3;;;;16560:30:2;16556:86;;16693:49;576:10455:3;6206:10:4;576:10455:3;;16693:49:2;;;576:10455:3;15690:150:2;4157:10;15690:150;;;;;;;:::i;:::-;576:10455:3;;15690:150:2;;;;;;10567:311:3;1813:10;10567:311;;;576:10455;;;;;;;;;;;;;;;3441:52;576:10455;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18061:4:2;576:10455:3;;;18061:4:2;576:10455:3;;;;;;;;;18061:4:2;576:10455:3;;;;;18423:15:2;;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18469:10:2;576:10455:3;;;;;;18423:15:2;;576:10455:3;;;;18152:578:2;;576:10455:3;;18152:578:2;;576:10455:3;;;18152:578:2;;576:10455:3;;;18152:578:2;;576:10455:3;;;18152:578:2;;576:10455:3;;;18152:578:2;;576:10455:3;;18152:578:2;;576:10455:3;;;;:::i;:::-;18152:578:2;;;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;;;;;;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;;;;;18061:4:2;576:10455:3;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;;;;;;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;;;;;;;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;18152:578:2;576:10455:3;;;;;;;;;;;18061:4:2;576:10455:3;;;;;;;;;;;;18152:578:2;;576:10455:3;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;18061:4:2;576:10455:3;;;;;;;;;;;;;;;;;;18779:35:2;576:10455:3;18779:35:2;;576:10455:3;;;;;;;;-1:-1:-1;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;18061:4:2;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18061:4:2;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;18061:4:2;576:10455:3;;;18152:578:2;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18061:4:2;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1434:7;576:10455;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;19235:10:2;19196:49;19192:109;;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;19424:37:2;;576:10455:3;19424:37:2;;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;19192:109:2;576:10455:3;;;19268:22:2;;;;576:10455:3;;;;;;;;;;;;;;;4695:45:2;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;7901:10:4;576:10455:3;;;;;;;;;;;;;;;;;;;;;8107:21:4;8092:36;;8088:106;;576:10455:3;;;;;;;2989:7:4;576:10455:3;;8478:15:4;:29;8474:101;;-1:-1:-1;576:10455:3;;8639:17:4;576:10455:3;;;7901:10:4;8779:25;576:10455:3;;8779:25:4;576:10455:3;8474:101:4;576:10455:3;;;;8530:34:4;;;;576:10455:3;8530:34:4;;576:10455:3;8530:34:4;8088:106;8151:32;576:10455:3;;8151:32:4;;;;576:10455:3;8151:32:4;;576:10455:3;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;576:10455:3;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;576:10455:3;;;;-1:-1:-1;576:10455:3;;;-1:-1:-1;576:10455:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::o;:::-;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;576:10455:3;;-1:-1:-1;576:10455:3;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:::o;:::-;;;-1:-1:-1;576:10455:3;;;;19774:590:2;576:10455:3;;;;19936:11:2;;19932:50;;20305:15;20346:1;20305:15;;;576:10455:3;;;;;;19774:590:2;:::o;19932:50::-;19963:8;;;19970:1;19963:8;:::o;576:10455:3:-;;;;;;;;;;;;;;;-1:-1:-1;576:10455:3;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;1940:189::-;;576:10455;;;;;;;1940:189;:::o;:::-;;576:10455;;;;;;;1940:189;:::o;:::-;;576:10455;;;;;;;1940:189;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5664:3289::-;;;;;;;;5999:9;;;:::i;:::-;576:10455;;;5988:28;;;576:10455;;;;;;;;;;;;5988:28;;;;;:::i;:::-;576:10455;5978:39;;576:10455;;-1:-1:-1;576:10455:3;6051:18;5988:28;576:10455;;;-1:-1:-1;576:10455:3;;;6270:19;6266:79;;576:10455;;;;;6470:15;576:10455;6463:33;;6459:89;;7059:9;;;:::i;:::-;7098:12;;5988:28;7098:12;;;:::i;:::-;7140:10;576:10455;7140:10;;;:::i;:::-;7180:13;576:10455;7180:13;;;:::i;:::-;7223:14;;;;;:::i;:::-;7267:15;;;;;:::i;:::-;7312;;;;;;:::i;:::-;7424;;;;;;;:::i;:::-;576:10455;;;;;:::i;:::-;;;;5988:28;576:10455;7408:33;7481:10;;;;;;;;:::i;:::-;576:10455;;;;;:::i;:::-;;;;5988:28;576:10455;7471:21;576:10455;;;6961:557;5988:28;6961:557;;1940:189;576:10455;;;;;1940:189;;576:10455;;;;1940:189;;576:10455;;;7223:14;1940:189;;576:10455;;;7267:15;1940:189;;576:10455;;;7312:15;1940:189;;576:10455;;;7424:15;1940:189;;576:10455;;;7481:10;1940:189;;576:10455;1940:189;;;576:10455;1940:189;;;;;576:10455;6961:557;;576:10455;1940:189;576:10455;;;1940:189;576:10455;;;-1:-1:-1;576:10455:3;;;1940:189;576:10455;;;;;;;5988:28;6961:557;;6926:614;6731:827;2576:254;6731:827;;;576:10455;;;;1940:189;;;576:10455;;1940:189;;;576:10455;1940:189;;;576:10455;7223:14;1940:189;576:10455;;6731:827;1940:189;576:10455;;;;;;;;;;;;;;;;;;;1940:189;576:10455;;;6731:827;;;6636:936;5840:17:1;5997:22;8980:11;;9044:111;;8935:14;9044:111;;;;6033:76;;5664:3289:3;6172:401:1;;-1:-1:-1;6172:401:1;;;;;6548:1013:0;6172:401:1;;;;-1:-1:-1;6172:401:1;;576:10455:3;6548:1013:0;;-1:-1:-1;6548:1013:0;;5988:28:3;6548:1013:0;576:10455:3;6548:1013:0;576:10455:3;6548:1013:0;5988:28:3;6548:1013:0;7223:14:3;-1:-1:-1;6548:1013:0;;;;;;;;;-1:-1:-1;576:10455:3;6548:1013:0;;576:10455:3;6548:1013:0;5988:28:3;7896:9;7886:29;7896:9;576:10455;7896:9;;;:::i;:::-;576:10455;;7886:29;;;;;;;;;-1:-1:-1;7886:29:3;;;5664:3289;576:10455;;;;;;;8006:34;8002:88;;6548:1013:0;576:10455:3;;;6548:1013:0;576:10455:3;;;;;;;;;6548:1013:0;576:10455:3;;;;-1:-1:-1;576:10455:3;7886:29;5988:28;576:10455;;-1:-1:-1;576:10455:3;;1940:189;;;:::i;:::-;576:10455;;;;;;;;1940:189;;5988:28;7098:12;;1940:189;:::i;:::-;576:10455;;;;;;;;;;;;;;;1940:189;;;576:10455;7140:10;;1940:189;:::i;:::-;576:10455;;;;;;;;;;;;;;;1940:189;;;576:10455;7180:13;;1940:189;:::i;:::-;576:10455;;;;;;;;;;;;;;;1940:189;;6548:1013:0;1940:189:3;;576:10455;1940:189;7223:14;;;1940:189;:::i;:::-;576:10455;;;;;;;;1940:189;;7267:15;;;1940:189;:::i;:::-;576:10455;;;;;;;;;;;;;;;1940:189;;7312:15;;;1940:189;:::i;:::-;576:10455;;;;;;;;;;;;;;1940:189;;7424:15;;;1940:189;;:::i;:::-;576:10455;1940:189;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1940:189:3;;;;;;;;;;;;;-1:-1:-1;;1940:189:3;;;;576:10455;;;;6548:1013:0;576:10455:3;;;;;;;;1940:189;;;;7481:10;1940:189;7481:10;;;1940:189;;:::i;:::-;576:10455;1940:189;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;1940:189:3;;;;;;;;;576:10455;1940:189;;-1:-1:-1;1940:189:3;;;;576:10455;;;;6548:1013:0;576:10455:3;;1940:189;576:10455;;;;;1940:189;;;-1:-1:-1;576:10455:3;6051:18;5988:28;576:10455;;-1:-1:-1;576:10455:3;;;;;;;;;;;;;;8598:35;-1:-1:-1;8598:35:3;;576:10455;8788:9;;;:::i;:::-;576:10455;-1:-1:-1;576:10455:3;8769:18;5988:28;576:10455;;;-1:-1:-1;576:10455:3;;;;;;8761:37;8757:105;;1940:189;576:10455;;;8916:30;-1:-1:-1;5664:3289:3;:::o;8757:105::-;8833:9;576:10455;8833:9;;:::i;:::-;576:10455;-1:-1:-1;576:10455:3;;;-1:-1:-1;576:10455:3;;;;;;;;;;8757:105;;;;1940:189;;;;-1:-1:-1;1940:189:3;;;;;5988:28;1940:189;;576:10455;;-1:-1:-1;576:10455:3;5988:28;-1:-1:-1;576:10455:3;1940:189;-1:-1:-1;1940:189:3;;;;;;;;;;;6548:1013:0;1940:189:3;576:10455;1940:189;;;;;;;;;;;;;;;;;576:10455;;;1940:189;576:10455;;;;1940:189;;;576:10455;1940:189;;;;;;;;;;5988:28;6548:1013:0;1940:189:3;;;;;;;;;;;;;;;;;;;-1:-1:-1;1940:189:3;;;;;5988:28;1940:189;;576:10455;;-1:-1:-1;576:10455:3;5988:28;-1:-1:-1;576:10455:3;1940:189;-1:-1:-1;1940:189:3;;;;;;;;6548:1013:0;1940:189:3;;;;;;;;;;;;;;;;;;;;;;;;;576:10455;;;;;;;;;1940:189;;;;;;;;;;5988:28;6548:1013:0;1940:189:3;;;;;;;;;;;;;;;8002:88;7886:29;576:10455;;8063:16;;;;7886:29;;;5988:28;7886:29;;5988:28;7886:29;;;;;;5988:28;7886:29;;;:::i;:::-;;;1940:189;;;;;576:10455;;;;;;;;7886:29;;;;;-1:-1:-1;7886:29:3;;6548:1013:0;;-1:-1:-1;6548:1013:0;;;;6033:76:1;7267:15:3;576:10455;;;8388:347:1;576:10455:3;;;;8388:347:1;8264:15;8388:347;;;;8307:18;8388:347;;;;9044:111;8388:347;;;;9044:111;8388:347;;;;576:10455:3;8388:347:1;6033:76;;;6459:89:3;6519:18;576:10455;;6519:18;;;;6266:79;6305:29;-1:-1:-1;6329:4:3;;6305:29;-1:-1:-1;;;;;;6305:29:3:o

Swarm Source

ipfs://95589eb4b5ab0766de415e6daf4ff18a4ce5190aac1c3052b77c63cb77e91b74
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.