Sepolia Testnet

Contract

0x25f9dcF802BdC0cB6955f684cBB94E10ee7e9f4f

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Adapter

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 300 runs

Other Settings:
default evmVersion
File 1 of 26 : Adapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {SafeERC20, Address} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import {IAdapter} from "./interfaces/IAdapter.sol";
import {IAdapterOwner} from "./interfaces/IAdapterOwner.sol";
import {IController} from "./interfaces/IController.sol";
import {IBasicRandcastConsumerBase} from "./interfaces/IBasicRandcastConsumerBase.sol";
import {RequestIdBase} from "./utils/RequestIdBase.sol";
import {BLS} from "./libraries/BLS.sol";
// solhint-disable-next-line no-global-import
import "./utils/Utils.sol" as Utils;
import {ChainHelper} from "./libraries/ChainHelper.sol";

contract Adapter is UUPSUpgradeable, IAdapter, IAdapterOwner, RequestIdBase, OwnableUpgradeable {
    using SafeERC20 for IERC20;
    using Address for address;

    // *Constants*
    uint16 public constant MAX_CONSUMERS = 100;
    uint16 public constant MAX_REQUEST_CONFIRMATIONS = 200;
    uint32 public constant RANDOMNESS_REWARD_GAS = 9000;
    uint32 public constant VERIFICATION_GAS_OVER_MINIMUM_THRESHOLD = 50000;
    uint32 public constant DEFAULT_MINIMUM_THRESHOLD = 3;

    // *State Variables*
    IController internal _controller;
    uint256 internal _cumulativeFlatFee;
    uint256 internal _cumulativeCommitterReward;
    uint256 internal _cumulativePartialSignatureReward;

    // Randomness Task State
    uint32 internal _lastAssignedGroupIndex;
    uint256 internal _lastRandomness;
    uint256 internal _randomnessCount;

    AdapterConfig internal _config;
    mapping(bytes32 => bytes32) internal _requestCommitments;
    /* consumerAddress - consumer */
    mapping(address => Consumer) internal _consumers;
    /* subId - subscription */
    mapping(uint64 => Subscription) internal _subscriptions;
    uint64 internal _currentSubId;

    // Referral Promotion
    ReferralConfig internal _referralConfig;

    // Flat Fee Promotion
    FlatFeeConfig internal _flatFeeConfig;

    // *Structs*
    // Note a nonce of 0 indicates an the consumer is not assigned to that subscription.
    struct Consumer {
        /* subId - nonce */
        mapping(uint64 => uint64) nonces;
        uint64 lastSubscription;
    }

    struct Subscription {
        address owner; // Owner can fund/withdraw/cancel the sub.
        address requestedOwner; // For safely transferring sub ownership.
        address[] consumers;
        uint256 balance; // Token balance used for all consumer requests.
        uint256 inflightCost; // Upper cost for pending requests(except drastic exchange rate changes).
        mapping(bytes32 => uint256) inflightPayments;
        uint64 reqCount; // For fee tiers
        uint64 freeRequestCount; // Number of free requests(flat fee) for this sub.
        uint64 referralSubId; //
        uint64 reqCountInCurrentPeriod;
        // Number of requests in the current period.
        uint256 lastRequestTimestamp; // Timestamp of the last request.
    }

    // *Events*
    event AdapterConfigSet(
        uint16 minimumRequestConfirmations,
        uint32 maxGasLimit,
        uint32 gasAfterPaymentCalculation,
        uint32 gasExceptCallback,
        uint256 signatureTaskExclusiveWindow,
        uint256 rewardPerSignature,
        uint256 committerRewardPerSignature
    );
    event FlatFeeConfigSet(
        FeeConfig flatFeeConfig,
        uint16 flatFeePromotionGlobalPercentage,
        bool isFlatFeePromotionEnabledPermanently,
        uint256 flatFeePromotionStartTimestamp,
        uint256 flatFeePromotionEndTimestamp
    );
    event ReferralConfigSet(
        bool isReferralEnabled, uint16 freeRequestCountForReferrer, uint16 freeRequestCountForReferee
    );
    event SubscriptionCreated(uint64 indexed subId, address indexed owner);
    event SubscriptionFunded(uint64 indexed subId, uint256 oldBalance, uint256 newBalance);
    event SubscriptionConsumerAdded(uint64 indexed subId, address consumer);
    event SubscriptionReferralSet(uint64 indexed subId, uint64 indexed referralSubId);
    event SubscriptionCanceled(uint64 indexed subId, address to, uint256 amount);
    event SubscriptionConsumerRemoved(uint64 indexed subId, address consumer);
    event RandomnessRequest(
        bytes32 indexed requestId,
        uint64 indexed subId,
        uint32 indexed groupIndex,
        RequestType requestType,
        bytes params,
        address sender,
        uint256 seed,
        uint16 requestConfirmations,
        uint32 callbackGasLimit,
        uint256 callbackMaxGasPrice,
        uint256 estimatedPayment
    );
    event RandomnessRequestResult(
        bytes32 indexed requestId,
        uint32 indexed groupIndex,
        address indexed committer,
        address[] participantMembers,
        uint256 randommness,
        uint256 payment,
        uint256 flatFee,
        bool success
    );
    event OvertimeRequestCanceled(bytes32 indexed requestId, uint64 indexed subId);

    // *Errors*
    error Reentrant();
    error InvalidRequestConfirmations(uint16 have, uint16 min, uint16 max);
    error TooManyConsumers();
    error InsufficientBalanceWhenRequest();
    error InsufficientBalanceWhenFulfill();
    error InvalidConsumer(uint64 subId, address consumer);
    error InvalidSubscription();
    error ReferralPromotionDisabled();
    error SubscriptionAlreadyHasReferral();
    error IdenticalSubscription();
    error AtLeastOneRequestIsRequired();
    error MustBeSubOwner(address owner);
    error NoAvailableGroups();
    error NoCorrespondingRequest();
    error IncorrectCommitment();
    error InvalidRequestByEOA();
    error TaskStillExclusive();
    error TaskStillWithinRequestConfirmations();
    error NotFromCommitter();
    error GroupNotExist(uint256 groupIndex);
    error SenderNotController();
    error PendingRequestExists();
    error InvalidZeroAddress();
    error GasLimitTooBig(uint32 have, uint32 want);
    error RequestNotExpired();

    // *Modifiers*
    modifier onlySubOwner(uint64 subId) {
        address owner = _subscriptions[subId].owner;
        if (owner == address(0)) {
            revert InvalidSubscription();
        }
        if (msg.sender != owner) {
            revert MustBeSubOwner(owner);
        }
        _;
    }

    modifier nonReentrant() {
        if (_config.reentrancyLock) {
            revert Reentrant();
        }
        _;
    }

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address controller) public initializer {
        _controller = IController(controller);

        __Ownable_init();
    }

    // solhint-disable-next-line no-empty-blocks
    function _authorizeUpgrade(address) internal override onlyOwner {}

    // =============
    // IAdapterOwner
    // =============
    function setAdapterConfig(
        uint16 minimumRequestConfirmations,
        uint32 maxGasLimit,
        uint32 gasAfterPaymentCalculation,
        uint32 gasExceptCallback,
        uint256 signatureTaskExclusiveWindow,
        uint256 rewardPerSignature,
        uint256 committerRewardPerSignature
    ) external override(IAdapterOwner) onlyOwner {
        if (minimumRequestConfirmations > MAX_REQUEST_CONFIRMATIONS) {
            revert InvalidRequestConfirmations(
                minimumRequestConfirmations, minimumRequestConfirmations, MAX_REQUEST_CONFIRMATIONS
            );
        }
        _config = AdapterConfig({
            minimumRequestConfirmations: minimumRequestConfirmations,
            maxGasLimit: maxGasLimit,
            gasAfterPaymentCalculation: gasAfterPaymentCalculation,
            gasExceptCallback: gasExceptCallback,
            signatureTaskExclusiveWindow: signatureTaskExclusiveWindow,
            rewardPerSignature: rewardPerSignature,
            committerRewardPerSignature: committerRewardPerSignature,
            reentrancyLock: false
        });

        emit AdapterConfigSet(
            minimumRequestConfirmations,
            maxGasLimit,
            gasAfterPaymentCalculation,
            gasExceptCallback,
            signatureTaskExclusiveWindow,
            rewardPerSignature,
            committerRewardPerSignature
        );
    }

    function setFlatFeeConfig(
        FeeConfig memory flatFeeConfig,
        uint16 flatFeePromotionGlobalPercentage,
        bool isFlatFeePromotionEnabledPermanently,
        uint256 flatFeePromotionStartTimestamp,
        uint256 flatFeePromotionEndTimestamp
    ) external override(IAdapterOwner) onlyOwner {
        _flatFeeConfig = FlatFeeConfig({
            config: flatFeeConfig,
            flatFeePromotionGlobalPercentage: flatFeePromotionGlobalPercentage,
            isFlatFeePromotionEnabledPermanently: isFlatFeePromotionEnabledPermanently,
            flatFeePromotionStartTimestamp: flatFeePromotionStartTimestamp,
            flatFeePromotionEndTimestamp: flatFeePromotionEndTimestamp
        });

        emit FlatFeeConfigSet(
            flatFeeConfig,
            flatFeePromotionGlobalPercentage,
            isFlatFeePromotionEnabledPermanently,
            flatFeePromotionStartTimestamp,
            flatFeePromotionEndTimestamp
        );
    }

    function setReferralConfig(
        bool isReferralEnabled,
        uint16 freeRequestCountForReferrer,
        uint16 freeRequestCountForReferee
    ) external override(IAdapterOwner) onlyOwner {
        _referralConfig = ReferralConfig({
            isReferralEnabled: isReferralEnabled,
            freeRequestCountForReferrer: freeRequestCountForReferrer,
            freeRequestCountForReferee: freeRequestCountForReferee
        });

        emit ReferralConfigSet(isReferralEnabled, freeRequestCountForReferrer, freeRequestCountForReferee);
    }

    function setFreeRequestCount(uint64[] memory subIds, uint64[] memory freeRequestCounts)
        external
        override(IAdapterOwner)
        onlyOwner
    {
        for (uint256 i = 0; i < subIds.length; i++) {
            _subscriptions[subIds[i]].freeRequestCount = freeRequestCounts[i];
        }
    }

    function ownerCancelSubscription(uint64 subId) external override(IAdapterOwner) onlyOwner {
        if (_subscriptions[subId].owner == address(0)) {
            revert InvalidSubscription();
        }
        _cancelSubscriptionHelper(subId, _subscriptions[subId].owner);
    }

    // =============
    // IAdapter
    // =============
    function nodeWithdrawETH(address recipient, uint256 ethAmount) external override(IAdapter) {
        if (msg.sender != address(_controller)) {
            revert SenderNotController();
        }
        payable(recipient).transfer(ethAmount);
    }

    function createSubscription() external override(IAdapter) nonReentrant returns (uint64) {
        _currentSubId++;

        _subscriptions[_currentSubId].owner = msg.sender;
        // flat fee free for the first request for each subscription
        _subscriptions[_currentSubId].freeRequestCount = 1;

        emit SubscriptionCreated(_currentSubId, msg.sender);
        return _currentSubId;
    }

    function addConsumer(uint64 subId, address consumer) external override(IAdapter) onlySubOwner(subId) nonReentrant {
        // Already maxed, cannot add any more consumers.
        if (_subscriptions[subId].consumers.length == MAX_CONSUMERS) {
            revert TooManyConsumers();
        }
        if (_consumers[consumer].nonces[subId] != 0) {
            // Idempotence - do nothing if already added.
            // Ensures uniqueness in subscriptions[subId].consumers.
            return;
        }
        // Initialize the nonce to 1, indicating the consumer is allocated.
        _consumers[consumer].nonces[subId] = 1;
        _consumers[consumer].lastSubscription = subId;
        _subscriptions[subId].consumers.push(consumer);

        emit SubscriptionConsumerAdded(subId, consumer);
    }

    function removeConsumer(uint64 subId, address consumer)
        external
        override(IAdapter)
        onlySubOwner(subId)
        nonReentrant
    {
        if (_subscriptions[subId].inflightCost != 0) {
            revert PendingRequestExists();
        }
        address[] memory consumers = _subscriptions[subId].consumers;
        if (consumers.length == 0) {
            revert InvalidConsumer(subId, consumer);
        }
        // Note bounded by MAX_CONSUMERS
        for (uint256 i = 0; i < consumers.length; i++) {
            if (consumers[i] == consumer) {
                _subscriptions[subId].consumers[i] = consumers[consumers.length - 1];
                _subscriptions[subId].consumers.pop();

                emit SubscriptionConsumerRemoved(subId, consumer);
                return;
            }
        }
        revert InvalidConsumer(subId, consumer);
    }

    function fundSubscription(uint64 subId) external payable override(IAdapter) nonReentrant {
        if (_subscriptions[subId].owner == address(0)) {
            revert InvalidSubscription();
        }

        // We do not check that the msg.sender is the subscription owner,
        // anyone can fund a subscription.
        uint256 oldBalance = _subscriptions[subId].balance;
        _subscriptions[subId].balance += msg.value;
        emit SubscriptionFunded(subId, oldBalance, oldBalance + msg.value);
    }

    function setReferral(uint64 subId, uint64 referralSubId)
        external
        override(IAdapter)
        onlySubOwner(subId)
        nonReentrant
    {
        if (!_referralConfig.isReferralEnabled) {
            revert ReferralPromotionDisabled();
        }
        if (_subscriptions[subId].owner == _subscriptions[referralSubId].owner) {
            revert IdenticalSubscription();
        }
        if (_subscriptions[subId].referralSubId != 0) {
            revert SubscriptionAlreadyHasReferral();
        }
        if (_subscriptions[subId].reqCount == 0 || _subscriptions[referralSubId].reqCount == 0) {
            revert AtLeastOneRequestIsRequired();
        }
        _subscriptions[referralSubId].freeRequestCount += _referralConfig.freeRequestCountForReferrer;
        _subscriptions[subId].freeRequestCount += _referralConfig.freeRequestCountForReferee;
        _subscriptions[subId].referralSubId = referralSubId;

        emit SubscriptionReferralSet(subId, referralSubId);
    }

    function cancelSubscription(uint64 subId, address to)
        external
        override(IAdapter)
        onlySubOwner(subId)
        nonReentrant
    {
        if (to == address(0)) {
            revert InvalidZeroAddress();
        }
        if (_subscriptions[subId].inflightCost != 0) {
            revert PendingRequestExists();
        }
        _cancelSubscriptionHelper(subId, to);
    }

    function cancelOvertimeRequest(bytes32 requestId, RequestDetail calldata requestDetail)
        external
        override(IAdapter)
        onlySubOwner(requestDetail.subId)
    {
        if (_requestCommitments[requestId] == 0) {
            revert NoCorrespondingRequest();
        }
        if (
            _requestCommitments[requestId]
                != keccak256(
                    abi.encode(
                        requestId,
                        requestDetail.subId,
                        requestDetail.groupIndex,
                        requestDetail.requestType,
                        requestDetail.params,
                        requestDetail.callbackContract,
                        requestDetail.seed,
                        requestDetail.requestConfirmations,
                        requestDetail.callbackGasLimit,
                        requestDetail.callbackMaxGasPrice,
                        requestDetail.blockNum
                    )
                )
        ) {
            revert IncorrectCommitment();
        }
        uint256 blockNum24H = 1 days / ChainHelper.getBlockTime();
        if (block.number < requestDetail.blockNum + blockNum24H) {
            revert RequestNotExpired();
        }
        delete _requestCommitments[requestId];
        _subscriptions[requestDetail.subId].inflightCost -=
            _subscriptions[requestDetail.subId].inflightPayments[requestId];
        delete _subscriptions[requestDetail.subId].inflightPayments[requestId];
        emit OvertimeRequestCanceled(requestId, requestDetail.subId);
    }

    function requestRandomness(RandomnessRequestParams calldata params)
        public
        virtual
        override(IAdapter)
        nonReentrant
        returns (bytes32)
    {
        RandomnessRequestParams memory p = params;

        // solhint-disable-next-line avoid-tx-origin
        if (msg.sender == tx.origin) {
            revert InvalidRequestByEOA();
        }

        Subscription storage sub = _subscriptions[p.subId];

        // Input validation using the subscription storage.
        if (sub.owner == address(0)) {
            revert InvalidSubscription();
        }
        // Its important to ensure that the consumer is in fact who they say they
        // are, otherwise they could use someone else's subscription balance.
        // A nonce of 0 indicates consumer is not allocated to the sub.
        if (_consumers[msg.sender].nonces[p.subId] == 0) {
            revert InvalidConsumer(p.subId, msg.sender);
        }

        if (
            p.requestConfirmations < _config.minimumRequestConfirmations
                || p.requestConfirmations > MAX_REQUEST_CONFIRMATIONS
        ) {
            revert InvalidRequestConfirmations(
                p.requestConfirmations, _config.minimumRequestConfirmations, MAX_REQUEST_CONFIRMATIONS
            );
        }
        // No lower bound on the requested gas limit. A user could request 0
        // and they would simply be billed for the proof verification and wouldn't be
        // able to do anything with the random value.
        if (p.callbackGasLimit > _config.maxGasLimit) {
            revert GasLimitTooBig(p.callbackGasLimit, _config.maxGasLimit);
        }

        // Choose current available group to handle randomness request(by round robin)
        _lastAssignedGroupIndex = uint32(_findGroupToAssignTask());

        // Calculate requestId for the task
        uint256 rawSeed = _makeRandcastInputSeed(p.seed, p.subId, msg.sender, _consumers[msg.sender].nonces[p.subId]);
        _consumers[msg.sender].lastSubscription = p.subId;
        _consumers[msg.sender].nonces[p.subId] += 1;
        bytes32 requestId = _makeRequestId(rawSeed);

        (, uint256 groupSize) = _controller.getGroupThreshold(_lastAssignedGroupIndex);

        uint256 payment =
            _freezePaymentBySubscription(sub, requestId, uint32(groupSize), p.callbackGasLimit, p.callbackMaxGasPrice);

        _requestCommitments[requestId] = keccak256(
            abi.encode(
                requestId,
                p.subId,
                _lastAssignedGroupIndex,
                p.requestType,
                p.params,
                msg.sender,
                rawSeed,
                p.requestConfirmations,
                p.callbackGasLimit,
                p.callbackMaxGasPrice,
                block.number
            )
        );

        emit RandomnessRequest(
            requestId,
            p.subId,
            _lastAssignedGroupIndex,
            p.requestType,
            p.params,
            msg.sender,
            rawSeed,
            p.requestConfirmations,
            p.callbackGasLimit,
            p.callbackMaxGasPrice,
            payment
        );

        return requestId;
    }

    function fulfillRandomness(
        uint32 groupIndex,
        bytes32 requestId,
        uint256 signature,
        RequestDetail calldata requestDetail,
        PartialSignature[] calldata partialSignatures
    ) public virtual override(IAdapter) nonReentrant {
        uint256 startGas = gasleft();

        bytes32 commitment = _requestCommitments[requestId];
        if (commitment == 0) {
            revert NoCorrespondingRequest();
        }
        if (
            commitment
                != keccak256(
                    abi.encode(
                        requestId,
                        requestDetail.subId,
                        requestDetail.groupIndex,
                        requestDetail.requestType,
                        requestDetail.params,
                        requestDetail.callbackContract,
                        requestDetail.seed,
                        requestDetail.requestConfirmations,
                        requestDetail.callbackGasLimit,
                        requestDetail.callbackMaxGasPrice,
                        requestDetail.blockNum
                    )
                )
        ) {
            revert IncorrectCommitment();
        }

        if (block.number < requestDetail.blockNum + requestDetail.requestConfirmations) {
            revert TaskStillWithinRequestConfirmations();
        }

        if (
            groupIndex != requestDetail.groupIndex
                && block.number <= requestDetail.blockNum + _config.signatureTaskExclusiveWindow
        ) {
            revert TaskStillExclusive();
        }
        if (groupIndex >= _controller.getGroupCount()) {
            revert GroupNotExist(groupIndex);
        }

        address[] memory participantMembers =
            _verifySignature(groupIndex, requestDetail.seed, requestDetail.blockNum, signature, partialSignatures);

        delete _requestCommitments[requestId];

        uint256 randomness = uint256(keccak256(abi.encode(signature)));

        _randomnessCount += 1;
        _lastRandomness = randomness;
        _controller.setLastOutput(randomness);
        // call user fulfill_randomness callback
        bool success = _fulfillCallback(requestId, randomness, requestDetail);

        (uint256 payment, uint256 flatFee) =
            _payBySubscription(_subscriptions[requestDetail.subId], requestId, partialSignatures.length, startGas);

        // rewardRandomness for participants
        _rewardRandomness(participantMembers, payment, flatFee);

        // Include payment in the event for tracking costs.
        emit RandomnessRequestResult(
            requestId, groupIndex, msg.sender, participantMembers, randomness, payment, flatFee, success
        );
    }

    function getLastSubscription(address consumer) public view override(IAdapter) returns (uint64) {
        return _consumers[consumer].lastSubscription;
    }

    function getSubscription(uint64 subId)
        external
        view
        override(IAdapter)
        returns (
            address owner,
            address[] memory consumers,
            uint256 balance,
            uint256 inflightCost,
            uint64 reqCount,
            uint64 freeRequestCount,
            uint64 referralSubId,
            uint64 reqCountInCurrentPeriod,
            uint256 lastRequestTimestamp
        )
    {
        Subscription storage sub = _subscriptions[subId];
        if (sub.owner == address(0)) {
            revert InvalidSubscription();
        }
        return (
            sub.owner,
            sub.consumers,
            sub.balance,
            sub.inflightCost,
            sub.reqCount,
            sub.freeRequestCount,
            sub.referralSubId,
            sub.reqCountInCurrentPeriod,
            sub.lastRequestTimestamp
        );
    }

    function getPendingRequestCommitment(bytes32 requestId) public view override(IAdapter) returns (bytes32) {
        return _requestCommitments[requestId];
    }

    function getLastAssignedGroupIndex() external view override(IAdapter) returns (uint256) {
        return _lastAssignedGroupIndex;
    }

    function getLastRandomness() external view override(IAdapter) returns (uint256) {
        return _lastRandomness;
    }

    function getRandomnessCount() external view override(IAdapter) returns (uint256) {
        return _randomnessCount;
    }

    function getCurrentSubId() external view override(IAdapter) returns (uint64) {
        return _currentSubId;
    }

    function getCumulativeData() external view override(IAdapter) returns (uint256, uint256, uint256) {
        return (_cumulativeFlatFee, _cumulativeCommitterReward, _cumulativePartialSignatureReward);
    }

    function getController() external view override(IAdapter) returns (address) {
        return address(_controller);
    }

    function getAdapterConfig()
        external
        view
        override(IAdapter)
        returns (
            uint16 minimumRequestConfirmations,
            uint32 maxGasLimit,
            uint32 gasAfterPaymentCalculation,
            uint32 gasExceptCallback,
            uint256 signatureTaskExclusiveWindow,
            uint256 rewardPerSignature,
            uint256 committerRewardPerSignature
        )
    {
        return (
            _config.minimumRequestConfirmations,
            _config.maxGasLimit,
            _config.gasAfterPaymentCalculation,
            _config.gasExceptCallback,
            _config.signatureTaskExclusiveWindow,
            _config.rewardPerSignature,
            _config.committerRewardPerSignature
        );
    }

    function getFlatFeeConfig()
        external
        view
        override(IAdapter)
        returns (
            uint32 fulfillmentFlatFeeLinkPPMTier1,
            uint32 fulfillmentFlatFeeLinkPPMTier2,
            uint32 fulfillmentFlatFeeLinkPPMTier3,
            uint32 fulfillmentFlatFeeLinkPPMTier4,
            uint32 fulfillmentFlatFeeLinkPPMTier5,
            uint24 reqsForTier2,
            uint24 reqsForTier3,
            uint24 reqsForTier4,
            uint24 reqsForTier5,
            uint16 flatFeePromotionGlobalPercentage,
            bool isFlatFeePromotionEnabledPermanently,
            uint256 flatFeePromotionStartTimestamp,
            uint256 flatFeePromotionEndTimestamp
        )
    {
        FeeConfig memory fc = _flatFeeConfig.config;
        return (
            fc.fulfillmentFlatFeeEthPPMTier1,
            fc.fulfillmentFlatFeeEthPPMTier2,
            fc.fulfillmentFlatFeeEthPPMTier3,
            fc.fulfillmentFlatFeeEthPPMTier4,
            fc.fulfillmentFlatFeeEthPPMTier5,
            fc.reqsForTier2,
            fc.reqsForTier3,
            fc.reqsForTier4,
            fc.reqsForTier5,
            _flatFeeConfig.flatFeePromotionGlobalPercentage,
            _flatFeeConfig.isFlatFeePromotionEnabledPermanently,
            _flatFeeConfig.flatFeePromotionStartTimestamp,
            _flatFeeConfig.flatFeePromotionEndTimestamp
        );
    }

    function getReferralConfig()
        external
        view
        override(IAdapter)
        returns (bool isReferralEnabled, uint16 freeRequestCountForReferrer, uint16 freeRequestCountForReferee)
    {
        return (
            _referralConfig.isReferralEnabled,
            _referralConfig.freeRequestCountForReferrer,
            _referralConfig.freeRequestCountForReferee
        );
    }

    function getFeeTier(uint64 reqCount) public view override(IAdapter) returns (uint32) {
        FeeConfig memory fc = _flatFeeConfig.config;
        if (reqCount <= fc.reqsForTier2) {
            return fc.fulfillmentFlatFeeEthPPMTier1;
        }
        if (fc.reqsForTier2 < reqCount && reqCount <= fc.reqsForTier3) {
            return fc.fulfillmentFlatFeeEthPPMTier2;
        }
        if (fc.reqsForTier3 < reqCount && reqCount <= fc.reqsForTier4) {
            return fc.fulfillmentFlatFeeEthPPMTier3;
        }
        if (fc.reqsForTier4 < reqCount && reqCount <= fc.reqsForTier5) {
            return fc.fulfillmentFlatFeeEthPPMTier4;
        }
        return fc.fulfillmentFlatFeeEthPPMTier5;
    }

    function estimatePaymentAmountInETH(
        uint32 callbackGasLimit,
        uint32 gasExceptCallback,
        uint32 fulfillmentFlatFeeEthPPM,
        uint256 weiPerUnitGas,
        uint32 groupSize
    ) public view override(IAdapter) returns (uint256) {
        // we estimate 1.5x the cost of the fulfillment calldata
        uint256 estimatedFulfillmentL1CostWei =
            ChainHelper.getTxL1GasFees(ChainHelper.getFulfillmentTxL1GasUsed(groupSize)) * 3 / 2;
        uint256 paymentNoFee = weiPerUnitGas * (gasExceptCallback + callbackGasLimit) + estimatedFulfillmentL1CostWei;
        return (paymentNoFee + 1e12 * uint256(fulfillmentFlatFeeEthPPM));
    }

    // =============
    // Internal
    // =============

    function _rewardRandomness(address[] memory participantMembers, uint256 payment, uint256 flatFee) internal {
        _cumulativeCommitterReward += _config.committerRewardPerSignature;
        _cumulativePartialSignatureReward += _config.rewardPerSignature * participantMembers.length;

        address[] memory committer = new address[](1);
        committer[0] = msg.sender;
        _controller.addReward(committer, payment - flatFee, _config.committerRewardPerSignature);
        _controller.addReward(participantMembers, flatFee / participantMembers.length, _config.rewardPerSignature);
    }

    function _fulfillCallback(bytes32 requestId, uint256 randomness, RequestDetail memory requestDetail)
        internal
        returns (bool success)
    {
        IBasicRandcastConsumerBase b;
        bytes memory resp;
        if (requestDetail.requestType == RequestType.Randomness) {
            resp = abi.encodeWithSelector(b.rawFulfillRandomness.selector, requestId, randomness);
        } else if (requestDetail.requestType == RequestType.RandomWords) {
            uint32 numWords = abi.decode(requestDetail.params, (uint32));
            uint256[] memory randomWords = new uint256[](numWords);
            for (uint256 i = 0; i < numWords; i++) {
                randomWords[i] = uint256(keccak256(abi.encode(randomness, i)));
            }
            resp = abi.encodeWithSelector(b.rawFulfillRandomWords.selector, requestId, randomWords);
        } else if (requestDetail.requestType == RequestType.Shuffling) {
            uint32 upper = abi.decode(requestDetail.params, (uint32));
            uint256[] memory shuffledArray = Utils.shuffle(upper, randomness);
            resp = abi.encodeWithSelector(b.rawFulfillShuffledArray.selector, requestId, shuffledArray);
        }

        // Call with explicitly the amount of callback gas requested
        // Important to not let them exhaust the gas budget and avoid oracle payment.
        // Do not allow any non-view/non-pure coordinator functions to be called
        // during the consumers callback code via reentrancyLock.
        // Note that callWithExactGas will revert if we do not have sufficient gas
        // to give the callee their requested amount.
        _config.reentrancyLock = true;
        success = Utils.callWithExactGas(requestDetail.callbackGasLimit, requestDetail.callbackContract, resp);
        _config.reentrancyLock = false;
    }

    function _freezePaymentBySubscription(
        Subscription storage sub,
        bytes32 requestId,
        uint32 groupSize,
        uint32 callbackGasLimit,
        uint256 callbackMaxGasPrice
    ) internal returns (uint256) {
        uint64 reqCount;
        if (_flatFeeConfig.isFlatFeePromotionEnabledPermanently) {
            reqCount = sub.reqCount;
        } else if (
            _flatFeeConfig
                //solhint-disable-next-line not-rely-on-time
                .flatFeePromotionStartTimestamp <= block.timestamp
            //solhint-disable-next-line not-rely-on-time
            && block.timestamp <= _flatFeeConfig.flatFeePromotionEndTimestamp
        ) {
            if (sub.lastRequestTimestamp < _flatFeeConfig.flatFeePromotionStartTimestamp) {
                reqCount = 1;
            } else {
                reqCount = sub.reqCountInCurrentPeriod + 1;
            }
        }

        // Estimate upper cost of this fulfillment.
        uint256 payment = estimatePaymentAmountInETH(
            callbackGasLimit,
            _config.gasExceptCallback + RANDOMNESS_REWARD_GAS * groupSize
                + VERIFICATION_GAS_OVER_MINIMUM_THRESHOLD * (groupSize - DEFAULT_MINIMUM_THRESHOLD),
            sub.freeRequestCount > 0
                ? 0
                : (getFeeTier(reqCount) * _flatFeeConfig.flatFeePromotionGlobalPercentage / 100),
            callbackMaxGasPrice,
            groupSize
        );

        if (sub.balance - sub.inflightCost < payment) {
            revert InsufficientBalanceWhenRequest();
        }

        sub.inflightCost += payment;
        sub.inflightPayments[requestId] = payment;

        return payment;
    }

    function _payBySubscription(
        Subscription storage sub,
        bytes32 requestId,
        uint256 partialSignersCount,
        uint256 startGas
    ) internal returns (uint256, uint256) {
        // Increment the req count for fee tier selection.
        sub.reqCount += 1;
        uint64 reqCount;
        if (_flatFeeConfig.isFlatFeePromotionEnabledPermanently) {
            reqCount = sub.reqCount;
        } else if (
            _flatFeeConfig
                //solhint-disable-next-line not-rely-on-time
                .flatFeePromotionStartTimestamp <= block.timestamp
            //solhint-disable-next-line not-rely-on-time
            && block.timestamp <= _flatFeeConfig.flatFeePromotionEndTimestamp
        ) {
            if (sub.lastRequestTimestamp < _flatFeeConfig.flatFeePromotionStartTimestamp) {
                sub.reqCountInCurrentPeriod = 1;
            } else {
                sub.reqCountInCurrentPeriod += 1;
            }
            reqCount = sub.reqCountInCurrentPeriod;
        }

        //solhint-disable-next-line not-rely-on-time
        sub.lastRequestTimestamp = block.timestamp;

        uint256 flatFee;
        if (sub.freeRequestCount > 0) {
            sub.freeRequestCount -= 1;
        } else {
            // The flat eth fee is specified in millionths of eth, if _config.fulfillmentFlatFeeEthPPM = 1
            // 1 eth / 1e6 = 1e18 eth wei / 1e6 = 1e12 eth wei.
            flatFee = 1e12 * uint256(getFeeTier(reqCount)) * _flatFeeConfig.flatFeePromotionGlobalPercentage / 100;
        }

        // We want to charge users exactly for how much gas they use in their callback.
        // The gasAfterPaymentCalculation is meant to cover these additional operations where we
        // decrement the subscription balance and increment the groups withdrawable balance.
        uint256 payment = _calculatePaymentAmountInETH(
            startGas,
            _config.gasAfterPaymentCalculation + RANDOMNESS_REWARD_GAS * partialSignersCount,
            flatFee,
            tx.gasprice
        );

        if (sub.balance < payment) {
            revert InsufficientBalanceWhenFulfill();
        }
        sub.inflightCost -= sub.inflightPayments[requestId];
        delete sub.inflightPayments[requestId];
        sub.balance -= payment;

        _cumulativeFlatFee += flatFee;

        return (payment, flatFee);
    }

    function _cancelSubscriptionHelper(uint64 subId, address to) internal nonReentrant {
        uint256 balance = _subscriptions[subId].balance;
        delete _subscriptions[subId].owner;
        emit SubscriptionCanceled(subId, to, balance);
        payable(to).transfer(balance);
    }

    // Get the amount of gas used for fulfillment
    function _calculatePaymentAmountInETH(
        uint256 startGas,
        uint256 gasAfterPaymentCalculation,
        uint256 flatFee,
        uint256 weiPerUnitGas
    ) internal view returns (uint256) {
        uint256 paymentNoFee =
            weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + ChainHelper.getCurrentTxL1GasFees();
        return paymentNoFee + flatFee;
    }

    function _findGroupToAssignTask() internal view returns (uint256) {
        uint256[] memory validGroupIndices = _controller.getValidGroupIndices();

        if (validGroupIndices.length == 0) {
            revert NoAvailableGroups();
        }

        uint256 groupCount = _controller.getGroupCount();

        uint256 currentAssignedGroupIndex = (_lastAssignedGroupIndex + 1) % groupCount;

        while (!Utils.containElement(validGroupIndices, currentAssignedGroupIndex)) {
            currentAssignedGroupIndex = (currentAssignedGroupIndex + 1) % groupCount;
        }

        return currentAssignedGroupIndex;
    }

    function _verifySignature(
        uint256 groupIndex,
        uint256 seed,
        uint256 blockNum,
        uint256 signature,
        PartialSignature[] memory partialSignatures
    ) internal view returns (address[] memory participantMembers) {
        if (!BLS.isValid(signature)) {
            revert BLS.InvalidSignatureFormat();
        }

        if (partialSignatures.length == 0) {
            revert BLS.EmptyPartialSignatures();
        }

        IController.Group memory g = _controller.getGroup(groupIndex);

        if (!Utils.containElement(g.committers, msg.sender)) {
            revert NotFromCommitter();
        }

        bytes memory actualSeed = abi.encodePacked(seed, blockNum);

        uint256[2] memory message = BLS.hashToPoint(actualSeed);

        // verify tss-aggregation signature for randomness
        if (!BLS.verifySingle(BLS.decompress(signature), g.publicKey, message)) {
            revert BLS.InvalidSignature();
        }

        // verify bls-aggregation signature for incentivizing worker list
        uint256[2][] memory partials = new uint256[2][](partialSignatures.length);
        uint256[4][] memory pubkeys = new uint256[4][](partialSignatures.length);
        participantMembers = new address[](partialSignatures.length);
        for (uint256 i = 0; i < partialSignatures.length; i++) {
            if (!BLS.isValid(partialSignatures[i].partialSignature)) {
                revert BLS.InvalidPartialSignatureFormat();
            }
            partials[i] = BLS.decompress(partialSignatures[i].partialSignature);
            pubkeys[i] = g.members[partialSignatures[i].index].partialPublicKey;
            participantMembers[i] = g.members[partialSignatures[i].index].nodeIdAddress;
        }
        if (!BLS.verifyPartials(partials, pubkeys, message)) {
            revert BLS.InvalidPartialSignatures();
        }
    }
}

