ETH Price: $2,108.14 (+4.18%)

Contract

0x595ececCEa09EE8Bfa8DB33120f7E114E493E434
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Poke245487792026-02-27 14:11:2313 days ago1772201483IN
0x595ececC...4E493E434
0 ETH0.000008470.10965016
Poke245416522026-02-26 14:20:3514 days ago1772115635IN
0x595ececC...4E493E434
0 ETH0.000014830.19246747
Poke245345332026-02-25 14:29:3515 days ago1772029775IN
0x595ececC...4E493E434
0 ETH0.000008270.10863038
Poke245274132026-02-24 14:39:2316 days ago1771943963IN
0x595ececC...4E493E434
0 ETH0.000016640.21849266
Poke245202792026-02-23 14:47:2317 days ago1771858043IN
0x595ececC...4E493E434
0 ETH0.000007210.09827332
Poke245131322026-02-22 14:53:2318 days ago1771772003IN
0x595ececC...4E493E434
0 ETH0.000004630.06318596
Poke245060082026-02-21 15:02:3519 days ago1771686155IN
0x595ececC...4E493E434
0 ETH0.000003630.04720728
Poke244988782026-02-20 15:11:5920 days ago1771600319IN
0x595ececC...4E493E434
0 ETH0.000026920.3624356
Poke244917512026-02-19 15:20:4721 days ago1771514447IN
0x595ececC...4E493E434
0 ETH0.000024440.32906632
Poke244846252026-02-18 15:29:5922 days ago1771428599IN
0x595ececC...4E493E434
0 ETH0.000013940.18084895
Poke244751532026-02-17 7:47:3523 days ago1771314455IN
0x595ececC...4E493E434
0 ETH0.000002230.02999644
Poke244466192026-02-13 8:19:1127 days ago1770970751IN
0x595ececC...4E493E434
0 ETH0.000003760.05048345
Poke244395052026-02-12 8:28:4728 days ago1770884927IN
0x595ececC...4E493E434
0 ETH0.000004470.05834194
Poke244323852026-02-11 8:38:2329 days ago1770799103IN
0x595ececC...4E493E434
0 ETH0.00000530.06881863
Poke244252712026-02-10 8:46:4730 days ago1770713207IN
0x595ececC...4E493E434
0 ETH0.000005460.0708339
Poke244181552026-02-09 8:56:1131 days ago1770627371IN
0x595ececC...4E493E434
0 ETH0.000004350.05863775
Poke244110642026-02-08 9:04:5932 days ago1770541499IN
0x595ececC...4E493E434
0 ETH0.00000380.05125021
Poke244039752026-02-07 9:13:3533 days ago1770455615IN
0x595ececC...4E493E434
0 ETH0.000008650.11230522
Poke243968562026-02-06 9:21:5934 days ago1770369719IN
0x595ececC...4E493E434
0 ETH0.000016670.22731502
Poke243897472026-02-05 9:30:3535 days ago1770283835IN
0x595ececC...4E493E434
0 ETH0.000019370.25135477
Poke243826452026-02-04 9:39:1136 days ago1770197951IN
0x595ececC...4E493E434
0 ETH0.000011130.14968896
Poke243755262026-02-03 9:46:1137 days ago1770111971IN
0x595ececC...4E493E434
0 ETH0.000013650.18376636
Poke243684112026-02-02 9:55:1138 days ago1770026111IN
0x595ececC...4E493E434
0 ETH0.000046420.62492228
Poke243612982026-02-01 10:04:3539 days ago1769940275IN
0x595ececC...4E493E434
0 ETH0.00003020.40411424
Poke243541752026-01-31 10:11:2340 days ago1769854283IN
0x595ececC...4E493E434
0 ETH0.000006920.08984074
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x60c06040242113532026-01-11 12:05:3560 days ago1768133135  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ChronicleVAO_Centrifuge_deJAAA_Consumer_2

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 10000 runs

Other Settings:
paris EvmVersion
File 1 of 13 : Consumer.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;

import {ChronicleVAO_Centrifuge_deJAAA_Consumer} from "../../src/Consumer.sol";

