Contract 0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c 3

 
Txn Hash Method
Block
From
To
Value
0x4cd4f2e9758730c7b0b682ee8e0fe02ffd2f25ab69a73f73529d5418cf15485bDeliver Compute132305822024-04-16 6:55:115 secs ago0xa160aaa257ba81627b0987290cf19af79a5fcd96 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000005559870.018516497
0x4d8f7fcdfeb4562d6cc04c0a70d45aca70a374ce417fd9ecbfaeeed631fa64a1Deliver Compute132305812024-04-16 6:55:097 secs ago0x11ea9589d8ad2f6d48b340b82148b6d96a6729e9 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006015470.018531245
0x5b519290729be2935d9ffbe924edb7171289f410054b344ca1a52595739b48f6Deliver Compute132305812024-04-16 6:55:097 secs ago0x9b87c21f9d8ab20a806a7576dfc15f30986f7c3d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006011980.018531245
0x229eb46a3b1fbf0efd1140ce62ade01583a3a4e236beb12cbba1c14331843c96Deliver Compute132305812024-04-16 6:55:097 secs ago0xbc23b4da3e1d8a54f41cebd88e075e5c91692bf4 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006012480.018531245
0x1cd9c0c0b73825ac1a9056dbf93e9cdeb5ad564aa3b25fbec08e982a63dc1f30Deliver Compute132305762024-04-16 6:54:5917 secs ago0x11ea9589d8ad2f6d48b340b82148b6d96a6729e9 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000005980450.018466177
0x0652dc7017df6ffb4315c04246c33a3e2df0d6b537388a6fd4eb83ce87567372Deliver Compute132305762024-04-16 6:54:5917 secs ago0xa160aaa257ba81627b0987290cf19af79a5fcd96 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000005529010.018466177
0xb3f1fda99f7d48c5960fb8084d789cf7146b477cd1b93350fd8a06c23981457bDeliver Compute132305762024-04-16 6:54:5917 secs ago0x9b87c21f9d8ab20a806a7576dfc15f30986f7c3d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000005977060.018466177
0xcb07bf3c4003d488071484009be23472d78b3b2fad04158a6b3da673adbfa467Deliver Compute132305762024-04-16 6:54:5917 secs ago0xbc23b4da3e1d8a54f41cebd88e075e5c91692bf4 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.000000597610.018466177
0x194f45d6176f86174037abf24a387b61b92108e0c3b9618db0e21804768475b1Deliver Compute132305742024-04-16 6:54:5521 secs ago0x08d0e7377163fd7e235b78cd41a00041596989a3 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000005987580.018495356
0xe185fe61338be03ff3b974f7a79ac34c348fcad49bb4184ffe4aba6cf1abd074Deliver Compute132305732024-04-16 6:54:5323 secs ago0x08d0e7377163fd7e235b78cd41a00041596989a3 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000005997550.018529241
0x07bfc9831be6f8802572d540dc88f8caeec7c85d172a2ca46879e0c3a87d4dcfDeliver Compute132305722024-04-16 6:54:5125 secs ago0x08d0e7377163fd7e235b78cd41a00041596989a3 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006033150.018557002
0x13cecb28193c05373cddb9a981823a85069db6d584c40adb7edaee8883ec5edbDeliver Compute132305722024-04-16 6:54:5125 secs ago0x11ea9589d8ad2f6d48b340b82148b6d96a6729e9 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006031630.018557002
0xe5d4080df05bcca66e923813e9e636bf4dd13f86df0ef1fc3cda93d6f3f62aaeDeliver Compute132305712024-04-16 6:54:4927 secs ago0x9b87c21f9d8ab20a806a7576dfc15f30986f7c3d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006029840.018563007
0x8ca510b8819faa34e5df28dfd8675ef9880162cf40c8ba50d5900b27740a8786Deliver Compute132305712024-04-16 6:54:4927 secs ago0xa160aaa257ba81627b0987290cf19af79a5fcd96 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000005584020.018563007
0x82a1a367e446b6dd921729f1fd410b8e42659794ca24162c9671be8ef3a6d5e7Deliver Compute132305712024-04-16 6:54:4927 secs ago0xbc23b4da3e1d8a54f41cebd88e075e5c91692bf4 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006034920.018563007
0xdb520cd6e63dbbcffac209ca6771d19aa0755c1ae5eb46f73651d1e50ddf0f77Deliver Compute132305702024-04-16 6:54:4729 secs ago0xa88f7401f9425f6f34b0b2d818fe44784d2bf6b8 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000015627380.018571298
0x4a247b972173de8c71fd7228e320fb24655c33038f8d3802dcfa7b96b39a8c05Deliver Compute132305702024-04-16 6:54:4729 secs ago0x08d0e7377163fd7e235b78cd41a00041596989a3 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006032160.018571298
0x1142cd13ef6c8ce3773d621a1d7a93a7529404920f3a8783e105816e530ca92eDeliver Compute132305692024-04-16 6:54:4531 secs ago0xa88f7401f9425f6f34b0b2d818fe44784d2bf6b8 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006041530.018585496
0x57f26a036d2dcfc518a2293f01a012592a626f0645e57b088f8acaae5902bf9cDeliver Compute132305682024-04-16 6:54:4333 secs ago0x08d0e7377163fd7e235b78cd41a00041596989a3 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006044110.018594242
0xc500c6c44676152867c16746265c8128c81245e585984b1a1911908acd4e0672Deliver Compute132305682024-04-16 6:54:4333 secs ago0xa88f7401f9425f6f34b0b2d818fe44784d2bf6b8 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006044110.018594242
0x05d17f7db3b63f0a80e20b6f9ff9449f4d6965fb5ae492282d803cc20323ba7aDeliver Compute132305682024-04-16 6:54:4333 secs ago0xa88f7401f9425f6f34b0b2d818fe44784d2bf6b8 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000015645810.018594242
0x72c84c2f4f301003799e476c6fded696b5c3b503a1645356c55de5225553e616Deliver Compute132305672024-04-16 6:54:4135 secs ago0x08d0e7377163fd7e235b78cd41a00041596989a3 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006045120.018602872
0x442b6fb1ecaf9a186b718188e4a080575be4e643064615da10bc496f272d8d53Deliver Compute132305662024-04-16 6:54:3937 secs ago0xbc23b4da3e1d8a54f41cebd88e075e5c91692bf4 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006054550.018629772
0x26494ffdb882e7475f74cabaf520c3d80ff15e8f6b0ab7fdacefdf7a121eb639Deliver Compute132305662024-04-16 6:54:3937 secs ago0x11ea9589d8ad2f6d48b340b82148b6d96a6729e9 IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006056080.018629772
0xba291616e1e3a68374f7bfa6927943ef38494329f43bc35abf5ea73778a21668Deliver Compute132305662024-04-16 6:54:3937 secs ago0x9b87c21f9d8ab20a806a7576dfc15f30986f7c3d IN  0x8d871ef2826ac9001fb2e33fdd6379b6aabf449c0 ETH0.0000006052520.018629772
[ 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.