File 2 of 26 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 3 of 26 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

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

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

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

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

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

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

File 4 of 26 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 5 of 26 : UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 6 of 26 : IAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

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

interface IAdapter is IRequestTypeBase {
    struct PartialSignature {
        uint256 index;
        uint256 partialSignature;
    }

    struct RandomnessRequestParams {
        RequestType requestType;
        bytes params;
        uint64 subId;
        uint256 seed;
        uint16 requestConfirmations;
        uint32 callbackGasLimit;
        uint256 callbackMaxGasPrice;
    }

    struct RequestDetail {
        uint64 subId;
        uint32 groupIndex;
        RequestType requestType;
        bytes params;
        address callbackContract;
        uint256 seed;
        uint16 requestConfirmations;
        uint32 callbackGasLimit;
        uint256 callbackMaxGasPrice;
        uint256 blockNum;
    }

    // controller transaction
    function nodeWithdrawETH(address recipient, uint256 ethAmount) external;

    // consumer contract transaction
    function requestRandomness(RandomnessRequestParams calldata params) external returns (bytes32);

    function fulfillRandomness(
        uint32 groupIndex,
        bytes32 requestId,
        uint256 signature,
        RequestDetail calldata requestDetail,
        PartialSignature[] calldata partialSignatures
    ) external;

    // user transaction
    function createSubscription() external returns (uint64);

    function addConsumer(uint64 subId, address consumer) external;

    function fundSubscription(uint64 subId) external payable;

    function setReferral(uint64 subId, uint64 referralSubId) external;

    function cancelSubscription(uint64 subId, address to) external;

    function removeConsumer(uint64 subId, address consumer) external;

    // delete the request that cannot be fulfilled, triggered by user themselves
    function cancelOvertimeRequest(bytes32 requestId, RequestDetail calldata requestDetail) external;

    // view
    function getLastSubscription(address consumer) external view returns (uint64);

    function getSubscription(uint64 subId)
        external
        view
        returns (
            address owner,
            address[] memory consumers,
            uint256 balance,
            uint256 inflightCost,
            uint64 reqCount,
            uint64 freeRequestCount,
            uint64 referralSubId,
            uint64 reqCountInCurrentPeriod,
            uint256 lastRequestTimestamp
        );

    function getPendingRequestCommitment(bytes32 requestId) external view returns (bytes32);

    function getLastAssignedGroupIndex() external view returns (uint256);

    function getLastRandomness() external view returns (uint256);

    function getRandomnessCount() external view returns (uint256);

    function getCurrentSubId() external view returns (uint64);

    function getCumulativeData() external view returns (uint256, uint256, uint256);

    function getController() external view returns (address);

    function getAdapterConfig()
        external
        view
        returns (
            uint16 minimumRequestConfirmations,
            uint32 maxGasLimit,
            uint32 gasAfterPaymentCalculation,
            uint32 gasExceptCallback,
            uint256 signatureTaskExclusiveWindow,
            uint256 rewardPerSignature,
            uint256 committerRewardPerSignature
        );

    function getFlatFeeConfig()
        external
        view
        returns (
            uint32 fulfillmentFlatFeeLinkPPMTier1,
            uint32 fulfillmentFlatFeeLinkPPMTier2,
            uint32 fulfillmentFlatFeeLinkPPMTier3,
            uint32 fulfillmentFlatFeeLinkPPMTier4,
            uint32 fulfillmentFlatFeeLinkPPMTier5,
            uint24 reqsForTier2,
            uint24 reqsForTier3,
            uint24 reqsForTier4,
            uint24 reqsForTier5,
            uint16 flatFeePromotionGlobalPercentage,
            bool isFlatFeePromotionEnabledPermanently,
            uint256 flatFeePromotionStartTimestamp,
            uint256 flatFeePromotionEndTimestamp
        );

    function getReferralConfig()
        external
        view
        returns (bool isReferralEnabled, uint16 freeRequestCountForReferrer, uint16 freeRequestCountForReferee);

    /*
     * @notice Compute fee based on the request count
     * @param reqCount number of requests
     * @return feePPM fee in ARPA PPM
     */
    function getFeeTier(uint64 reqCount) external view returns (uint32);

    // Estimate the amount of gas used for fulfillment
    function estimatePaymentAmountInETH(
        uint32 callbackGasLimit,
        uint32 gasExceptCallback,
        uint32 fulfillmentFlatFeeEthPPM,
        uint256 weiPerUnitGas,
        uint32 groupSize
    ) external view returns (uint256);
}

File 7 of 26 : IAdapterOwner.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IAdapterOwner {
    struct AdapterConfig {
        // Minimum number of blocks a request must wait before being fulfilled.
        uint16 minimumRequestConfirmations;
        // Maximum gas limit for fulfillRandomness requests.
        uint32 maxGasLimit;
        // Reentrancy protection.
        bool reentrancyLock;
        // Gas to cover group payment after we calculate the payment.
        // We make it configurable in case those operations are repriced.
        uint32 gasAfterPaymentCalculation;
        // Gas except callback during fulfillment of randomness. Only used for estimating inflight cost.
        uint32 gasExceptCallback;
        // The assigned group is exclusive for fulfilling the task within this block window
        uint256 signatureTaskExclusiveWindow;
        // reward per signature for every participating node
        uint256 rewardPerSignature;
        // reward per signature for the committer
        uint256 committerRewardPerSignature;
    }

    struct FeeConfig {
        // Flat fee charged per fulfillment in millionths of arpa
        uint32 fulfillmentFlatFeeEthPPMTier1;
        uint32 fulfillmentFlatFeeEthPPMTier2;
        uint32 fulfillmentFlatFeeEthPPMTier3;
        uint32 fulfillmentFlatFeeEthPPMTier4;
        uint32 fulfillmentFlatFeeEthPPMTier5;
        uint24 reqsForTier2;
        uint24 reqsForTier3;
        uint24 reqsForTier4;
        uint24 reqsForTier5;
    }

    struct FlatFeeConfig {
        FeeConfig config;
        uint16 flatFeePromotionGlobalPercentage;
        bool isFlatFeePromotionEnabledPermanently;
        uint256 flatFeePromotionStartTimestamp;
        uint256 flatFeePromotionEndTimestamp;
    }

    struct ReferralConfig {
        bool isReferralEnabled;
        uint16 freeRequestCountForReferrer;
        uint16 freeRequestCountForReferee;
    }

    /**
     * @notice Sets the configuration of the adapter
     * @param minimumRequestConfirmations global min for request confirmations
     * @param maxGasLimit global max for request gas limit
     * @param gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement
     * @param signatureTaskExclusiveWindow window in which a signature task is exclusive to the assigned group
     * @param rewardPerSignature reward per signature for every participating node
     * @param committerRewardPerSignature reward per signature for the committer
     */
    function setAdapterConfig(
        uint16 minimumRequestConfirmations,
        uint32 maxGasLimit,
        uint32 gasAfterPaymentCalculation,
        uint32 gasExceptCallback,
        uint256 signatureTaskExclusiveWindow,
        uint256 rewardPerSignature,
        uint256 committerRewardPerSignature
    ) external;

    /**
     * @notice Sets the flat fee configuration of the adapter
     * @param flatFeeConfig flat fee tier configuration
     * @param flatFeePromotionGlobalPercentage global percentage of flat fee promotion
     * @param isFlatFeePromotionEnabledPermanently whether flat fee promotion is enabled permanently
     * @param flatFeePromotionStartTimestamp flat fee promotion start timestamp
     * @param flatFeePromotionEndTimestamp flat fee promotion end timestamp
     */
    function setFlatFeeConfig(
        FeeConfig memory flatFeeConfig,
        uint16 flatFeePromotionGlobalPercentage,
        bool isFlatFeePromotionEnabledPermanently,
        uint256 flatFeePromotionStartTimestamp,
        uint256 flatFeePromotionEndTimestamp
    ) external;

    /**
     * @notice Sets the referral configuration of the adapter
     * @param isReferralEnabled whether referral is enabled
     * @param freeRequestCountForReferrer free request count for referrer
     * @param freeRequestCountForReferee free request count for referee
     */
    function setReferralConfig(
        bool isReferralEnabled,
        uint16 freeRequestCountForReferrer,
        uint16 freeRequestCountForReferee
    ) external;

    /**
     * @notice Sets free request count for subscriptions
     * @param subIds subscription ids
     * @param freeRequestCounts free request count for each subscription
     */
    function setFreeRequestCount(uint64[] memory subIds, uint64[] memory freeRequestCounts) external;

    /**
     * @notice Owner cancel subscription, sends remaining eth directly to the subscription owner
     * @param subId subscription id
     * @dev notably can be called even if there are pending requests
     */
    function ownerCancelSubscription(uint64 subId) external;
}