contract ChronicleVAO_Centrifuge_deJAAA_Consumer_2 is ChronicleVAO_Centrifuge_deJAAA_Consumer {

    constructor(address initialAuthed, address router)
        ChronicleVAO_Centrifuge_deJAAA_Consumer(initialAuthed, router)
    {}
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;

import {Toll} from "chronicle-std@v2/toll/Toll.sol";

import {UScribe} from "uscribe@v1/UScribe.sol";

import {IChronicleVAO_Centrifuge_deJAAA_Reader as IReader} from "./IReader.sol";

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

// The poke struct is the single struct that is being poked.
struct PokeData {
    uint48 age;
    uint128 val;
}

/**
 * @title ChronicleVAO_Centrifuge_deJAAA_Consumer
 *
 * @custom:version 0.1.0
 *
 * @author Chronicle Labs, Inc
 * @custom:security-contact security@chroniclelabs.org
 */
contract ChronicleVAO_Centrifuge_deJAAA_Consumer is
    UScribe,
    TollWithImmutableRouter,
    IReader
{
    /// @notice Thrown if attempted to poke a stale message.
    error StaleMessage();

    /// @notice Thrown if attempted to poke a future message.
    error FutureMessage();

    /// @notice Emitted when a poke is received.
    /// @param caller The caller's address.
    /// @param val The value poked.
    /// @param age The age of the value poked.
    event Poked(address indexed caller, uint128 val, uint48 age);

    //--------------------------------------------------------------------------
    // Storage

    uint128 internal _val;

    //--------------------------------------------------------------------------
    // Constructor

    constructor(address initialAuthed, address router)
        UScribe(initialAuthed, "VAO::Centrifuge_deJAAA")
        TollWithImmutableRouter(router)
    {}

    /// @dev Defines authorization for IToll's authenticated functions.
    function toll_auth() internal override(TollWithImmutableRouter) auth {}

    /// @dev Function to handle state update.
    ///
    ///      This function is being called by the upstream uScribe
    ///      implementation iff the poke's signature verification succeeded.
    ///
    ///      Therefore, this function MUST only verify the payload contains
    ///      correctly encoded, non-stale and non-future data before committing
    ///      a state update.
    ///
    /// @dev Reverts if:
    ///      - Decoding payload to expected format fails
    ///
    /// @dev Returns error if:
    ///      - Payload is stale
    ///      - Payload is signed at a future date to block timestamp
    ///
    /// @dev The payload is expected to be encoded using the PokeData struct
    ///      containing the fields:
    ///
    ///      - age: uint48
    ///      - val: uint128
    ///
    ///  @dev The age stored after a poke is equal to the current blocktime,
    ///       not the age sent in the poke.
    function _poke(bytes calldata payload)
        internal
        override(UScribe)
        returns (bytes4)
    {
        PokeData memory pokeData = abi.decode(payload, (PokeData));

        // Fail if payload stale.
        if (pokeData.age <= latestPoke()) {
            return StaleMessage.selector;
        }

        // Fail if payload from the future.
        if (pokeData.age > block.timestamp) {
            return FutureMessage.selector;
        }

        // Store the poke's val.
        _val = pokeData.val;

        emit Poked(msg.sender, pokeData.val, pokeData.age);

        return _NO_ERR;
    }

    //--------------------------------------------------------------------------
    // IReader Functionality
    //
    // Note that read functions differ from Scribe with regards to `val = 0` not
    // being a failure code. Read functions only revert/fail if
    // `latestPoke() = 0`, implying no valid poke occured yet.
    //
    // Side effect of this is that the read functions cannot be disabled.

    //// @inheritdoc IVAOReader
    function read() public view toll returns (uint val) {
        bool ok;
        (ok, val,) = _tryReadWithAge();
        require(ok);
    }

    //// @inheritdoc IVAOReader
    function tryRead() public view toll returns (bool ok, uint val) {
        (ok, val,) = _tryReadWithAge();
        // assert(ok || val == 0);
    }

    //// @inheritdoc IVAOReader
    function readWithAge() public view toll returns (uint val, uint age) {
        bool ok;
        (ok, val, age) = _tryReadWithAge();
        require(ok);
    }

    //// @inheritdoc IVAOReader
    function tryReadWithAge()
        public
        view
        toll
        returns (bool ok, uint val, uint age)
    {
        (ok, val, age) = _tryReadWithAge();
    }

    function _tryReadWithAge()
        internal
        view
        returns (bool ok, uint val, uint age)
    {
        age = latestPoke();
        val = _val;
        ok = age != 0;
        // assert(ok || val == 0);
    }
}

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

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

/**
 * @title Toll Module
 *
 * @notice "Toll paid, we kiss - but dissension looms, maybe diss?"
 *
 * @dev The `Toll` contract module provides a basic access control mechanism,
 *      where a set of addresses are granted access to protected functions.
 *      These addresses are said the be _tolled_.
 *
 *      Initially, no address is tolled. Through the `kiss(address)` and
 *      `diss(address)` functions, auth'ed callers are able to toll/de-toll
 *      addresses. Authentication for these functions is defined via the
 *      downstream implemented `toll_auth()` function.
 *
 *      This module is used through inheritance. It will make available the
 *      modifier `toll`, which can be applied to functions to restrict their
 *      use to only tolled callers.
 */
abstract contract Toll is IToll {
    /// @dev Mapping storing whether address is tolled.
    /// @custom:invariant Image of mapping is {0, 1}.
    ///                     ∀x ∊ Address: _buds[x] ∊ {0, 1}
    /// @custom:invariant Only functions `kiss` and `diss` may mutate the mapping's state.
    ///                     ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
    ///                                     → (msg.sig == "kiss" ∨ msg.sig == "diss")
    /// @custom:invariant Mapping's state may only be mutated by authenticated caller.
    ///                     ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
    ///                                     → toll_auth()
    mapping(address => uint) private _buds;

    /// @dev List of addresses possibly being tolled.
    /// @dev May contain duplicates.
    /// @dev May contain addresses not being tolled anymore.
    /// @custom:invariant Every address being tolled once is element of the list.
    ///                     ∀x ∊ Address: tolled(x) → x ∊ _budsTouched
    address[] private _budsTouched;

    /// @dev Ensures caller is tolled.
    modifier toll() {
        assembly ("memory-safe") {
            // Compute slot of _buds[msg.sender].
            mstore(0x00, caller())
            mstore(0x20, _buds.slot)
            let slot := keccak256(0x00, 0x40)

            // Revert if caller not tolled.
            let isTolled := sload(slot)
            if iszero(isTolled) {
                // Store selector of `NotTolled(address)`.
                mstore(0x00, 0xd957b595)
                // Store msg.sender.
                mstore(0x20, caller())
                // Revert with (offset, size).
                revert(0x1c, 0x24)
            }
        }
        _;
    }

    /// @dev Reverts if caller not allowed to access protected function.
    /// @dev Must be implemented in downstream contract.
    function toll_auth() internal virtual;

    /// @inheritdoc IToll
    function kiss(address who) external {
        toll_auth();

        if (_buds[who] == 1) return;

        _buds[who] = 1;
        _budsTouched.push(who);
        emit TollGranted(msg.sender, who);
    }

    /// @inheritdoc IToll
    function diss(address who) external {
        toll_auth();

        if (_buds[who] == 0) return;

        _buds[who] = 0;
        emit TollRenounced(msg.sender, who);
    }

    /// @inheritdoc IToll
    function tolled(address who) public view returns (bool) {
        return _buds[who] == 1;
    }

    /// @inheritdoc IToll
    /// @custom:invariant Only contains tolled addresses.
    ///                     ∀x ∊ tolled(): _tolled[x]
    /// @custom:invariant Contains all tolled addresses.
    ///                     ∀x ∊ Address: _tolled[x] == 1 → x ∊ tolled()
    function tolled() public view returns (address[] memory) {
        // Initiate array with upper limit length.
        address[] memory budsList = new address[](_budsTouched.length);

        // Iterate through all possible tolled addresses.
        uint ctr;
        for (uint i; i < budsList.length; i++) {
            // Add address only if still tolled.
            if (_buds[_budsTouched[i]] == 1) {
                budsList[ctr++] = _budsTouched[i];
            }
        }

        // Set length of array to number of tolled addresses actually included.
        assembly ("memory-safe") {
            mstore(budsList, ctr)
        }

        return budsList;
    }

    /// @inheritdoc IToll
    function bud(address who) public view returns (uint) {
        return _buds[who];
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import {Auth} from "chronicle-std@v2/auth/Auth.sol";

import {IUScribe} from "./IUScribe.sol";
import {UPokeData, SchnorrData, ECDSAData} from "./Types.sol";

import {LibSchnorr} from "./libs/LibSchnorr.sol";
import {LibSecp256k1} from "./libs/LibSecp256k1.sol";

/**
 * @title UScribe
 * @custom:version 1.2.0
 *
 * @notice A universal Oracle
 *
 * @author Chronicle Labs, Inc
 * @custom:security-contact security@chroniclelabs.org
 */
abstract contract UScribe is IUScribe, Auth {
    using LibSchnorr for LibSecp256k1.Point;
    using LibSecp256k1 for LibSecp256k1.Point;
    using LibSecp256k1 for LibSecp256k1.JacobianPoint;

    //--------------------------------------------------------------------------
    // Constants and Immutables

    bytes4 internal constant _NO_ERR = bytes4(0);

    /// @inheritdoc IUScribe
    bytes32 public immutable wat;

    // Note that strings cannot be marked as immutable.
    // @custom:invariant Is immutable.
    string private _name;

    //--------------------------------------------------------------------------
    // Storage

    uint48 private _latestPoke;

    struct SchnorrStorage {
        LibSecp256k1.Point[256] pubKeys;
        uint8 bar;
    }

    SchnorrStorage private __schnorrStorage;

    struct ECDSAStorage {
        address[256] validators;
        uint8 bar;
    }

    ECDSAStorage private __ecdsaStorage;

    //--------------------------------------------------------------------------
    // Constructor

    constructor(address initialAuthed, string memory name_)
        Auth(initialAuthed)
    {
        require(bytes(name_).length != 0);

        _name = name_;
        wat = keccak256(bytes(name_));

        // Note to not have bars of zero.
        __schnorrStorage.bar = type(uint8).max;
        __ecdsaStorage.bar = type(uint8).max;
    }

    /// @inheritdoc IUScribe
    function name() external view returns (string memory) {
        return _name;
    }

    //--------------------------------------------------------------------------
    // Consumer Implemented Functionality

    /// @dev Function implemented in downstream consumer contract to handle
    ///      application specific state update.
    ///
    /// @dev The implementation MUST deserialize the payload and perform
    ///      necessary sanity checks.
    ///
    ///      It SHOULD NOT revert but instead return the error types' selector
    ///      whenever possible. This allows uScribe to wrap the application
    ///      specific error into a `PokeError_ConsumerRejectedPayload()` error.
    ///
    ///      To indicate a successful poke, the function MUST return the
    ///      `_NO_ERR = bytes4(0)` constant.
    ///
    /// @dev Note that this function is vulnerable to replay attacks.
    ///
    ///      Consumers MUST implement application specific logic to prevent
    ///      replayability issues. uScribe only verifies that the respective
    ///      validators attested to the payload at some point in time, ie
    ///      uScribe performs a stateless signature verification.
    ///
    ///      Note that this requires the payload to contain sufficient data for
    ///      the consumer logic to protect against replayability issues.
    ///
    ///      Protections against replayability issues MAY be including a nonce
    ///      in the payload or only accepting payloads with strictly
    ///      monotonically increasing timestamps. The `latestPoke()(uint)`
    ///      function can be used by consumers to access the timestamp of the
    ///      last poke.
    ///
    ///      To protect against cross-chain replayability issues the payload
    ///      MAY be expected to include the chain's id.
    ///
    /// @param payload The verified payload blob.
    /// @return bytes4 `_NO_ERR` if poke successful, application's error type
    ///                selector otherwise.
    function _poke(bytes calldata payload) internal virtual returns (bytes4);

    //--------------------------------------------------------------------------
    // Poke Functionality

    /// @inheritdoc IUScribe
    function poke(UPokeData calldata uPokeData, SchnorrData calldata schnorr)
        external
    {
        bytes4 err;
        bytes32 message;

        // Construct Schnorr Chronicle Signed Message of uPokeData.
        message = constructChronicleSignedMessage({
            scheme: bytes32("SCHNORR"),
            uPokeData: uPokeData
        });

        // Verify Schnorr signature.
        err = __verifySchnorrSignature(message, schnorr);
        if (err != _NO_ERR) {
            revert PokeError_VerificationFailed(err);
        }

        // Poke's security verified.
        emit UPoked(msg.sender, uPokeData.proofURI);

        // Forward payload to consumer.
        err = _poke(uPokeData.payload);
        if (err != _NO_ERR) {
            revert PokeError_ConsumerRejectedPayload(err);
        }

        // Update latest poke timestamp once poke accepted by consumer.
        _latestPoke = uint48(block.timestamp);
    }

    /// @inheritdoc IUScribe
    function poke(UPokeData calldata uPokeData, ECDSAData[] calldata ecdsas)
        external
    {
        bytes4 err;
        bytes32 message;

        // Construct ECDSA Chronicle Signed Message of uPokeData.
        message = constructChronicleSignedMessage({
            scheme: bytes32("ECDSA"),
            uPokeData: uPokeData
        });

        // Verify ECDSA signatures.
        err = __verifyECDSASignatures(message, ecdsas);
        if (err != _NO_ERR) {
            revert PokeError_VerificationFailed(err);
        }

        // Poke's security verified.
        emit UPoked(msg.sender, uPokeData.proofURI);

        // Forward payload to consumer.
        err = _poke(uPokeData.payload);
        if (err != _NO_ERR) {
            revert PokeError_ConsumerRejectedPayload(err);
        }

        // Update latest poke timestamp once poke accepted by consumer.
        _latestPoke = uint48(block.timestamp);
    }

    //--------------------------------------------------------------------------
    // Chronicle Signed Message Functionality

    /// @inheritdoc IUScribe
    function constructChronicleSignedMessage(
        bytes32 scheme,
        UPokeData calldata uPokeData
    ) public view returns (bytes32) {
        return keccak256(
            abi.encodePacked(
                "\x19Chronicle Signed Message:\n32",
                keccak256(
                    abi.encodePacked(
                        scheme,
                        wat,
                        keccak256(abi.encodePacked(uPokeData.payload)),
                        keccak256(abi.encodePacked(uPokeData.proofURI))
                    )
                )
            )
        );
    }

    //--------------------------------------------------------------------------
    // Signature Verification Functionality

    /// @custom:invariant Reverts iff out of gas.
    /// @custom:invariant Runtime is O(__schnorrStorage.bar).
    function __verifySchnorrSignature(
        bytes32 message,
        SchnorrData calldata schnorr
    ) private view returns (bytes4) {
        // Let pubKey be the currently processed validator's public key.
        LibSecp256k1.Point memory pubKey;
        // Let id be the currently processed validator's id.
        uint8 id;
        // Let aggPubKey be the sum of processed validator public keys.
        // Note that Jacobian coordinates are used.
        LibSecp256k1.JacobianPoint memory aggPubKey;
        // Let bloom be a bloom filter to guarantee signer uniqueness.
        uint bloom;

        // Fail if number of validators unequal to bar.
        //
        // Note that requiring equality constrains the verification's runtime
        // from Ω(bar) to Θ(bar).
        uint bar = __schnorrStorage.bar;
        if (schnorr.validatorIds.length != bar) {
            return VerificationError_BarNotReached.selector;
        }

        // Initiate validator variables.
        id = uint8(schnorr.validatorIds[0]);
        pubKey = __schnorrStorage.pubKeys[id];
        if (pubKey.isZeroPoint()) {
            return VerificationError_ValidatorInvalid.selector;
        }

        // Initiate bloom filter and aggPubKey.
        bloom = 1 << id;
        aggPubKey = pubKey.toJacobian();

        // Aggregation loop.
        for (uint i = 1; i < bar; i++) {
            // Update validator variables.
            id = uint8(schnorr.validatorIds[i]);
            pubKey = __schnorrStorage.pubKeys[id];
            if (pubKey.isZeroPoint()) {
                return VerificationError_ValidatorInvalid.selector;
            }

            // Fail if double signing attempted.
            if (bloom & (1 << id) != 0) {
                return VerificationError_DoubleSigningAttempted.selector;
            }

            // Update bloom filter.
            bloom |= 1 << id;

            // Add pubKey to aggPubKey.
            aggPubKey.addAffinePoint(pubKey);
        }

        // Perform signature verification.
        bool ok = aggPubKey.toAffine().verifySignature(
            message, schnorr.signature, schnorr.commitment
        );
        if (!ok) {
            return VerificationError_SignatureInvalid.selector;
        }

        return _NO_ERR;
    }

    /// @custom:invariant Reverts iff out of gas.
    /// @custom:invariant Runtime is O(__ecdsaStorage.bar).
    function __verifyECDSASignatures(
        bytes32 message,
        ECDSAData[] calldata ecdsas
    ) private view returns (bytes4) {
        // Let ecdsa be the currently processed ECDSA signature.
        ECDSAData memory ecdsa;
        // Let signer be the currently processed ECDSA signature's signer.
        address signer;
        // Let id the the currently processed ECDSA signature's signer id.
        uint id;
        // Let bloom be a bloom filter to guarantee signer uniqueness.
        uint bloom;

        // Fail if number of validators unequal to bar.
        //
        // Note that requiring equality constrains the verification's runtime
        // from Ω(bar) to Θ(bar).
        uint bar = __ecdsaStorage.bar;
        if (ecdsas.length != bar) {
            return VerificationError_BarNotReached.selector;
        }

        for (uint i; i < bar; i++) {
            // Update ECDSA variables.
            ecdsa = ecdsas[i];
            signer = ecrecover(message, ecdsa.v, ecdsa.r, ecdsa.s);
            id = uint160(signer) >> 152;

            // Fail if signature invalid or signer not a validator.
            // forgefmt: disable-next-item
            if (signer == address(0) || __ecdsaStorage.validators[id] != signer) {
                return VerificationError_SignatureInvalid.selector;
            }

            // Fail if double signing attempted.
            if (bloom & (1 << id) != 0) {
                return VerificationError_DoubleSigningAttempted.selector;
            }

            // Update bloom filter.
            bloom |= 1 << id;
        }

        return _NO_ERR;
    }

    //--------------------------------------------------------------------------
    // Auth'ed Functionality

    //----------------------------------
    // SchnorrStorage

    /// @inheritdoc IUScribe
    function liftSchnorr(LibSecp256k1.Point[] calldata pubKeys) external auth {
        for (uint i; i < pubKeys.length; i++) {
            LibSecp256k1.Point memory pubKey = pubKeys[i];
            require(!pubKey.isZeroPoint());
            // assert(pubKey.toAddress() != address(0));

            address validator = pubKey.toAddress();
            uint id = uint160(validator) >> 152;

            LibSecp256k1.Point memory sPubKey = __schnorrStorage.pubKeys[id];
            if (sPubKey.isZeroPoint()) {
                __schnorrStorage.pubKeys[id] = pubKey;
                emit ValidatorLiftedSchnorr(msg.sender, validator);
            } else {
                require(validator == sPubKey.toAddress());
            }
        }
    }

    /// @inheritdoc IUScribe
    function dropSchnorr(uint8[] calldata ids) external auth {
        for (uint i; i < ids.length; i++) {
            uint8 id = ids[i];

            LibSecp256k1.Point memory pubKey = __schnorrStorage.pubKeys[id];
            if (!pubKey.isZeroPoint()) {
                delete __schnorrStorage.pubKeys[id];
                emit ValidatorDroppedSchnorr(msg.sender, pubKey.toAddress());
            }
        }
    }

    /// @inheritdoc IUScribe
    function setBarSchnorr(uint8 bar) external auth {
        require(bar != 0);

        if (__schnorrStorage.bar != bar) {
            emit BarUpdatedSchnorr(msg.sender, __schnorrStorage.bar, bar);
            __schnorrStorage.bar = bar;
        }
    }

    //----------------------------------
    // ECDSAStorage

    /// @inheritdoc IUScribe
    function liftECDSA(address[] calldata validators) external auth {
        for (uint i; i < validators.length; i++) {
            address validator = validators[i];
            require(validator != address(0));

            uint id = uint160(validator) >> 152;

            if (__ecdsaStorage.validators[id] == address(0)) {
                __ecdsaStorage.validators[id] = validator;
                emit ValidatorLiftedECDSA(msg.sender, validator);
            } else {
                require(__ecdsaStorage.validators[id] == validator);
            }
        }
    }

    /// @inheritdoc IUScribe
    function dropECDSA(uint8[] calldata ids) external auth {
        for (uint i; i < ids.length; i++) {
            uint8 id = ids[i];
            address validator = __ecdsaStorage.validators[id];

            if (validator != address(0)) {
                // assert(uint160(validator) >> 152 == id);
                delete __ecdsaStorage.validators[id];
                emit ValidatorDroppedECDSA(msg.sender, validator);
            }
        }
    }

    /// @inheritdoc IUScribe
    function setBarECDSA(uint8 bar) external auth {
        require(bar != 0);

        if (__ecdsaStorage.bar != bar) {
            emit BarUpdatedECDSA(msg.sender, __ecdsaStorage.bar, bar);
            __ecdsaStorage.bar = bar;
        }
    }

    //--------------------------------------------------------------------------
    // Public View Functions

    /// @inheritdoc IUScribe
    ///
    /// @dev Note that function is public to grant read-only access to
    ///      downstream consumer.
    function latestPoke() public view returns (uint) {
        return _latestPoke;
    }

    //----------------------------------
    // SchnorrStorage

    /// @inheritdoc IUScribe
    function validatorsSchnorr(address who) external view returns (bool) {
        uint id = uint160(who) >> 152;
        LibSecp256k1.Point memory pubKey = __schnorrStorage.pubKeys[id];

        return !pubKey.isZeroPoint() && pubKey.toAddress() == who;
    }

    /// @inheritdoc IUScribe
    function validatorsSchnorr(uint8 id)
        external
        view
        returns (bool, address)
    {
        LibSecp256k1.Point memory pubKey = __schnorrStorage.pubKeys[id];

        return !pubKey.isZeroPoint()
            ? (true, pubKey.toAddress())
            : (false, address(0));
    }

    /// @inheritdoc IUScribe
    function validatorsSchnorr() external view returns (address[] memory) {
        address[] memory validators = new address[](256);

        LibSecp256k1.Point memory pubKey;
        uint ctr;
        for (uint i; i < 256; i++) {
            pubKey = __schnorrStorage.pubKeys[i];

            if (!pubKey.isZeroPoint()) {
                validators[ctr++] = pubKey.toAddress();
            }
        }

        assembly ("memory-safe") {
            mstore(validators, ctr)
        }

        return validators;
    }

    /// @inheritdoc IUScribe
    function barSchnorr() external view returns (uint8) {
        return __schnorrStorage.bar;
    }

    //----------------------------------
    // ECDSAStorage

    /// @inheritdoc IUScribe
    function validatorsECDSA(address who) external view returns (bool) {
        uint id = uint160(who) >> 152;

        return who != address(0) && __ecdsaStorage.validators[id] == who;
    }

    /// @inheritdoc IUScribe
    function validatorsECDSA(uint id) external view returns (bool, address) {
        address validator = __ecdsaStorage.validators[id];

        return validator != address(0) ? (true, validator) : (false, address(0));
    }

    /// @inheritdoc IUScribe
    function validatorsECDSA() external view returns (address[] memory) {
        address[] memory validators = new address[](256);

        address validator;
        uint ctr;
        for (uint i; i < 256; i++) {
            validator = __ecdsaStorage.validators[i];

            if (validator != address(0)) {
                validators[ctr++] = validator;
            }
        }

        assembly ("memory-safe") {
            mstore(validators, ctr)
        }

        return validators;
    }

    /// @inheritdoc IUScribe
    function barECDSA() external view returns (uint8) {
        return __ecdsaStorage.bar;
    }
}

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

interface IChronicleVAO_Centrifuge_deJAAA_Reader {

    /// @notice Returns the oracle's current value.
    /// @dev Reverts if:
    ///      - Not yet poked
    /// @return val The oracle's current value.
    function read() external view returns (uint val);

    /// @notice Returns the oracle's current value.
    /// @return ok True if previously poked, false otherwise.
    /// @return val The oracle's current value if it exists, zero otherwise.
    function tryRead() external view returns (bool ok, uint val);

    /// @notice Returns the oracle's current value and its age.
    /// @dev Reverts if:
    ///      - Not yet poked
    /// @return val The oracle's current value.
    /// @return age The value's age.
    function readWithAge() external view returns (uint val, uint age);

    /// @notice Returns the oracle's current value and its age.
    /// @return ok True if previously poked, false otherwise.
    /// @return val The oracle's current value if it exists, zero otherwise.
    /// @return age The value's age if value exists, zero otherwise.
    function tryReadWithAge()
        external
        view
        returns (bool ok, uint val, uint age);
}

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

import {IToll} from "chronicle-std@v2/toll/IToll.sol";

/**
 * @title TollWithImmutableRouter
 *
 * @notice "Toll paid, we kiss - but dissension looms, maybe diss?"
 *
 * @dev The `TollWithImmutableRouter` contract module provides a basic access
 *      control mechanism, where a set of addresses are granted access to
 *      protected functions.
 *      These addresses are said the be _tolled_.
 *
 *      Note that this module differs from chronicle-std/Toll in that a router
 *      address given at construction is immutably tolled.
 *
 *      This path reduces gas costs for customers connecting to the router
 *      instead of directly reading from the uscribe consumer.
 *
 *      Initially, only the router is tolled. Through the `kiss(address)` and
 *      `diss(address)` functions, auth'ed callers are able to toll/de-toll
 *      addresses. Authentication for these functions is defined via the
 *      downstream implemented `toll_auth()` function.
 *
 *      This module is used through inheritance. It will make available the
 *      modifier `toll`, which can be applied to functions to restrict their
 *      use to only tolled callers.
 */
abstract contract TollWithImmutableRouter is IToll {
    /// @dev Address of the immutably tolled router.
    address private immutable _router;

    /// @dev Mapping storing whether address is tolled.
    /// @custom:invariant Image of mapping is {0, 1}.
    ///                     ∀x ∊ Address: _buds[x] ∊ {0, 1}
    /// @custom:invariant Only functions `kiss`, `diss` or constructor may
    ///                   mutate the mapping's state.
    ///                     ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
    ///                                     → (msg.sig == "kiss" ∨ msg.sig == "diss" ∨ msg.sig == "")
    /// @custom:invariant Mapping's state may only be mutated by authenticated
    ///                   caller or during construction.
    ///                     ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
    ///                                     → (toll_auth() ∨ msg.sig == "")
    mapping(address => uint) private _buds;

    /// @dev List of addresses possibly being tolled.
    /// @dev May contain duplicates.
    /// @dev May contain addresses not being tolled anymore.
    /// @custom:invariant Every address being tolled once is element of the list.
    ///                     ∀x ∊ Address: tolled(x) → x ∊ _budsTouched
    address[] private _budsTouched;

    constructor(address router) {
        _router = router;

        _buds[router] = 1;
        _budsTouched.push(router);
        emit TollGranted(msg.sender, router);
    }

    /// @dev Ensures caller is tolled.
    modifier toll() {
        if (msg.sender != _router) {
            assembly ("memory-safe") {
                // Compute slot of _buds[msg.sender].
                mstore(0x00, caller())
                mstore(0x20, _buds.slot)
                let slot := keccak256(0x00, 0x40)

                // Revert if caller not tolled.
                let isTolled := sload(slot)
                if iszero(isTolled) {
                    // Store selector of `NotTolled(address)`.
                    mstore(0x00, 0xd957b595)
                    // Store msg.sender.
                    mstore(0x20, caller())
                    // Revert with (offset, size).
                    revert(0x1c, 0x24)
                }
            }
        }
        _;
    }

    /// @dev Reverts if caller not allowed to access protected function.
    /// @dev Must be implemented in downstream contract.
    function toll_auth() internal virtual;

    /// @inheritdoc IToll
    function kiss(address who) external {
        toll_auth();

        if (_buds[who] == 1) return;

        _buds[who] = 1;
        _budsTouched.push(who);
        emit TollGranted(msg.sender, who);
    }

    /// @inheritdoc IToll
    function diss(address who) external {
        toll_auth();

        require(who != _router, "TollWithImmutableRouter: cannot diss router");

        if (_buds[who] == 0) return;

        _buds[who] = 0;
        emit TollRenounced(msg.sender, who);
    }

    /// @inheritdoc IToll
    function tolled(address who) public view returns (bool) {
        return _buds[who] == 1;
    }

    /// @inheritdoc IToll
    /// @custom:invariant Only contains tolled addresses.
    ///                     ∀x ∊ tolled(): _buds[x] == 1
    /// @custom:invariant Contains all tolled addresses.
    ///                     ∀x ∊ Address: _buds[x] == 1 → x ∊ tolled()
    function tolled() public view returns (address[] memory) {
        // Initiate array with upper limit length.
        address[] memory budsList = new address[](_budsTouched.length);

        // Iterate through all possible tolled addresses.
        uint ctr;
        for (uint i; i < budsList.length; i++) {
            // Add address only if still tolled.
            if (_buds[_budsTouched[i]] == 1) {
                budsList[ctr++] = _budsTouched[i];
            }
        }

        // Set length of array to number of tolled addresses actually included.
        assembly ("memory-safe") {
            mstore(budsList, ctr)
        }

        return budsList;
    }

    /// @inheritdoc IToll
    function bud(address who) public view returns (uint) {
        return _buds[who];
    }
}

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

interface IToll {
    /// @notice Thrown by protected function if caller not tolled.
    /// @param caller The caller's address.
    error NotTolled(address caller);

    /// @notice Emitted when toll granted to address.
    /// @param caller The caller's address.
    /// @param who The address toll got granted to.
    event TollGranted(address indexed caller, address indexed who);

    /// @notice Emitted when toll renounced from address.
    /// @param caller The caller's address.
    /// @param who The address toll got renounced from.
    event TollRenounced(address indexed caller, address indexed who);

    /// @notice Grants address `who` toll.
    /// @dev Only callable by auth'ed address.
    /// @param who The address to grant toll.
    function kiss(address who) external;

    /// @notice Renounces address `who`'s toll.
    /// @dev Only callable by auth'ed address.
    /// @param who The address to renounce toll.
    function diss(address who) external;

    /// @notice Returns whether address `who` is tolled.
    /// @param who The address to check.
    /// @return True if `who` is tolled, false otherwise.
    function tolled(address who) external view returns (bool);

    /// @notice Returns full list of addresses tolled.
    /// @dev May contain duplicates.
    /// @return List of addresses tolled.
    function tolled() external view returns (address[] memory);

    /// @notice Returns whether address `who` is tolled.
    /// @custom:deprecated Use `tolled(address)(bool)` instead.
    /// @param who The address to check.
    /// @return 1 if `who` is tolled, 0 otherwise.
    function bud(address who) external view returns (uint);
}

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

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

/**
 * @title Auth Module
 *
 * @dev The `Auth` contract module provides a basic access control mechanism,
 *      where a set of addresses are granted access to protected functions.
 *      These addresses are said to be _auth'ed_.
 *
 *      Initially, the address given as constructor argument is the only address
 *      auth'ed. Through the `rely(address)` and `deny(address)` functions,
 *      auth'ed callers are able to grant/renounce auth to/from addresses.
 *
 *      This module is used through inheritance. It will make available the
 *      modifier `auth`, which can be applied to functions to restrict their
 *      use to only auth'ed callers.
 */
abstract contract Auth is IAuth {
    /// @dev Mapping storing whether address is auth'ed.
    /// @custom:invariant Image of mapping is {0, 1}.
    ///                     ∀x ∊ Address: _wards[x] ∊ {0, 1}
    /// @custom:invariant Only address given as constructor argument is authenticated after deployment.
    ///                     deploy(initialAuthed) → (∀x ∊ Address: _wards[x] == 1 → x == initialAuthed)
    /// @custom:invariant Only functions `rely` and `deny` may mutate the mapping's state.
    ///                     ∀x ∊ Address: preTx(_wards[x]) != postTx(_wards[x])
    ///                                     → (msg.sig == "rely" ∨ msg.sig == "deny")
    /// @custom:invariant Mapping's state may only be mutated by authenticated caller.
    ///                     ∀x ∊ Address: preTx(_wards[x]) != postTx(_wards[x]) → _wards[msg.sender] = 1
    mapping(address => uint) private _wards;

    /// @dev List of addresses possibly being auth'ed.
    /// @dev May contain duplicates.
    /// @dev May contain addresses not being auth'ed anymore.
    /// @custom:invariant Every address being auth'ed once is element of the list.
    ///                     ∀x ∊ Address: authed(x) -> x ∊ _wardsTouched
    address[] private _wardsTouched;

    /// @dev Ensures caller is auth'ed.
    modifier auth() {
        assembly ("memory-safe") {
            // Compute slot of _wards[msg.sender].
            mstore(0x00, caller())
            mstore(0x20, _wards.slot)
            let slot := keccak256(0x00, 0x40)

            // Revert if caller not auth'ed.
            let isAuthed := sload(slot)
            if iszero(isAuthed) {
                // Store selector of `NotAuthorized(address)`.
                mstore(0x00, 0x4a0bfec1)
                // Store msg.sender.
                mstore(0x20, caller())
                // Revert with (offset, size).
                revert(0x1c, 0x24)
            }
        }
        _;
    }

    constructor(address initialAuthed) {
        _wards[initialAuthed] = 1;
        _wardsTouched.push(initialAuthed);

        // Note to use address(0) as caller to indicate address was auth'ed
        // during deployment.
        emit AuthGranted(address(0), initialAuthed);
    }

    /// @inheritdoc IAuth
    function rely(address who) external auth {
        if (_wards[who] == 1) return;

        _wards[who] = 1;
        _wardsTouched.push(who);
        emit AuthGranted(msg.sender, who);
    }

    /// @inheritdoc IAuth
    function deny(address who) external auth {
        if (_wards[who] == 0) return;

        _wards[who] = 0;
        emit AuthRenounced(msg.sender, who);
    }

    /// @inheritdoc IAuth
    function authed(address who) public view returns (bool) {
        return _wards[who] == 1;
    }

    /// @inheritdoc IAuth
    /// @custom:invariant Only contains auth'ed addresses.
    ///                     ∀x ∊ authed(): _wards[x] == 1
    /// @custom:invariant Contains all auth'ed addresses.
    ///                     ∀x ∊ Address: _wards[x] == 1 → x ∊ authed()
    function authed() public view returns (address[] memory) {
        // Initiate array with upper limit length.
        address[] memory wardsList = new address[](_wardsTouched.length);

        // Iterate through all possible auth'ed addresses.
        uint ctr;
        for (uint i; i < wardsList.length; i++) {
            // Add address only if still auth'ed.
            if (_wards[_wardsTouched[i]] == 1) {
                wardsList[ctr++] = _wardsTouched[i];
            }
        }

        // Set length of array to number of auth'ed addresses actually included.
        assembly ("memory-safe") {
            mstore(wardsList, ctr)
        }

        return wardsList;
    }

    /// @inheritdoc IAuth
    function wards(address who) public view returns (uint) {
        return _wards[who];
    }
}

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

import {UPokeData, SchnorrData, ECDSAData} from "./Types.sol";
import {LibSecp256k1} from "./libs/LibSecp256k1.sol";

interface IUScribe {
    //--------------------------------------------------------------------------
    // Errors

    /// @notice Thrown if poke verification failed.
    /// @param err The verification error.
    error PokeError_VerificationFailed(bytes4 err);

    /// @notice Thrown if poke rejected by consumer.
    /// @param err The consumer error.
    error PokeError_ConsumerRejectedPayload(bytes4 err);

    //----------------------------------
    // Verification Errors

    /// @notice Verification error thrown via `PokeError_VerificationFailed` if
    ///         poke did not reach bar threshold.
    error VerificationError_BarNotReached();

    /// @notice Verification error thrown via `PokeError_VerificationFailed` if
    ///         poke attempted double signing.
    error VerificationError_DoubleSigningAttempted();

    /// @notice Verification error thrown via `PokeError_VerificationFailed` if
    ///         poke included invalid validator.
    error VerificationError_ValidatorInvalid();

    /// @notice Verification error thrown via `PokeError_VerificationFailed` if
    ///         poke included invalid signature.
    error VerificationError_SignatureInvalid();

    //--------------------------------------------------------------------------
    // Events

    /// @notice Emitted when oracle was successfully poked.
    /// @param caller The caller's address.
    /// @param proofURI Optional URI to validity proof.
    event UPoked(address indexed caller, string proofURI);

    /// @notice Emitted when new validator lifted for Schnorr verification.
    /// @param caller The caller's address.
    /// @param validator The validator address lifted.
    event ValidatorLiftedSchnorr(
        address indexed caller, address indexed validator
    );

    /// @notice Emitted when validator dropped from Schnorr verification.
    /// @param caller The caller's address.
    /// @param validator The validator address dropped.
    event ValidatorDroppedSchnorr(
        address indexed caller, address indexed validator
    );

    /// @notice Emitted when bar for Schnorr verification updated.
    /// @param caller The caller's address.
    /// @param oldBar The old bar's value.
    /// @param newBar The new bar's value.
    event BarUpdatedSchnorr(address indexed caller, uint8 oldBar, uint8 newBar);

    /// @notice Emitted when new validator lifted for ECDSA verification.
    /// @param caller The caller's address.
    /// @param validator The validator address lifted.
    event ValidatorLiftedECDSA(
        address indexed caller, address indexed validator
    );

    /// @notice Emitted when validator dropped from ECDSA verification.
    /// @param caller The caller's address.
    /// @param validator The validator address dropped.
    event ValidatorDroppedECDSA(
        address indexed caller, address indexed validator
    );

    /// @notice Emitted when bar for ECDSA verification updated.
    /// @param caller The caller's address.
    /// @param oldBar The old bar's value.
    /// @param newBar The new bar's value.
    event BarUpdatedECDSA(address indexed caller, uint8 oldBar, uint8 newBar);

    //--------------------------------------------------------------------------
    // Poke Functionality

    /// @notice Pokes the oracle using Schnorr verification.
    /// @param uPokeData The UPokeData being poked.
    /// @param schnorrData The SchnorrData proving the `uPokeData`'s integrity.
    function poke(
        UPokeData calldata uPokeData,
        SchnorrData calldata schnorrData
    ) external;

    /// @notice Pokes the oracle using ECDSA verification.
    /// @param uPokeData The UPokeData being poked.
    /// @param ecdsaDatas The list of ECDSAData proving the `uPokeData`'s
    ///                   integrity.
    function poke(UPokeData calldata uPokeData, ECDSAData[] calldata ecdsaDatas)
        external;

    /// @notice Construct a Chronicle Signed Message.
    /// @param scheme The scheme to construct the message for.
    /// @param uPokeData The UPokeData to inlcude in the message.
    function constructChronicleSignedMessage(
        bytes32 scheme,
        UPokeData calldata uPokeData
    ) external view returns (bytes32);

    //--------------------------------------------------------------------------
    // Auth'ed Functionality

    /// @notice Lifts list of public keys `pubKeys` for Schnorr verification.
    /// @dev Only callable by auth'ed address.
    /// @param pubKeys The list of public keys to lift.
    function liftSchnorr(LibSecp256k1.Point[] calldata pubKeys) external;

    /// @notice Drops list of validator ids `ids` from Schnorr verification.
    /// @dev Only callable by auth'ed address.
    /// @param ids The list of validator ids to drop.
    function dropSchnorr(uint8[] calldata ids) external;

    /// @notice Updates the bar security parameter for Schnorr verification.
    /// @dev Only callable by auth'ed address.
    /// @param bar The value to update bar to.
    function setBarSchnorr(uint8 bar) external;

    /// @notice Lifts list of addresses `validators` for ECDSA verification.
    /// @dev Only callable by auth'ed address.
    /// @param validators The list of addresses to lift.
    function liftECDSA(address[] calldata validators) external;

    /// @notice Drops list of validator ids `ids` from ECDSA verification.
    /// @dev Only callable by auth'ed address.
    /// @param ids The list of validator ids to drop.
    function dropECDSA(uint8[] calldata ids) external;

    /// @notice Updates the bar security parameter for ECDSA verification.
    /// @dev Only callable by auth'ed address.
    /// @param bar The value to update bar to.
    function setBarECDSA(uint8 bar) external;

    //--------------------------------------------------------------------------
    // Public View Functions

    /// @notice Returns the oracle's identifier.
    /// @dev The wat is derived from `name()`:
    ///
    ///      ```solidity
    ///      assert(wat() = keccak256(bytes(name())));
    ///      ```
    /// @return bytes32 The oracle's identifier.
    function wat() external view returns (bytes32);

    /// @notice Returns the oracle's name.
    /// @return string The oracle's name.
    function name() external view returns (string memory);

    /// @notice Returns the timestamp of the latest poke.
    /// @dev This timestamp is updated on every poke and allows uniform
    ///      staleness monitoring accross uscribe instances.
    /// @return uint The timestamp of the latest poke.
    function latestPoke() external view returns (uint);

    /// @notice Returns whether address `who` is a validator for Schnorr
    ///         verification.
    /// @param who The address to check.
    /// @return bool True if `who` is a validator for Schnorr verification,
    ///              false otherwise.
    function validatorsSchnorr(address who) external view returns (bool);

    /// @notice Returns whether validator id `id` is a validator for Schnorr
    ///         verification and, if so, the validator's address.
    /// @param id The validator id to check.
    /// @return bool True if `who` is a validator for Schnorr verification,
    ///              false otherwise.
    /// @return address Address of the validator if `id` is a validator for
    ///                 Schnorr verification, zero address otherwise.
    function validatorsSchnorr(uint8 id)
        external
        view
        returns (bool, address);

    /// @notice Returns the lift of validator addresses for Schnorr
    ///         verification.
    /// @return address[] The lift of validator addresses for Schnorr
    ///                   verification.
    function validatorsSchnorr() external view returns (address[] memory);

    /// @notice Returns the bar security parameter for Schnorr verification.
    /// @return uint8 The bar security parameter for Schnorr verification.
    function barSchnorr() external view returns (uint8);

    /// @notice Returns whether address `who` is a validator for ECDSA
    ///         verification.
    /// @param who The address to check.
    /// @return bool True if `who` is a validator for ECDSA verification, false
    ///              otherwise.
    function validatorsECDSA(address who) external view returns (bool);

    /// @notice Returns whether validator id `id` is a validator for ECDSA
    ///         verification and, if so, the validator's address.
    /// @param id The validator id to check.
    /// @return bool True if `who` is a validator for ECDSA verification,
    ///              false otherwise.
    /// @return address Address of the validator if `id` is a validator for
    ///                 ECDSA verification, zero address otherwise.
    function validatorsECDSA(uint id) external view returns (bool, address);

    /// @notice Returns the lift of validator addresses for ECDSA verification.
    /// @return address[] The lift of validator addresses for ECDSA
    ///                   verification.
    function validatorsECDSA() external view returns (address[] memory);

    /// @notice Returns the bar security parameter for ECDSA verification.
    /// @return uint8 The bar security parameter for ECDSA verification.
    function barECDSA() external view returns (uint8);
}

File 10 of 13 : Types.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

struct UPokeData {
    bytes payload;
    string proofURI;
}

struct SchnorrData {
    bytes32 signature;
    address commitment;
    bytes validatorIds;
}

struct ECDSAData {
    uint8 v;
    bytes32 r;
    bytes32 s;
}

File 11 of 13 : LibSchnorr.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

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

///////////////////////////////////////////////////////////////////////////////
//
// Library copied from Scribe@v2.0.1
//
// Reference: https://github.com/chronicleprotocol/scribe/blob/7d2106a265a8d82f259b506c4c8fec42002546ef/src/libs/LibSchnorr.sol
//
///////////////////////////////////////////////////////////////////////////////

/**
 * @title LibSchnorr
 *
 * @notice Custom-purpose library for Schnorr signature verification on the
 *         secp256k1 curve
 */
library LibSchnorr {
    using LibSecp256k1 for LibSecp256k1.Point;

    /// @dev Returns whether `signature` and `commitment` sign via `pubKey`
    ///      message `message`.
    ///
    /// @custom:invariant Reverts iff out of gas.
    /// @custom:invariant Uses constant amount of gas.
    function verifySignature(
        LibSecp256k1.Point memory pubKey,
        bytes32 message,
        bytes32 signature,
        address commitment
    ) internal pure returns (bool) {
        // Return false if signature or commitment is zero.
        if (signature == 0 || commitment == address(0)) {
            return false;
        }

        // Note to enforce pubKey is valid secp256k1 point.
        //
        // While the Scribe contract ensures to only verify signatures for valid
        // public keys, this check is enabled as an additional defense
        // mechanism.
        if (!pubKey.isOnCurve()) {
            return false;
        }

        // Note to enforce signature is less than Q to prevent signature
        // malleability.
        //
        // While the Scribe contract only accepts messages with strictly
        // monotonically increasing timestamps, circumventing replay attack
        // vectors and therefore also signature malleability issues at a higher
        // level, this check is enabled as an additional defense mechanism.
        if (uint(signature) >= LibSecp256k1.Q()) {
            return false;
        }

        // Construct challenge = H(Pₓ ‖ Pₚ ‖ m ‖ Rₑ) mod Q
        uint challenge = uint(
            keccak256(
                abi.encodePacked(
                    pubKey.x, uint8(pubKey.yParity()), message, commitment
                )
            )
        ) % LibSecp256k1.Q();

        // Compute msgHash = -sig * Pₓ      (mod Q)
        //                 = Q - (sig * Pₓ) (mod Q)
        //
        // Unchecked because the only protected operation performed is the
        // subtraction from Q where the subtrahend is the result of a (mod Q)
        // computation, i.e. the subtrahend is guaranteed to be less than Q.
        uint msgHash;
        unchecked {
            msgHash = LibSecp256k1.Q()
                - mulmod(uint(signature), pubKey.x, LibSecp256k1.Q());
        }

        // Compute v = Pₚ + 27
        //
        // Unchecked because pubKey.yParity() ∊ {0, 1} which cannot overflow
        // by adding 27.
        uint v;
        unchecked {
            v = pubKey.yParity() + 27;
        }

        // Set r = Pₓ
        uint r = pubKey.x;

        // Compute s = Q - (e * Pₓ) (mod Q)
        //
        // Unchecked because the only protected operation performed is the
        // subtraction from Q where the subtrahend is the result of a (mod Q)
        // computation, i.e. the subtrahend is guaranteed to be less than Q.
        uint s;
        unchecked {
            s = LibSecp256k1.Q() - mulmod(challenge, pubKey.x, LibSecp256k1.Q());
        }

        // Compute ([s]G - [e]P)ₑ via ecrecover.
        address recovered =
            ecrecover(bytes32(msgHash), uint8(v), bytes32(r), bytes32(s));

        // Verification succeeds iff ([s]G - [e]P)ₑ = Rₑ.
        //
        // Note that commitment is guaranteed to not be zero.
        return commitment == recovered;
    }
}

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

///////////////////////////////////////////////////////////////////////////////
//
// Library copied from Scribe@v2.0.1
//
// Reference: https://github.com/chronicleprotocol/scribe/blob/7d2106a265a8d82f259b506c4c8fec42002546ef/src/libs/LibSecp256k1.sol
//
///////////////////////////////////////////////////////////////////////////////

/**
 * @title LibSecp256k1
 *
 * @notice Library for secp256k1 elliptic curve computations
 *
 * @dev This library was developed to efficiently compute aggregated public
 *      keys for Schnorr signatures based on secp256k1, i.e. it is _not_ a
 *      general purpose elliptic curve library!
 *
 *      References to the Ethereum Yellow Paper are based on the following
 *      version: "BERLIN VERSION beacfbd – 2022-10-24".
 */
library LibSecp256k1 {
    using LibSecp256k1 for LibSecp256k1.Point;
    using LibSecp256k1 for LibSecp256k1.JacobianPoint;

    uint private constant ADDRESS_MASK =
        0x000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

    // -- Secp256k1 Constants --
    //
    // Taken from https://www.secg.org/sec2-v2.pdf.
    // See section 2.4.1 "Recommended Parameters secp256k1".

    uint private constant _A = 0;
    uint private constant _B = 7;
    uint private constant _P =
        0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;

    /// @dev Returns the order of the group.
    function Q() internal pure returns (uint) {
        return
            0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
    }

    /// @dev Returns the generator G.
    ///      Note that the generator is also called base point.
    function G() internal pure returns (Point memory) {
        return Point({
            x: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
            y: 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
        });
    }

    /// @dev Returns the zero point.
    function ZERO_POINT() internal pure returns (Point memory) {
        return Point({x: 0, y: 0});
    }

    // -- (Affine) Point --

    /// @dev Point encapsulates a secp256k1 point in Affine coordinates.
    struct Point {
        uint x;
        uint y;
    }

    /// @dev Returns the Ethereum address of `self`.
    ///
    /// @dev An Ethereum address is defined as the rightmost 160 bits of the
    ///      keccak256 hash of the concatenation of the hex-encoded x and y
    ///      coordinates of the corresponding ECDSA public key.
    ///      See "Appendix F: Signing Transactions" §134 in the Yellow Paper.
    function toAddress(Point memory self) internal pure returns (address) {
        address addr;
        // Functionally equivalent Solidity code:
        // addr = address(uint160(uint(keccak256(abi.encode(self.x, self.y)))));
        assembly ("memory-safe") {
            addr := and(keccak256(self, 0x40), ADDRESS_MASK)
        }
        return addr;
    }

    /// @dev Returns Affine point `self` in Jacobian coordinates.
    function toJacobian(Point memory self)
        internal
        pure
        returns (JacobianPoint memory)
    {
        return JacobianPoint({x: self.x, y: self.y, z: 1});
    }

    /// @dev Returns whether `self` is the zero point.
    function isZeroPoint(Point memory self) internal pure returns (bool) {
        return (self.x | self.y) == 0;
    }

    /// @dev Returns whether `self` is a point on the curve.
    ///
    /// @dev The secp256k1 curve is specified as y² ≡ x³ + ax + b (mod P)
    ///      where:
    ///         a = 0
    ///         b = 7
    function isOnCurve(Point memory self) internal pure returns (bool) {
        uint left = mulmod(self.y, self.y, _P);
        // Note that adding a * x can be waived as ∀x: a * x = 0.
        uint right =
            addmod(mulmod(self.x, mulmod(self.x, self.x, _P), _P), _B, _P);

        return left == right;
    }

    /// @dev Returns the parity of `self`'s y coordinate.
    ///
    /// @dev The value 0 represents an even y value and 1 represents an odd y
    ///      value.
    ///      See "Appendix F: Signing Transactions" in the Yellow Paper.
    function yParity(Point memory self) internal pure returns (uint) {
        return self.y & 1;
    }

    // -- Jacobian Point --

    /// @dev JacobianPoint encapsulates a secp256k1 point in Jacobian
    ///      coordinates.
    struct JacobianPoint {
        uint x;
        uint y;
        uint z;
    }

    /// @dev Returns Jacobian point `self` in Affine coordinates.
    ///
    /// @custom:invariant Reverts iff out of gas.
    /// @custom:invariant Does not run into an infinite loop.
    function toAffine(JacobianPoint memory self)
        internal
        pure
        returns (Point memory)
    {
        Point memory result;

        // Compute z⁻¹, i.e. the modular inverse of self.z.
        uint zInv = _invMod(self.z);

        // Compute (z⁻¹)² (mod P)
        uint zInv_2 = mulmod(zInv, zInv, _P);

        // Compute self.x * (z⁻¹)² (mod P), i.e. the x coordinate of given
        // Jacobian point in Affine representation.
        result.x = mulmod(self.x, zInv_2, _P);

        // Compute self.y * (z⁻¹)³ (mod P), i.e. the y coordinate of given
        // Jacobian point in Affine representation.
        result.y = mulmod(self.y, mulmod(zInv, zInv_2, _P), _P);

        return result;
    }

    /// @dev Adds Affine point `p` to Jacobian point `self`.
    ///
    ///      It is the caller's responsibility to ensure given points are on the
    ///      curve!
    ///
    ///      Computation based on: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-madd-2007-bl.
    ///
    ///      Note that the formula assumes z2 = 1, which always holds if z2's
    ///      point is given in Affine coordinates.
    ///
    ///      Note that eventhough the function is marked as pure, to be
    ///      understood as only being dependent on the input arguments, it
    ///      nevertheless has side effects by writing the result into the
    ///      `self` memory variable.
    ///
    /// @custom:invariant Only mutates `self` memory variable.
    /// @custom:invariant Reverts iff out of gas.
    /// @custom:invariant Uses constant amount of gas.
    function addAffinePoint(JacobianPoint memory self, Point memory p)
        internal
        pure
    {
        // Addition formula:
        //      x = r² - j - (2 * v)             (mod P)
        //      y = (r * (v - x)) - (2 * y1 * j) (mod P)
        //      z = (z1 + h)² - z1² - h²         (mod P)
        //
        // where:
        //      r = 2 * (s - y1) (mod P)
        //      j = h * i        (mod P)
        //      v = x1 * i       (mod P)
        //      h = u - x1       (mod P)
        //      s = y2 * z1³     (mod P)       Called s2 in reference
        //      i = 4 * h²       (mod P)
        //      u = x2 * z1²     (mod P)       Called u2 in reference
        //
        // and:
        //      x1 = self.x
        //      y1 = self.y
        //      z1 = self.z
        //      x2 = p.x
        //      y2 = p.y
        //
        // Note that in order to save memory allocations the result is stored
        // in the self variable, i.e. the following holds true after the
        // functions execution:
        //      x = self.x
        //      y = self.y
        //      z = self.z

        // Cache self's coordinates on stack.
        uint x1 = self.x;
        uint y1 = self.y;
        uint z1 = self.z;

        // Compute z1_2 = z1²     (mod P)
        //              = z1 * z1 (mod P)
        uint z1_2 = mulmod(z1, z1, _P);

        // Compute h = u        - x1       (mod P)
        //           = u        + (P - x1) (mod P)
        //           = x2 * z1² + (P - x1) (mod P)
        //
        // Unchecked because the only protected operation performed is P - x1
        // where x1 is guaranteed by the caller to be an x coordinate belonging
        // to a point on the curve, i.e. being less than P.
        uint h;
        unchecked {
            h = addmod(mulmod(p.x, z1_2, _P), _P - x1, _P);
        }

        // Compute h_2 = h²    (mod P)
        //             = h * h (mod P)
        uint h_2 = mulmod(h, h, _P);

        // Compute i = 4 * h² (mod P)
        uint i = mulmod(4, h_2, _P);

        // Compute z = (z1 + h)² - z1²       - h²       (mod P)
        //           = (z1 + h)² - z1²       + (P - h²) (mod P)
        //           = (z1 + h)² + (P - z1²) + (P - h²) (mod P)
        //             ╰───────╯   ╰───────╯   ╰──────╯
        //               left         mid       right
        //
        // Unchecked because the only protected operations performed are
        // subtractions from P where the subtrahend is the result of a (mod P)
        // computation, i.e. the subtrahend being guaranteed to be less than P.
        unchecked {
            uint left = mulmod(addmod(z1, h, _P), addmod(z1, h, _P), _P);
            uint mid = _P - z1_2;
            uint right = _P - h_2;

            self.z = addmod(left, addmod(mid, right, _P), _P);
        }

        // Compute v = x1 * i (mod P)
        uint v = mulmod(x1, i, _P);

        // Compute j = h * i (mod P)
        uint j = mulmod(h, i, _P);

        // Compute r = 2 * (s               - y1)       (mod P)
        //           = 2 * (s               + (P - y1)) (mod P)
        //           = 2 * ((y2 * z1³)      + (P - y1)) (mod P)
        //           = 2 * ((y2 * z1² * z1) + (P - y1)) (mod P)
        //
        // Unchecked because the only protected operation performed is P - y1
        // where y1 is guaranteed by the caller to be an y coordinate belonging
        // to a point on the curve, i.e. being less than P.
        uint r;
        unchecked {
            r = mulmod(
                2,
                addmod(mulmod(p.y, mulmod(z1_2, z1, _P), _P), _P - y1, _P),
                _P
            );
        }

        // Compute x = r² - j - (2 * v)             (mod P)
        //           = r² - j + (P - (2 * v))       (mod P)
        //           = r² + (P - j) + (P - (2 * v)) (mod P)
        //                  ╰─────╯   ╰───────────╯
        //                    mid         right
        //
        // Unchecked because the only protected operations performed are
        // subtractions from P where the subtrahend is the result of a (mod P)
        // computation, i.e. the subtrahend being guaranteed to be less than P.
        unchecked {
            uint r_2 = mulmod(r, r, _P);
            uint mid = _P - j;
            uint right = _P - mulmod(2, v, _P);

            self.x = addmod(r_2, addmod(mid, right, _P), _P);
        }

        // Compute y = (r * (v - x))       - (2 * y1 * j)       (mod P)
        //           = (r * (v - x))       + (P - (2 * y1 * j)) (mod P)
        //           = (r * (v + (P - x))) + (P - (2 * y1 * j)) (mod P)
        //             ╰─────────────────╯   ╰────────────────╯
        //                    left                 right
        //
        // Unchecked because the only protected operations performed are
        // subtractions from P where the subtrahend is the result of a (mod P)
        // computation, i.e. the subtrahend being guaranteed to be less than P.
        unchecked {
            uint left = mulmod(r, addmod(v, _P - self.x, _P), _P);
            uint right = _P - mulmod(2, mulmod(y1, j, _P), _P);

            self.y = addmod(left, right, _P);
        }
    }

    // -- Private Helpers --

    /// @dev Returns the modular inverse of `x` for modulo `_P`.
    ///
    ///      It is the caller's responsibility to ensure `x` is less than `_P`!
    ///
    ///      The modular inverse of `x` is x⁻¹ such that x * x⁻¹ ≡ 1 (mod P).
    ///
    /// @dev Modified from Jordi Baylina's [ecsol](https://github.com/jbaylina/ecsol/blob/c2256afad126b7500e6f879a9369b100e47d435d/ec.sol#L51-L67).
    ///
    /// @custom:invariant Reverts iff out of gas.
    /// @custom:invariant Does not run into an infinite loop.
    function _invMod(uint x) private pure returns (uint) {
        uint t;
        uint q;
        uint newT = 1;
        uint r = _P;

        assembly ("memory-safe") {
            // Implemented in assembly to circumvent division-by-zero
            // and over-/underflow protection.
            //
            // Functionally equivalent Solidity code:
            //      while (x != 0) {
            //          q = r / x;
            //          (t, newT) = (newT, addmod(t, (_P - mulmod(q, newT, _P)), _P));
            //          (r, x) = (x, r - (q * x));
            //      }
            //
            // For the division r / x, x is guaranteed to not be zero via the
            // loop condition.
            //
            // The subtraction of form P - mulmod(_, _, P) is guaranteed to not
            // underflow due to the subtrahend being a (mod P) result,
            // i.e. the subtrahend being guaranteed to be less than P.
            //
            // The subterm q * x is guaranteed to not overflow because
            // q * x ≤ r due to q = ⎣r / x⎦.
            //
            // The term r - (q * x) is guaranteed to not underflow because
            // q * x ≤ r and therefore r - (q * x) ≥ 0.
            for {} x {} {
                q := div(r, x)

                let tmp := t
                t := newT
                newT := addmod(tmp, sub(_P, mulmod(q, newT, _P)), _P)

                tmp := r
                r := x
                x := sub(tmp, mul(q, x))
            }
        }

        return t;
    }
}

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

interface IAuth {
    /// @notice Thrown by protected function if caller not auth'ed.
    /// @param caller The caller's address.
    error NotAuthorized(address caller);

    /// @notice Emitted when auth granted to address.
    /// @param caller The caller's address.
    /// @param who The address auth got granted to.
    event AuthGranted(address indexed caller, address indexed who);

    /// @notice Emitted when auth renounced from address.
    /// @param caller The caller's address.
    /// @param who The address auth got renounced from.
    event AuthRenounced(address indexed caller, address indexed who);

    /// @notice Grants address `who` auth.
    /// @dev Only callable by auth'ed address.
    /// @param who The address to grant auth.
    function rely(address who) external;

    /// @notice Renounces address `who`'s auth.
    /// @dev Only callable by auth'ed address.
    /// @param who The address to renounce auth.
    function deny(address who) external;

    /// @notice Returns whether address `who` is auth'ed.
    /// @param who The address to check.
    /// @return True if `who` is auth'ed, false otherwise.
    function authed(address who) external view returns (bool);

    /// @notice Returns full list of addresses granted auth.
    /// @dev May contain duplicates.
    /// @return List of addresses granted auth.
    function authed() external view returns (address[] memory);

    /// @notice Returns whether address `who` is auth'ed.
    /// @custom:deprecated Use `authed(address)(bool)` instead.
    /// @param who The address to check.
    /// @return 1 if `who` is auth'ed, 0 otherwise.
    function wards(address who) external view returns (uint);
}

Settings
{
  "remappings": [
    "forge-std@v1/=dependencies/forge-std-1.9.7/src/",
    "chronicle-std@v2/=dependencies/chronicle-std-2.1.0/src/",
    "uscribe@v1/=dependencies/uscribe-1.3.0/src/",
    "uscribe-tests@v1/=dependencies/uscribe-1.3.0/test/",
    "greenhouse@v1/=dependencies/greenhouse-1.0.0/src/",
    "openzeppelin@v5/=dependencies/openzeppelin-5.2.0/contracts/",
    "@openzeppelin/contracts/=dependencies/openzeppelin-5.2.0/contracts/",
    "chronicle-std-2.1.0/=dependencies/chronicle-std-2.1.0/",
    "chronicle-std/=dependencies/greenhouse-1.0.0/lib/chronicle-std/",
    "ds-test/=dependencies/chronicle-std-2.1.0/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=dependencies/openzeppelin-5.2.0/lib/erc4626-tests/",
    "forge-std-1.9.7/=dependencies/forge-std-1.9.7/src/",
    "forge-std/=dependencies/chronicle-std-2.1.0/lib/forge-std/src/",
    "greenhouse-1.0.0/=dependencies/greenhouse-1.0.0/",
    "halmos-cheatcodes/=dependencies/openzeppelin-5.2.0/lib/halmos-cheatcodes/src/",
    "openzeppelin-5.2.0/=dependencies/openzeppelin-5.2.0/",
    "uscribe-1.3.0/=dependencies/uscribe-1.3.0/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"initialAuthed","type":"address"},{"internalType":"address","name":"router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FutureMessage","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotAuthorized","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotTolled","type":"error"},{"inputs":[{"internalType":"bytes4","name":"err","type":"bytes4"}],"name":"PokeError_ConsumerRejectedPayload","type":"error"},{"inputs":[{"internalType":"bytes4","name":"err","type":"bytes4"}],"name":"PokeError_VerificationFailed","type":"error"},{"inputs":[],"name":"StaleMessage","type":"error"},{"inputs":[],"name":"VerificationError_BarNotReached","type":"error"},{"inputs":[],"name":"VerificationError_DoubleSigningAttempted","type":"error"},{"inputs":[],"name":"VerificationError_SignatureInvalid","type":"error"},{"inputs":[],"name":"VerificationError_ValidatorInvalid","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"AuthGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"AuthRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint8","name":"oldBar","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"newBar","type":"uint8"}],"name":"BarUpdatedECDSA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint8","name":"oldBar","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"newBar","type":"uint8"}],"name":"BarUpdatedSchnorr","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint128","name":"val","type":"uint128"},{"indexed":false,"internalType":"uint48","name":"age","type":"uint48"}],"name":"Poked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"TollGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"TollRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"string","name":"proofURI","type":"string"}],"name":"UPoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorDroppedECDSA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorDroppedSchnorr","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorLiftedECDSA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorLiftedSchnorr","type":"event"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"authed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authed","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"barECDSA","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"barSchnorr","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"bud","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"scheme","type":"bytes32"},{"components":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"proofURI","type":"string"}],"internalType":"struct UPokeData","name":"uPokeData","type":"tuple"}],"name":"constructChronicleSignedMessage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"diss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"ids","type":"uint8[]"}],"name":"dropECDSA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"ids","type":"uint8[]"}],"name":"dropSchnorr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"kiss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"latestPoke","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"validators","type":"address[]"}],"name":"liftECDSA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct LibSecp256k1.Point[]","name":"pubKeys","type":"tuple[]"}],"name":"liftSchnorr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"proofURI","type":"string"}],"internalType":"struct UPokeData","name":"uPokeData","type":"tuple"},{"components":[{"internalType":"bytes32","name":"signature","type":"bytes32"},{"internalType":"address","name":"commitment","type":"address"},{"internalType":"bytes","name":"validatorIds","type":"bytes"}],"internalType":"struct SchnorrData","name":"schnorr","type":"tuple"}],"name":"poke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"proofURI","type":"string"}],"internalType":"struct UPokeData","name":"uPokeData","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ECDSAData[]","name":"ecdsas","type":"tuple[]"}],"name":"poke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"read","outputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"readWithAge","outputs":[{"internalType":"uint256","name":"val","type":"uint256"},{"internalType":"uint256","name":"age","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"bar","type":"uint8"}],"name":"setBarECDSA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"bar","type":"uint8"}],"name":"setBarSchnorr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"tolled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tolled","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tryRead","outputs":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tryReadWithAge","outputs":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"uint256","name":"val","type":"uint256"},{"internalType":"uint256","name":"age","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"validatorsECDSA","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorsECDSA","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"validatorsECDSA","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorsSchnorr","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"validatorsSchnorr","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"validatorsSchnorr","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wat","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]

60c0604052346103bf57604051601f612d2738819003918201601f19168301916001600160401b038311848410176102b35780849260409485528339810103126103bf576100586020610051836103c4565b92016103c4565b604080519192919081016001600160401b038111828210176102b3576040526016815260208101917f56414f3a3a43656e747269667567655f64654a41414100000000000000000000835260018060a01b03168060005260006020526001604060002055600154680100000000000000008110156102b357600181018060015581101561029d57600160009081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69190910180546001600160a01b031916831790557fe31c10b0adbedd0c6e5d024286c6eeead7761e65a67608dcf0b67604c0da7e2f8180a3805180156103bf576001600160401b0381116102b357600254600181811c911680156103b5575b602082101461039f57601f811161033a575b50806020601f82116001146102d4576000916102c9575b508160011b916000199060031b1c1916176002555b51902060805260ff80196102045416176102045560ff8019610305541617610305558060a05260018060a01b031680600052610306602052600160406000205561030754680100000000000000008110156102b35760018101806103075581101561029d576103076000526020600020018160018060a01b031982541617905560405190337f75d30ca40c7bcd48e685894b82b864808b9cb566090efc53444a2e61742f18a3600080a361294e90816103d9823960805181818161034d01528181610c32015281816111320152611614015260a05181818161069c0152818161104501528181611274015281816116c80152611cf30152f35b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b90508201513861018f565b600260009081528181209250601f198416905b81811061032257509083600194939210610309575b5050811b016002556101a4565b84015160001960f88460031b161c1916905538806102fc565b919260206001819286890151815501940192016102e7565b60026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c81019160208410610395575b601f0160051c01905b8181106103895750610178565b6000815560010161037c565b9091508190610373565b634e487b7160e01b600052602260045260246000fd5b90607f1690610166565b600080fd5b51906001600160a01b03821682036103bf5756fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde031461184a575080630e9472351461179e5780630fce34151461175157806310b07b71146116a057806314043209146114fc57806318969a2d14611410578063224242ca1461136957806338e3e01314611301578063393e5ede1461124c5780633bee58f9146111fe57806344baa5fd146111555780634ca299231461111a5780634fce7a2a146110cf57806357de26a41461101d5780635b2f752514610ffb5780635ffcbba714610f0e578063635d4acd14610e7957806365c4ce7a14610e3f57806365fae35e14610df15780638265eed614610dcb5780638575738614610af75780638cf6a8f114610a755780639954b0dc146109b25780639c52a7f114610964578063a7260f9f14610834578063bf353dbb146107ea578063cb8370a31461072b578063ceed3ef214610674578063e32da6e8146104b6578063e891c09514610494578063ef4097cc146103d6578063f0b76dd71461029a578063f29c29c41461025e5763fc8717c31461019557600080fd5b34610259576020600319360112610259576101ae6119c0565b61010081101561022a576101c79060011b600401611c94565b80516020820151171561022157604073ffffffffffffffffffffffffffffffffffffffff91201660015b60408051911515825273ffffffffffffffffffffffffffffffffffffffff909216602082015290819081015b0390f35b506000806101f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff811681036102595761029890611f32565b005b346102595760406003193601126102595760243567ffffffffffffffff8111610259578060040190604060031982360301126102595761031460209260246102e28280611adb565b6103098760405183819483830196873781016000838201520301601f198101835282611ab8565b519020930190611adb565b61033b8460405183819483830196873781016000838201520301601f198101835282611ab8565b519020604051908382019260043584527f00000000000000000000000000000000000000000000000000000000000000006040840152606083015260808201526080815261038a60a082611ab8565b519020604051828101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d81526103cb605d82611ab8565b519020604051908152f35b34610259576020600319360112610259576103ef6119c0565b336000526000602052604060002054156104825760ff8116908115610259576103055460ff811683810361041f57005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917ff1f337dab208fa554bd26f24051a905078905ccd741043ca59e486a3b9e03f4c91a2161761030555005b634a0bfec1600052336020526024601cfd5b3461025957600060031936011261025957602060ff6102045416604051908152f35b346102595760206003193601126102595760043567ffffffffffffffff8111610259573660238201121561025957806004013567ffffffffffffffff8111610259573660248260061b8401011161025957336000526000602052604060002054156104825760005b81811015610298576000908060061b840160407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8236030112610670576040519261056884611a51565b604460248301359283865201356020850192818452171561064057604084209173ffffffffffffffffffffffffffffffffffffffff83169261010060ff8260981c1610156106435760971c6101fe1690600482016105c581611c94565b9687516020890151171560001461061257600197509060059291519055519101557f189ea7fe6fa9a5be238df17366f57d37c1943a76871a92123a439f66bc489335339180a35b0161051e565b505050509192604073ffffffffffffffffffffffffffffffffffffffff91201603610640575060019061060c565b80fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b8280fd5b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610705575b60606106f065ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b90604051921515835260208301526040820152f35b336000526103066020526040600020546106c35763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff81168082036102595761010060ff8360981c16101561022a576107a97401fffffffffffffffffffffffffffffffffffffffe6101fe6d01fffffffffffffffffffffffffe60209560971c161616600401611c94565b9081518383015117151591826107c6575b50506040519015158152f35b6040902073ffffffffffffffffffffffffffffffffffffffff1614905082806107ba565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff81168091036102595760005260006020526020604060002054604051908152f35b346102595760206003193601126102595760043567ffffffffffffffff8111610259576108659036906004016119d0565b90336000526000602052604060002054156104825760005b82811061088657005b610899610894828585611b54565b611f11565b9073ffffffffffffffffffffffffffffffffffffffff82169182156102595760ff9060981c1691610100831015928361022a57610205019273ffffffffffffffffffffffffffffffffffffffff845416801560001461094f575061022a5782817fffffffffffffffffffffffff00000000000000000000000000000000000000006001955416179055337fafb0e3c5f69ca0548e193d035ea46175485ad76d40ebac3f49531a414447047f600080a35b0161087d565b92935050600091036106405750600190610949565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116810361025957336000526000602052604060002054156104825761029890611eaf565b34610259576000600319360112610259576109cf61030754611b8a565b60009060005b8151811015610a62578073ffffffffffffffffffffffffffffffffffffffff6109ff600193611bd6565b90549060031b1c166000526103066020528160406000205414610a23575b016109d5565b73ffffffffffffffffffffffffffffffffffffffff610a4182611bd6565b90549060031b1c16610a5c610a5586611c0b565b9585611c67565b52610a1d565b5061021d91815260405191829182611a01565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116908181036102595760981c60ff16908015159081610ac6575b6020826040519015158152f35b905061010082101561022a5773ffffffffffffffffffffffffffffffffffffffff6020926102050154161482610ab9565b346102595760406003193601126102595760043567ffffffffffffffff8111610259578060040190604060031982360301126102595760243567ffffffffffffffff811161025957366023820112156102595780600401359067ffffffffffffffff8211610259573660246060840283010111610259577fffffffff0000000000000000000000000000000000000000000000000000000091610cbc91602480610ba18880611adb565b610bc9602060405183819483830196873781016000838201520301601f198101835282611ab8565b519020960195610bd98789611adb565b610c01602060405183819483830196873781016000838201520301601f198101835282611ab8565b5190206040519060208201927f454344534100000000000000000000000000000000000000000000000000000084527f000000000000000000000000000000000000000000000000000000000000000060408401526060830152608082015260808152610c6f60a082611ab8565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152610cb1605d82611ab8565b519020910190612543565b1680610d9e577fffffffff00000000000000000000000000000000000000000000000000000000610d37610d3185610d287f16f91548bee0e0722f10b5b21a55dae299cd9024229347fd3063ffe2eee8ea34610d188884611adb565b6040513394909283929083611b2c565b0390a280611adb565b90612421565b1680610d7157600380547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff16179055005b7fda45eb1c0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fc61f8ee60000000000000000000000000000000000000000000000000000000060005260045260246000fd5b3461025957600060031936011261025957602065ffffffffffff60035416604051908152f35b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116810361025957336000526000602052604060002054156104825761029890611dee565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff811681036102595761029890611cb2565b3461025957600060031936011261025957604051601f19612020610e9d8184611ab8565b6101008352013660208301376000805b610100811015610efd5760019073ffffffffffffffffffffffffffffffffffffffff8161020501541680610ee3575b5001610ead565b610ef6610eef85611c0b565b9486611c67565b5284610edc565b8183526040518061021d8582611a01565b346102595760206003193601126102595760043567ffffffffffffffff811161025957610f3f9036906004016119d0565b90336000526000602052604060002054156104825760005b828110610f6057005b610f73610f6e828585611b54565b611b64565b9061010082101561022a57600191821b80600401610f9081611c94565b908151602083015117610fa7575b50505001610f57565b73ffffffffffffffffffffffffffffffffffffffff9160409160056000958680935501552016907f52ce30f1a5a6d183f1c399b08dbbebaa6bcd0e2a3f6da47ff3b6984b863d28de339180a3848080610f9e565b3461025957600060031936011261025957602060ff6103055416604051908152f35b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036110a9575b61109765ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b50901561025957602090604051908152f35b3360005261030660205260406000205461106c5763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116809103610259576000526103066020526020604060002054604051908152f35b346102595760006003193601126102595760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461025957600060031936011261025957604051601f196120206111798184611ab8565b610100835201366020830137604051600061119382611a51565b80825260208201525060009060005b610100811015610a62576001906111bd81831b600401611c94565b80516020820151176111d1575b50016111a2565b604073ffffffffffffffffffffffffffffffffffffffff9120166111f7610a5586611c0b565b52846111ca565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116809103610259576000526103066020526020600160406000205414604051908152f35b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036112db575b6112c665ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b91156102595760409182519182526020820152f35b3360005261030660205260406000205461129b5763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043561010081101561022a57610205015473ffffffffffffffffffffffffffffffffffffffff16801561022157604080516001815273ffffffffffffffffffffffffffffffffffffffff92909216602083015290f35b3461025957600060031936011261025957611385600154611b8a565b60009060005b8151811015610a62578073ffffffffffffffffffffffffffffffffffffffff6113b5600193611bbb565b90549060031b1c16600052600060205281604060002054146113d8575b0161138b565b73ffffffffffffffffffffffffffffffffffffffff6113f682611bbb565b90549060031b1c1661140a610a5586611c0b565b526113d2565b346102595760206003193601126102595760043567ffffffffffffffff8111610259576114419036906004016119d0565b90336000526000602052604060002054156104825760005b82811061146257005b611470610f6e828585611b54565b9061010082101561022a576001916102050173ffffffffffffffffffffffffffffffffffffffff81541690816114a9575b505001611459565b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055337f7d553b93bbf05f357fad190f996038832a2de9be7a99c6647f6b047cf3284fc9600080a384806114a1565b346102595760406003193601126102595760043567ffffffffffffffff8111610259578060040190604060031982360301126102595760243567ffffffffffffffff8111610259576060600319823603011261025957610cbc7fffffffff000000000000000000000000000000000000000000000000000000009160246115838680611adb565b6115ab602060405183819483830196873781016000838201520301601f198101835282611ab8565b5190209401936115bb8587611adb565b6115e3602060405183819483830196873781016000838201520301601f198101835282611ab8565b5190206040519060208201927f5343484e4f52520000000000000000000000000000000000000000000000000084527f00000000000000000000000000000000000000000000000000000000000000006040840152606083015260808201526080815261165160a082611ab8565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152611693605d82611ab8565b5190209060040190611ffb565b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361172b575b604061171c65ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b50825191151582526020820152f35b336000526103066020526040600020546116ef5763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff81168091036102595760005260006020526020600160406000205414604051908152f35b34610259576020600319360112610259576117b76119c0565b336000526000602052604060002054156104825760ff8116908115610259576102045460ff81168381036117e757005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917f6725eac4d9463d79b15ccb65e620936de0a75d44795151a2fc5a6f62f1dc376c91a2161761020455005b34610259576000600319360112610259576000600254908160011c916001811680156119b6575b60208410811461198957838552849291811561194c57506001146118eb575b61189c92500382611ab8565b60405190602082528181519182602083015260005b8381106118d3575050601f19601f836000604080968601015201168101030190f35b602082820181015160408784010152859350016118b1565b509060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b81831061193057505090602061189c92820101611890565b6020919350806001915483858801015201910190918392611918565b6020925061189c9491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101611890565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b92607f1692611871565b6004359060ff8216820361025957565b9181601f840112156102595782359167ffffffffffffffff8311610259576020808501948460051b01011161025957565b602060408183019282815284518094520192019060005b818110611a255750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611a18565b6040810190811067ffffffffffffffff821117611a6d57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff821117611a6d57604052565b90601f601f19910116810190811067ffffffffffffffff821117611a6d57604052565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610259570180359067ffffffffffffffff82116102595760200191813603831361025957565b90601f83604094601f1993602086528160208701528686013760008582860101520116010190565b919081101561022a5760051b0190565b3560ff811681036102595790565b67ffffffffffffffff8111611a6d5760051b60200190565b90611b9482611b72565b611ba16040519182611ab8565b828152601f19611bb18294611b72565b0190602036910137565b60015481101561022a57600160005260206000200190600090565b6103075481101561022a5761030760005260206000200190600090565b805482101561022a5760005260206000200190600090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c385760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b805182101561022a5760209160051b010190565b60405190611c8882611a51565b60006020838281520152565b90604051611ca181611a51565b602060018294805484520154910152565b336000526000602052604060002054156104825773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168114611d6a578060005261030660205260406000205415611d67578060005261030660205260006040812055337fdadd1471db1ea2f303654fb1bdcc010e5a664214ab41934c0f752aabca88a491600080a3565b50565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f546f6c6c57697468496d6d757461626c65526f757465723a2063616e6e6f742060448201527f6469737320726f757465720000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff811690816000526000602052600160406000205414611eab5781600052600060205260016040600020556001549068010000000000000000821015611a6d57611e57826001611e8394016001556001611bf3565b90919073ffffffffffffffffffffffffffffffffffffffff8084549260031b9316831b921b1916179055565b337fe31c10b0adbedd0c6e5d024286c6eeead7761e65a67608dcf0b67604c0da7e2f600080a3565b5050565b73ffffffffffffffffffffffffffffffffffffffff1680600052600060205260406000205415611d675780600052600060205260006040812055337f58466e5837b54e559819c9ba8a5d7c77c97c985d1aabf4bdc5f41069fa5d65a0600080a3565b3573ffffffffffffffffffffffffffffffffffffffff811681036102595790565b336000526000602052604060002054156104825773ffffffffffffffffffffffffffffffffffffffff81169081600052610306602052600160406000205414611eab57816000526103066020526001604060002055610307549068010000000000000000821015611a6d57611e57826001611fb4940161030755610307611bf3565b337f75d30ca40c7bcd48e685894b82b864808b9cb566090efc53444a2e61742f18a3600080a3565b60405190611fe982611a9c565b60006040838281528260208201520152565b9190600092612008611c7b565b50612011611fdc565b5060ff61020454169060408301948261202a8786611adb565b9050036123f85761203b8685611adb565b156123cb57358060f81c9161010083101561237357506101fe806120669260f71c1616600401611c94565b928351916020850192835117156123a0576001909791971b93612087611fdc565b50519151966040519261209984611a9c565b8352602083019788526040830194600186526001926000935b8381106121cf5750505050506120c6611c7b565b50604051926120d484611a51565b60008452600060208501525195600096600190807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f915b61219257505050957ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8092612164979882808580098093510987525192099009602083015261215c60208401611f11565b9235916126ff565b1561216e57600090565b7fcbc4755f0000000000000000000000000000000000000000000000000000000090565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183949b930492818c850982039008929091820290038061210b565b6121d9828a611adb565b6000908310156123735750810135908160f81c9161010083101561022a576101fe8061220c9260f71c1616600401611c94565b93845192602086019384511715612342576001901b9081811661231157179387518d51978b51906122e2576001947ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f83818f818f978f9982809b818b8180809e819a82809a818085819609809c510990820390089d8e91838b818080878009928184600409998a988d0893820390820308918009089052099b099b5192820394099009086002099481808086600209810383820308818880090880985260009e09600209820394820390089009088c52016120b2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b507fe7908552000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b507f552e5639000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526032600452fd5b507f552e56390000000000000000000000000000000000000000000000000000000096505050505050565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b507f19877c60000000000000000000000000000000000000000000000000000000009450505050565b9081604091810103126102595760405160009161243d82611a51565b80359065ffffffffffff82169182810361253f5790602091845201356fffffffffffffffffffffffffffffffff81169283820361253f576020015265ffffffffffff60035416811115612518574281116124f157817fffffffffffffffffffffffffffffffff000000000000000000000000000000006103085416176103085560405191825260208201527f9f8b8154174dc4a9ed8bbe5a985ecf6d8b2db481a1c64a02c8d94ae7929e0ba660403392a290565b5050507f5507d1ac0000000000000000000000000000000000000000000000000000000090565b5050507f4ef874670000000000000000000000000000000000000000000000000000000090565b8480fd5b61254b611fdc565b5060009160ff6103055416938481036126d6576000935b85851061257457505050505050600090565b8185101561022a576060850283016060813603126102595760405161259881611a9c565b81359160ff8316808403610259576125ee8360209560009552604086850135948588840152013590816040820152506040519384938b859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156126ca5760005160ff73ffffffffffffffffffffffffffffffffffffffff82169160981c1690801590811561269a575b5061266f576001901b8082166126445760019117940193612562565b505050505050507fe79085520000000000000000000000000000000000000000000000000000000090565b505050505050507fcbc4755f0000000000000000000000000000000000000000000000000000000090565b905061010082101561022a5773ffffffffffffffffffffffffffffffffffffffff82610205015416141538612628565b6040513d6000823e3d90fd5b50505050507f19877c600000000000000000000000000000000000000000000000000000000090565b9091801580156128fa575b6128f157602082019081517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f80600781875181818009900908918009036128e7577ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418110156128e7576128b983601b60017ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418060209960009951908951907f0100000000000000000000000000000000000000000000000000000000000000604051928e840194855260f81b16604083015260418201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008d60601b1660618201526055815261281b607582611ab8565b5190200695845190097ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414103955116019051809460ff7ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641416040519788970991865290921660ff16602085015260408401527ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410360608301526080820190565b838052039060015afa156126ca5773ffffffffffffffffffffffffffffffffffffffff806000511691161490565b5050505050600090565b50505050600090565b5073ffffffffffffffffffffffffffffffffffffffff84161561270a56fea2646970667358221220e289b003264c4f458512a5e91fa48c2c940569d37035801cc4ec1fa2c6eff3d864736f6c634300081c0033000000000000000000000000c50dfedb7e93ef7a3daccad7987d0960c4e2cd4b00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c90816306fdde031461184a575080630e9472351461179e5780630fce34151461175157806310b07b71146116a057806314043209146114fc57806318969a2d14611410578063224242ca1461136957806338e3e01314611301578063393e5ede1461124c5780633bee58f9146111fe57806344baa5fd146111555780634ca299231461111a5780634fce7a2a146110cf57806357de26a41461101d5780635b2f752514610ffb5780635ffcbba714610f0e578063635d4acd14610e7957806365c4ce7a14610e3f57806365fae35e14610df15780638265eed614610dcb5780638575738614610af75780638cf6a8f114610a755780639954b0dc146109b25780639c52a7f114610964578063a7260f9f14610834578063bf353dbb146107ea578063cb8370a31461072b578063ceed3ef214610674578063e32da6e8146104b6578063e891c09514610494578063ef4097cc146103d6578063f0b76dd71461029a578063f29c29c41461025e5763fc8717c31461019557600080fd5b34610259576020600319360112610259576101ae6119c0565b61010081101561022a576101c79060011b600401611c94565b80516020820151171561022157604073ffffffffffffffffffffffffffffffffffffffff91201660015b60408051911515825273ffffffffffffffffffffffffffffffffffffffff909216602082015290819081015b0390f35b506000806101f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff811681036102595761029890611f32565b005b346102595760406003193601126102595760243567ffffffffffffffff8111610259578060040190604060031982360301126102595761031460209260246102e28280611adb565b6103098760405183819483830196873781016000838201520301601f198101835282611ab8565b519020930190611adb565b61033b8460405183819483830196873781016000838201520301601f198101835282611ab8565b519020604051908382019260043584527ffa74b361496a96255b8bf1f1c19d09538cc04d367335e21fe25fbd606eccfd896040840152606083015260808201526080815261038a60a082611ab8565b519020604051828101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d81526103cb605d82611ab8565b519020604051908152f35b34610259576020600319360112610259576103ef6119c0565b336000526000602052604060002054156104825760ff8116908115610259576103055460ff811683810361041f57005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917ff1f337dab208fa554bd26f24051a905078905ccd741043ca59e486a3b9e03f4c91a2161761030555005b634a0bfec1600052336020526024601cfd5b3461025957600060031936011261025957602060ff6102045416604051908152f35b346102595760206003193601126102595760043567ffffffffffffffff8111610259573660238201121561025957806004013567ffffffffffffffff8111610259573660248260061b8401011161025957336000526000602052604060002054156104825760005b81811015610298576000908060061b840160407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8236030112610670576040519261056884611a51565b604460248301359283865201356020850192818452171561064057604084209173ffffffffffffffffffffffffffffffffffffffff83169261010060ff8260981c1610156106435760971c6101fe1690600482016105c581611c94565b9687516020890151171560001461061257600197509060059291519055519101557f189ea7fe6fa9a5be238df17366f57d37c1943a76871a92123a439f66bc489335339180a35b0161051e565b505050509192604073ffffffffffffffffffffffffffffffffffffffff91201603610640575060019061060c565b80fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b8280fd5b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa163303610705575b60606106f065ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b90604051921515835260208301526040820152f35b336000526103066020526040600020546106c35763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff81168082036102595761010060ff8360981c16101561022a576107a97401fffffffffffffffffffffffffffffffffffffffe6101fe6d01fffffffffffffffffffffffffe60209560971c161616600401611c94565b9081518383015117151591826107c6575b50506040519015158152f35b6040902073ffffffffffffffffffffffffffffffffffffffff1614905082806107ba565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff81168091036102595760005260006020526020604060002054604051908152f35b346102595760206003193601126102595760043567ffffffffffffffff8111610259576108659036906004016119d0565b90336000526000602052604060002054156104825760005b82811061088657005b610899610894828585611b54565b611f11565b9073ffffffffffffffffffffffffffffffffffffffff82169182156102595760ff9060981c1691610100831015928361022a57610205019273ffffffffffffffffffffffffffffffffffffffff845416801560001461094f575061022a5782817fffffffffffffffffffffffff00000000000000000000000000000000000000006001955416179055337fafb0e3c5f69ca0548e193d035ea46175485ad76d40ebac3f49531a414447047f600080a35b0161087d565b92935050600091036106405750600190610949565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116810361025957336000526000602052604060002054156104825761029890611eaf565b34610259576000600319360112610259576109cf61030754611b8a565b60009060005b8151811015610a62578073ffffffffffffffffffffffffffffffffffffffff6109ff600193611bd6565b90549060031b1c166000526103066020528160406000205414610a23575b016109d5565b73ffffffffffffffffffffffffffffffffffffffff610a4182611bd6565b90549060031b1c16610a5c610a5586611c0b565b9585611c67565b52610a1d565b5061021d91815260405191829182611a01565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116908181036102595760981c60ff16908015159081610ac6575b6020826040519015158152f35b905061010082101561022a5773ffffffffffffffffffffffffffffffffffffffff6020926102050154161482610ab9565b346102595760406003193601126102595760043567ffffffffffffffff8111610259578060040190604060031982360301126102595760243567ffffffffffffffff811161025957366023820112156102595780600401359067ffffffffffffffff8211610259573660246060840283010111610259577fffffffff0000000000000000000000000000000000000000000000000000000091610cbc91602480610ba18880611adb565b610bc9602060405183819483830196873781016000838201520301601f198101835282611ab8565b519020960195610bd98789611adb565b610c01602060405183819483830196873781016000838201520301601f198101835282611ab8565b5190206040519060208201927f454344534100000000000000000000000000000000000000000000000000000084527ffa74b361496a96255b8bf1f1c19d09538cc04d367335e21fe25fbd606eccfd8960408401526060830152608082015260808152610c6f60a082611ab8565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152610cb1605d82611ab8565b519020910190612543565b1680610d9e577fffffffff00000000000000000000000000000000000000000000000000000000610d37610d3185610d287f16f91548bee0e0722f10b5b21a55dae299cd9024229347fd3063ffe2eee8ea34610d188884611adb565b6040513394909283929083611b2c565b0390a280611adb565b90612421565b1680610d7157600380547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000164265ffffffffffff16179055005b7fda45eb1c0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fc61f8ee60000000000000000000000000000000000000000000000000000000060005260045260246000fd5b3461025957600060031936011261025957602065ffffffffffff60035416604051908152f35b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116810361025957336000526000602052604060002054156104825761029890611dee565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff811681036102595761029890611cb2565b3461025957600060031936011261025957604051601f19612020610e9d8184611ab8565b6101008352013660208301376000805b610100811015610efd5760019073ffffffffffffffffffffffffffffffffffffffff8161020501541680610ee3575b5001610ead565b610ef6610eef85611c0b565b9486611c67565b5284610edc565b8183526040518061021d8582611a01565b346102595760206003193601126102595760043567ffffffffffffffff811161025957610f3f9036906004016119d0565b90336000526000602052604060002054156104825760005b828110610f6057005b610f73610f6e828585611b54565b611b64565b9061010082101561022a57600191821b80600401610f9081611c94565b908151602083015117610fa7575b50505001610f57565b73ffffffffffffffffffffffffffffffffffffffff9160409160056000958680935501552016907f52ce30f1a5a6d183f1c399b08dbbebaa6bcd0e2a3f6da47ff3b6984b863d28de339180a3848080610f9e565b3461025957600060031936011261025957602060ff6103055416604051908152f35b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa1633036110a9575b61109765ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b50901561025957602090604051908152f35b3360005261030660205260406000205461106c5763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116809103610259576000526103066020526020604060002054604051908152f35b346102595760006003193601126102595760206040517ffa74b361496a96255b8bf1f1c19d09538cc04d367335e21fe25fbd606eccfd898152f35b3461025957600060031936011261025957604051601f196120206111798184611ab8565b610100835201366020830137604051600061119382611a51565b80825260208201525060009060005b610100811015610a62576001906111bd81831b600401611c94565b80516020820151176111d1575b50016111a2565b604073ffffffffffffffffffffffffffffffffffffffff9120166111f7610a5586611c0b565b52846111ca565b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff8116809103610259576000526103066020526020600160406000205414604051908152f35b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa1633036112db575b6112c665ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b91156102595760409182519182526020820152f35b3360005261030660205260406000205461129b5763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043561010081101561022a57610205015473ffffffffffffffffffffffffffffffffffffffff16801561022157604080516001815273ffffffffffffffffffffffffffffffffffffffff92909216602083015290f35b3461025957600060031936011261025957611385600154611b8a565b60009060005b8151811015610a62578073ffffffffffffffffffffffffffffffffffffffff6113b5600193611bbb565b90549060031b1c16600052600060205281604060002054146113d8575b0161138b565b73ffffffffffffffffffffffffffffffffffffffff6113f682611bbb565b90549060031b1c1661140a610a5586611c0b565b526113d2565b346102595760206003193601126102595760043567ffffffffffffffff8111610259576114419036906004016119d0565b90336000526000602052604060002054156104825760005b82811061146257005b611470610f6e828585611b54565b9061010082101561022a576001916102050173ffffffffffffffffffffffffffffffffffffffff81541690816114a9575b505001611459565b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055337f7d553b93bbf05f357fad190f996038832a2de9be7a99c6647f6b047cf3284fc9600080a384806114a1565b346102595760406003193601126102595760043567ffffffffffffffff8111610259578060040190604060031982360301126102595760243567ffffffffffffffff8111610259576060600319823603011261025957610cbc7fffffffff000000000000000000000000000000000000000000000000000000009160246115838680611adb565b6115ab602060405183819483830196873781016000838201520301601f198101835282611ab8565b5190209401936115bb8587611adb565b6115e3602060405183819483830196873781016000838201520301601f198101835282611ab8565b5190206040519060208201927f5343484e4f52520000000000000000000000000000000000000000000000000084527ffa74b361496a96255b8bf1f1c19d09538cc04d367335e21fe25fbd606eccfd896040840152606083015260808201526080815261165160a082611ab8565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152611693605d82611ab8565b5190209060040190611ffb565b346102595760006003193601126102595773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa16330361172b575b604061171c65ffffffffffff600354166fffffffffffffffffffffffffffffffff61030854169080151592565b50825191151582526020820152f35b336000526103066020526040600020546116ef5763d957b595600052336020526024601cfd5b346102595760206003193601126102595760043573ffffffffffffffffffffffffffffffffffffffff81168091036102595760005260006020526020600160406000205414604051908152f35b34610259576020600319360112610259576117b76119c0565b336000526000602052604060002054156104825760ff8116908115610259576102045460ff81168381036117e757005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917f6725eac4d9463d79b15ccb65e620936de0a75d44795151a2fc5a6f62f1dc376c91a2161761020455005b34610259576000600319360112610259576000600254908160011c916001811680156119b6575b60208410811461198957838552849291811561194c57506001146118eb575b61189c92500382611ab8565b60405190602082528181519182602083015260005b8381106118d3575050601f19601f836000604080968601015201168101030190f35b602082820181015160408784010152859350016118b1565b509060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b81831061193057505090602061189c92820101611890565b6020919350806001915483858801015201910190918392611918565b6020925061189c9491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101611890565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b92607f1692611871565b6004359060ff8216820361025957565b9181601f840112156102595782359167ffffffffffffffff8311610259576020808501948460051b01011161025957565b602060408183019282815284518094520192019060005b818110611a255750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611a18565b6040810190811067ffffffffffffffff821117611a6d57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff821117611a6d57604052565b90601f601f19910116810190811067ffffffffffffffff821117611a6d57604052565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610259570180359067ffffffffffffffff82116102595760200191813603831361025957565b90601f83604094601f1993602086528160208701528686013760008582860101520116010190565b919081101561022a5760051b0190565b3560ff811681036102595790565b67ffffffffffffffff8111611a6d5760051b60200190565b90611b9482611b72565b611ba16040519182611ab8565b828152601f19611bb18294611b72565b0190602036910137565b60015481101561022a57600160005260206000200190600090565b6103075481101561022a5761030760005260206000200190600090565b805482101561022a5760005260206000200190600090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611c385760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b805182101561022a5760209160051b010190565b60405190611c8882611a51565b60006020838281520152565b90604051611ca181611a51565b602060018294805484520154910152565b336000526000602052604060002054156104825773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa168114611d6a578060005261030660205260406000205415611d67578060005261030660205260006040812055337fdadd1471db1ea2f303654fb1bdcc010e5a664214ab41934c0f752aabca88a491600080a3565b50565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f546f6c6c57697468496d6d757461626c65526f757465723a2063616e6e6f742060448201527f6469737320726f757465720000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff811690816000526000602052600160406000205414611eab5781600052600060205260016040600020556001549068010000000000000000821015611a6d57611e57826001611e8394016001556001611bf3565b90919073ffffffffffffffffffffffffffffffffffffffff8084549260031b9316831b921b1916179055565b337fe31c10b0adbedd0c6e5d024286c6eeead7761e65a67608dcf0b67604c0da7e2f600080a3565b5050565b73ffffffffffffffffffffffffffffffffffffffff1680600052600060205260406000205415611d675780600052600060205260006040812055337f58466e5837b54e559819c9ba8a5d7c77c97c985d1aabf4bdc5f41069fa5d65a0600080a3565b3573ffffffffffffffffffffffffffffffffffffffff811681036102595790565b336000526000602052604060002054156104825773ffffffffffffffffffffffffffffffffffffffff81169081600052610306602052600160406000205414611eab57816000526103066020526001604060002055610307549068010000000000000000821015611a6d57611e57826001611fb4940161030755610307611bf3565b337f75d30ca40c7bcd48e685894b82b864808b9cb566090efc53444a2e61742f18a3600080a3565b60405190611fe982611a9c565b60006040838281528260208201520152565b9190600092612008611c7b565b50612011611fdc565b5060ff61020454169060408301948261202a8786611adb565b9050036123f85761203b8685611adb565b156123cb57358060f81c9161010083101561237357506101fe806120669260f71c1616600401611c94565b928351916020850192835117156123a0576001909791971b93612087611fdc565b50519151966040519261209984611a9c565b8352602083019788526040830194600186526001926000935b8381106121cf5750505050506120c6611c7b565b50604051926120d484611a51565b60008452600060208501525195600096600190807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f915b61219257505050957ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8092612164979882808580098093510987525192099009602083015261215c60208401611f11565b9235916126ff565b1561216e57600090565b7fcbc4755f0000000000000000000000000000000000000000000000000000000090565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183949b930492818c850982039008929091820290038061210b565b6121d9828a611adb565b6000908310156123735750810135908160f81c9161010083101561022a576101fe8061220c9260f71c1616600401611c94565b93845192602086019384511715612342576001901b9081811661231157179387518d51978b51906122e2576001947ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f83818f818f978f9982809b818b8180809e819a82809a818085819609809c510990820390089d8e91838b818080878009928184600409998a988d0893820390820308918009089052099b099b5192820394099009086002099481808086600209810383820308818880090880985260009e09600209820394820390089009088c52016120b2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b507fe7908552000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b507f552e5639000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526032600452fd5b507f552e56390000000000000000000000000000000000000000000000000000000096505050505050565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b507f19877c60000000000000000000000000000000000000000000000000000000009450505050565b9081604091810103126102595760405160009161243d82611a51565b80359065ffffffffffff82169182810361253f5790602091845201356fffffffffffffffffffffffffffffffff81169283820361253f576020015265ffffffffffff60035416811115612518574281116124f157817fffffffffffffffffffffffffffffffff000000000000000000000000000000006103085416176103085560405191825260208201527f9f8b8154174dc4a9ed8bbe5a985ecf6d8b2db481a1c64a02c8d94ae7929e0ba660403392a290565b5050507f5507d1ac0000000000000000000000000000000000000000000000000000000090565b5050507f4ef874670000000000000000000000000000000000000000000000000000000090565b8480fd5b61254b611fdc565b5060009160ff6103055416938481036126d6576000935b85851061257457505050505050600090565b8185101561022a576060850283016060813603126102595760405161259881611a9c565b81359160ff8316808403610259576125ee8360209560009552604086850135948588840152013590816040820152506040519384938b859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156126ca5760005160ff73ffffffffffffffffffffffffffffffffffffffff82169160981c1690801590811561269a575b5061266f576001901b8082166126445760019117940193612562565b505050505050507fe79085520000000000000000000000000000000000000000000000000000000090565b505050505050507fcbc4755f0000000000000000000000000000000000000000000000000000000090565b905061010082101561022a5773ffffffffffffffffffffffffffffffffffffffff82610205015416141538612628565b6040513d6000823e3d90fd5b50505050507f19877c600000000000000000000000000000000000000000000000000000000090565b9091801580156128fa575b6128f157602082019081517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f80600781875181818009900908918009036128e7577ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418110156128e7576128b983601b60017ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418060209960009951908951907f0100000000000000000000000000000000000000000000000000000000000000604051928e840194855260f81b16604083015260418201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008d60601b1660618201526055815261281b607582611ab8565b5190200695845190097ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414103955116019051809460ff7ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641416040519788970991865290921660ff16602085015260408401527ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410360608301526080820190565b838052039060015afa156126ca5773ffffffffffffffffffffffffffffffffffffffff806000511691161490565b5050505050600090565b50505050600090565b5073ffffffffffffffffffffffffffffffffffffffff84161561270a56fea2646970667358221220e289b003264c4f458512a5e91fa48c2c940569d37035801cc4ec1fa2c6eff3d864736f6c634300081c0033

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

000000000000000000000000c50dfedb7e93ef7a3daccad7987d0960c4e2cd4b00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa

-----Decoded View---------------
Arg [0] : initialAuthed (address): 0xc50dFeDb7E93eF7A3DacCAd7987D0960c4e2CD4b
Arg [1] : router (address): 0x25563a9F085975CC6B86F66F3c010c24c12B3Ffa

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c50dfedb7e93ef7a3daccad7987d0960c4e2cd4b
Arg [1] : 00000000000000000000000025563a9f085975cc6b86f66f3c010c24c12b3ffa


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.