File 8 of 26 : IController.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IController {
    struct Group {
        uint256 index;
        uint256 epoch;
        uint256 size;
        uint256 threshold;
        Member[] members;
        address[] committers;
        CommitCache[] commitCacheList;
        bool isStrictlyMajorityConsensusReached;
        uint256[4] publicKey;
    }

    struct Member {
        address nodeIdAddress;
        uint256[4] partialPublicKey;
    }

    struct CommitResult {
        uint256 groupEpoch;
        uint256[4] publicKey;
        address[] disqualifiedNodes;
    }

    struct CommitCache {
        address[] nodeIdAddress;
        CommitResult commitResult;
    }

    struct Node {
        address idAddress;
        bytes dkgPublicKey;
        bool state;
        uint256 pendingUntilBlock;
    }

    struct CommitDkgParams {
        uint256 groupIndex;
        uint256 groupEpoch;
        bytes publicKey;
        bytes partialPublicKey;
        address[] disqualifiedNodes;
    }

    // node transaction
    function nodeRegister(bytes calldata dkgPublicKey) external;

    function nodeActivate() external;

    function nodeQuit() external;

    function changeDkgPublicKey(bytes calldata dkgPublicKey) external;

    function commitDkg(CommitDkgParams memory params) external;

    function postProcessDkg(uint256 groupIndex, uint256 groupEpoch) external;

    function nodeWithdraw(address recipient) external;

    // adapter transaction
    function addReward(address[] memory nodes, uint256 ethAmount, uint256 arpaAmount) external;

    function setLastOutput(uint256 lastOutput) external;

    // view
    function getControllerConfig()
        external
        view
        returns (
            address stakingContractAddress,
            address adapterContractAddress,
            uint256 nodeStakingAmount,
            uint256 disqualifiedNodePenaltyAmount,
            uint256 defaultNumberOfCommitters,
            uint256 defaultDkgPhaseDuration,
            uint256 groupMaxCapacity,
            uint256 idealNumberOfGroups,
            uint256 pendingBlockAfterQuit,
            uint256 dkgPostProcessReward
        );

    /// @notice Get list of all group indexes where group.isStrictlyMajorityConsensusReached == true
    /// @return uint256[] List of valid group indexes
    function getValidGroupIndices() external view returns (uint256[] memory);

    function getGroupEpoch() external view returns (uint256);

    function getGroupCount() external view returns (uint256);

    function getGroup(uint256 index) external view returns (Group memory);

    function getGroupThreshold(uint256 groupIndex) external view returns (uint256, uint256);

    function getNode(address nodeAddress) external view returns (Node memory);

    function getMember(uint256 groupIndex, uint256 memberIndex) external view returns (Member memory);

    /// @notice Get the group index and member index of a given node.
    function getBelongingGroup(address nodeAddress) external view returns (int256, int256);

    function getCoordinator(uint256 groupIndex) external view returns (address);

    function getNodeWithdrawableTokens(address nodeAddress) external view returns (uint256, uint256);

    function getLastOutput() external view returns (uint256);

    /// @notice Check to see if a group has a partial public key registered for a given node.
    /// @return bool True if the node has a partial public key registered for the group.
    function isPartialKeyRegistered(uint256 groupIndex, address nodeIdAddress) external view returns (bool);
}

File 9 of 26 : IBasicRandcastConsumerBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IBasicRandcastConsumerBase {
    function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external;

    function rawFulfillRandomWords(bytes32 requestId, uint256[] memory randomWords) external;

    function rawFulfillShuffledArray(bytes32 requestId, uint256[] memory shuffledArray) external;
}

File 10 of 26 : RequestIdBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract RequestIdBase {
    function _makeRandcastInputSeed(uint256 userSeed, uint64 subId, address requester, uint256 nonce)
        internal
        view
        returns (uint256)
    {
        return uint256(keccak256(abi.encode(block.chainid, userSeed, subId, requester, nonce)));
    }

    function _makeRequestId(uint256 inputSeed) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(inputSeed));
    }
}

File 11 of 26 : BLS.sol
// SPDX-License-Identifier: LGPL 3.0
pragma solidity ^0.8.18;

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

/**
 * @title BLS operations on bn254 curve
 * @author ARPA-Network adapted from https://github.com/ChihChengLiang/bls_solidity_python
 * @dev Homepage: https://github.com/ARPA-Network/BLS-TSS-Network
 *      Signature and Point hashed to G1 are represented by affine coordinate in big-endian order, deserialized from compressed format.
 *      Public key is represented and serialized by affine coordinate Q-x-re(x0), Q-x-im(x1), Q-y-re(y0), Q-y-im(y1) in big-endian order.
 */
library BLS {
    // Field order
    uint256 public constant N = 21888242871839275222246405745257275088696311157297823662689037894645226208583;

    // Negated genarator of G2
    uint256 public constant N_G2_X1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
    uint256 public constant N_G2_X0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
    uint256 public constant N_G2_Y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052;
    uint256 public constant N_G2_Y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653;

    uint256 public constant FIELD_MASK = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    error MustNotBeInfinity();
    error InvalidPublicKeyEncoding();
    error InvalidSignatureFormat();
    error InvalidSignature();
    error InvalidPartialSignatureFormat();
    error InvalidPartialSignatures();
    error EmptyPartialSignatures();
    error InvalidPublicKey();
    error InvalidPartialPublicKey();

    function verifySingle(uint256[2] memory signature, uint256[4] memory pubkey, uint256[2] memory message)
        public
        view
        returns (bool)
    {
        uint256[12] memory input = [
            signature[0],
            signature[1],
            N_G2_X1,
            N_G2_X0,
            N_G2_Y1,
            N_G2_Y0,
            message[0],
            message[1],
            pubkey[1],
            pubkey[0],
            pubkey[3],
            pubkey[2]
        ];
        uint256[1] memory out;
        bool success;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 8, input, 384, out, 0x20)
            switch success
            case 0 { invalid() }
        }
        require(success, "");
        return out[0] != 0;
    }

    function verifyPartials(uint256[2][] memory partials, uint256[4][] memory pubkeys, uint256[2] memory message)
        public
        view
        returns (bool)
    {
        uint256[2] memory aggregatedSignature;
        uint256[4] memory aggregatedPublicKey;
        for (uint256 i = 0; i < partials.length; i++) {
            aggregatedSignature = addPoints(aggregatedSignature, partials[i]);
            aggregatedPublicKey = BN256G2.ecTwistAdd(aggregatedPublicKey, pubkeys[i]);
        }

        uint256[12] memory input = [
            aggregatedSignature[0],
            aggregatedSignature[1],
            N_G2_X1,
            N_G2_X0,
            N_G2_Y1,
            N_G2_Y0,
            message[0],
            message[1],
            aggregatedPublicKey[1],
            aggregatedPublicKey[0],
            aggregatedPublicKey[3],
            aggregatedPublicKey[2]
        ];
        uint256[1] memory out;
        bool success;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 8, input, 384, out, 0x20)
            switch success
            case 0 { invalid() }
        }
        require(success, "");
        return out[0] != 0;
    }

    // TODO a simple hash and increment implementation, can be improved later
    function hashToPoint(bytes memory data) public view returns (uint256[2] memory p) {
        bool found;
        bytes32 candidateHash = keccak256(data);
        while (true) {
            (p, found) = mapToPoint(candidateHash);
            if (found) {
                break;
            }
            candidateHash = keccak256(bytes.concat(candidateHash));
        }
    }

    //  we take the y-coordinate as the lexicographically largest of the two associated with the encoded x-coordinate
    function mapToPoint(bytes32 _x) internal view returns (uint256[2] memory p, bool found) {
        uint256 y;
        uint256 x = uint256(_x) % N;
        (y, found) = deriveYOnG1(x);
        if (found) {
            p[0] = x;
            p[1] = y > N / 2 ? N - y : y;
        }
    }

    function deriveYOnG1(uint256 x) internal view returns (uint256, bool) {
        uint256 y;
        y = mulmod(x, x, N);
        y = mulmod(y, x, N);
        y = addmod(y, 3, N);
        return sqrt(y);
    }

    function isValidPublicKey(uint256[4] memory publicKey) public pure returns (bool) {
        if ((publicKey[0] >= N) || (publicKey[1] >= N) || (publicKey[2] >= N || (publicKey[3] >= N))) {
            return false;
        } else {
            return isOnCurveG2(publicKey);
        }
    }

    function fromBytesPublicKey(bytes memory point) public pure returns (uint256[4] memory pubkey) {
        if (point.length != 128) {
            revert InvalidPublicKeyEncoding();
        }
        uint256 x0;
        uint256 x1;
        uint256 y0;
        uint256 y1;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            // look the first 32 bytes of a bytes struct is its length
            x0 := mload(add(point, 32))
            x1 := mload(add(point, 64))
            y0 := mload(add(point, 96))
            y1 := mload(add(point, 128))
        }
        pubkey = [x0, x1, y0, y1];
    }

    function decompress(uint256 compressedSignature) public view returns (uint256[2] memory uncompressed) {
        uint256 x = compressedSignature & FIELD_MASK;
        // The most significant bit, when set, indicates that the y-coordinate of the point
        // is the lexicographically largest of the two associated values.
        // The second-most significant bit indicates that the point is at infinity. If this bit is set,
        // the remaining bits of the group element's encoding should be set to zero.
        // We don't accept infinity as valid signature.
        uint256 decision = compressedSignature >> 254;
        if (decision & 1 == 1) {
            revert MustNotBeInfinity();
        }
        uint256 y;
        (y,) = deriveYOnG1(x);

        // If the following two conditions or their negative forms are not met at the same time, get the negative y.
        // 1. The most significant bit of compressed signature is set
        // 2. The y we recovered first is the lexicographically largest
        if (((decision >> 1) ^ (y > N / 2 ? 1 : 0)) == 1) {
            y = N - y;
        }
        return [x, y];
    }

    function isValid(uint256 compressedSignature) public view returns (bool) {
        uint256 x = compressedSignature & FIELD_MASK;
        if (x >= N) {
            return false;
        } else if (x == 0) {
            return false;
        }
        return isOnCurveG1(x);
    }

    function isOnCurveG1(uint256[2] memory point) internal pure returns (bool _isOnCurve) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let t0 := mload(point)
            let t1 := mload(add(point, 32))
            let t2 := mulmod(t0, t0, N)
            t2 := mulmod(t2, t0, N)
            t2 := addmod(t2, 3, N)
            t1 := mulmod(t1, t1, N)
            _isOnCurve := eq(t1, t2)
        }
    }

    function isOnCurveG1(uint256 x) internal view returns (bool _isOnCurve) {
        bool callSuccess;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let t0 := x
            let t1 := mulmod(t0, t0, N)
            t1 := mulmod(t1, t0, N)
            // x ^ 3 + b
            t1 := addmod(t1, 3, N)

            let freemem := mload(0x40)
            mstore(freemem, 0x20)
            mstore(add(freemem, 0x20), 0x20)
            mstore(add(freemem, 0x40), 0x20)
            mstore(add(freemem, 0x60), t1)
            // (N - 1) / 2 = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3
            mstore(add(freemem, 0x80), 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3)
            // N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
            mstore(add(freemem, 0xA0), 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47)
            callSuccess := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20)
            _isOnCurve := eq(1, mload(freemem))
        }
    }

    function isOnCurveG2(uint256[4] memory point) internal pure returns (bool _isOnCurve) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            // x0, x1
            let t0 := mload(point)
            let t1 := mload(add(point, 32))
            // x0 ^ 2
            let t2 := mulmod(t0, t0, N)
            // x1 ^ 2
            let t3 := mulmod(t1, t1, N)
            // 3 * x0 ^ 2
            let t4 := add(add(t2, t2), t2)
            // 3 * x1 ^ 2
            let t5 := addmod(add(t3, t3), t3, N)
            // x0 * (x0 ^ 2 - 3 * x1 ^ 2)
            t2 := mulmod(add(t2, sub(N, t5)), t0, N)
            // x1 * (3 * x0 ^ 2 - x1 ^ 2)
            t3 := mulmod(add(t4, sub(N, t3)), t1, N)

            // x ^ 3 + b
            t0 := addmod(t2, 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5, N)
            t1 := addmod(t3, 0x009713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2, N)

            // y0, y1
            t2 := mload(add(point, 64))
            t3 := mload(add(point, 96))
            // y ^ 2
            t4 := mulmod(addmod(t2, t3, N), addmod(t2, sub(N, t3), N), N)
            t3 := mulmod(shl(1, t2), t3, N)

            // y ^ 2 == x ^ 3 + b
            _isOnCurve := and(eq(t0, t4), eq(t1, t3))
        }
    }

    function sqrt(uint256 xx) internal view returns (uint256 x, bool hasRoot) {
        bool callSuccess;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let freemem := mload(0x40)
            mstore(freemem, 0x20)
            mstore(add(freemem, 0x20), 0x20)
            mstore(add(freemem, 0x40), 0x20)
            mstore(add(freemem, 0x60), xx)
            // this is enabled by N % 4 = 3 and Fermat's little theorem
            // (N + 1) / 4 = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52
            mstore(add(freemem, 0x80), 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52)
            // N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
            mstore(add(freemem, 0xA0), 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47)
            callSuccess := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20)
            x := mload(freemem)
            hasRoot := eq(xx, mulmod(x, x, N))
        }
        require(callSuccess, "BLS: sqrt modexp call failed");
    }

    /// @notice Add two points in G1
    function addPoints(uint256[2] memory p1, uint256[2] memory p2) internal view returns (uint256[2] memory ret) {
        uint256[4] memory input;
        input[0] = p1[0];
        input[1] = p1[1];
        input[2] = p2[0];
        input[3] = p2[1];
        bool success;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 6, input, 0xc0, ret, 0x60)
        }
        // solhint-disable-next-line reason-string
        require(success);
    }
}

File 12 of 26 : Utils.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

// 5k is plenty for an EXTCODESIZE call (2600) + warm CALL (100)
// and some arithmetic operations.
uint256 constant GAS_FOR_CALL_EXACT_CHECK = 5_000;

function containElement(uint256[] memory arr, uint256 element) pure returns (bool) {
    for (uint256 i = 0; i < arr.length; i++) {
        if (arr[i] == element) {
            return true;
        }
    }
    return false;
}

function containElement(address[] memory arr, address element) pure returns (bool) {
    for (uint256 i = 0; i < arr.length; i++) {
        if (arr[i] == element) {
            return true;
        }
    }
    return false;
}

/**
 * @dev returns the minimum threshold for a group of size groupSize
 */
function minimumThreshold(uint256 groupSize) pure returns (uint256) {
    return groupSize / 2 + 1;
}

/**
 * @dev choose one random index from an array.
 */
function pickRandomIndex(uint256 seed, uint256 length) pure returns (uint256) {
    return uint256(keccak256(abi.encodePacked(seed))) % length;
}

/**
 * @dev choose "count" random indices from "indices" array.
 */
function pickRandomIndex(uint256 seed, uint256[] memory indices, uint256 count) pure returns (uint256[] memory) {
    uint256[] memory chosenIndices = new uint256[](count);

    // Create copy of indices to avoid modifying original array.
    uint256[] memory remainingIndices = new uint256[](indices.length);
    for (uint256 i = 0; i < indices.length; i++) {
        remainingIndices[i] = indices[i];
    }

    uint256 remainingCount = remainingIndices.length;
    for (uint256 i = 0; i < count; i++) {
        uint256 index = uint256(keccak256(abi.encodePacked(seed, i))) % remainingCount;
        chosenIndices[i] = remainingIndices[index];
        remainingIndices[index] = remainingIndices[remainingCount - 1];
        remainingCount--;
    }
    return chosenIndices;
}

/**
 * @dev iterates through list of members and remove disqualified nodes.
 */
function getNonDisqualifiedMajorityMembers(address[] memory nodeAddresses, address[] memory disqualifiedNodes)
    pure
    returns (address[] memory)
{
    address[] memory majorityMembers = new address[](nodeAddresses.length);
    uint256 majorityMembersLength = 0;
    for (uint256 i = 0; i < nodeAddresses.length; i++) {
        if (!containElement(disqualifiedNodes, nodeAddresses[i])) {
            majorityMembers[majorityMembersLength] = nodeAddresses[i];
            majorityMembersLength++;
        }
    }

    // remove trailing zero addresses
    return trimTrailingElements(majorityMembers, majorityMembersLength);
}

function trimTrailingElements(uint256[] memory arr, uint256 newLength) pure returns (uint256[] memory) {
    uint256[] memory output = new uint256[](newLength);
    for (uint256 i = 0; i < newLength; i++) {
        output[i] = arr[i];
    }
    return output;
}

function trimTrailingElements(address[] memory arr, uint256 newLength) pure returns (address[] memory) {
    address[] memory output = new address[](newLength);
    for (uint256 i = 0; i < newLength; i++) {
        output[i] = arr[i];
    }
    return output;
}

/**
 * @dev calls target address with exactly gasAmount gas and data as calldata
 * or reverts if at least gasAmount gas is not available.
 */
function callWithExactGas(uint256 gasAmount, address target, bytes memory data) returns (bool success) {
    // solhint-disable-next-line no-inline-assembly
    assembly {
        let g := gas()
        // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow
        // The gas actually passed to the callee is min(gasAmount, 63//64*gas available).
        // We want to ensure that we revert if gasAmount >  63//64*gas available
        // as we do not want to provide them with less, however that check itself costs
        // gas.  GAS_FOR_CALL_EXACT_CHECK ensures we have at least enough gas to be able
        // to revert if gasAmount >  63//64*gas available.
        if lt(g, GAS_FOR_CALL_EXACT_CHECK) { revert(0, 0) }
        g := sub(g, GAS_FOR_CALL_EXACT_CHECK)
        // if g - g//64 <= gasAmount, revert
        // (we subtract g//64 because of EIP-150)
        if iszero(gt(sub(g, div(g, 64)), gasAmount)) { revert(0, 0) }
        // solidity calls check that a contract actually exists at the destination, so we do the same
        if iszero(extcodesize(target)) { revert(0, 0) }
        // call and return whether we succeeded. ignore return data
        // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
        success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0)
    }
    return success;
}

function shuffle(uint256 upper, uint256 randomness) pure returns (uint256[] memory) {
    uint256[] memory arr = new uint256[](upper);
    for (uint256 k = 0; k < upper; k++) {
        arr[k] = k;
    }
    uint256 i = arr.length;
    uint256 j;
    uint256 t;
    while (--i > 0) {
        j = randomness % i;
        randomness = uint256(keccak256(abi.encode(randomness)));
        t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
    return arr;
}

File 13 of 26 : ChainHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {IOPGasPriceOracle} from "../interfaces/IOPGasPriceOracle.sol";

library ChainHelper {
    address public constant OP_GAS_PRICE_ORACLE_ADDR = address(0x420000000000000000000000000000000000000F);
    uint256 public constant OP_MAINNET_CHAIN_ID = 10;
    uint256 public constant OP_GOERLI_TESTNET_CHAIN_ID = 420;
    uint256 public constant OP_DEVNET_L1_CHAIN_ID = 900;
    uint256 public constant OP_DEVNET_L2_CHAIN_ID = 901;
    uint32 public constant OP_BASIC_FULFILLMENT_L1_GAS_USED = 5016;
    uint32 public constant OP_FULFILLMENT_GAS_PER_PARTICIPANT = 652;
    uint256 public constant OP_DIVISOR_DECIMALS = 6;

    function getBlockTime() public view returns (uint256) {
        uint256 chainId = block.chainid;
        if (chainId == OP_MAINNET_CHAIN_ID || chainId == OP_GOERLI_TESTNET_CHAIN_ID || chainId == OP_DEVNET_L2_CHAIN_ID)
        {
            return 2;
        } else if (chainId == OP_DEVNET_L1_CHAIN_ID) {
            return 3;
        }
        return 12;
    }

    function getCurrentTxL1GasFees() public view returns (uint256) {
        uint256 chainId = block.chainid;
        if (chainId == OP_MAINNET_CHAIN_ID || chainId == OP_GOERLI_TESTNET_CHAIN_ID || chainId == OP_DEVNET_L2_CHAIN_ID)
        {
            return IOPGasPriceOracle(OP_GAS_PRICE_ORACLE_ADDR).getL1Fee(msg.data);
        }
        return 0;
    }

    function getTxL1GasFees(uint256 l1GasUsed) public view returns (uint256) {
        uint256 chainId = block.chainid;
        if (chainId == OP_MAINNET_CHAIN_ID || chainId == OP_GOERLI_TESTNET_CHAIN_ID || chainId == OP_DEVNET_L2_CHAIN_ID)
        {
            uint256 l1Fee = l1GasUsed * IOPGasPriceOracle(OP_GAS_PRICE_ORACLE_ADDR).l1BaseFee();
            uint256 divisor = 10 ** OP_DIVISOR_DECIMALS;
            uint256 unscaled = l1Fee * IOPGasPriceOracle(OP_GAS_PRICE_ORACLE_ADDR).scalar();
            return unscaled / divisor;
        }
        return 0;
    }

    function getFulfillmentTxL1GasUsed(uint32 groupSize) public view returns (uint256) {
        uint256 chainId = block.chainid;
        if (chainId == OP_MAINNET_CHAIN_ID || chainId == OP_GOERLI_TESTNET_CHAIN_ID || chainId == OP_DEVNET_L2_CHAIN_ID)
        {
            return OP_BASIC_FULFILLMENT_L1_GAS_USED + groupSize * OP_FULFILLMENT_GAS_PER_PARTICIPANT;
        }
        return 0;
    }
}

File 14 of 26 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

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

File 15 of 26 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

File 16 of 26 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 17 of 26 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 18 of 26 : draft-IERC1822Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 19 of 26 : ERC1967UpgradeUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/IERC1967Upgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 20 of 26 : IRequestTypeBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IRequestTypeBase {
    enum RequestType {
        Randomness,
        RandomWords,
        Shuffling
    }
}

File 21 of 26 : BN256G2.sol
// SPDX-License-Identifier: LGPL 3.0
pragma solidity ^0.8.18;

/**
 * @title Elliptic curve operations on twist points for alt_bn128
 * @author ARPA-Network adapted from https://github.com/musalbas/solidity-BN256G2
 * @dev Homepage: https://github.com/ARPA-Network/BLS-TSS-Network
 */

library BN256G2 {
    uint256 public constant FIELD_MODULUS = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47;
    uint256 public constant TWISTBX = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5;
    uint256 public constant TWISTBY = 0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2;
    uint256 public constant PTXX = 0;
    uint256 public constant PTXY = 1;
    uint256 public constant PTYX = 2;
    uint256 public constant PTYY = 3;
    uint256 public constant PTZX = 4;
    uint256 public constant PTZY = 5;

    function ecTwistAdd(uint256[4] memory pt1, uint256[4] memory pt2) internal view returns (uint256[4] memory pt) {
        (uint256 xx, uint256 xy, uint256 yx, uint256 yy) =
            ecTwistAdd(pt1[0], pt1[1], pt1[2], pt1[3], pt2[0], pt2[1], pt2[2], pt2[3]);
        pt = [xx, xy, yx, yy];
    }

    /**
     * @notice Add two twist points
     * @param pt1xx Coefficient 1 of x on point 1
     * @param pt1xy Coefficient 2 of x on point 1
     * @param pt1yx Coefficient 1 of y on point 1
     * @param pt1yy Coefficient 2 of y on point 1
     * @param pt2xx Coefficient 1 of x on point 2
     * @param pt2xy Coefficient 2 of x on point 2
     * @param pt2yx Coefficient 1 of y on point 2
     * @param pt2yy Coefficient 2 of y on point 2
     * @return (pt3xx, pt3xy, pt3yx, pt3yy)
     */
    function ecTwistAdd(
        uint256 pt1xx,
        uint256 pt1xy,
        uint256 pt1yx,
        uint256 pt1yy,
        uint256 pt2xx,
        uint256 pt2xy,
        uint256 pt2yx,
        uint256 pt2yy
    ) internal view returns (uint256, uint256, uint256, uint256) {
        if (pt1xx == 0 && pt1xy == 0 && pt1yx == 0 && pt1yy == 0) {
            if (!(pt2xx == 0 && pt2xy == 0 && pt2yx == 0 && pt2yy == 0)) {
                assert(isOnCurve(pt2xx, pt2xy, pt2yx, pt2yy));
            }
            return (pt2xx, pt2xy, pt2yx, pt2yy);
        } else if (pt2xx == 0 && pt2xy == 0 && pt2yx == 0 && pt2yy == 0) {
            assert(isOnCurve(pt1xx, pt1xy, pt1yx, pt1yy));
            return (pt1xx, pt1xy, pt1yx, pt1yy);
        }

        assert(isOnCurve(pt1xx, pt1xy, pt1yx, pt1yy));
        assert(isOnCurve(pt2xx, pt2xy, pt2yx, pt2yy));

        uint256[6] memory pt1 = [pt1xx, pt1xy, pt1yx, pt1yy, 1, 0];
        uint256[6] memory pt2 = [pt2xx, pt2xy, pt2yx, pt2yy, 1, 0];
        uint256[6] memory pt3 = ecTwistAddJacobian(pt1, pt2);

        return fromJacobian(pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]);
    }

    function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) {
        return addmod(a, n - b, n);
    }

    function fq2Mul(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (uint256, uint256) {
        return (
            submod(mulmod(xx, yx, FIELD_MODULUS), mulmod(xy, yy, FIELD_MODULUS), FIELD_MODULUS),
            addmod(mulmod(xx, yy, FIELD_MODULUS), mulmod(xy, yx, FIELD_MODULUS), FIELD_MODULUS)
        );
    }

    function fq2Muc(uint256 xx, uint256 xy, uint256 c) internal pure returns (uint256, uint256) {
        return (mulmod(xx, c, FIELD_MODULUS), mulmod(xy, c, FIELD_MODULUS));
    }

    function fq2Sub(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (uint256 rx, uint256 ry) {
        return (submod(xx, yx, FIELD_MODULUS), submod(xy, yy, FIELD_MODULUS));
    }

    function fq2Inv(uint256 x, uint256 y) internal view returns (uint256, uint256) {
        uint256 inv =
            modInv(addmod(mulmod(y, y, FIELD_MODULUS), mulmod(x, x, FIELD_MODULUS), FIELD_MODULUS), FIELD_MODULUS);
        return (mulmod(x, inv, FIELD_MODULUS), FIELD_MODULUS - mulmod(y, inv, FIELD_MODULUS));
    }

    function isOnCurve(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (bool) {
        uint256 yyx;
        uint256 yyy;
        uint256 xxxx;
        uint256 xxxy;
        (yyx, yyy) = fq2Mul(yx, yy, yx, yy);
        (xxxx, xxxy) = fq2Mul(xx, xy, xx, xy);
        (xxxx, xxxy) = fq2Mul(xxxx, xxxy, xx, xy);
        (yyx, yyy) = fq2Sub(yyx, yyy, xxxx, xxxy);
        (yyx, yyy) = fq2Sub(yyx, yyy, TWISTBX, TWISTBY);
        return yyx == 0 && yyy == 0;
    }

    function modInv(uint256 a, uint256 n) internal view returns (uint256 result) {
        bool success;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let freemem := mload(0x40)
            mstore(freemem, 0x20)
            mstore(add(freemem, 0x20), 0x20)
            mstore(add(freemem, 0x40), 0x20)
            mstore(add(freemem, 0x60), a)
            mstore(add(freemem, 0x80), sub(n, 2))
            mstore(add(freemem, 0xA0), n)
            success := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20)
            result := mload(freemem)
        }
        // solhint-disable-next-line reason-string
        require(success);
    }

    function fromJacobian(uint256 pt1xx, uint256 pt1xy, uint256 pt1yx, uint256 pt1yy, uint256 pt1zx, uint256 pt1zy)
        internal
        view
        returns (uint256 pt2xx, uint256 pt2xy, uint256 pt2yx, uint256 pt2yy)
    {
        uint256 invzx;
        uint256 invzy;
        (invzx, invzy) = fq2Inv(pt1zx, pt1zy);
        (pt2xx, pt2xy) = fq2Mul(pt1xx, pt1xy, invzx, invzy);
        (pt2yx, pt2yy) = fq2Mul(pt1yx, pt1yy, invzx, invzy);
    }

    function ecTwistAddJacobian(uint256[6] memory pt1, uint256[6] memory pt2)
        public
        pure
        returns (uint256[6] memory pt3)
    {
        if (pt1[4] == 0 && pt1[5] == 0) {
            (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) =
                (pt2[0], pt2[1], pt2[2], pt2[3], pt2[4], pt2[5]);
            return pt3;
        } else if (pt2[4] == 0 && pt2[5] == 0) {
            (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) =
                (pt1[0], pt1[1], pt1[2], pt1[3], pt1[4], pt1[5]);
            return pt3;
        }

        (pt2[2], pt2[3]) = fq2Mul(pt2[2], pt2[3], pt1[4], pt1[5]); // U1 = y2 * z1
        (pt3[PTYX], pt3[PTYY]) = fq2Mul(pt1[2], pt1[3], pt2[4], pt2[5]); // U2 = y1 * z2
        (pt2[0], pt2[1]) = fq2Mul(pt2[0], pt2[1], pt1[4], pt1[5]); // V1 = x2 * z1
        (pt3[PTZX], pt3[PTZY]) = fq2Mul(pt1[0], pt1[1], pt2[4], pt2[5]); // V2 = x1 * z2

        if (pt2[0] == pt3[PTZX] && pt2[1] == pt3[PTZY]) {
            if (pt2[2] == pt3[PTYX] && pt2[3] == pt3[PTYY]) {
                (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) =
                    ecTwistDoubleJacobian(pt1[0], pt1[1], pt1[2], pt1[3], pt1[4], pt1[5]);
                return pt3;
            }
            (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) = (1, 0, 1, 0, 0, 0);
            return pt3;
        }

        (pt2[4], pt2[5]) = fq2Mul(pt1[4], pt1[5], pt2[4], pt2[5]); // W = z1 * z2
        (pt1[0], pt1[1]) = fq2Sub(pt2[2], pt2[3], pt3[PTYX], pt3[PTYY]); // U = U1 - U2
        (pt1[2], pt1[3]) = fq2Sub(pt2[0], pt2[1], pt3[PTZX], pt3[PTZY]); // V = V1 - V2
        (pt1[4], pt1[5]) = fq2Mul(pt1[2], pt1[3], pt1[2], pt1[3]); // V_squared = V * V
        (pt2[2], pt2[3]) = fq2Mul(pt1[4], pt1[5], pt3[PTZX], pt3[PTZY]); // V_squared_times_V2 = V_squared * V2
        (pt1[4], pt1[5]) = fq2Mul(pt1[4], pt1[5], pt1[2], pt1[3]); // V_cubed = V * V_squared
        (pt3[PTZX], pt3[PTZY]) = fq2Mul(pt1[4], pt1[5], pt2[4], pt2[5]); // newz = V_cubed * W
        (pt2[0], pt2[1]) = fq2Mul(pt1[0], pt1[1], pt1[0], pt1[1]); // U * U
        (pt2[0], pt2[1]) = fq2Mul(pt2[0], pt2[1], pt2[4], pt2[5]); // U * U * W
        (pt2[0], pt2[1]) = fq2Sub(pt2[0], pt2[1], pt1[4], pt1[5]); // U * U * W - V_cubed
        (pt2[4], pt2[5]) = fq2Muc(pt2[2], pt2[3], 2); // 2 * V_squared_times_V2
        (pt2[0], pt2[1]) = fq2Sub(pt2[0], pt2[1], pt2[4], pt2[5]); // A = U * U * W - V_cubed - 2 * V_squared_times_V2
        (pt3[PTXX], pt3[PTXY]) = fq2Mul(pt1[2], pt1[3], pt2[0], pt2[1]); // newx = V * A
        (pt1[2], pt1[3]) = fq2Sub(pt2[2], pt2[3], pt2[0], pt2[1]); // V_squared_times_V2 - A
        (pt1[2], pt1[3]) = fq2Mul(pt1[0], pt1[1], pt1[2], pt1[3]); // U * (V_squared_times_V2 - A)
        (pt1[0], pt1[1]) = fq2Mul(pt1[4], pt1[5], pt3[PTYX], pt3[PTYY]); // V_cubed * U2
        (pt3[PTYX], pt3[PTYY]) = fq2Sub(pt1[2], pt1[3], pt1[0], pt1[1]); // newy = U * (V_squared_times_V2 - A) - V_cubed * U2
    }

    function ecTwistDoubleJacobian(
        uint256 pt1xx,
        uint256 pt1xy,
        uint256 pt1yx,
        uint256 pt1yy,
        uint256 pt1zx,
        uint256 pt1zy
    ) public pure returns (uint256 pt2xx, uint256 pt2xy, uint256 pt2yx, uint256 pt2yy, uint256 pt2zx, uint256 pt2zy) {
        (pt2xx, pt2xy) = fq2Muc(pt1xx, pt1xy, 3); // 3 * x
        (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt1xx, pt1xy); // W = 3 * x * x
        (pt1zx, pt1zy) = fq2Mul(pt1yx, pt1yy, pt1zx, pt1zy); // S = y * z
        (pt2yx, pt2yy) = fq2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // x * y
        (pt2yx, pt2yy) = fq2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // B = x * y * S
        (pt1xx, pt1xy) = fq2Mul(pt2xx, pt2xy, pt2xx, pt2xy); // W * W
        (pt2zx, pt2zy) = fq2Muc(pt2yx, pt2yy, 8); // 8 * B
        (pt1xx, pt1xy) = fq2Sub(pt1xx, pt1xy, pt2zx, pt2zy); // H = W * W - 8 * B
        (pt2zx, pt2zy) = fq2Mul(pt1zx, pt1zy, pt1zx, pt1zy); // S_squared = S * S
        (pt2yx, pt2yy) = fq2Muc(pt2yx, pt2yy, 4); // 4 * B
        (pt2yx, pt2yy) = fq2Sub(pt2yx, pt2yy, pt1xx, pt1xy); // 4 * B - H
        (pt2yx, pt2yy) = fq2Mul(pt2yx, pt2yy, pt2xx, pt2xy); // W * (4 * B - H)
        (pt2xx, pt2xy) = fq2Muc(pt1yx, pt1yy, 8); // 8 * y
        (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt1yx, pt1yy); // 8 * y * y
        (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // 8 * y * y * S_squared
        (pt2yx, pt2yy) = fq2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // newy = W * (4 * B - H) - 8 * y * y * S_squared
        (pt2xx, pt2xy) = fq2Muc(pt1xx, pt1xy, 2); // 2 * H
        (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // newx = 2 * H * S
        (pt2zx, pt2zy) = fq2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // S * S_squared
        (pt2zx, pt2zy) = fq2Muc(pt2zx, pt2zy, 8); // newz = 8 * S * S_squared
    }
}

File 22 of 26 : IOPGasPriceOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IOPGasPriceOracle {
    /// @notice Computes the L1 portion of the fee based on the size of the rlp encoded input
    ///         transaction, the current L1 base fee, and the various dynamic parameters.
    /// @param _data Unsigned fully RLP-encoded transaction to get the L1 fee for.
    /// @return L1 fee that should be paid for the tx
    function getL1Fee(bytes memory _data) external view returns (uint256);
    /// @notice Retrieves the current fee scalar.
    /// @return Current fee scalar.
    function scalar() external view returns (uint256);
    /// @notice Retrieves the latest known L1 base fee.
    /// @return Latest known L1 base fee.
    function l1BaseFee() external view returns (uint256);
}

File 23 of 26 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

File 24 of 26 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 25 of 26 : IERC1967Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 *
 * _Available since v4.9._
 */
interface IERC1967Upgradeable {
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);
}

File 26 of 26 : StorageSlotUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

Settings
{
  "remappings": [
    "Randcast-User-Contract/=lib/Randcast-User-Contract/contracts/",
    "Staking-v0.1/=lib/Staking-v0.1/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 300
  },
  "metadata": {
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {
    "src/libraries/BLS.sol": {
      "BLS": "0x34E6885e0e9BBEA0Bae36d00D4D9B4ED873f2cA8"
    },
    "src/libraries/ChainHelper.sol": {
      "ChainHelper": "0x8fFe9b19591b031c7b76a27D1B356eD0A8441B80"
    }
  }
}

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AtLeastOneRequestIsRequired","type":"error"},{"inputs":[],"name":"EmptyPartialSignatures","type":"error"},{"inputs":[{"internalType":"uint32","name":"have","type":"uint32"},{"internalType":"uint32","name":"want","type":"uint32"}],"name":"GasLimitTooBig","type":"error"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"GroupNotExist","type":"error"},{"inputs":[],"name":"IdenticalSubscription","type":"error"},{"inputs":[],"name":"IncorrectCommitment","type":"error"},{"inputs":[],"name":"InsufficientBalanceWhenFulfill","type":"error"},{"inputs":[],"name":"InsufficientBalanceWhenRequest","type":"error"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"address","name":"consumer","type":"address"}],"name":"InvalidConsumer","type":"error"},{"inputs":[],"name":"InvalidPartialSignatureFormat","type":"error"},{"inputs":[],"name":"InvalidPartialSignatures","type":"error"},{"inputs":[],"name":"InvalidRequestByEOA","type":"error"},{"inputs":[{"internalType":"uint16","name":"have","type":"uint16"},{"internalType":"uint16","name":"min","type":"uint16"},{"internalType":"uint16","name":"max","type":"uint16"}],"name":"InvalidRequestConfirmations","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureFormat","type":"error"},{"inputs":[],"name":"InvalidSubscription","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"MustBeSubOwner","type":"error"},{"inputs":[],"name":"NoAvailableGroups","type":"error"},{"inputs":[],"name":"NoCorrespondingRequest","type":"error"},{"inputs":[],"name":"NotFromCommitter","type":"error"},{"inputs":[],"name":"PendingRequestExists","type":"error"},{"inputs":[],"name":"Reentrant","type":"error"},{"inputs":[],"name":"ReferralPromotionDisabled","type":"error"},{"inputs":[],"name":"RequestNotExpired","type":"error"},{"inputs":[],"name":"SenderNotController","type":"error"},{"inputs":[],"name":"SubscriptionAlreadyHasReferral","type":"error"},{"inputs":[],"name":"TaskStillExclusive","type":"error"},{"inputs":[],"name":"TaskStillWithinRequestConfirmations","type":"error"},{"inputs":[],"name":"TooManyConsumers","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"minimumRequestConfirmations","type":"uint16"},{"indexed":false,"internalType":"uint32","name":"maxGasLimit","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"gasAfterPaymentCalculation","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"gasExceptCallback","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"signatureTaskExclusiveWindow","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerSignature","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"committerRewardPerSignature","type":"uint256"}],"name":"AdapterConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier1","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier2","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier3","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier4","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier5","type":"uint32"},{"internalType":"uint24","name":"reqsForTier2","type":"uint24"},{"internalType":"uint24","name":"reqsForTier3","type":"uint24"},{"internalType":"uint24","name":"reqsForTier4","type":"uint24"},{"internalType":"uint24","name":"reqsForTier5","type":"uint24"}],"indexed":false,"internalType":"struct IAdapterOwner.FeeConfig","name":"flatFeeConfig","type":"tuple"},{"indexed":false,"internalType":"uint16","name":"flatFeePromotionGlobalPercentage","type":"uint16"},{"indexed":false,"internalType":"bool","name":"isFlatFeePromotionEnabledPermanently","type":"bool"},{"indexed":false,"internalType":"uint256","name":"flatFeePromotionStartTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flatFeePromotionEndTimestamp","type":"uint256"}],"name":"FlatFeeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"}],"name":"OvertimeRequestCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"},{"indexed":true,"internalType":"uint32","name":"groupIndex","type":"uint32"},{"indexed":false,"internalType":"enum IRequestTypeBase.RequestType","name":"requestType","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"params","type":"bytes"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"seed","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"requestConfirmations","type":"uint16"},{"indexed":false,"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"callbackMaxGasPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"estimatedPayment","type":"uint256"}],"name":"RandomnessRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":true,"internalType":"uint32","name":"groupIndex","type":"uint32"},{"indexed":true,"internalType":"address","name":"committer","type":"address"},{"indexed":false,"internalType":"address[]","name":"participantMembers","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"randommness","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flatFee","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"RandomnessRequestResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isReferralEnabled","type":"bool"},{"indexed":false,"internalType":"uint16","name":"freeRequestCountForReferrer","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"freeRequestCountForReferee","type":"uint16"}],"name":"ReferralConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SubscriptionCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"},{"indexed":false,"internalType":"address","name":"consumer","type":"address"}],"name":"SubscriptionConsumerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"},{"indexed":false,"internalType":"address","name":"consumer","type":"address"}],"name":"SubscriptionConsumerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"SubscriptionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"oldBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"SubscriptionFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"subId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"referralSubId","type":"uint64"}],"name":"SubscriptionReferralSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DEFAULT_MINIMUM_THRESHOLD","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CONSUMERS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_REQUEST_CONFIRMATIONS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RANDOMNESS_REWARD_GAS","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERIFICATION_GAS_OVER_MINIMUM_THRESHOLD","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"address","name":"consumer","type":"address"}],"name":"addConsumer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"components":[{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"uint32","name":"groupIndex","type":"uint32"},{"internalType":"enum IRequestTypeBase.RequestType","name":"requestType","type":"uint8"},{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"address","name":"callbackContract","type":"address"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint16","name":"requestConfirmations","type":"uint16"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"callbackMaxGasPrice","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"}],"internalType":"struct IAdapter.RequestDetail","name":"requestDetail","type":"tuple"}],"name":"cancelOvertimeRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"address","name":"to","type":"address"}],"name":"cancelSubscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createSubscription","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint32","name":"gasExceptCallback","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPM","type":"uint32"},{"internalType":"uint256","name":"weiPerUnitGas","type":"uint256"},{"internalType":"uint32","name":"groupSize","type":"uint32"}],"name":"estimatePaymentAmountInETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"groupIndex","type":"uint32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"signature","type":"uint256"},{"components":[{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"uint32","name":"groupIndex","type":"uint32"},{"internalType":"enum IRequestTypeBase.RequestType","name":"requestType","type":"uint8"},{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"address","name":"callbackContract","type":"address"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint16","name":"requestConfirmations","type":"uint16"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"callbackMaxGasPrice","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"}],"internalType":"struct IAdapter.RequestDetail","name":"requestDetail","type":"tuple"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"partialSignature","type":"uint256"}],"internalType":"struct IAdapter.PartialSignature[]","name":"partialSignatures","type":"tuple[]"}],"name":"fulfillRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"}],"name":"fundSubscription","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAdapterConfig","outputs":[{"internalType":"uint16","name":"minimumRequestConfirmations","type":"uint16"},{"internalType":"uint32","name":"maxGasLimit","type":"uint32"},{"internalType":"uint32","name":"gasAfterPaymentCalculation","type":"uint32"},{"internalType":"uint32","name":"gasExceptCallback","type":"uint32"},{"internalType":"uint256","name":"signatureTaskExclusiveWindow","type":"uint256"},{"internalType":"uint256","name":"rewardPerSignature","type":"uint256"},{"internalType":"uint256","name":"committerRewardPerSignature","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCumulativeData","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentSubId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"reqCount","type":"uint64"}],"name":"getFeeTier","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFlatFeeConfig","outputs":[{"internalType":"uint32","name":"fulfillmentFlatFeeLinkPPMTier1","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeLinkPPMTier2","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeLinkPPMTier3","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeLinkPPMTier4","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeLinkPPMTier5","type":"uint32"},{"internalType":"uint24","name":"reqsForTier2","type":"uint24"},{"internalType":"uint24","name":"reqsForTier3","type":"uint24"},{"internalType":"uint24","name":"reqsForTier4","type":"uint24"},{"internalType":"uint24","name":"reqsForTier5","type":"uint24"},{"internalType":"uint16","name":"flatFeePromotionGlobalPercentage","type":"uint16"},{"internalType":"bool","name":"isFlatFeePromotionEnabledPermanently","type":"bool"},{"internalType":"uint256","name":"flatFeePromotionStartTimestamp","type":"uint256"},{"internalType":"uint256","name":"flatFeePromotionEndTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastAssignedGroupIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRandomness","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"consumer","type":"address"}],"name":"getLastSubscription","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"name":"getPendingRequestCommitment","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRandomnessCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReferralConfig","outputs":[{"internalType":"bool","name":"isReferralEnabled","type":"bool"},{"internalType":"uint16","name":"freeRequestCountForReferrer","type":"uint16"},{"internalType":"uint16","name":"freeRequestCountForReferee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"}],"name":"getSubscription","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address[]","name":"consumers","type":"address[]"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"inflightCost","type":"uint256"},{"internalType":"uint64","name":"reqCount","type":"uint64"},{"internalType":"uint64","name":"freeRequestCount","type":"uint64"},{"internalType":"uint64","name":"referralSubId","type":"uint64"},{"internalType":"uint64","name":"reqCountInCurrentPeriod","type":"uint64"},{"internalType":"uint256","name":"lastRequestTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"ethAmount","type":"uint256"}],"name":"nodeWithdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"}],"name":"ownerCancelSubscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"address","name":"consumer","type":"address"}],"name":"removeConsumer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum IRequestTypeBase.RequestType","name":"requestType","type":"uint8"},{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint16","name":"requestConfirmations","type":"uint16"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"callbackMaxGasPrice","type":"uint256"}],"internalType":"struct IAdapter.RandomnessRequestParams","name":"params","type":"tuple"}],"name":"requestRandomness","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"minimumRequestConfirmations","type":"uint16"},{"internalType":"uint32","name":"maxGasLimit","type":"uint32"},{"internalType":"uint32","name":"gasAfterPaymentCalculation","type":"uint32"},{"internalType":"uint32","name":"gasExceptCallback","type":"uint32"},{"internalType":"uint256","name":"signatureTaskExclusiveWindow","type":"uint256"},{"internalType":"uint256","name":"rewardPerSignature","type":"uint256"},{"internalType":"uint256","name":"committerRewardPerSignature","type":"uint256"}],"name":"setAdapterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier1","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier2","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier3","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier4","type":"uint32"},{"internalType":"uint32","name":"fulfillmentFlatFeeEthPPMTier5","type":"uint32"},{"internalType":"uint24","name":"reqsForTier2","type":"uint24"},{"internalType":"uint24","name":"reqsForTier3","type":"uint24"},{"internalType":"uint24","name":"reqsForTier4","type":"uint24"},{"internalType":"uint24","name":"reqsForTier5","type":"uint24"}],"internalType":"struct IAdapterOwner.FeeConfig","name":"flatFeeConfig","type":"tuple"},{"internalType":"uint16","name":"flatFeePromotionGlobalPercentage","type":"uint16"},{"internalType":"bool","name":"isFlatFeePromotionEnabledPermanently","type":"bool"},{"internalType":"uint256","name":"flatFeePromotionStartTimestamp","type":"uint256"},{"internalType":"uint256","name":"flatFeePromotionEndTimestamp","type":"uint256"}],"name":"setFlatFeeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"subIds","type":"uint64[]"},{"internalType":"uint64[]","name":"freeRequestCounts","type":"uint64[]"}],"name":"setFreeRequestCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"uint64","name":"referralSubId","type":"uint64"}],"name":"setReferral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isReferralEnabled","type":"bool"},{"internalType":"uint16","name":"freeRequestCountForReferrer","type":"uint16"},{"internalType":"uint16","name":"freeRequestCountForReferee","type":"uint16"}],"name":"setReferralConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]

60a0604052306080523480156200001557600080fd5b506200002062000026565b620000e8565b600054610100900460ff1615620000935760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e6576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b608051615f306200012060003960008181610af701528181610b4001528181610bdc01528181610c1c0152610caf0152615f306000f3fe6080604052600436106102565760003560e01c806391a6fe7711610149578063c725a833116100c6578063dcdb7b881161008a578063f2fde38b11610064578063f2fde38b1461090a578063f362ca611461092a578063f4cc97fc1461094a57600080fd5b8063dcdb7b8814610721578063dfaba79414610889578063ef6f42731461089c57600080fd5b8063c725a83314610670578063caba5284146106a1578063d2f9f9a7146106c1578063d7ae1d30146106e1578063d89f241f1461070157600080fd5b8063a39402d71161010d578063a39402d7146105d1578063a47c7696146105f1578063a4c343f214610626578063aa81d59a1461063b578063c4d66de81461065057600080fd5b806391a6fe7714610541578063931d92041461055c5780639f87fad71461057c578063a141bbd81461059c578063a21a23e4146105bc57600080fd5b806352d1902d116101d75780637341c10c1161019b5780637341c10c1461048057806376a911bc146104a05780638166d459146104e2578063877d38bb1461050d5780638da5cb5b1461052357600080fd5b806352d1902d1461040c578063636021741461042157806364d51a2a14610436578063715018a61461044b57806371b7ca051461046057600080fd5b806315c48b841161021e57806315c48b841461032f5780631e58a872146103575780633018205f146103a75780633659cfe6146103d95780634f1ef286146103f957600080fd5b806302bcc5b61461025b578063056e5ede1461027d57806306bfa6371461029d5780630ad98f6a146102d45780631565034c146102f4575b600080fd5b34801561026757600080fd5b5061027b6102763660046147c2565b61096a565b005b34801561028957600080fd5b5061027b61029836600461496a565b6109e1565b3480156102a957600080fd5b5060d7546001600160401b03165b6040516001600160401b0390911681526020015b60405180910390f35b3480156102e057600080fd5b5061027b6102ef3660046149ed565b610a8c565b34801561030057600080fd5b5061032161030f366004614a19565b600090815260d4602052604090205490565b6040519081526020016102cb565b34801561033b57600080fd5b5061034460c881565b60405161ffff90911681526020016102cb565b34801561036357600080fd5b5061038560d85460ff81169161ffff6101008304811692630100000090041690565b60408051931515845261ffff92831660208501529116908201526060016102cb565b3480156103b357600080fd5b5060c9546001600160a01b03165b6040516001600160a01b0390911681526020016102cb565b3480156103e557600080fd5b5061027b6103f4366004614a32565b610aed565b61027b610407366004614abe565b610bd2565b34801561041857600080fd5b50610321610ca2565b34801561042d57600080fd5b5060cf54610321565b34801561044257600080fd5b50610344606481565b34801561045757600080fd5b5061027b610d55565b34801561046c57600080fd5b5061027b61047b366004614b32565b610d69565b34801561048c57600080fd5b5061027b61049b366004614ba7565b610ebd565b3480156104ac57600080fd5b506102b76104bb366004614a32565b6001600160a01b0316600090815260d560205260409020600101546001600160401b031690565b3480156104ee57600080fd5b506104f861232881565b60405163ffffffff90911681526020016102cb565b34801561051957600080fd5b506104f861c35081565b34801561052f57600080fd5b506097546001600160a01b03166103c1565b34801561054d57600080fd5b5060cd5463ffffffff16610321565b34801561056857600080fd5b5061027b610577366004614bde565b611080565b34801561058857600080fd5b5061027b610597366004614ba7565b61135d565b3480156105a857600080fd5b506103216105b7366004614c11565b611693565b3480156105c857600080fd5b506102b76117e6565b3480156105dd57600080fd5b506103216105ec366004614c79565b6118df565b3480156105fd57600080fd5b5061061161060c3660046147c2565b611cfd565b6040516102cb99989796959493929190614cf7565b34801561063257600080fd5b5060ce54610321565b34801561064757600080fd5b506104f8600381565b34801561065c57600080fd5b5061027b61066b366004614a32565b611e1d565b34801561067c57600080fd5b5060ca5460cb5460cc54604080519384526020840192909252908201526060016102cb565b3480156106ad57600080fd5b5061027b6106bc366004614d7a565b611f49565b3480156106cd57600080fd5b506104f86106dc3660046147c2565b612397565b3480156106ed57600080fd5b5061027b6106fc366004614ba7565b612514565b34801561070d57600080fd5b5061027b61071c366004614e38565b612620565b34801561072d57600080fd5b50604080516101208101825260d95463ffffffff8082168084526401000000008304821660208501819052600160401b84048316958501869052600160601b8404831660608601819052600160801b85049093166080860181905262ffffff600160a01b8604811660a08801819052600160b81b8704821660c08901819052600160d01b8804831660e08a01819052600160e81b90980490921661010090980188905260da5460db5460dc54969a95999598949692959394939261ffff83169260ff620100009091041691906040516102cb9d9c9b9a9998979695949392919063ffffffff9d8e1681529b8d1660208d0152998c1660408c0152978b1660608b015295909916608089015262ffffff93841660a089015291831660c0880152821660e08701521661010085015261ffff949094166101208401529215156101408301526101608201929092526101808101919091526101a00190565b61027b6108973660046147c2565b612971565b3480156108a857600080fd5b5060d05460d15460d25460d3546040805161ffff8616815263ffffffff62010000870481166020830152600160381b8704811692820192909252600160581b909504166060850152608084019290925260a083015260c082015260e0016102cb565b34801561091657600080fd5b5061027b610925366004614a32565b612a5d565b34801561093657600080fd5b5061027b610945366004614e8d565b612ad3565b34801561095657600080fd5b5061027b610965366004614ee5565b612b6d565b610972612da7565b6001600160401b038116600090815260d660205260409020546001600160a01b03166109b157604051630fb532db60e11b815260040160405180910390fd5b6001600160401b038116600090815260d660205260409020546109de9082906001600160a01b0316612e01565b50565b6109e9612da7565b60005b8251811015610a8757818181518110610a0757610a07614fe7565b602002602001015160d66000858481518110610a2557610a25614fe7565b60200260200101516001600160401b03166001600160401b0316815260200190815260200160002060060160086101000a8154816001600160401b0302191690836001600160401b031602179055508080610a7f90615013565b9150506109ec565b505050565b60c9546001600160a01b03163314610ab757604051630f5caa3360e41b815260040160405180910390fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610a87573d6000803e3d6000fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610b3e5760405162461bcd60e51b8152600401610b359061502c565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610b87600080516020615eb4833981519152546001600160a01b031690565b6001600160a01b031614610bad5760405162461bcd60e51b8152600401610b3590615078565b610bb681612ed3565b604080516000808252602082019092526109de91839190612edb565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610c1a5760405162461bcd60e51b8152600401610b359061502c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610c63600080516020615eb4833981519152546001600160a01b031690565b6001600160a01b031614610c895760405162461bcd60e51b8152600401610b3590615078565b610c9282612ed3565b610c9e82826001612edb565b5050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d425760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610b35565b50600080516020615eb483398151915290565b610d5d612da7565b610d676000613046565b565b610d71612da7565b60c861ffff88161115610dab5760405163539c34bb60e11b815261ffff881660048201819052602482015260c86044820152606401610b35565b604080516101008101825261ffff891680825263ffffffff89811660208085018290526000858701528a83166060808701829052938b16608080880182905260a08089018d905260c0808a018d905260e0998a018c905260d0805465ffffffffffff19168a17620100008902176effffffffffffffffff0000000000001916600160381b87026effffffff0000000000000000000000191617600160581b860217905560d18e905560d28d905560d38c90558a519889529488019590955297860191909152928401929092529382018790529281018590529182018390527fefeb3292465cf72a302efdd83695ad560a2828353a1e018844e9abd19a642037910160405180910390a150505050505050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b031680610eff57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610f3357604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff1615610f5e5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038416600090815260d6602052604090206002015460631901610f9b576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b038316600090815260d5602090815260408083206001600160401b038089168552925282205416900361107a576001600160a01b038316600081815260d5602090815260408083206001600160401b0389168085528184528285208054600167ffffffffffffffff1991821681179092559281018054909316821790925560d68452828520600201805492830181558552938390200180546001600160a01b031916851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e0910160405180910390a25b50505050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b0316806110c257604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146110f657604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff16156111215760405163769dd35360e11b815260040160405180910390fd5b60d85460ff1661114457604051636dac270160e01b815260040160405180910390fd5b6001600160401b03808416600090815260d660205260408082205492871682529020546001600160a01b039182169116036111925760405163027f035560e51b815260040160405180910390fd5b6001600160401b03808516600090815260d66020526040902060060154600160801b900416156111d55760405163cae26ee160e01b815260040160405180910390fd5b6001600160401b03808516600090815260d6602052604090206006015416158061121a57506001600160401b03808416600090815260d6602052604090206006015416155b156112385760405163a760a23760e01b815260040160405180910390fd5b60d8546001600160401b03848116600090815260d660205260409020600601805461010090930461ffff1692909160089161127c918591600160401b9004166150c4565b82546101009290920a6001600160401b0381810219909316918316021790915560d854868216600090815260d6602052604090206006018054630100000090920461ffff169350916008916112da918591600160401b9004166150c4565b82546101009290920a6001600160401b03818102199093169183160217909155858116600081815260d66020526040808220600601805467ffffffffffffffff60801b1916600160801b958a169586021790555192935090917fb661d46b53034f62a6c7d50df2a5e055fab98889aaf62f8c618e457edd96c6889190a350505050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b03168061139f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146113d357604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff16156113fe5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038416600090815260d660205260409020600401541561143857604051631685ecdd60e31b815260040160405180910390fd5b6001600160401b038416600090815260d660209081526040808320600201805482518185028101850190935280835291929091908301828280156114a557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611487575b5050505050905080516000036114e857604051637800cff360e11b81526001600160401b03861660048201526001600160a01b0385166024820152604401610b35565b60005b815181101561165f57846001600160a01b031682828151811061151057611510614fe7565b60200260200101516001600160a01b03160361164d57816001835161153591906150eb565b8151811061154557611545614fe7565b602002602001015160d66000886001600160401b03166001600160401b03168152602001908152602001600020600201828154811061158657611586614fe7565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092556001600160401b038816815260d6909152604090206002018054806115da576115da6150fe565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03871681526001600160401b038816917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a2505061107a565b8061165781615013565b9150506114eb565b50604051637800cff360e11b81526001600160401b03861660048201526001600160a01b0385166024820152604401610b35565b60405163745e0dcf60e01b815263ffffffff821660048201526000908190600290738ffe9b19591b031c7b76a27d1b356ed0a8441b8090638e3976f690829063745e0dcf90602401602060405180830381865af41580156116f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171c9190615114565b6040518263ffffffff1660e01b815260040161173a91815260200190565b602060405180830381865af4158015611757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177b9190615114565b61178690600361512d565b611790919061515a565b905060008161179f898961516e565b6117af9063ffffffff168761512d565b6117b9919061518b565b90506117d063ffffffff871664e8d4a5100061512d565b6117da908261518b565b98975050505050505050565b60d054600090600160301b900460ff16156118145760405163769dd35360e11b815260040160405180910390fd5b60d780546001600160401b031690600061182d8361519e565b82546001600160401b039182166101009390930a92830292820219169190911790915560d780548216600090815260d6602052604080822080546001600160a01b0319163390811790915583548516835281832060060180546fffffffffffffffff00000000000000001916600160401b17905592549051929450909216917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf91a35060d7546001600160401b031690565b60d054600090600160301b900460ff161561190d5760405163769dd35360e11b815260040160405180910390fd5b6000611918836151d3565b905032330361193a57604051638a3150e760e01b815260040160405180910390fd5b6040808201516001600160401b0316600090815260d66020522080546001600160a01b031661197c57604051630fb532db60e11b815260040160405180910390fd5b33600090815260d560209081526040808320858201516001600160401b03908116855292528220541690036119db576040808301519051637800cff360e11b81526001600160401b039091166004820152336024820152604401610b35565b60d054608083015161ffff91821691161080611a03575060c861ffff16826080015161ffff16115b15611a3e57608082015160d05460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610b35565b60d05460a083015163ffffffff62010000909204821691161115611a955760a082015160d054604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610b35565b611a9d613098565b60cd805463ffffffff191663ffffffff9290921691909117905560608201516040808401805133600081815260d5602090815285822094516001600160401b039081168352949052938420549394611af794909316613209565b6040848101805133600090815260d560209081528482206001808201805467ffffffffffffffff19166001600160401b03968716179055945184168352905292832080549495509193919291611b4f918591166150c4565b92506101000a8154816001600160401b0302191690836001600160401b031602179055506000611b7e82613268565b60c95460cd5460405163f49e0ba960e01b815263ffffffff90911660048201529192506000916001600160a01b039091169063f49e0ba9906024016040805180830381865afa158015611bd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf99190615271565b9150506000611c138584848960a001518a60c0015161329a565b60408088015160cd5489516020808c015160808d015160a08e015160c08f01519751989950611c59988c9863ffffffff90971696939433948f949392909143910161531d565b60408051601f198184030181528282528051602091820120600087815260d483528390205560cd54918901518951918a015160808b015160a08c015160c08d015163ffffffff909616966001600160401b03909416958a957fd26299589dd9197a8dc30a0fa17b0fe7dd432bc3441aa5f5631ea1e14c1af74495611ce7959194919333938f93928d906153a8565b60405180910390a450909450505050505b919050565b6001600160401b038116600090815260d660205260408120805460609183918291829182918291829182916001600160a01b0316611d4e57604051630fb532db60e11b815260040160405180910390fd5b80546003820154600483015460068401546007850154600286018054604080516020808402820181019092528281526001600160a01b0390981697929695946001600160401b0380821695600160401b8304821695600160801b8404831695600160c01b9094049092169390928a91830182828015611df657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611dd8575b50505050509750995099509950995099509950995099509950509193959799909294969850565b600054610100900460ff1615808015611e3d5750600054600160ff909116105b80611e575750303b158015611e57575060005460ff166001145b611eba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610b35565b6000805460ff191660011790558015611edd576000805461ff0019166101001790555b60c980546001600160a01b0319166001600160a01b038416179055611f00613420565b8015610c9e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60d054600160301b900460ff1615611f745760405163769dd35360e11b815260040160405180910390fd5b60005a600087815260d46020526040812054919250819003611fa957604051631b44092560e11b815260040160405180910390fd5b86611fb760208701876147c2565b611fc7604088016020890161540f565b611fd76060890160408a0161542c565b611fe460608a018a615447565b611ff460a08c0160808d01614a32565b60a08c013561200960e08e0160c08f01615494565b8d60e001602081019061201c919061540f565b8e61010001358f61012001356040516020016120439c9b9a999897969594939291906154af565b6040516020818303038152906040528051906020012081146120785760405163354a450b60e21b815260040160405180910390fd5b61208860e0860160c08701615494565b61209b9061ffff1661012087013561518b565b4310156120bb5760405163619a4abd60e01b815260040160405180910390fd5b6120cb604086016020870161540f565b63ffffffff168863ffffffff16141580156120f7575060d1546120f39061012087013561518b565b4311155b15612115576040516378373bbd60e11b815260040160405180910390fd5b60c960009054906101000a90046001600160a01b03166001600160a01b03166306545a936040518163ffffffff1660e01b8152600401602060405180830381865afa158015612168573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218c9190615114565b8863ffffffff16106121b957604051637f6efcb560e11b815263ffffffff89166004820152602401610b35565b60006122298963ffffffff168760a001358861012001358a8989808060200260200160405190810160405280939291908181526020016000905b8282101561221f5761221060408302860136819003810190615557565b815260200190600101906121f3565b505050505061344f565b600089815260d46020908152604080832083905580518083018c9052815180820384018152908201909152805191012060cf805493945090926001929061227190849061518b565b909155505060ce81905560c9546040516379ef840160e11b8152600481018390526001600160a01b039091169063f3df080290602401600060405180830381600087803b1580156122c157600080fd5b505af11580156122d5573d6000803e3d6000fd5b5050505060006122ef8a838a6122ea90615589565b613b3a565b905060008061232860d68261230760208e018e6147c2565b6001600160401b0316815260208101919091526040016000208d8a8a613dd5565b9150915061233785838361408e565b336001600160a01b03168d63ffffffff168d7f6fc1bcb4bd7d5fdf4017f746304b61ae4472496256e906c6bb44682aa2c9a6d8888887878a604051612380959493929190615656565b60405180910390a450505050505050505050505050565b604080516101208101825260d95463ffffffff8082168352640100000000820481166020840152600160401b8204811693830193909352600160601b810483166060830152600160801b8104909216608082015262ffffff600160a01b8304811660a08301819052600160b81b8404821660c0840152600160d01b8404821660e0840152600160e81b909304166101008201526000916001600160401b03841611612443575192915050565b826001600160401b03168160a0015162ffffff1610801561247657508060c0015162ffffff16836001600160401b031611155b15612485576020015192915050565b826001600160401b03168160c0015162ffffff161080156124b857508060e0015162ffffff16836001600160401b031611155b156124c7576040015192915050565b826001600160401b03168160e0015162ffffff161080156124fb575080610100015162ffffff16836001600160401b031611155b1561250a576060015192915050565b6080015192915050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b03168061255657604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461258a57604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff16156125b55760405163769dd35360e11b815260040160405180910390fd5b6001600160a01b0383166125dc5760405163f6b2911f60e01b815260040160405180910390fd5b6001600160401b038416600090815260d660205260409020600401541561261657604051631685ecdd60e31b815260040160405180910390fd5b61107a8484612e01565b61262d60208201826147c2565b6001600160401b038116600090815260d660205260409020546001600160a01b03168061266d57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146126a157604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b600084815260d4602052604081205490036126cf57604051631b44092560e11b815260040160405180910390fd5b836126dd60208501856147c2565b6126ed604086016020870161540f565b6126fd606087016040880161542c565b61270a6060880188615447565b61271a60a08a0160808b01614a32565b60a08a013561272f60e08c0160c08d01615494565b6127406101008d0160e08e0161540f565b8c61010001358d61012001356040516020016127679c9b9a999897969594939291906154af565b60408051601f198184030181529181528151602092830120600087815260d4909352912054146127aa5760405163354a450b60e21b815260040160405180910390fd5b6000738ffe9b19591b031c7b76a27d1b356ed0a8441b806387ceff096040518163ffffffff1660e01b8152600401602060405180830381865af41580156127f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128199190615114565b612826906201518061515a565b90506128378161012086013561518b565b43101561285757604051636c804b5d60e01b815260040160405180910390fd5b600085815260d460209081526040822082905560d6919061287a908701876147c2565b6001600160401b03168152602080820192909252604090810160009081208882526005018352908120549160d691906128b5908801886147c2565b6001600160401b03166001600160401b0316815260200190815260200160002060040160008282546128e791906150eb565b9091555060d6905060006128fe60208701876147c2565b6001600160401b0316815260208082019290925260409081016000908120888252600501835290812055612934908501856147c2565b6001600160401b0316857fc1cf1d318384ee8dee53eed48bbf121b2b14fa61e9da5fd2f597dfbee4e5c2e660405160405180910390a35050505050565b60d054600160301b900460ff161561299c5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038116600090815260d660205260409020546001600160a01b03166129db57604051630fb532db60e11b815260040160405180910390fd5b6001600160401b038116600090815260d660205260408120600301805491349190612a06838561518b565b90915550506001600160401b0382167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882612a41348261518b565b6040805192835260208301919091520160405180910390a25050565b612a65612da7565b6001600160a01b038116612aca5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b35565b6109de81613046565b612adb612da7565b604080516060808201835285151580835261ffff868116602080860182905291871694860185905260d8805462ffffff191662ffff001985161761010083021764ffff000000191663010000008702179055855192835290820152928301919091527faf8d657c268b3f943977d5288bfb2306420bcb17b7ef17397cffa5d2f4891643910160405180910390a1505050565b612b75612da7565b6040518060a001604052808681526020018561ffff16815260200184151581526020018381526020018281525060d960008201518160000160008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160146101000a81548162ffffff021916908362ffffff16021790555060c08201518160000160176101000a81548162ffffff021916908362ffffff16021790555060e082015181600001601a6101000a81548162ffffff021916908362ffffff16021790555061010082015181600001601d6101000a81548162ffffff021916908362ffffff160217905550505060208201518160010160006101000a81548161ffff021916908361ffff16021790555060408201518160010160026101000a81548160ff02191690831515021790555060608201518160020155608082015181600301559050507f1851d8853c0ab5ed26d95d456344506f759953621e7c115677f2244696b8ba978585858585604051612d9895949392919061568f565b60405180910390a15050505050565b6097546001600160a01b03163314610d675760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b35565b60d054600160301b900460ff1615612e2c5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038216600081815260d66020908152604091829020600381015481546001600160a01b03191690915582516001600160a01b038616815291820181905292917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a26040516001600160a01b0383169082156108fc029083906000818181858888f1935050505015801561107a573d6000803e3d6000fd5b6109de612da7565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612f0e57610a8783614206565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612f68575060408051601f3d908101601f19168201909252612f6591810190615114565b60015b612fcb5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610b35565b600080516020615eb4833981519152811461303a5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610b35565b50610a878383836142a2565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008060c960009054906101000a90046001600160a01b03166001600160a01b031663b330a0fd6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156130ee573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131169190810190615751565b9050805160000361313a57604051636905ab6760e01b815260040160405180910390fd5b60c954604080516306545a9360e01b815290516000926001600160a01b0316916306545a939160048083019260209291908290030181865afa158015613184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a89190615114565b60cd5490915060009082906131c49063ffffffff16600161516e565b63ffffffff166131d491906157e1565b90505b6131e183826142c7565b61320257816131f182600161518b565b6131fb91906157e1565b90506131d7565b9392505050565b604080514660208201529081018590526001600160401b03841660608201526001600160a01b038316608082015260a0810182905260009060c0016040516020818303038152906040528051906020012060001c90505b949350505050565b60008160405160200161327d91815260200190565b604051602081830303815290604052805190602001209050919050565b60da54600090819062010000900460ff16156132c4575060068601546001600160401b0316613316565b60db5442108015906132d8575060dc544211155b156133165760db54600788015410156132f357506001613316565b600687015461331390600160c01b90046001600160401b031660016150c4565b90505b60006133b2856133276003896157f5565b6133339061c350615812565b61333f89612328615812565b60d0546133599190600160581b900463ffffffff1661516e565b613363919061516e565b60068b0154600160401b90046001600160401b03166133a85760da5460649061ffff1661338f87612397565b6133999190615812565b6133a3919061583a565b6133ab565b60005b878a611693565b905080886004015489600301546133c991906150eb565b10156133e85760405163444a5eaf60e11b815260040160405180910390fd5b808860040160008282546133fc919061518b565b90915550506000878152600589016020526040902081905591505095945050505050565b600054610100900460ff166134475760405162461bcd60e51b8152600401610b359061585d565b610d6761431c565b60405162f577a560e81b8152600481018390526060907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca89063f577a50090602401602060405180830381865af41580156134a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c591906158b3565b6134e257604051638529df1f60e01b815260040160405180910390fd5b815160000361350457604051638bdcc37560e01b815260040160405180910390fd5b60c9546040516333ad819560e21b8152600481018890526000916001600160a01b03169063ceb6065490602401600060405180830381865afa15801561354e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135769190810190615b60565b90506135868160a001513361434c565b6135a35760405163d9ce719d60e01b815260040160405180910390fd5b60408051602081018890528082018790528151808203830181526060820192839052633033cc5160e01b9092526000907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890633033cc51906135fd908590606401615c65565b6040805180830381865af4158015613619573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061363d9190615c78565b90507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca863ebbdac917334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca86313bc64ee896040518263ffffffff1660e01b815260040161369291815260200190565b6040805180830381865af41580156136ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d29190615c78565b856101000151846040518463ffffffff1660e01b81526004016136f793929190615d1e565b602060405180830381865af4158015613714573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373891906158b3565b61375557604051638baa579f60e01b815260040160405180910390fd5b600085516001600160401b03811115613770576137706147dd565b6040519080825280602002602001820160405280156137a957816020015b61379661476f565b81526020019060019003908161378e5790505b509050600086516001600160401b038111156137c7576137c76147dd565b60405190808252806020026020018201604052801561380057816020015b6137ed61478d565b8152602001906001900390816137e55790505b50905086516001600160401b0381111561381c5761381c6147dd565b604051908082528060200260200182016040528015613845578160200160208202803683370190505b50955060005b8751811015613a92577334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca863f577a50089838151811061388057613880614fe7565b6020026020010151602001516040518263ffffffff1660e01b81526004016138aa91815260200190565b602060405180830381865af41580156138c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138eb91906158b3565b61390857604051636b849b7d60e11b815260040160405180910390fd5b7334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca86313bc64ee89838151811061393457613934614fe7565b6020026020010151602001516040518263ffffffff1660e01b815260040161395e91815260200190565b6040805180830381865af415801561397a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399e9190615c78565b8382815181106139b0576139b0614fe7565b602002602001018190525085608001518882815181106139d2576139d2614fe7565b602002602001015160000151815181106139ee576139ee614fe7565b602002602001015160200151828281518110613a0c57613a0c614fe7565b60200260200101819052508560800151888281518110613a2e57613a2e614fe7565b60200260200101516000015181518110613a4a57613a4a614fe7565b602002602001015160000151878281518110613a6857613a68614fe7565b6001600160a01b039092166020928302919091019091015280613a8a81615013565b91505061384b565b50604051630d6870d760e21b81527334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8906335a1c35c90613ace90859085908890600401615d47565b602060405180830381865af4158015613aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0f91906158b3565b613b2c57604051639c2d1c6d60e01b815260040160405180910390fd5b505050505095945050505050565b60008060608184604001516002811115613b5657613b56615295565b03613ba05750604080516024810187905260448082018790528251808303909101815260649091019091526020810180516001600160e01b03166394985ddd60e01b179052613d8a565b600184604001516002811115613bb857613bb8615295565b03613ceb5760008460600151806020019051810190613bd79190615ddd565b905060008163ffffffff166001600160401b03811115613bf957613bf96147dd565b604051908082528060200260200182016040528015613c22578160200160208202803683370190505b50905060005b8263ffffffff16811015613c925760408051602081018a90529081018290526060016040516020818303038152906040528051906020012060001c828281518110613c7557613c75614fe7565b602090810291909101015280613c8a81615013565b915050613c28565b506040516375bf929b60e01b90613caf908a908490602401615dfa565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091529250613d8a915050565b600284604001516002811115613d0357613d03615295565b03613d8a5760008460600151806020019051810190613d229190615ddd565b90506000613d368263ffffffff16886143a7565b9050639e5836f660e01b8882604051602401613d53929190615dfa565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152925050505b60d0805466ff0000000000001916600160301b17905560e08401516080850151613dbb9163ffffffff169083614502565b60d0805466ff000000000000191690559695505050505050565b6006840180546000918291600191908390613dfa9084906001600160401b03166150c4565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550600060d960010160029054906101000a900460ff1615613e4c575060068601546001600160401b0316613f03565b60db544210801590613e60575060dc544211155b15613f035760db5460078801541015613ea05760068701805477ffffffffffffffffffffffffffffffffffffffffffffffff16600160c01b179055613eec565b60018760060160188282829054906101000a90046001600160401b0316613ec791906150c4565b92506101000a8154816001600160401b0302191690836001600160401b031602179055505b506006860154600160c01b90046001600160401b03165b4260078801556006870154600090600160401b90046001600160401b031615613f765760018860060160088282829054906101000a90046001600160401b0316613f4d9190615e3b565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550613fb5565b60da5460649061ffff16613f8984612397565b613f9e9063ffffffff1664e8d4a5100061512d565b613fa8919061512d565b613fb2919061515a565b90505b6000613fe886613fc78961232861512d565b60d054613fe19190600160381b900463ffffffff1661518b565b843a61454e565b9050808960030154101561400f5760405163964d765f60e01b815260040160405180910390fd5b600088815260058a01602052604081205460048b018054919290916140359084906150eb565b9091555050600088815260058a016020526040812081905560038a0180548392906140619084906150eb565b925050819055508160ca600082825461407a919061518b565b909155509099919850909650505050505050565b60d35460cb80546000906140a390849061518b565b9091555050825160d2546140b7919061512d565b60cc60008282546140c8919061518b565b909155505060408051600180825281830190925260009160208083019080368337019050509050338160008151811061410357614103614fe7565b6001600160a01b03928316602091820292909201015260c9541663914eb34d8261412d85876150eb565b60d3546040516001600160e01b031960e086901b16815261415393929190600401615e5b565b600060405180830381600087803b15801561416d57600080fd5b505af1158015614181573d6000803e3d6000fd5b505060c95486516001600160a01b03909116925063914eb34d915086906141a8908661515a565b60d2546040516001600160e01b031960e086901b1681526141ce93929190600401615e5b565b600060405180830381600087803b1580156141e857600080fd5b505af11580156141fc573d6000803e3d6000fd5b5050505050505050565b6001600160a01b0381163b6142735760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610b35565b600080516020615eb483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6142ab836145fd565b6000825111806142b85750805b15610a875761107a838361463d565b6000805b835181101561431057828482815181106142e7576142e7614fe7565b6020026020010151036142fe576001915050614316565b8061430881615013565b9150506142cb565b50600090505b92915050565b600054610100900460ff166143435760405162461bcd60e51b8152600401610b359061585d565b610d6733613046565b6000805b835181101561431057826001600160a01b031684828151811061437557614375614fe7565b60200260200101516001600160a01b031603614395576001915050614316565b8061439f81615013565b915050614350565b60606000836001600160401b038111156143c3576143c36147dd565b6040519080825280602002602001820160405280156143ec578160200160208202803683370190505b50905060005b8481101561442a578082828151811061440d5761440d614fe7565b60209081029190910101528061442281615013565b9150506143f2565b5080516000805b600061443c84615e80565b93508311156144f75761444f83876157e1565b91508560405160200161446491815260200190565b6040516020818303038152906040528051906020012060001c955083838151811061449157614491614fe7565b602002602001015190508382815181106144ad576144ad614fe7565b60200260200101518484815181106144c7576144c7614fe7565b602002602001018181525050808483815181106144e6576144e6614fe7565b602002602001018181525050614431565b509195945050505050565b60005a61138881101561451457600080fd5b61138881039050846040820482031161452c57600080fd5b50823b61453857600080fd5b60008083516020850160008789f1949350505050565b600080738ffe9b19591b031c7b76a27d1b356ed0a8441b8063c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865af415801561459a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145be9190615114565b5a6145c9888861518b565b6145d391906150eb565b6145dd908561512d565b6145e7919061518b565b90506145f3848261518b565b9695505050505050565b61460681614206565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6146a55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b35565b600080846001600160a01b0316846040516146c09190615e97565b600060405180830381855af49150503d80600081146146fb576040519150601f19603f3d011682016040523d82523d6000602084013e614700565b606091505b50915091506147288282604051806060016040528060278152602001615ed460279139614731565b95945050505050565b60608315614740575081613202565b61320283838151156147555781518083602001fd5b8060405162461bcd60e51b8152600401610b359190615c65565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b80356001600160401b0381168114611cf857600080fd5b6000602082840312156147d457600080fd5b613202826147ab565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614816576148166147dd565b60405290565b60405160e081016001600160401b0381118282101715614816576148166147dd565b604080519081016001600160401b0381118282101715614816576148166147dd565b60405161014081016001600160401b0381118282101715614816576148166147dd565b604051606081016001600160401b0381118282101715614816576148166147dd565b604051601f8201601f191681016001600160401b03811182821017156148cd576148cd6147dd565b604052919050565b60006001600160401b038211156148ee576148ee6147dd565b5060051b60200190565b600082601f83011261490957600080fd5b8135602061491e614919836148d5565b6148a5565b82815260059290921b8401810191818101908684111561493d57600080fd5b8286015b8481101561495f57614952816147ab565b8352918301918301614941565b509695505050505050565b6000806040838503121561497d57600080fd5b82356001600160401b038082111561499457600080fd5b6149a0868387016148f8565b935060208501359150808211156149b657600080fd5b506149c3858286016148f8565b9150509250929050565b6001600160a01b03811681146109de57600080fd5b8035611cf8816149cd565b60008060408385031215614a0057600080fd5b8235614a0b816149cd565b946020939093013593505050565b600060208284031215614a2b57600080fd5b5035919050565b600060208284031215614a4457600080fd5b8135613202816149cd565b600082601f830112614a6057600080fd5b81356001600160401b03811115614a7957614a796147dd565b614a8c601f8201601f19166020016148a5565b818152846020838601011115614aa157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614ad157600080fd5b8235614adc816149cd565b915060208301356001600160401b03811115614af757600080fd5b6149c385828601614a4f565b803561ffff81168114611cf857600080fd5b63ffffffff811681146109de57600080fd5b8035611cf881614b15565b600080600080600080600060e0888a031215614b4d57600080fd5b614b5688614b03565b96506020880135614b6681614b15565b95506040880135614b7681614b15565b94506060880135614b8681614b15565b9699959850939660808101359560a0820135955060c0909101359350915050565b60008060408385031215614bba57600080fd5b614bc3836147ab565b91506020830135614bd3816149cd565b809150509250929050565b60008060408385031215614bf157600080fd5b614bfa836147ab565b9150614c08602084016147ab565b90509250929050565b600080600080600060a08688031215614c2957600080fd5b8535614c3481614b15565b94506020860135614c4481614b15565b93506040860135614c5481614b15565b9250606086013591506080860135614c6b81614b15565b809150509295509295909350565b600060208284031215614c8b57600080fd5b81356001600160401b03811115614ca157600080fd5b820160e0818503121561320257600080fd5b600081518084526020808501945080840160005b83811015614cec5781516001600160a01b031687529582019590820190600101614cc7565b509495945050505050565b60006101206001600160a01b038c168352806020840152614d1a8184018c614cb3565b604084019a909a52505060608101969096526001600160401b03948516608087015292841660a086015290831660c085015290911660e08301526101009091015292915050565b60006101408284031215614d7457600080fd5b50919050565b60008060008060008060a08789031215614d9357600080fd5b8635614d9e81614b15565b9550602087013594506040870135935060608701356001600160401b0380821115614dc857600080fd5b614dd48a838b01614d61565b94506080890135915080821115614dea57600080fd5b818901915089601f830112614dfe57600080fd5b813581811115614e0d57600080fd5b8a60208260061b8501011115614e2257600080fd5b6020830194508093505050509295509295509295565b60008060408385031215614e4b57600080fd5b8235915060208301356001600160401b03811115614e6857600080fd5b6149c385828601614d61565b80151581146109de57600080fd5b8035611cf881614e74565b600080600060608486031215614ea257600080fd5b8335614ead81614e74565b9250614ebb60208501614b03565b9150614ec960408501614b03565b90509250925092565b803562ffffff81168114611cf857600080fd5b60008060008060008587036101a0811215614eff57600080fd5b61012080821215614f0f57600080fd5b614f176147f3565b9150614f2288614b27565b8252614f3060208901614b27565b6020830152614f4160408901614b27565b6040830152614f5260608901614b27565b6060830152614f6360808901614b27565b6080830152614f7460a08901614ed2565b60a0830152614f8560c08901614ed2565b60c0830152614f9660e08901614ed2565b60e0830152610100614fa9818a01614ed2565b8184015250819650614fbc818901614b03565b95505050614fcd6101408701614e82565b949793965093946101608101359450610180013592915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161502557615025614ffd565b5060010190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6001600160401b038181168382160190808211156150e4576150e4614ffd565b5092915050565b8181038181111561431657614316614ffd565b634e487b7160e01b600052603160045260246000fd5b60006020828403121561512657600080fd5b5051919050565b808202811582820484141761431657614316614ffd565b634e487b7160e01b600052601260045260246000fd5b60008261516957615169615144565b500490565b63ffffffff8181168382160190808211156150e4576150e4614ffd565b8082018082111561431657614316614ffd565b60006001600160401b038083168181036151ba576151ba614ffd565b6001019392505050565b803560038110611cf857600080fd5b600060e082360312156151e557600080fd5b6151ed61481c565b6151f6836151c4565b815260208301356001600160401b0381111561521157600080fd5b61521d36828601614a4f565b60208301525061522f604084016147ab565b60408201526060830135606082015261524a60808401614b03565b608082015261525b60a08401614b27565b60a082015260c092830135928101929092525090565b6000806040838503121561528457600080fd5b505080516020909101519092909150565b634e487b7160e01b600052602160045260246000fd5b600381106152c957634e487b7160e01b600052602160045260246000fd5b9052565b60005b838110156152e85781810151838201526020016152d0565b50506000910152565b600081518084526153098160208601602086016152cd565b601f01601f19169290920160200192915050565b60006101608d83526001600160401b038d16602084015263ffffffff808d16604085015261534e606085018d6152ab565b8160808501526153608285018c6152f1565b6001600160a01b039a909a1660a085015260c0840198909852505061ffff9490941660e085015291909316610100830152610120820192909252610140015295945050505050565b60006101006153b7838c6152ab565b8060208401526153c98184018b6152f1565b6001600160a01b039990991660408401525050606081019590955261ffff93909316608085015263ffffffff9190911660a084015260c083015260e09091015292915050565b60006020828403121561542157600080fd5b813561320281614b15565b60006020828403121561543e57600080fd5b613202826151c4565b6000808335601e1984360301811261545e57600080fd5b8301803591506001600160401b0382111561547857600080fd5b60200191503681900382131561548d57600080fd5b9250929050565b6000602082840312156154a657600080fd5b61320282614b03565b60006101608e83526001600160401b038e16602084015263ffffffff8d1660408401526154df606084018d6152ab565b806080840152898184015250610180898b8285013760008a84018201526001600160a01b03891660a0840152601f19601f8b011683010190508660c083015261552e60e083018761ffff169052565b63ffffffff851661010083015261012082019390935261014001529a9950505050505050505050565b60006040828403121561556957600080fd5b61557161483e565b82358152602083013560208201528091505092915050565b6000610140823603121561559c57600080fd5b6155a4614860565b6155ad836147ab565b81526155bb60208401614b27565b60208201526155cc604084016151c4565b604082015260608301356001600160401b038111156155ea57600080fd5b6155f636828601614a4f565b606083015250615608608084016149e2565b608082015260a083013560a082015261562360c08401614b03565b60c082015261563460e08401614b27565b60e0820152610100838101359082015261012092830135928101929092525090565b60a08152600061566960a0830188614cb3565b905085602083015284604083015283606083015282151560808301529695505050505050565b855163ffffffff9081168252602080880151821690830152604080880151821690830152606080880151821690830152608080880151918216908301526101a08201905060a08701516156e960a084018262ffffff169052565b5060c087015161570060c084018262ffffff169052565b5060e087015161571760e084018262ffffff169052565b506101009687015162ffffff169682019690965261ffff949094166101208501529115156101408401526101608301526101809091015290565b6000602080838503121561576457600080fd5b82516001600160401b0381111561577a57600080fd5b8301601f8101851361578b57600080fd5b8051615799614919826148d5565b81815260059190911b820183019083810190878311156157b857600080fd5b928401925b828410156157d6578351825292840192908401906157bd565b979650505050505050565b6000826157f0576157f0615144565b500690565b63ffffffff8281168282160390808211156150e4576150e4614ffd565b63ffffffff81811683821602808216919082811461583257615832614ffd565b505092915050565b600063ffffffff8084168061585157615851615144565b92169190910492915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b8051611cf881614e74565b6000602082840312156158c557600080fd5b815161320281614e74565b600082601f8301126158e157600080fd5b604051608081018181106001600160401b0382111715615903576159036147dd565b60405280608084018581111561591857600080fd5b845b818110156144f757805183526020928301920161591a565b600082601f83011261594357600080fd5b81516020615953614919836148d5565b82815260a0928302850182019282820191908785111561597257600080fd5b8387015b858110156159c05781818a03121561598e5760008081fd5b61599661483e565b81516159a1816149cd565b81526159af8a8388016158d0565b818701528452928401928101615976565b5090979650505050505050565b600082601f8301126159de57600080fd5b815160206159ee614919836148d5565b82815260059290921b84018101918181019086841115615a0d57600080fd5b8286015b8481101561495f578051615a24816149cd565b8352918301918301615a11565b600082601f830112615a4257600080fd5b81516020615a52614919836148d5565b82815260059290921b84018101918181019086841115615a7157600080fd5b8286015b8481101561495f5780516001600160401b0380821115615a9457600080fd5b908801906040601f19838c038101821315615aae57600080fd5b615ab661483e565b8885015184811115615ac757600080fd5b615ad58e8b838901016159cd565b8252508285015184811115615ae957600080fd5b949094019360c0858e0383011215615b015760008081fd5b615b09614883565b9150888501518252615b1d8d8487016158d0565b8983015260c085015184811115615b345760008081fd5b615b428e8b838901016159cd565b93830193909352808901919091528652505050918301918301615a75565b600060208284031215615b7257600080fd5b81516001600160401b0380821115615b8957600080fd5b908301906101808286031215615b9e57600080fd5b615ba66147f3565b82518152602083015160208201526040830151604082015260608301516060820152608083015182811115615bda57600080fd5b615be687828601615932565b60808301525060a083015182811115615bfe57600080fd5b615c0a878286016159cd565b60a08301525060c083015182811115615c2257600080fd5b615c2e87828601615a31565b60c083015250615c4060e084016158a8565b60e08201526101009150615c56868385016158d0565b91810191909152949350505050565b60208152600061320260208301846152f1565b600060408284031215615c8a57600080fd5b82601f830112615c9957600080fd5b615ca161483e565b806040840185811115615cb357600080fd5b845b81811015615ccd578051845260209384019301615cb5565b509095945050505050565b8060005b600281101561107a578151845260209384019390910190600101615cdc565b8060005b600481101561107a578151845260209384019390910190600101615cff565b6101008101615d2d8286615cd8565b615d3a6040830185615cfb565b61326060c0830184615cd8565b608080825284518282018190526000919060209060a0850190828901855b82811015615d8b57615d78848351615cd8565b6040939093019290840190600101615d65565b5050508481038286015286518082528783019183019060005b81811015615dc757615db7838551615cfb565b9284019291850191600101615da4565b5050809450505050506132606040830184615cd8565b600060208284031215615def57600080fd5b815161320281614b15565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156159c057845183529383019391830191600101615e1f565b6001600160401b038281168282160390808211156150e4576150e4614ffd565b606081526000615e6e6060830186614cb3565b60208301949094525060400152919050565b600081615e8f57615e8f614ffd565b506000190190565b60008251615ea98184602087016152cd565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c8bc09fbba0404d1748ce032f33b2c531725d05734c46b60697551ef575283be64736f6c63430008120033

Deployed Bytecode

0x6080604052600436106102565760003560e01c806391a6fe7711610149578063c725a833116100c6578063dcdb7b881161008a578063f2fde38b11610064578063f2fde38b1461090a578063f362ca611461092a578063f4cc97fc1461094a57600080fd5b8063dcdb7b8814610721578063dfaba79414610889578063ef6f42731461089c57600080fd5b8063c725a83314610670578063caba5284146106a1578063d2f9f9a7146106c1578063d7ae1d30146106e1578063d89f241f1461070157600080fd5b8063a39402d71161010d578063a39402d7146105d1578063a47c7696146105f1578063a4c343f214610626578063aa81d59a1461063b578063c4d66de81461065057600080fd5b806391a6fe7714610541578063931d92041461055c5780639f87fad71461057c578063a141bbd81461059c578063a21a23e4146105bc57600080fd5b806352d1902d116101d75780637341c10c1161019b5780637341c10c1461048057806376a911bc146104a05780638166d459146104e2578063877d38bb1461050d5780638da5cb5b1461052357600080fd5b806352d1902d1461040c578063636021741461042157806364d51a2a14610436578063715018a61461044b57806371b7ca051461046057600080fd5b806315c48b841161021e57806315c48b841461032f5780631e58a872146103575780633018205f146103a75780633659cfe6146103d95780634f1ef286146103f957600080fd5b806302bcc5b61461025b578063056e5ede1461027d57806306bfa6371461029d5780630ad98f6a146102d45780631565034c146102f4575b600080fd5b34801561026757600080fd5b5061027b6102763660046147c2565b61096a565b005b34801561028957600080fd5b5061027b61029836600461496a565b6109e1565b3480156102a957600080fd5b5060d7546001600160401b03165b6040516001600160401b0390911681526020015b60405180910390f35b3480156102e057600080fd5b5061027b6102ef3660046149ed565b610a8c565b34801561030057600080fd5b5061032161030f366004614a19565b600090815260d4602052604090205490565b6040519081526020016102cb565b34801561033b57600080fd5b5061034460c881565b60405161ffff90911681526020016102cb565b34801561036357600080fd5b5061038560d85460ff81169161ffff6101008304811692630100000090041690565b60408051931515845261ffff92831660208501529116908201526060016102cb565b3480156103b357600080fd5b5060c9546001600160a01b03165b6040516001600160a01b0390911681526020016102cb565b3480156103e557600080fd5b5061027b6103f4366004614a32565b610aed565b61027b610407366004614abe565b610bd2565b34801561041857600080fd5b50610321610ca2565b34801561042d57600080fd5b5060cf54610321565b34801561044257600080fd5b50610344606481565b34801561045757600080fd5b5061027b610d55565b34801561046c57600080fd5b5061027b61047b366004614b32565b610d69565b34801561048c57600080fd5b5061027b61049b366004614ba7565b610ebd565b3480156104ac57600080fd5b506102b76104bb366004614a32565b6001600160a01b0316600090815260d560205260409020600101546001600160401b031690565b3480156104ee57600080fd5b506104f861232881565b60405163ffffffff90911681526020016102cb565b34801561051957600080fd5b506104f861c35081565b34801561052f57600080fd5b506097546001600160a01b03166103c1565b34801561054d57600080fd5b5060cd5463ffffffff16610321565b34801561056857600080fd5b5061027b610577366004614bde565b611080565b34801561058857600080fd5b5061027b610597366004614ba7565b61135d565b3480156105a857600080fd5b506103216105b7366004614c11565b611693565b3480156105c857600080fd5b506102b76117e6565b3480156105dd57600080fd5b506103216105ec366004614c79565b6118df565b3480156105fd57600080fd5b5061061161060c3660046147c2565b611cfd565b6040516102cb99989796959493929190614cf7565b34801561063257600080fd5b5060ce54610321565b34801561064757600080fd5b506104f8600381565b34801561065c57600080fd5b5061027b61066b366004614a32565b611e1d565b34801561067c57600080fd5b5060ca5460cb5460cc54604080519384526020840192909252908201526060016102cb565b3480156106ad57600080fd5b5061027b6106bc366004614d7a565b611f49565b3480156106cd57600080fd5b506104f86106dc3660046147c2565b612397565b3480156106ed57600080fd5b5061027b6106fc366004614ba7565b612514565b34801561070d57600080fd5b5061027b61071c366004614e38565b612620565b34801561072d57600080fd5b50604080516101208101825260d95463ffffffff8082168084526401000000008304821660208501819052600160401b84048316958501869052600160601b8404831660608601819052600160801b85049093166080860181905262ffffff600160a01b8604811660a08801819052600160b81b8704821660c08901819052600160d01b8804831660e08a01819052600160e81b90980490921661010090980188905260da5460db5460dc54969a95999598949692959394939261ffff83169260ff620100009091041691906040516102cb9d9c9b9a9998979695949392919063ffffffff9d8e1681529b8d1660208d0152998c1660408c0152978b1660608b015295909916608089015262ffffff93841660a089015291831660c0880152821660e08701521661010085015261ffff949094166101208401529215156101408301526101608201929092526101808101919091526101a00190565b61027b6108973660046147c2565b612971565b3480156108a857600080fd5b5060d05460d15460d25460d3546040805161ffff8616815263ffffffff62010000870481166020830152600160381b8704811692820192909252600160581b909504166060850152608084019290925260a083015260c082015260e0016102cb565b34801561091657600080fd5b5061027b610925366004614a32565b612a5d565b34801561093657600080fd5b5061027b610945366004614e8d565b612ad3565b34801561095657600080fd5b5061027b610965366004614ee5565b612b6d565b610972612da7565b6001600160401b038116600090815260d660205260409020546001600160a01b03166109b157604051630fb532db60e11b815260040160405180910390fd5b6001600160401b038116600090815260d660205260409020546109de9082906001600160a01b0316612e01565b50565b6109e9612da7565b60005b8251811015610a8757818181518110610a0757610a07614fe7565b602002602001015160d66000858481518110610a2557610a25614fe7565b60200260200101516001600160401b03166001600160401b0316815260200190815260200160002060060160086101000a8154816001600160401b0302191690836001600160401b031602179055508080610a7f90615013565b9150506109ec565b505050565b60c9546001600160a01b03163314610ab757604051630f5caa3360e41b815260040160405180910390fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610a87573d6000803e3d6000fd5b6001600160a01b037f00000000000000000000000025f9dcf802bdc0cb6955f684cbb94e10ee7e9f4f163003610b3e5760405162461bcd60e51b8152600401610b359061502c565b60405180910390fd5b7f00000000000000000000000025f9dcf802bdc0cb6955f684cbb94e10ee7e9f4f6001600160a01b0316610b87600080516020615eb4833981519152546001600160a01b031690565b6001600160a01b031614610bad5760405162461bcd60e51b8152600401610b3590615078565b610bb681612ed3565b604080516000808252602082019092526109de91839190612edb565b6001600160a01b037f00000000000000000000000025f9dcf802bdc0cb6955f684cbb94e10ee7e9f4f163003610c1a5760405162461bcd60e51b8152600401610b359061502c565b7f00000000000000000000000025f9dcf802bdc0cb6955f684cbb94e10ee7e9f4f6001600160a01b0316610c63600080516020615eb4833981519152546001600160a01b031690565b6001600160a01b031614610c895760405162461bcd60e51b8152600401610b3590615078565b610c9282612ed3565b610c9e82826001612edb565b5050565b6000306001600160a01b037f00000000000000000000000025f9dcf802bdc0cb6955f684cbb94e10ee7e9f4f1614610d425760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610b35565b50600080516020615eb483398151915290565b610d5d612da7565b610d676000613046565b565b610d71612da7565b60c861ffff88161115610dab5760405163539c34bb60e11b815261ffff881660048201819052602482015260c86044820152606401610b35565b604080516101008101825261ffff891680825263ffffffff89811660208085018290526000858701528a83166060808701829052938b16608080880182905260a08089018d905260c0808a018d905260e0998a018c905260d0805465ffffffffffff19168a17620100008902176effffffffffffffffff0000000000001916600160381b87026effffffff0000000000000000000000191617600160581b860217905560d18e905560d28d905560d38c90558a519889529488019590955297860191909152928401929092529382018790529281018590529182018390527fefeb3292465cf72a302efdd83695ad560a2828353a1e018844e9abd19a642037910160405180910390a150505050505050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b031680610eff57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610f3357604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff1615610f5e5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038416600090815260d6602052604090206002015460631901610f9b576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b038316600090815260d5602090815260408083206001600160401b038089168552925282205416900361107a576001600160a01b038316600081815260d5602090815260408083206001600160401b0389168085528184528285208054600167ffffffffffffffff1991821681179092559281018054909316821790925560d68452828520600201805492830181558552938390200180546001600160a01b031916851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e0910160405180910390a25b50505050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b0316806110c257604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146110f657604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff16156111215760405163769dd35360e11b815260040160405180910390fd5b60d85460ff1661114457604051636dac270160e01b815260040160405180910390fd5b6001600160401b03808416600090815260d660205260408082205492871682529020546001600160a01b039182169116036111925760405163027f035560e51b815260040160405180910390fd5b6001600160401b03808516600090815260d66020526040902060060154600160801b900416156111d55760405163cae26ee160e01b815260040160405180910390fd5b6001600160401b03808516600090815260d6602052604090206006015416158061121a57506001600160401b03808416600090815260d6602052604090206006015416155b156112385760405163a760a23760e01b815260040160405180910390fd5b60d8546001600160401b03848116600090815260d660205260409020600601805461010090930461ffff1692909160089161127c918591600160401b9004166150c4565b82546101009290920a6001600160401b0381810219909316918316021790915560d854868216600090815260d6602052604090206006018054630100000090920461ffff169350916008916112da918591600160401b9004166150c4565b82546101009290920a6001600160401b03818102199093169183160217909155858116600081815260d66020526040808220600601805467ffffffffffffffff60801b1916600160801b958a169586021790555192935090917fb661d46b53034f62a6c7d50df2a5e055fab98889aaf62f8c618e457edd96c6889190a350505050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b03168061139f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146113d357604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff16156113fe5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038416600090815260d660205260409020600401541561143857604051631685ecdd60e31b815260040160405180910390fd5b6001600160401b038416600090815260d660209081526040808320600201805482518185028101850190935280835291929091908301828280156114a557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611487575b5050505050905080516000036114e857604051637800cff360e11b81526001600160401b03861660048201526001600160a01b0385166024820152604401610b35565b60005b815181101561165f57846001600160a01b031682828151811061151057611510614fe7565b60200260200101516001600160a01b03160361164d57816001835161153591906150eb565b8151811061154557611545614fe7565b602002602001015160d66000886001600160401b03166001600160401b03168152602001908152602001600020600201828154811061158657611586614fe7565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092556001600160401b038816815260d6909152604090206002018054806115da576115da6150fe565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03871681526001600160401b038816917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a2505061107a565b8061165781615013565b9150506114eb565b50604051637800cff360e11b81526001600160401b03861660048201526001600160a01b0385166024820152604401610b35565b60405163745e0dcf60e01b815263ffffffff821660048201526000908190600290738ffe9b19591b031c7b76a27d1b356ed0a8441b8090638e3976f690829063745e0dcf90602401602060405180830381865af41580156116f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171c9190615114565b6040518263ffffffff1660e01b815260040161173a91815260200190565b602060405180830381865af4158015611757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177b9190615114565b61178690600361512d565b611790919061515a565b905060008161179f898961516e565b6117af9063ffffffff168761512d565b6117b9919061518b565b90506117d063ffffffff871664e8d4a5100061512d565b6117da908261518b565b98975050505050505050565b60d054600090600160301b900460ff16156118145760405163769dd35360e11b815260040160405180910390fd5b60d780546001600160401b031690600061182d8361519e565b82546001600160401b039182166101009390930a92830292820219169190911790915560d780548216600090815260d6602052604080822080546001600160a01b0319163390811790915583548516835281832060060180546fffffffffffffffff00000000000000001916600160401b17905592549051929450909216917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf91a35060d7546001600160401b031690565b60d054600090600160301b900460ff161561190d5760405163769dd35360e11b815260040160405180910390fd5b6000611918836151d3565b905032330361193a57604051638a3150e760e01b815260040160405180910390fd5b6040808201516001600160401b0316600090815260d66020522080546001600160a01b031661197c57604051630fb532db60e11b815260040160405180910390fd5b33600090815260d560209081526040808320858201516001600160401b03908116855292528220541690036119db576040808301519051637800cff360e11b81526001600160401b039091166004820152336024820152604401610b35565b60d054608083015161ffff91821691161080611a03575060c861ffff16826080015161ffff16115b15611a3e57608082015160d05460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610b35565b60d05460a083015163ffffffff62010000909204821691161115611a955760a082015160d054604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610b35565b611a9d613098565b60cd805463ffffffff191663ffffffff9290921691909117905560608201516040808401805133600081815260d5602090815285822094516001600160401b039081168352949052938420549394611af794909316613209565b6040848101805133600090815260d560209081528482206001808201805467ffffffffffffffff19166001600160401b03968716179055945184168352905292832080549495509193919291611b4f918591166150c4565b92506101000a8154816001600160401b0302191690836001600160401b031602179055506000611b7e82613268565b60c95460cd5460405163f49e0ba960e01b815263ffffffff90911660048201529192506000916001600160a01b039091169063f49e0ba9906024016040805180830381865afa158015611bd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf99190615271565b9150506000611c138584848960a001518a60c0015161329a565b60408088015160cd5489516020808c015160808d015160a08e015160c08f01519751989950611c59988c9863ffffffff90971696939433948f949392909143910161531d565b60408051601f198184030181528282528051602091820120600087815260d483528390205560cd54918901518951918a015160808b015160a08c015160c08d015163ffffffff909616966001600160401b03909416958a957fd26299589dd9197a8dc30a0fa17b0fe7dd432bc3441aa5f5631ea1e14c1af74495611ce7959194919333938f93928d906153a8565b60405180910390a450909450505050505b919050565b6001600160401b038116600090815260d660205260408120805460609183918291829182918291829182916001600160a01b0316611d4e57604051630fb532db60e11b815260040160405180910390fd5b80546003820154600483015460068401546007850154600286018054604080516020808402820181019092528281526001600160a01b0390981697929695946001600160401b0380821695600160401b8304821695600160801b8404831695600160c01b9094049092169390928a91830182828015611df657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611dd8575b50505050509750995099509950995099509950995099509950509193959799909294969850565b600054610100900460ff1615808015611e3d5750600054600160ff909116105b80611e575750303b158015611e57575060005460ff166001145b611eba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610b35565b6000805460ff191660011790558015611edd576000805461ff0019166101001790555b60c980546001600160a01b0319166001600160a01b038416179055611f00613420565b8015610c9e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60d054600160301b900460ff1615611f745760405163769dd35360e11b815260040160405180910390fd5b60005a600087815260d46020526040812054919250819003611fa957604051631b44092560e11b815260040160405180910390fd5b86611fb760208701876147c2565b611fc7604088016020890161540f565b611fd76060890160408a0161542c565b611fe460608a018a615447565b611ff460a08c0160808d01614a32565b60a08c013561200960e08e0160c08f01615494565b8d60e001602081019061201c919061540f565b8e61010001358f61012001356040516020016120439c9b9a999897969594939291906154af565b6040516020818303038152906040528051906020012081146120785760405163354a450b60e21b815260040160405180910390fd5b61208860e0860160c08701615494565b61209b9061ffff1661012087013561518b565b4310156120bb5760405163619a4abd60e01b815260040160405180910390fd5b6120cb604086016020870161540f565b63ffffffff168863ffffffff16141580156120f7575060d1546120f39061012087013561518b565b4311155b15612115576040516378373bbd60e11b815260040160405180910390fd5b60c960009054906101000a90046001600160a01b03166001600160a01b03166306545a936040518163ffffffff1660e01b8152600401602060405180830381865afa158015612168573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218c9190615114565b8863ffffffff16106121b957604051637f6efcb560e11b815263ffffffff89166004820152602401610b35565b60006122298963ffffffff168760a001358861012001358a8989808060200260200160405190810160405280939291908181526020016000905b8282101561221f5761221060408302860136819003810190615557565b815260200190600101906121f3565b505050505061344f565b600089815260d46020908152604080832083905580518083018c9052815180820384018152908201909152805191012060cf805493945090926001929061227190849061518b565b909155505060ce81905560c9546040516379ef840160e11b8152600481018390526001600160a01b039091169063f3df080290602401600060405180830381600087803b1580156122c157600080fd5b505af11580156122d5573d6000803e3d6000fd5b5050505060006122ef8a838a6122ea90615589565b613b3a565b905060008061232860d68261230760208e018e6147c2565b6001600160401b0316815260208101919091526040016000208d8a8a613dd5565b9150915061233785838361408e565b336001600160a01b03168d63ffffffff168d7f6fc1bcb4bd7d5fdf4017f746304b61ae4472496256e906c6bb44682aa2c9a6d8888887878a604051612380959493929190615656565b60405180910390a450505050505050505050505050565b604080516101208101825260d95463ffffffff8082168352640100000000820481166020840152600160401b8204811693830193909352600160601b810483166060830152600160801b8104909216608082015262ffffff600160a01b8304811660a08301819052600160b81b8404821660c0840152600160d01b8404821660e0840152600160e81b909304166101008201526000916001600160401b03841611612443575192915050565b826001600160401b03168160a0015162ffffff1610801561247657508060c0015162ffffff16836001600160401b031611155b15612485576020015192915050565b826001600160401b03168160c0015162ffffff161080156124b857508060e0015162ffffff16836001600160401b031611155b156124c7576040015192915050565b826001600160401b03168160e0015162ffffff161080156124fb575080610100015162ffffff16836001600160401b031611155b1561250a576060015192915050565b6080015192915050565b6001600160401b038216600090815260d6602052604090205482906001600160a01b03168061255657604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461258a57604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b60d054600160301b900460ff16156125b55760405163769dd35360e11b815260040160405180910390fd5b6001600160a01b0383166125dc5760405163f6b2911f60e01b815260040160405180910390fd5b6001600160401b038416600090815260d660205260409020600401541561261657604051631685ecdd60e31b815260040160405180910390fd5b61107a8484612e01565b61262d60208201826147c2565b6001600160401b038116600090815260d660205260409020546001600160a01b03168061266d57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146126a157604051636c51fda960e11b81526001600160a01b0382166004820152602401610b35565b600084815260d4602052604081205490036126cf57604051631b44092560e11b815260040160405180910390fd5b836126dd60208501856147c2565b6126ed604086016020870161540f565b6126fd606087016040880161542c565b61270a6060880188615447565b61271a60a08a0160808b01614a32565b60a08a013561272f60e08c0160c08d01615494565b6127406101008d0160e08e0161540f565b8c61010001358d61012001356040516020016127679c9b9a999897969594939291906154af565b60408051601f198184030181529181528151602092830120600087815260d4909352912054146127aa5760405163354a450b60e21b815260040160405180910390fd5b6000738ffe9b19591b031c7b76a27d1b356ed0a8441b806387ceff096040518163ffffffff1660e01b8152600401602060405180830381865af41580156127f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128199190615114565b612826906201518061515a565b90506128378161012086013561518b565b43101561285757604051636c804b5d60e01b815260040160405180910390fd5b600085815260d460209081526040822082905560d6919061287a908701876147c2565b6001600160401b03168152602080820192909252604090810160009081208882526005018352908120549160d691906128b5908801886147c2565b6001600160401b03166001600160401b0316815260200190815260200160002060040160008282546128e791906150eb565b9091555060d6905060006128fe60208701876147c2565b6001600160401b0316815260208082019290925260409081016000908120888252600501835290812055612934908501856147c2565b6001600160401b0316857fc1cf1d318384ee8dee53eed48bbf121b2b14fa61e9da5fd2f597dfbee4e5c2e660405160405180910390a35050505050565b60d054600160301b900460ff161561299c5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038116600090815260d660205260409020546001600160a01b03166129db57604051630fb532db60e11b815260040160405180910390fd5b6001600160401b038116600090815260d660205260408120600301805491349190612a06838561518b565b90915550506001600160401b0382167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882612a41348261518b565b6040805192835260208301919091520160405180910390a25050565b612a65612da7565b6001600160a01b038116612aca5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b35565b6109de81613046565b612adb612da7565b604080516060808201835285151580835261ffff868116602080860182905291871694860185905260d8805462ffffff191662ffff001985161761010083021764ffff000000191663010000008702179055855192835290820152928301919091527faf8d657c268b3f943977d5288bfb2306420bcb17b7ef17397cffa5d2f4891643910160405180910390a1505050565b612b75612da7565b6040518060a001604052808681526020018561ffff16815260200184151581526020018381526020018281525060d960008201518160000160008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160146101000a81548162ffffff021916908362ffffff16021790555060c08201518160000160176101000a81548162ffffff021916908362ffffff16021790555060e082015181600001601a6101000a81548162ffffff021916908362ffffff16021790555061010082015181600001601d6101000a81548162ffffff021916908362ffffff160217905550505060208201518160010160006101000a81548161ffff021916908361ffff16021790555060408201518160010160026101000a81548160ff02191690831515021790555060608201518160020155608082015181600301559050507f1851d8853c0ab5ed26d95d456344506f759953621e7c115677f2244696b8ba978585858585604051612d9895949392919061568f565b60405180910390a15050505050565b6097546001600160a01b03163314610d675760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b35565b60d054600160301b900460ff1615612e2c5760405163769dd35360e11b815260040160405180910390fd5b6001600160401b038216600081815260d66020908152604091829020600381015481546001600160a01b03191690915582516001600160a01b038616815291820181905292917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a26040516001600160a01b0383169082156108fc029083906000818181858888f1935050505015801561107a573d6000803e3d6000fd5b6109de612da7565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612f0e57610a8783614206565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612f68575060408051601f3d908101601f19168201909252612f6591810190615114565b60015b612fcb5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610b35565b600080516020615eb4833981519152811461303a5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610b35565b50610a878383836142a2565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008060c960009054906101000a90046001600160a01b03166001600160a01b031663b330a0fd6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156130ee573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131169190810190615751565b9050805160000361313a57604051636905ab6760e01b815260040160405180910390fd5b60c954604080516306545a9360e01b815290516000926001600160a01b0316916306545a939160048083019260209291908290030181865afa158015613184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a89190615114565b60cd5490915060009082906131c49063ffffffff16600161516e565b63ffffffff166131d491906157e1565b90505b6131e183826142c7565b61320257816131f182600161518b565b6131fb91906157e1565b90506131d7565b9392505050565b604080514660208201529081018590526001600160401b03841660608201526001600160a01b038316608082015260a0810182905260009060c0016040516020818303038152906040528051906020012060001c90505b949350505050565b60008160405160200161327d91815260200190565b604051602081830303815290604052805190602001209050919050565b60da54600090819062010000900460ff16156132c4575060068601546001600160401b0316613316565b60db5442108015906132d8575060dc544211155b156133165760db54600788015410156132f357506001613316565b600687015461331390600160c01b90046001600160401b031660016150c4565b90505b60006133b2856133276003896157f5565b6133339061c350615812565b61333f89612328615812565b60d0546133599190600160581b900463ffffffff1661516e565b613363919061516e565b60068b0154600160401b90046001600160401b03166133a85760da5460649061ffff1661338f87612397565b6133999190615812565b6133a3919061583a565b6133ab565b60005b878a611693565b905080886004015489600301546133c991906150eb565b10156133e85760405163444a5eaf60e11b815260040160405180910390fd5b808860040160008282546133fc919061518b565b90915550506000878152600589016020526040902081905591505095945050505050565b600054610100900460ff166134475760405162461bcd60e51b8152600401610b359061585d565b610d6761431c565b60405162f577a560e81b8152600481018390526060907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca89063f577a50090602401602060405180830381865af41580156134a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c591906158b3565b6134e257604051638529df1f60e01b815260040160405180910390fd5b815160000361350457604051638bdcc37560e01b815260040160405180910390fd5b60c9546040516333ad819560e21b8152600481018890526000916001600160a01b03169063ceb6065490602401600060405180830381865afa15801561354e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135769190810190615b60565b90506135868160a001513361434c565b6135a35760405163d9ce719d60e01b815260040160405180910390fd5b60408051602081018890528082018790528151808203830181526060820192839052633033cc5160e01b9092526000907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890633033cc51906135fd908590606401615c65565b6040805180830381865af4158015613619573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061363d9190615c78565b90507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca863ebbdac917334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca86313bc64ee896040518263ffffffff1660e01b815260040161369291815260200190565b6040805180830381865af41580156136ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d29190615c78565b856101000151846040518463ffffffff1660e01b81526004016136f793929190615d1e565b602060405180830381865af4158015613714573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373891906158b3565b61375557604051638baa579f60e01b815260040160405180910390fd5b600085516001600160401b03811115613770576137706147dd565b6040519080825280602002602001820160405280156137a957816020015b61379661476f565b81526020019060019003908161378e5790505b509050600086516001600160401b038111156137c7576137c76147dd565b60405190808252806020026020018201604052801561380057816020015b6137ed61478d565b8152602001906001900390816137e55790505b50905086516001600160401b0381111561381c5761381c6147dd565b604051908082528060200260200182016040528015613845578160200160208202803683370190505b50955060005b8751811015613a92577334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca863f577a50089838151811061388057613880614fe7565b6020026020010151602001516040518263ffffffff1660e01b81526004016138aa91815260200190565b602060405180830381865af41580156138c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138eb91906158b3565b61390857604051636b849b7d60e11b815260040160405180910390fd5b7334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca86313bc64ee89838151811061393457613934614fe7565b6020026020010151602001516040518263ffffffff1660e01b815260040161395e91815260200190565b6040805180830381865af415801561397a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399e9190615c78565b8382815181106139b0576139b0614fe7565b602002602001018190525085608001518882815181106139d2576139d2614fe7565b602002602001015160000151815181106139ee576139ee614fe7565b602002602001015160200151828281518110613a0c57613a0c614fe7565b60200260200101819052508560800151888281518110613a2e57613a2e614fe7565b60200260200101516000015181518110613a4a57613a4a614fe7565b602002602001015160000151878281518110613a6857613a68614fe7565b6001600160a01b039092166020928302919091019091015280613a8a81615013565b91505061384b565b50604051630d6870d760e21b81527334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8906335a1c35c90613ace90859085908890600401615d47565b602060405180830381865af4158015613aeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0f91906158b3565b613b2c57604051639c2d1c6d60e01b815260040160405180910390fd5b505050505095945050505050565b60008060608184604001516002811115613b5657613b56615295565b03613ba05750604080516024810187905260448082018790528251808303909101815260649091019091526020810180516001600160e01b03166394985ddd60e01b179052613d8a565b600184604001516002811115613bb857613bb8615295565b03613ceb5760008460600151806020019051810190613bd79190615ddd565b905060008163ffffffff166001600160401b03811115613bf957613bf96147dd565b604051908082528060200260200182016040528015613c22578160200160208202803683370190505b50905060005b8263ffffffff16811015613c925760408051602081018a90529081018290526060016040516020818303038152906040528051906020012060001c828281518110613c7557613c75614fe7565b602090810291909101015280613c8a81615013565b915050613c28565b506040516375bf929b60e01b90613caf908a908490602401615dfa565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091529250613d8a915050565b600284604001516002811115613d0357613d03615295565b03613d8a5760008460600151806020019051810190613d229190615ddd565b90506000613d368263ffffffff16886143a7565b9050639e5836f660e01b8882604051602401613d53929190615dfa565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152925050505b60d0805466ff0000000000001916600160301b17905560e08401516080850151613dbb9163ffffffff169083614502565b60d0805466ff000000000000191690559695505050505050565b6006840180546000918291600191908390613dfa9084906001600160401b03166150c4565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550600060d960010160029054906101000a900460ff1615613e4c575060068601546001600160401b0316613f03565b60db544210801590613e60575060dc544211155b15613f035760db5460078801541015613ea05760068701805477ffffffffffffffffffffffffffffffffffffffffffffffff16600160c01b179055613eec565b60018760060160188282829054906101000a90046001600160401b0316613ec791906150c4565b92506101000a8154816001600160401b0302191690836001600160401b031602179055505b506006860154600160c01b90046001600160401b03165b4260078801556006870154600090600160401b90046001600160401b031615613f765760018860060160088282829054906101000a90046001600160401b0316613f4d9190615e3b565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550613fb5565b60da5460649061ffff16613f8984612397565b613f9e9063ffffffff1664e8d4a5100061512d565b613fa8919061512d565b613fb2919061515a565b90505b6000613fe886613fc78961232861512d565b60d054613fe19190600160381b900463ffffffff1661518b565b843a61454e565b9050808960030154101561400f5760405163964d765f60e01b815260040160405180910390fd5b600088815260058a01602052604081205460048b018054919290916140359084906150eb565b9091555050600088815260058a016020526040812081905560038a0180548392906140619084906150eb565b925050819055508160ca600082825461407a919061518b565b909155509099919850909650505050505050565b60d35460cb80546000906140a390849061518b565b9091555050825160d2546140b7919061512d565b60cc60008282546140c8919061518b565b909155505060408051600180825281830190925260009160208083019080368337019050509050338160008151811061410357614103614fe7565b6001600160a01b03928316602091820292909201015260c9541663914eb34d8261412d85876150eb565b60d3546040516001600160e01b031960e086901b16815261415393929190600401615e5b565b600060405180830381600087803b15801561416d57600080fd5b505af1158015614181573d6000803e3d6000fd5b505060c95486516001600160a01b03909116925063914eb34d915086906141a8908661515a565b60d2546040516001600160e01b031960e086901b1681526141ce93929190600401615e5b565b600060405180830381600087803b1580156141e857600080fd5b505af11580156141fc573d6000803e3d6000fd5b5050505050505050565b6001600160a01b0381163b6142735760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610b35565b600080516020615eb483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6142ab836145fd565b6000825111806142b85750805b15610a875761107a838361463d565b6000805b835181101561431057828482815181106142e7576142e7614fe7565b6020026020010151036142fe576001915050614316565b8061430881615013565b9150506142cb565b50600090505b92915050565b600054610100900460ff166143435760405162461bcd60e51b8152600401610b359061585d565b610d6733613046565b6000805b835181101561431057826001600160a01b031684828151811061437557614375614fe7565b60200260200101516001600160a01b031603614395576001915050614316565b8061439f81615013565b915050614350565b60606000836001600160401b038111156143c3576143c36147dd565b6040519080825280602002602001820160405280156143ec578160200160208202803683370190505b50905060005b8481101561442a578082828151811061440d5761440d614fe7565b60209081029190910101528061442281615013565b9150506143f2565b5080516000805b600061443c84615e80565b93508311156144f75761444f83876157e1565b91508560405160200161446491815260200190565b6040516020818303038152906040528051906020012060001c955083838151811061449157614491614fe7565b602002602001015190508382815181106144ad576144ad614fe7565b60200260200101518484815181106144c7576144c7614fe7565b602002602001018181525050808483815181106144e6576144e6614fe7565b602002602001018181525050614431565b509195945050505050565b60005a61138881101561451457600080fd5b61138881039050846040820482031161452c57600080fd5b50823b61453857600080fd5b60008083516020850160008789f1949350505050565b600080738ffe9b19591b031c7b76a27d1b356ed0a8441b8063c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865af415801561459a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145be9190615114565b5a6145c9888861518b565b6145d391906150eb565b6145dd908561512d565b6145e7919061518b565b90506145f3848261518b565b9695505050505050565b61460681614206565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6146a55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b35565b600080846001600160a01b0316846040516146c09190615e97565b600060405180830381855af49150503d80600081146146fb576040519150601f19603f3d011682016040523d82523d6000602084013e614700565b606091505b50915091506147288282604051806060016040528060278152602001615ed460279139614731565b95945050505050565b60608315614740575081613202565b61320283838151156147555781518083602001fd5b8060405162461bcd60e51b8152600401610b359190615c65565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b80356001600160401b0381168114611cf857600080fd5b6000602082840312156147d457600080fd5b613202826147ab565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614816576148166147dd565b60405290565b60405160e081016001600160401b0381118282101715614816576148166147dd565b604080519081016001600160401b0381118282101715614816576148166147dd565b60405161014081016001600160401b0381118282101715614816576148166147dd565b604051606081016001600160401b0381118282101715614816576148166147dd565b604051601f8201601f191681016001600160401b03811182821017156148cd576148cd6147dd565b604052919050565b60006001600160401b038211156148ee576148ee6147dd565b5060051b60200190565b600082601f83011261490957600080fd5b8135602061491e614919836148d5565b6148a5565b82815260059290921b8401810191818101908684111561493d57600080fd5b8286015b8481101561495f57614952816147ab565b8352918301918301614941565b509695505050505050565b6000806040838503121561497d57600080fd5b82356001600160401b038082111561499457600080fd5b6149a0868387016148f8565b935060208501359150808211156149b657600080fd5b506149c3858286016148f8565b9150509250929050565b6001600160a01b03811681146109de57600080fd5b8035611cf8816149cd565b60008060408385031215614a0057600080fd5b8235614a0b816149cd565b946020939093013593505050565b600060208284031215614a2b57600080fd5b5035919050565b600060208284031215614a4457600080fd5b8135613202816149cd565b600082601f830112614a6057600080fd5b81356001600160401b03811115614a7957614a796147dd565b614a8c601f8201601f19166020016148a5565b818152846020838601011115614aa157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614ad157600080fd5b8235614adc816149cd565b915060208301356001600160401b03811115614af757600080fd5b6149c385828601614a4f565b803561ffff81168114611cf857600080fd5b63ffffffff811681146109de57600080fd5b8035611cf881614b15565b600080600080600080600060e0888a031215614b4d57600080fd5b614b5688614b03565b96506020880135614b6681614b15565b95506040880135614b7681614b15565b94506060880135614b8681614b15565b9699959850939660808101359560a0820135955060c0909101359350915050565b60008060408385031215614bba57600080fd5b614bc3836147ab565b91506020830135614bd3816149cd565b809150509250929050565b60008060408385031215614bf157600080fd5b614bfa836147ab565b9150614c08602084016147ab565b90509250929050565b600080600080600060a08688031215614c2957600080fd5b8535614c3481614b15565b94506020860135614c4481614b15565b93506040860135614c5481614b15565b9250606086013591506080860135614c6b81614b15565b809150509295509295909350565b600060208284031215614c8b57600080fd5b81356001600160401b03811115614ca157600080fd5b820160e0818503121561320257600080fd5b600081518084526020808501945080840160005b83811015614cec5781516001600160a01b031687529582019590820190600101614cc7565b509495945050505050565b60006101206001600160a01b038c168352806020840152614d1a8184018c614cb3565b604084019a909a52505060608101969096526001600160401b03948516608087015292841660a086015290831660c085015290911660e08301526101009091015292915050565b60006101408284031215614d7457600080fd5b50919050565b60008060008060008060a08789031215614d9357600080fd5b8635614d9e81614b15565b9550602087013594506040870135935060608701356001600160401b0380821115614dc857600080fd5b614dd48a838b01614d61565b94506080890135915080821115614dea57600080fd5b818901915089601f830112614dfe57600080fd5b813581811115614e0d57600080fd5b8a60208260061b8501011115614e2257600080fd5b6020830194508093505050509295509295509295565b60008060408385031215614e4b57600080fd5b8235915060208301356001600160401b03811115614e6857600080fd5b6149c385828601614d61565b80151581146109de57600080fd5b8035611cf881614e74565b600080600060608486031215614ea257600080fd5b8335614ead81614e74565b9250614ebb60208501614b03565b9150614ec960408501614b03565b90509250925092565b803562ffffff81168114611cf857600080fd5b60008060008060008587036101a0811215614eff57600080fd5b61012080821215614f0f57600080fd5b614f176147f3565b9150614f2288614b27565b8252614f3060208901614b27565b6020830152614f4160408901614b27565b6040830152614f5260608901614b27565b6060830152614f6360808901614b27565b6080830152614f7460a08901614ed2565b60a0830152614f8560c08901614ed2565b60c0830152614f9660e08901614ed2565b60e0830152610100614fa9818a01614ed2565b8184015250819650614fbc818901614b03565b95505050614fcd6101408701614e82565b949793965093946101608101359450610180013592915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161502557615025614ffd565b5060010190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6001600160401b038181168382160190808211156150e4576150e4614ffd565b5092915050565b8181038181111561431657614316614ffd565b634e487b7160e01b600052603160045260246000fd5b60006020828403121561512657600080fd5b5051919050565b808202811582820484141761431657614316614ffd565b634e487b7160e01b600052601260045260246000fd5b60008261516957615169615144565b500490565b63ffffffff8181168382160190808211156150e4576150e4614ffd565b8082018082111561431657614316614ffd565b60006001600160401b038083168181036151ba576151ba614ffd565b6001019392505050565b803560038110611cf857600080fd5b600060e082360312156151e557600080fd5b6151ed61481c565b6151f6836151c4565b815260208301356001600160401b0381111561521157600080fd5b61521d36828601614a4f565b60208301525061522f604084016147ab565b60408201526060830135606082015261524a60808401614b03565b608082015261525b60a08401614b27565b60a082015260c092830135928101929092525090565b6000806040838503121561528457600080fd5b505080516020909101519092909150565b634e487b7160e01b600052602160045260246000fd5b600381106152c957634e487b7160e01b600052602160045260246000fd5b9052565b60005b838110156152e85781810151838201526020016152d0565b50506000910152565b600081518084526153098160208601602086016152cd565b601f01601f19169290920160200192915050565b60006101608d83526001600160401b038d16602084015263ffffffff808d16604085015261534e606085018d6152ab565b8160808501526153608285018c6152f1565b6001600160a01b039a909a1660a085015260c0840198909852505061ffff9490941660e085015291909316610100830152610120820192909252610140015295945050505050565b60006101006153b7838c6152ab565b8060208401526153c98184018b6152f1565b6001600160a01b039990991660408401525050606081019590955261ffff93909316608085015263ffffffff9190911660a084015260c083015260e09091015292915050565b60006020828403121561542157600080fd5b813561320281614b15565b60006020828403121561543e57600080fd5b613202826151c4565b6000808335601e1984360301811261545e57600080fd5b8301803591506001600160401b0382111561547857600080fd5b60200191503681900382131561548d57600080fd5b9250929050565b6000602082840312156154a657600080fd5b61320282614b03565b60006101608e83526001600160401b038e16602084015263ffffffff8d1660408401526154df606084018d6152ab565b806080840152898184015250610180898b8285013760008a84018201526001600160a01b03891660a0840152601f19601f8b011683010190508660c083015261552e60e083018761ffff169052565b63ffffffff851661010083015261012082019390935261014001529a9950505050505050505050565b60006040828403121561556957600080fd5b61557161483e565b82358152602083013560208201528091505092915050565b6000610140823603121561559c57600080fd5b6155a4614860565b6155ad836147ab565b81526155bb60208401614b27565b60208201526155cc604084016151c4565b604082015260608301356001600160401b038111156155ea57600080fd5b6155f636828601614a4f565b606083015250615608608084016149e2565b608082015260a083013560a082015261562360c08401614b03565b60c082015261563460e08401614b27565b60e0820152610100838101359082015261012092830135928101929092525090565b60a08152600061566960a0830188614cb3565b905085602083015284604083015283606083015282151560808301529695505050505050565b855163ffffffff9081168252602080880151821690830152604080880151821690830152606080880151821690830152608080880151918216908301526101a08201905060a08701516156e960a084018262ffffff169052565b5060c087015161570060c084018262ffffff169052565b5060e087015161571760e084018262ffffff169052565b506101009687015162ffffff169682019690965261ffff949094166101208501529115156101408401526101608301526101809091015290565b6000602080838503121561576457600080fd5b82516001600160401b0381111561577a57600080fd5b8301601f8101851361578b57600080fd5b8051615799614919826148d5565b81815260059190911b820183019083810190878311156157b857600080fd5b928401925b828410156157d6578351825292840192908401906157bd565b979650505050505050565b6000826157f0576157f0615144565b500690565b63ffffffff8281168282160390808211156150e4576150e4614ffd565b63ffffffff81811683821602808216919082811461583257615832614ffd565b505092915050565b600063ffffffff8084168061585157615851615144565b92169190910492915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b8051611cf881614e74565b6000602082840312156158c557600080fd5b815161320281614e74565b600082601f8301126158e157600080fd5b604051608081018181106001600160401b0382111715615903576159036147dd565b60405280608084018581111561591857600080fd5b845b818110156144f757805183526020928301920161591a565b600082601f83011261594357600080fd5b81516020615953614919836148d5565b82815260a0928302850182019282820191908785111561597257600080fd5b8387015b858110156159c05781818a03121561598e5760008081fd5b61599661483e565b81516159a1816149cd565b81526159af8a8388016158d0565b818701528452928401928101615976565b5090979650505050505050565b600082601f8301126159de57600080fd5b815160206159ee614919836148d5565b82815260059290921b84018101918181019086841115615a0d57600080fd5b8286015b8481101561495f578051615a24816149cd565b8352918301918301615a11565b600082601f830112615a4257600080fd5b81516020615a52614919836148d5565b82815260059290921b84018101918181019086841115615a7157600080fd5b8286015b8481101561495f5780516001600160401b0380821115615a9457600080fd5b908801906040601f19838c038101821315615aae57600080fd5b615ab661483e565b8885015184811115615ac757600080fd5b615ad58e8b838901016159cd565b8252508285015184811115615ae957600080fd5b949094019360c0858e0383011215615b015760008081fd5b615b09614883565b9150888501518252615b1d8d8487016158d0565b8983015260c085015184811115615b345760008081fd5b615b428e8b838901016159cd565b93830193909352808901919091528652505050918301918301615a75565b600060208284031215615b7257600080fd5b81516001600160401b0380821115615b8957600080fd5b908301906101808286031215615b9e57600080fd5b615ba66147f3565b82518152602083015160208201526040830151604082015260608301516060820152608083015182811115615bda57600080fd5b615be687828601615932565b60808301525060a083015182811115615bfe57600080fd5b615c0a878286016159cd565b60a08301525060c083015182811115615c2257600080fd5b615c2e87828601615a31565b60c083015250615c4060e084016158a8565b60e08201526101009150615c56868385016158d0565b91810191909152949350505050565b60208152600061320260208301846152f1565b600060408284031215615c8a57600080fd5b82601f830112615c9957600080fd5b615ca161483e565b806040840185811115615cb357600080fd5b845b81811015615ccd578051845260209384019301615cb5565b509095945050505050565b8060005b600281101561107a578151845260209384019390910190600101615cdc565b8060005b600481101561107a578151845260209384019390910190600101615cff565b6101008101615d2d8286615cd8565b615d3a6040830185615cfb565b61326060c0830184615cd8565b608080825284518282018190526000919060209060a0850190828901855b82811015615d8b57615d78848351615cd8565b6040939093019290840190600101615d65565b5050508481038286015286518082528783019183019060005b81811015615dc757615db7838551615cfb565b9284019291850191600101615da4565b5050809450505050506132606040830184615cd8565b600060208284031215615def57600080fd5b815161320281614b15565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156159c057845183529383019391830191600101615e1f565b6001600160401b038281168282160390808211156150e4576150e4614ffd565b606081526000615e6e6060830186614cb3565b60208301949094525060400152919050565b600081615e8f57615e8f614ffd565b506000190190565b60008251615ea98184602087016152cd565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c8bc09fbba0404d1748ce032f33b2c531725d05734c46b60697551ef575283be64736f6c63430008120033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.