Sepolia Testnet

Contract

0x8D88c1EB48e8549bEac11B696944599DB7B60520
Transaction Hash
Method
Block
From
To
Claim For New Me...71513342024-11-25 18:26:36119 days ago1732559196IN
0x8D88c1EB...DB7B60520
0 ETH0.0048396116.17221191
Claim For New Me...71513082024-11-25 18:21:00119 days ago1732558860IN
0x8D88c1EB...DB7B60520
0 ETH0.0019658318.18416398
Set New Campaign71511952024-11-25 17:56:36119 days ago1732557396IN
0x8D88c1EB...DB7B60520
0 ETH0.0040533311.22783249

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CometRewardsV2

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 10 : CometRewardsV2.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometInterface.sol";
import "./IERC20NonStandard.sol";
import "./MerkleProof.sol";

/**
 * @title Compound's CometRewards Contract
 * @notice Hold and claim token rewards
 * @author Compound
 */

contract CometRewardsV2 {
    /**
     * @notice struct for token multiplier
     * @param token The token address
     * @param multiplier The multiplier for the token
     */
    struct TokenMultiplier {
        address token;
        uint256 multiplier;
    }

    /**
     * @notice The configuration for a reward token
     * @param multiplier The multiplier for the token
     * @param rescaleFactor The rescale factor for the token
     * @dev rescaleFactor = baseAccrualScale / tokenDecimals,
     *      so for example if baseAccrualScale = 1e18 and tokenDecimals = 1e6, rescaleFactor = 1e12
     * @param shouldUpscale Whether or not to upscale the token
     * @dev If the baseAccrualScale is greater than the tokenDecimals, we should upscale the token
     */
    struct AssetConfig {
        uint256 multiplier;
        uint128 rescaleFactor;
        bool shouldUpscale;
    }

    /**
     * @notice The configuration for a campaign
     * @param startRoot The root of the Merkle tree for the startAccrued
     * @param finishRoot The root of the Merkle tree for the finishAccrued
     * @param assets The reward tokens addresses
     * @param configs The reward tokens configurations
     * @param claimed The claimed rewards for each user
     * @param finishTimestamp The timestamp when the campaign ends
     */
    struct Campaign {
        bytes32 startRoot;
        bytes32 finishRoot;
        address[] assets;
        /// @dev token => AssetConfig
        mapping(address => AssetConfig)configs;
        /// @dev user => token => claimed
        mapping(address => mapping(address => uint256)) claimed;
        uint256 finishTimestamp;        
    }

    /**
     * @notice The reward owed to an account
     * @param token The reward token address
     * @param owed The amount of the reward token owed
     */
    struct RewardOwed {
        address token;
        uint256 owed;
    }

    /**
     * @notice The proof for a user in the start tree
     * @param startIndex The index of the user in the start tree
     * @param finishIndex The index of the user in the finish tree
     * @param startAccrued The accrued value for the user in the start tree
     * @param finishAccrued The accrued value for the user in the finish tree
     * @param startMerkleProof The Merkle proof for the start tree
     * @param finishMerkleProof The Merkle proof for the finish tree
     */
    struct Proofs {
        uint256 startIndex;
        uint256 finishIndex;
        uint256 startAccrued;
        uint256 finishAccrued;
        bytes32[] startMerkleProof;
        bytes32[] finishMerkleProof;
    }

    /**
     * @notice The proof for 2 users
     * @param proofs The proofs for each user
     */
    struct MultiProofs{
        Proofs[2] proofs;
    }

    /**
     * @notice The proof for a user in the finish tree
     * @param finishIndex The index of the user in the finish tree
     * @param finishAccrued The accrued value for the user in the finish tree
     * @param finishMerkleProof The Merkle proof for the finish tree
     */
    struct FinishProof{
        uint256 finishIndex;
        uint256 finishAccrued;
        bytes32[] finishMerkleProof;
    }

    /// @notice The governor address which controls the contract
    address public governor;
    /// @notice Campaigns per Comet instance
    /// @dev comet => Campaign[]
    mapping(address => Campaign[]) public campaigns;

    /// @notice The maximum duration for a campaign
    uint256 public constant MAX_CAMPAIGN_DURATION = 180 days;

    /// @dev The scale for factors
    uint256 internal constant FACTOR_SCALE = 1e18;

    /** Custom events **/

    event GovernorTransferred(
        address indexed oldGovernor,
        address indexed newGovernor
    );

    event RewardsClaimedSet(
        uint256 campaignId,
        address indexed user,
        address indexed comet,
        address indexed token,
        uint256 amount
    );

    event RewardClaimed(
        uint256 campaignId,
        address indexed comet,
        address indexed src,
        address indexed recipient,
        address token,
        uint256 amount
    );

    event ConfigUpdated(
        uint256 campaignId,
        address indexed comet,
        address indexed token,
        uint256 multiplier
    );

    event NewCampaign(
        address comet,
        uint256 campaignId
    );

    event NewCampaignFinishRoot(
        address comet,
        bytes32 finishRoot,
        uint256 campaignId
    );

    event TokenWithdrawn(
        address indexed token,
        address indexed to,
        uint256 amount
    );

    event TransferOutFailed(
        address indexed token,
        address indexed to,
        uint256 amount
    );

    /** Custom errors **/

    error BadData();
    error InvalidUint128(uint256);
    error NotPermitted(address);
    error NotSupported(address, address);
    error NullGovernor();
    error InvalidProof();
    error NotANewMember(address);
    error CampaignEnded(address, uint256);

    /**
     * @notice Construct a new rewards pool
     * @param governor_ The governor who will control the contract
     */
    constructor(address governor_) {
        if(governor_ == address(0)) revert NullGovernor();
        governor = governor_;
    }

    /**
     * @notice Adds a new campaign to a Comet with custom multipliers for each token
     * @param comet Comet protocol address
     * @param startRoot The root of the Merkle tree for the startAccrued
     * @param assets Reward tokens addresses
     * @param duration The duration of the campaign
     * @return campaignId Id of the created campaign
     */
    function setNewCampaignWithCustomTokenMultiplier(
        address comet,
        bytes32 startRoot,
        TokenMultiplier[] memory assets,
        uint256 duration
    ) public returns(uint256 campaignId) {
        if(msg.sender != governor) revert NotPermitted(msg.sender);
        if(startRoot == bytes32(0)) revert BadData();
        if(assets.length == 0) revert BadData();
        if(duration > MAX_CAMPAIGN_DURATION) revert BadData();

        uint64 accrualScale = CometInterface(comet).baseAccrualScale();
        Campaign storage $ = campaigns[comet].push();
        campaignId = campaigns[comet].length - 1;
        $.startRoot = startRoot;
        for (uint256 i = 0; i < assets.length; i++) {
            if(assets[i].multiplier == 0) revert BadData();
            uint128 tokenScale = safe128(10 ** IERC20NonStandard(assets[i].token).decimals());

            emit ConfigUpdated(campaignId, comet, assets[i].token, assets[i].multiplier);

            if(accrualScale > tokenScale) {
                $.configs[assets[i].token] = AssetConfig({
                    multiplier: assets[i].multiplier,
                    rescaleFactor: accrualScale / tokenScale,
                    shouldUpscale: false
                });
            } else {
                $.configs[assets[i].token] = AssetConfig({
                    multiplier: assets[i].multiplier,
                    rescaleFactor: tokenScale / accrualScale,
                    shouldUpscale: true
                });
            }

            $.assets.push(assets[i].token);
        }
        $.finishTimestamp = block.timestamp + duration;

        emit NewCampaign(
            comet,
            campaignId
        );

        return(campaignId);
    }

    /**
     * @notice Adds a new campaign to a Comet
     * @param comet The protocol instance
     * @param startRoot The root of the Merkle tree for the startAccrued
     * @param tokens The reward tokens addresses
     * @return campaignId Id of the created campaign
     */
    function setNewCampaign(
        address comet,
        bytes32 startRoot,
        address[] calldata tokens,
        uint256 duration
    ) external returns(uint256 campaignId) {
        TokenMultiplier[] memory assets = new TokenMultiplier[](tokens.length);
        for (uint256 i = 0; i < tokens.length; i++) {
            assets[i] = TokenMultiplier({token: tokens[i], multiplier: FACTOR_SCALE});
        }
        return setNewCampaignWithCustomTokenMultiplier(comet, startRoot, assets, duration);
    }

    /**
     * @notice Set the reward token for a Comet instance for multiple users
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param users The list of users to populate the data for
     * @param tokens The list of tokens to populate the data with
     * @param claimedAmounts The list of amounts to populate the data with
     */
    function setRewardsClaimed(
        address comet,
        uint256 campaignId,
        address[] calldata users,
        address[][] calldata tokens,
        uint256[][] calldata claimedAmounts
    ) external {
        if(msg.sender != governor) revert NotPermitted(msg.sender);
        if(users.length != claimedAmounts.length) revert BadData();
        if(tokens.length != claimedAmounts.length) revert BadData();

        Campaign storage $ = campaigns[comet][campaignId];

        for (uint256 i = 0; i < claimedAmounts.length; i++) {
            if($.assets.length != claimedAmounts[i].length) revert BadData();
            if($.assets.length != tokens[i].length) revert BadData();
            for(uint256 j = 0; j < claimedAmounts[i].length; j++){
                emit RewardsClaimedSet(campaignId, users[i], comet, tokens[i][j], claimedAmounts[i][j]);
                $.claimed[users[i]][tokens[i][j]] = claimedAmounts[i][j];
            }
        }
    }

    /**
     * @notice Set finish root for a campaign
     * @param comet The protocol instance
     * @param campaignId The id of the campaign
     * @param finishRoot The root of the Merkle tree for the finishAccrued
     */
    function setCampaignFinishRoot(
        address comet,
        uint256 campaignId,
        bytes32 finishRoot
    ) public {
        if(msg.sender != governor) revert NotPermitted(msg.sender);
        if(finishRoot == bytes32(0)) revert BadData();
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(campaignId >= campaigns[comet].length) revert BadData();
        
        emit NewCampaignFinishRoot(comet, finishRoot, campaignId);
        campaigns[comet][campaignId].finishRoot = finishRoot;
    }

    /**
     * @notice Withdraw tokens from the contract
     * @param token The reward token address
     * @param to Where to send the tokens
     * @param amount The number of tokens to withdraw
     */
    function withdrawToken(address token, address to, uint256 amount) external {
        if(msg.sender != governor) revert NotPermitted(msg.sender);

        if(doTransferOut(token, to, amount) > 0)
            emit TokenWithdrawn(token, to, amount);
    }

    /**
     * @notice Transfers the governor rights to a new address
     * @param newGovernor The address of the new governor
     */
    function transferGovernor(address newGovernor) external {
        if(msg.sender != governor) revert NotPermitted(msg.sender);
        if(newGovernor == address(0)) revert NullGovernor();

        emit GovernorTransferred(governor, newGovernor);
        governor = newGovernor;
    }

    /**
     * @notice Calculates the amount of a reward token owed to an account
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param token Reward token address
     * @param account The account to check rewards for
     * @param startAccrued Start accrued value
     * @param finishAccrued Finish accrued value if finishRoot is set
     */
    function getRewardsOwed(
        address comet,
        uint256 campaignId,
        address token,
        address account,
        uint256 startAccrued,
        uint256 finishAccrued,
        bool shouldAccrue
    ) external returns (RewardOwed memory) {        
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(campaignId >= campaigns[comet].length) revert BadData();

        Campaign storage $ = campaigns[comet][campaignId];
        AssetConfig memory config = $.configs[token];

        if(config.multiplier == 0) revert NotSupported(comet, token);

        if($.finishRoot == bytes32(0) && shouldAccrue)
            CometInterface(comet).accrueAccount(account);
        uint256 claimed = $.claimed[account][token];
        uint256 accrued = getRewardsAccrued(
                comet,
                account,
                startAccrued,
                finishAccrued,
                config
            );

        return RewardOwed(
            token,
            accrued > claimed ? accrued - claimed : 0
        );
    }

    /**
     * @notice Calculates the amount of each reward token owed to an account in a batch
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param account The account to check rewards for
     * @param startAccrued Start accrued value
     * @param finishAccrued Finish accrued value if finishRoot is set
     * @return owed List of RewardOwed
     */
    function getRewardsOwedBatch(
        address comet,
        uint256 campaignId,
        address account,
        uint256 startAccrued,
        uint256 finishAccrued,
        bool shouldAccrue
    ) external returns (RewardOwed[] memory) {
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(campaignId >= campaigns[comet].length) revert BadData();

        Campaign storage $ = campaigns[comet][campaignId];
        RewardOwed[] memory owed = new RewardOwed[]($.assets.length);

        
        if($.finishRoot == bytes32(0) && shouldAccrue)
            CometInterface(comet).accrueAccount(account);

        for (uint256 j; j < $.assets.length; j++) {
            address token = $.assets[j];
            AssetConfig memory config = $.configs[token];

            uint256 claimed = $.claimed[account][token];
            uint256 accrued = getRewardsAccrued(
                comet,
                account,
                startAccrued,
                finishAccrued,
                config
            );

            owed[j] = RewardOwed(
                token,
                accrued > claimed ? accrued - claimed : 0
            );
        }

        return owed;
    }

    /**
     * @notice Claim rewards with each token from a comet instance to owner address
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param src The owner to claim for
     * @param shouldAccrue Whether or not to call accrue first
     * @dev This function is designed for new members (everyone who is not in a startTree) who want to claim rewards.
     *      To prove that they are indeed new members, users need to provide evidence that verifies their status.
     *      We use a Sorted Merkle Tree for this verification process.
     *      This tree is organized based on account addresses.
     *      In order to prove that an account is new, the user must provide the Merkle proofs for the two closest addresses to their own address.
     *      If the user's address is either lower than the first address or higher than the last address in the tree,
     *      the Merkle Tree includes placeholders (zero and maximum address) for comparison, ensuring there are always at least two addresses available for comparison.
     *      Additionally, the Merkle Tree contains the index of each address, serving as proof of existing users' membership.
     * @param neighbors The neighbors of the account
     * @param proofs The Merkle proofs for each neighbor
     * @param finishProof The Merkle proof for the finish accrued if finishRoot is set
     */
    function claimForNewMember(
        address comet,
        uint256 campaignId,
        address src,
        bool shouldAccrue,
        address[2] calldata neighbors,
        Proofs[2] calldata proofs,
        FinishProof calldata finishProof
    ) external {
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        verifyNewMember(comet, src, campaignId, neighbors, proofs);

        claimInternalForNewMember(
            comet,
            src,
            src,
            campaignId,
            shouldAccrue,
            finishProof
        );
    }

    /**
     * @notice Claim rewards for all chosen campaigns for given comet instance
     * @param comet Comet protocol address
     * @param campaignIDs The list of campaigns to claim for
     * @param src The owner to claim for
     * @param shouldAccrue Whether or not to call accrue first
     * @param neighbors The neighbors of the account
     * @param multiProofs The Merkle proofs for each neighbor
     * @param finishProofs The Merkle proof for the finish accrued if finishRoot is set
     */
    function claimBatchForNewMember(
        address comet,
        uint256[] memory campaignIDs,
        address src,
        bool shouldAccrue,
        address[2][] calldata neighbors,
        MultiProofs[] calldata multiProofs,
        FinishProof[] calldata finishProofs
    ) external {
        if(campaignIDs.length != neighbors.length) revert BadData();
        if(campaignIDs.length != multiProofs.length) revert BadData();
        if(campaignIDs.length != finishProofs.length) revert BadData();
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(shouldAccrue)
            CometInterface(comet).accrueAccount(src);
        for (uint256 i; i < campaignIDs.length; i++) {
            verifyNewMember(comet, src, campaignIDs[i], neighbors[i], multiProofs[i].proofs);

            claimInternalForNewMember(
                comet,
                src,
                src,
                campaignIDs[i],
                false,
                finishProofs[i]
            );
        }
    }

    /**
     * @notice Claim rewards with each token from a comet instance to a target address
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param src The owner to claim for
     * @param to The address to receive the rewards
     * @param shouldAccrue Whether or not to call accrue first
     * @param neighbors The neighbors of the account
     * @param proofs The Merkle proofs for each neighbor
     * @param finishProof The Merkle proof for the finish accrued if finishRoot is set
     */
    function claimToForNewMember(
        address comet,
        uint256 campaignId,
        address src,
        address to,
        bool shouldAccrue,
        address[2] calldata neighbors,
        Proofs[2] calldata proofs,
        FinishProof calldata finishProof
    ) external {
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(!CometInterface(comet).hasPermission(src, msg.sender))
            revert NotPermitted(msg.sender);
        
        verifyNewMember(comet, src, campaignId, neighbors, proofs);

        claimInternalForNewMember(
            comet,
            src,
            to,
            campaignId,
            shouldAccrue,
            finishProof
        );
    }

    /**
     * @notice Claim rewards for all chosen campaigns for given comet instance to a target address
     * @param comet Comet protocol address
     * @param campaignIDs The list of campaigns to claim for
     * @param src The owner to claim for
     * @param to The address to receive the rewards
     * @param shouldAccrue Whether or not to call accrue first
     * @param neighbors The neighbors of the account
     * @param multiProofs The Merkle proofs for each neighbor
     * @param finishProofs The Merkle proof for the finish accrued if finishRoot is set
     */
    function claimToBatchForNewMember(
        address comet,
        uint256[] memory campaignIDs,
        address src,
        address to,
        bool shouldAccrue,
        address[2][] calldata neighbors,
        MultiProofs[] calldata multiProofs,
        FinishProof[] calldata finishProofs
    ) external {
        if(campaignIDs.length != neighbors.length) revert BadData();
        if(campaignIDs.length != multiProofs.length) revert BadData();
        if(campaignIDs.length != finishProofs.length) revert BadData();
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(shouldAccrue)
            CometInterface(comet).accrueAccount(src);
        for (uint256 i; i < campaignIDs.length; i++) {
            if(!CometInterface(comet).hasPermission(src, msg.sender))
                revert NotPermitted(msg.sender);
            
            verifyNewMember(comet, src, campaignIDs[i], neighbors[i], multiProofs[i].proofs);

            claimInternalForNewMember(
                comet,
                src,
                to,
                campaignIDs[i],
                false,
                finishProofs[i]
            );
        }
    }

    /**
     * @notice Claim rewards with each token from a comet instance to owner address
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param src The owner to claim for
     * @param shouldAccrue Whether or not to call accrue first
     * @param proofs The Merkle proofs for the start and finish accrued
     */
    function claim(
        address comet,
        uint256 campaignId,
        address src,
        bool shouldAccrue,
        Proofs calldata proofs
    ) external {
        claimInternal(comet, src, src, campaignId, proofs, shouldAccrue);
    }

    /**
     * @notice Claim rewards for all chosen campaigns for given comet instance
     * @param comet Comet protocol address
     * @param campaignIds The list of campaigns to claim for
     * @param src The owner to claim for
     * @param shouldAccrue Whether or not to call accrue first
     * @param proofs The Merkle proofs for the start and finish accrued
     */
    function claimBatch(
        address comet,
        uint256[] memory campaignIds,
        address src,
        bool shouldAccrue,
        Proofs[] calldata proofs
    ) external {
        claimInternalBatch(comet, src, src, campaignIds, proofs, shouldAccrue);
    }

    /**
     * @notice Claim rewards with each token from a comet instance to a target address
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param src The owner to claim for
     * @param to The address to receive the rewards
     * @param shouldAccrue Whether or not to call accrue first
     * @param proofs The Merkle proofs for the start and finish accrued
     */
    function claimTo(
        address comet,
        uint256 campaignId,
        address src,
        address to,
        bool shouldAccrue,
        Proofs calldata proofs
    ) external {
        if(!CometInterface(comet).hasPermission(src, msg.sender))
            revert NotPermitted(msg.sender);

        claimInternal(comet, src, to, campaignId, proofs, shouldAccrue);
    }

    /**
     * @notice Returns claimed rewards for a user in a specific campaign for a specific token
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param src The owner to check for
     * @param token The reward token address
     * @return The amount of claimed rewards
     */
    function rewardsClaimed(
        address comet,
        uint256 campaignId,
        address src,
        address token
    ) external view returns(uint256) {
        return campaigns[comet][campaignId].claimed[src][token];
    }

    /**
     * @notice Returns the reward configuration for all tokens in a specific campaign
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @return The reward configuration
     */
    function rewardConfig(
        address comet,
        uint256 campaignId
    ) external view returns(address[] memory, AssetConfig[] memory) {
        Campaign storage $ = campaigns[comet][campaignId];
        AssetConfig[] memory configs = new AssetConfig[]($.assets.length);
        for (uint256 i; i < $.assets.length; i++) {
            configs[i] = $.configs[$.assets[i]];
        }
        return ($.assets, configs);
    }

    /**
     * @notice Returns all campaigns for a specific Comet instance
     * @param comet Comet protocol address
     * @return startRoots The start roots for each campaign
     * @return finishRoots The finish roots for each campaign
     * @return assets The reward tokens for each campaign
     * @return finishTimestamps The finish timestamps for each campaign
     */
    function getCometCampaignsInfo(address comet) external view returns(
        bytes32[] memory startRoots,
        bytes32[] memory finishRoots,
        address[][] memory assets,
        uint256[] memory finishTimestamps
    ) {
        if(campaigns[comet].length == 0) return (startRoots, finishRoots, assets, finishTimestamps);
        startRoots = new bytes32[](campaigns[comet].length);
        finishRoots = new bytes32[](campaigns[comet].length);
        assets = new address[][](campaigns[comet].length);
        finishTimestamps = new uint256[](campaigns[comet].length);
        for (uint256 i; i < campaigns[comet].length; i++) {
            Campaign storage $ = campaigns[comet][i];
            startRoots[i] = $.startRoot;
            finishRoots[i] = $.finishRoot;
            assets[i] = $.assets;
            finishTimestamps[i] = $.finishTimestamp;
        }
    }

    /**
     * @notice Returns true if the proof is valid
     * @param root The root of the Merkle tree
     * @param proofs The Merkle proofs
     * @param account The account to check for
     * @param index The index of the account
     * @param accrued The accrued value for the account
     * @return True if the proof is valid
     */
    function verifyProof(
        bytes32 root,
        bytes32[] calldata proofs,
        address account,
        uint256 index,
        uint256 accrued
    ) external pure returns(bool) {
        return MerkleProof.verifyCalldata(
            proofs,
            root,
            keccak256(bytes.concat(keccak256(abi.encode(account, index, accrued))))
        );
    }


    /**
     * @notice Returns the reward configuration for a specific token in a specific campaign
     * @param comet Comet protocol address
     * @param campaignId Id of the campaign
     * @param token The reward token address
     * @return The reward configuration
     */
    function rewardConfigForToken(
        address comet,
        uint256 campaignId,
        address token
    ) external view returns(AssetConfig memory) {
        return campaigns[comet][campaignId].configs[token];
    }

    /**
     * @notice Claim rewards for all chosen campaigns for given comet instance to a target address
     * @param comet Comet protocol address
     * @param campaignIds The list of campaigns to claim for
     * @param src The owner to claim for
     * @param to The address to receive the rewards
     * @param shouldAccrue Whether or not to call accrue first
     * @param proofs The Merkle proofs for the start and finish accrued
     */
    function claimToBatch(
        address comet,
        uint256[] memory campaignIds,
        address src,
        address to,
        bool shouldAccrue,
        Proofs[] calldata proofs
    ) external {
        if(!CometInterface(comet).hasPermission(src, msg.sender))
            revert NotPermitted(msg.sender);

        claimInternalBatch(comet, src, to, campaignIds, proofs, shouldAccrue);
    }

    /**
     * @dev Verify the membership of an account
     */
    function verifyNewMember(
        address comet,
        address account,
        uint256 campaignId,
        address[2] calldata neighbors,
        Proofs[2] calldata proofs
    ) internal view returns(bool) {
        // check if the account is in between the neighbors
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(campaignId >= campaigns[comet].length) revert BadData();
        if(!(neighbors[0] < account && account < neighbors[1])) revert BadData();
        // check if the neighbors are in the right order
        if(!((proofs[1].startIndex > proofs[0].startIndex) && (proofs[1].startIndex - proofs[0].startIndex == 1))) revert BadData();

        Campaign storage $ = campaigns[comet][campaignId];

        bool isValidProof = MerkleProof.verifyCalldata(
            proofs[0].startMerkleProof,
            $.startRoot,
            keccak256(bytes.concat(keccak256(abi.encode(neighbors[0], proofs[0].startIndex, proofs[0].startAccrued)))
            )
        );

        if(!isValidProof) revert InvalidProof();

        isValidProof = MerkleProof.verifyCalldata(
            proofs[1].startMerkleProof,
            $.startRoot,
            keccak256(bytes.concat(keccak256(abi.encode(neighbors[1], proofs[1].startIndex, proofs[1].startAccrued)))
            )
        );

        if(!isValidProof) revert InvalidProof();

        return true;
    }

    /**
     * @dev Claim rewards for a new member
     */
    function claimInternalForNewMember(
        address comet,
        address src,
        address to,
        uint256 campaignId,
        bool shouldAccrue,
        FinishProof calldata finishProof
    ) internal {
        Campaign storage $ = campaigns[comet][campaignId];
        if($.finishRoot != bytes32(0)) {
            bool isValidProof = MerkleProof.verifyCalldata(
                finishProof.finishMerkleProof,
                $.finishRoot,
                keccak256(bytes.concat(keccak256(abi.encode(src, finishProof.finishIndex, finishProof.finishAccrued))))
            );

            if(!isValidProof) revert InvalidProof();
        }
        else if($.finishTimestamp < block.timestamp) revert CampaignEnded(comet, campaignId);
        if(shouldAccrue) {
            CometInterface(comet).accrueAccount(src);
        }
        for (uint256 j; j < $.assets.length; j++) {
            AssetConfig memory config = $.configs[$.assets[j]];
            address token = $.assets[j];
            uint256 claimed = $.claimed[src][token];
            uint256 accrued = getRewardsAccrued(
                comet,
                src,
                0,
                $.finishRoot != bytes32(0) ? finishProof.finishAccrued : 0,
                config
            );
            if(accrued > claimed) {
                uint256 owed = accrued - claimed;
                if(doTransferOut(token, to, owed) > 0){
                    $.claimed[src][token] = accrued;                    
                    emit RewardClaimed(campaignId, comet, src, to, token, owed);
                }
            }
        }
    }

    /**
     * @dev Claim rewards for an established member
     */
    function claimInternal(
        address comet,
        address src,
        address to,
        uint256 campaignId,
        Proofs calldata proofs,
        bool shouldAccrue
    ) internal {
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(campaignId >= campaigns[comet].length) revert BadData();
        Campaign storage $ = campaigns[comet][campaignId];
        
        bool isValidProof = MerkleProof.verifyCalldata(
            proofs.startMerkleProof,
            $.startRoot,
            keccak256(bytes.concat(keccak256(abi.encode(src, proofs.startIndex, proofs.startAccrued))))
        );

        if(!isValidProof) revert InvalidProof();

        if($.finishRoot != bytes32(0)) {
            bool isValidProof2 = MerkleProof.verifyCalldata(
                proofs.finishMerkleProof,
                $.finishRoot,
                keccak256(bytes.concat(keccak256(abi.encode(src, proofs.finishIndex, proofs.finishAccrued))))
            );

            if(!isValidProof2) revert InvalidProof();
        }
        else if($.finishTimestamp < block.timestamp) revert CampaignEnded(comet, campaignId);
        if(shouldAccrue) {
            //remove from loop
            CometInterface(comet).accrueAccount(src);
        }
        for (uint256 j; j < $.assets.length; j++) {
            address token = $.assets[j];
            AssetConfig memory config = $.configs[token];


            uint256 claimed = $.claimed[src][token];
            uint256 accrued = getRewardsAccrued(
                comet,
                src,
                proofs.startAccrued,
                $.finishRoot != bytes32(0) ? proofs.finishAccrued : 0,
                config
            );
            if(accrued > claimed) {
                uint256 owed = accrued - claimed;
                if(doTransferOut(token, to, owed) > 0){
                    $.claimed[src][token] = accrued;                    
                    emit RewardClaimed(campaignId, comet, src, to, token, owed);
                }
            }
        }
    }

    /**
     * @dev Claim rewards for multiple campaigns
     */
    function claimInternalBatch(
        address comet,
        address src,
        address to,
        uint256[] memory campaignIds,
        Proofs[] calldata proofs,
        bool shouldAccrue
    ) internal {
        if(campaignIds.length != proofs.length) revert BadData();
        if(campaigns[comet].length == 0) revert NotSupported(comet, address(0));
        if(shouldAccrue)
            CometInterface(comet).accrueAccount(src);
        for (uint256 i; i < campaignIds.length; i++) {
            if(campaignIds[i] >= campaigns[comet].length) revert BadData();
            claimInternal(
                comet,
                src,
                to,
                campaignIds[i],
                proofs[i],
                false
            );
        }
    }

    /**
     * @dev Calculate the accrued value
     */
    function getRewardsAccrued(
        address comet,
        address account,
        uint256 startAccrued, //if startAccrued = 0 => it is a new member
        uint256 finishAccrued,
        AssetConfig memory config
    ) internal view returns (uint256 accrued) {
        if(finishAccrued > 0) {
            accrued = finishAccrued - startAccrued;
        } else{
            accrued = CometInterface(comet).baseTrackingAccrued(account) -
                startAccrued;
        }
        if(config.shouldUpscale) {
            accrued *= config.rescaleFactor;
        } else {
            accrued /= config.rescaleFactor;
        }
        return (accrued * config.multiplier) / FACTOR_SCALE;
    }

    /**
     * @dev Safe ERC20 transfer out
     */
    function doTransferOut(address token, address to, uint256 amount) internal returns(uint256 amountOut) {
        if(amount == 0) return 0;
        IERC20NonStandard(token).transfer(to, amount);
        bool success;
        assembly ("memory-safe") {
            switch returndatasize()
                case 0 {                       // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                      // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of override external call
                }
                default {                      // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        if(!success) emit TransferOutFailed(token, to, amount);
        else return amount;
    }

    /**
     * @dev Safe cast to uint128
     */
    function safe128(uint256 n) internal pure returns (uint128) {
        if(n > type(uint128).max) revert InvalidUint128(n);
        return uint128(n);
    }
}

File 2 of 10 : CometConfiguration.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Configuration Interface
 * @author Compound
 */
contract CometConfiguration {
    struct ExtConfiguration {
        bytes32 name32;
        bytes32 symbol32;
    }

    struct Configuration {
        address governor;
        address pauseGuardian;
        address baseToken;
        address baseTokenPriceFeed;
        address extensionDelegate;

        uint64 supplyKink;
        uint64 supplyPerYearInterestRateSlopeLow;
        uint64 supplyPerYearInterestRateSlopeHigh;
        uint64 supplyPerYearInterestRateBase;
        uint64 borrowKink;
        uint64 borrowPerYearInterestRateSlopeLow;
        uint64 borrowPerYearInterestRateSlopeHigh;
        uint64 borrowPerYearInterestRateBase;
        uint64 storeFrontPriceFactor;
        uint64 trackingIndexScale;
        uint64 baseTrackingSupplySpeed;
        uint64 baseTrackingBorrowSpeed;
        uint104 baseMinForRewards;
        uint104 baseBorrowMin;
        uint104 targetReserves;

        AssetConfig[] assetConfigs;
    }

    struct AssetConfig {
        address asset;
        address priceFeed;
        uint8 decimals;
        uint64 borrowCollateralFactor;
        uint64 liquidateCollateralFactor;
        uint64 liquidationFactor;
        uint128 supplyCap;
    }
}

File 3 of 10 : CometCore.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometConfiguration.sol";
import "./CometStorage.sol";
import "./CometMath.sol";

abstract contract CometCore is CometConfiguration, CometStorage, CometMath {
    struct AssetInfo {
        uint8 offset;
        address asset;
        address priceFeed;
        uint64 scale;
        uint64 borrowCollateralFactor;
        uint64 liquidateCollateralFactor;
        uint64 liquidationFactor;
        uint128 supplyCap;
    }

    /** Internal constants **/

    /// @dev The max number of assets this contract is hardcoded to support
    ///  Do not change this variable without updating all the fields throughout the contract,
    //    including the size of UserBasic.assetsIn and corresponding integer conversions.
    uint8 internal constant MAX_ASSETS = 15;

    /// @dev The max number of decimals base token can have
    ///  Note this cannot just be increased arbitrarily.
    uint8 internal constant MAX_BASE_DECIMALS = 18;

    /// @dev The max value for a collateral factor (1)
    uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE;

    /// @dev Offsets for specific actions in the pause flag bit array
    uint8 internal constant PAUSE_SUPPLY_OFFSET = 0;
    uint8 internal constant PAUSE_TRANSFER_OFFSET = 1;
    uint8 internal constant PAUSE_WITHDRAW_OFFSET = 2;
    uint8 internal constant PAUSE_ABSORB_OFFSET = 3;
    uint8 internal constant PAUSE_BUY_OFFSET = 4;

    /// @dev The decimals required for a price feed
    uint8 internal constant PRICE_FEED_DECIMALS = 8;

    /// @dev 365 days * 24 hours * 60 minutes * 60 seconds
    uint64 internal constant SECONDS_PER_YEAR = 31_536_000;

    /// @dev The scale for base tracking accrual
    uint64 internal constant BASE_ACCRUAL_SCALE = 1e6;

    /// @dev The scale for base index (depends on time/rate scales, not base token)
    uint64 internal constant BASE_INDEX_SCALE = 1e15;

    /// @dev The scale for prices (in USD)
    uint64 internal constant PRICE_SCALE = uint64(10 ** PRICE_FEED_DECIMALS);

    /// @dev The scale for factors
    uint64 internal constant FACTOR_SCALE = 1e18;

    /// @dev The storage slot for reentrancy guard flags
    bytes32 internal constant REENTRANCY_GUARD_FLAG_SLOT = bytes32(keccak256("comet.reentrancy.guard"));

    /// @dev The reentrancy guard statuses
    uint256 internal constant REENTRANCY_GUARD_NOT_ENTERED = 0;
    uint256 internal constant REENTRANCY_GUARD_ENTERED = 1;

    /**
     * @notice Determine if the manager has permission to act on behalf of the owner
     * @param owner The owner account
     * @param manager The manager account
     * @return Whether or not the manager has permission
     */
    function hasPermission(address owner, address manager) public view returns (bool) {
        return owner == manager || isAllowed[owner][manager];
    }

    /**
     * @dev The positive present supply balance if positive or the negative borrow balance if negative
     */
    function presentValue(int104 principalValue_) internal view returns (int256) {
        if (principalValue_ >= 0) {
            return signed256(presentValueSupply(baseSupplyIndex, uint104(principalValue_)));
        } else {
            return -signed256(presentValueBorrow(baseBorrowIndex, uint104(-principalValue_)));
        }
    }

    /**
     * @dev The principal amount projected forward by the supply index
     */
    function presentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internal pure returns (uint256) {
        return uint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE;
    }

    /**
     * @dev The principal amount projected forward by the borrow index
     */
    function presentValueBorrow(uint64 baseBorrowIndex_, uint104 principalValue_) internal pure returns (uint256) {
        return uint256(principalValue_) * baseBorrowIndex_ / BASE_INDEX_SCALE;
    }

    /**
     * @dev The positive principal if positive or the negative principal if negative
     */
    function principalValue(int256 presentValue_) internal view returns (int104) {
        if (presentValue_ >= 0) {
            return signed104(principalValueSupply(baseSupplyIndex, uint256(presentValue_)));
        } else {
            return -signed104(principalValueBorrow(baseBorrowIndex, uint256(-presentValue_)));
        }
    }

    /**
     * @dev The present value projected backward by the supply index (rounded down)
     *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
     */
    function principalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internal pure returns (uint104) {
        return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_);
    }

    /**
     * @dev The present value projected backward by the borrow index (rounded up)
     *  Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals.
     */
    function principalValueBorrow(uint64 baseBorrowIndex_, uint256 presentValue_) internal pure returns (uint104) {
        return safe104((presentValue_ * BASE_INDEX_SCALE + baseBorrowIndex_ - 1) / baseBorrowIndex_);
    }
}

File 4 of 10 : CometExtInterface.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometCore.sol";

/**
 * @title Compound's Comet Ext Interface
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometExtInterface is CometCore {
    error BadAmount();
    error BadNonce();
    error BadSignatory();
    error InvalidValueS();
    error InvalidValueV();
    error SignatureExpired();

    function allow(address manager, bool isAllowed) virtual external;
    function allowBySig(address owner, address manager, bool isAllowed, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) virtual external;

    function collateralBalanceOf(address account, address asset) virtual external view returns (uint128);
    function baseTrackingAccrued(address account) virtual external view returns (uint64);

    function baseAccrualScale() virtual external view returns (uint64);
    function baseIndexScale() virtual external view returns (uint64);
    function factorScale() virtual external view returns (uint64);
    function priceScale() virtual external view returns (uint64);

    function maxAssets() virtual external view returns (uint8);

    function totalsBasic() virtual external view returns (TotalsBasic memory);

    function version() virtual external view returns (string memory);

    /**
      * ===== ERC20 interfaces =====
      * Does not include the following functions/events, which are defined in `CometMainInterface` instead:
      * - function decimals() virtual external view returns (uint8)
      * - function totalSupply() virtual external view returns (uint256)
      * - function transfer(address dst, uint amount) virtual external returns (bool)
      * - function transferFrom(address src, address dst, uint amount) virtual external returns (bool)
      * - function balanceOf(address owner) virtual external view returns (uint256)
      * - event Transfer(address indexed from, address indexed to, uint256 amount)
      */
    function name() virtual external view returns (string memory);
    function symbol() virtual external view returns (string memory);

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved (-1 means infinite)
      * @return Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) virtual external returns (bool);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return The number of tokens allowed to be spent (-1 means infinite)
      */
    function allowance(address owner, address spender) virtual external view returns (uint256);

    event Approval(address indexed owner, address indexed spender, uint256 amount);
}

File 5 of 10 : CometInterface.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometMainInterface.sol";
import "./CometExtInterface.sol";

/**
 * @title Compound's Comet Interface
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometInterface is CometMainInterface, CometExtInterface {}

File 6 of 10 : CometMainInterface.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometCore.sol";

/**
 * @title Compound's Comet Main Interface (without Ext)
 * @notice An efficient monolithic money market protocol
 * @author Compound
 */
abstract contract CometMainInterface is CometCore {
    error Absurd();
    error AlreadyInitialized();
    error BadAsset();
    error BadDecimals();
    error BadDiscount();
    error BadMinimum();
    error BadPrice();
    error BorrowTooSmall();
    error BorrowCFTooLarge();
    error InsufficientReserves();
    error LiquidateCFTooLarge();
    error NoSelfTransfer();
    error NotCollateralized();
    error NotForSale();
    error NotLiquidatable();
    error Paused();
    error ReentrantCallBlocked();
    error SupplyCapExceeded();
    error TimestampTooLarge();
    error TooManyAssets();
    error TooMuchSlippage();
    error TransferInFailed();
    error TransferOutFailed();
    error Unauthorized();

    event Supply(address indexed from, address indexed dst, uint amount);
    event Transfer(address indexed from, address indexed to, uint amount);
    event Withdraw(address indexed src, address indexed to, uint amount);

    event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint amount);
    event TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount);
    event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount);

    /// @notice Event emitted when a borrow position is absorbed by the protocol
    event AbsorbDebt(address indexed absorber, address indexed borrower, uint basePaidOut, uint usdValue);

    /// @notice Event emitted when a user's collateral is absorbed by the protocol
    event AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint collateralAbsorbed, uint usdValue);

    /// @notice Event emitted when a collateral asset is purchased from the protocol
    event BuyCollateral(address indexed buyer, address indexed asset, uint baseAmount, uint collateralAmount);

    /// @notice Event emitted when an action is paused/unpaused
    event PauseAction(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused);

    /// @notice Event emitted when reserves are withdrawn by the governor
    event WithdrawReserves(address indexed to, uint amount);

    function supply(address asset, uint amount) virtual external;
    function supplyTo(address dst, address asset, uint amount) virtual external;
    function supplyFrom(address from, address dst, address asset, uint amount) virtual external;

    function transfer(address dst, uint amount) virtual external returns (bool);
    function transferFrom(address src, address dst, uint amount) virtual external returns (bool);

    function transferAsset(address dst, address asset, uint amount) virtual external;
    function transferAssetFrom(address src, address dst, address asset, uint amount) virtual external;

    function withdraw(address asset, uint amount) virtual external;
    function withdrawTo(address to, address asset, uint amount) virtual external;
    function withdrawFrom(address src, address to, address asset, uint amount) virtual external;

    function approveThis(address manager, address asset, uint amount) virtual external;
    function withdrawReserves(address to, uint amount) virtual external;

    function absorb(address absorber, address[] calldata accounts) virtual external;
    function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) virtual external;
    function quoteCollateral(address asset, uint baseAmount) virtual public view returns (uint);

    function getAssetInfo(uint8 i) virtual public view returns (AssetInfo memory);
    function getAssetInfoByAddress(address asset) virtual public view returns (AssetInfo memory);
    function getCollateralReserves(address asset) virtual public view returns (uint);
    function getReserves() virtual public view returns (int);
    function getPrice(address priceFeed) virtual public view returns (uint);

    function isBorrowCollateralized(address account) virtual public view returns (bool);
    function isLiquidatable(address account) virtual public view returns (bool);

    function totalSupply() virtual external view returns (uint256);
    function totalBorrow() virtual external view returns (uint256);
    function balanceOf(address owner) virtual public view returns (uint256);
    function borrowBalanceOf(address account) virtual public view returns (uint256);

    function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused) virtual external;
    function isSupplyPaused() virtual public view returns (bool);
    function isTransferPaused() virtual public view returns (bool);
    function isWithdrawPaused() virtual public view returns (bool);
    function isAbsorbPaused() virtual public view returns (bool);
    function isBuyPaused() virtual public view returns (bool);

    function accrueAccount(address account) virtual external;
    function getSupplyRate(uint utilization) virtual public view returns (uint64);
    function getBorrowRate(uint utilization) virtual public view returns (uint64);
    function getUtilization() virtual public view returns (uint);

    function governor() virtual external view returns (address);
    function pauseGuardian() virtual external view returns (address);
    function baseToken() virtual external view returns (address);
    function baseTokenPriceFeed() virtual external view returns (address);
    function extensionDelegate() virtual external view returns (address);

    /// @dev uint64
    function supplyKink() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateSlopeLow() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
    /// @dev uint64
    function supplyPerSecondInterestRateBase() virtual external view returns (uint);
    /// @dev uint64
    function borrowKink() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateSlopeLow() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
    /// @dev uint64
    function borrowPerSecondInterestRateBase() virtual external view returns (uint);
    /// @dev uint64
    function storeFrontPriceFactor() virtual external view returns (uint);

    /// @dev uint64
    function baseScale() virtual external view returns (uint);
    /// @dev uint64
    function trackingIndexScale() virtual external view returns (uint);

    /// @dev uint64
    function baseTrackingSupplySpeed() virtual external view returns (uint);
    /// @dev uint64
    function baseTrackingBorrowSpeed() virtual external view returns (uint);
    /// @dev uint104
    function baseMinForRewards() virtual external view returns (uint);
    /// @dev uint104
    function baseBorrowMin() virtual external view returns (uint);
    /// @dev uint104
    function targetReserves() virtual external view returns (uint);

    function numAssets() virtual external view returns (uint8);
    function decimals() virtual external view returns (uint8);

    function initializeStorage() virtual external;
}

File 7 of 10 : CometMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Math Contract
 * @dev Pure math functions
 * @author Compound
 */
contract CometMath {
    /** Custom errors **/

    error InvalidUInt64();
    error InvalidUInt104();
    error InvalidUInt128();
    error InvalidInt104();
    error InvalidInt256();
    error NegativeNumber();

    function safe64(uint n) internal pure returns (uint64) {
        if (n > type(uint64).max) revert InvalidUInt64();
        return uint64(n);
    }

    function safe104(uint n) internal pure returns (uint104) {
        if (n > type(uint104).max) revert InvalidUInt104();
        return uint104(n);
    }

    function safe128(uint n) internal pure returns (uint128) {
        if (n > type(uint128).max) revert InvalidUInt128();
        return uint128(n);
    }

    function signed104(uint104 n) internal pure returns (int104) {
        if (n > uint104(type(int104).max)) revert InvalidInt104();
        return int104(n);
    }

    function signed256(uint256 n) internal pure returns (int256) {
        if (n > uint256(type(int256).max)) revert InvalidInt256();
        return int256(n);
    }

    function unsigned104(int104 n) internal pure returns (uint104) {
        if (n < 0) revert NegativeNumber();
        return uint104(n);
    }

    function unsigned256(int256 n) internal pure returns (uint256) {
        if (n < 0) revert NegativeNumber();
        return uint256(n);
    }

    function toUInt8(bool x) internal pure returns (uint8) {
        return x ? 1 : 0;
    }

    function toBool(uint8 x) internal pure returns (bool) {
        return x != 0;
    }
}

File 8 of 10 : CometStorage.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title Compound's Comet Storage Interface
 * @dev Versions can enforce append-only storage slots via inheritance.
 * @author Compound
 */
contract CometStorage {
    // 512 bits total = 2 slots
    struct TotalsBasic {
        // 1st slot
        uint64 baseSupplyIndex;
        uint64 baseBorrowIndex;
        uint64 trackingSupplyIndex;
        uint64 trackingBorrowIndex;
        // 2nd slot
        uint104 totalSupplyBase;
        uint104 totalBorrowBase;
        uint40 lastAccrualTime;
        uint8 pauseFlags;
    }

    struct TotalsCollateral {
        uint128 totalSupplyAsset;
        uint128 _reserved;
    }

    struct UserBasic {
        int104 principal;
        uint64 baseTrackingIndex;
        uint64 baseTrackingAccrued;
        uint16 assetsIn;
        uint8 _reserved;
    }

    struct UserCollateral {
        uint128 balance;
        uint128 _reserved;
    }

    struct LiquidatorPoints {
        uint32 numAbsorbs;
        uint64 numAbsorbed;
        uint128 approxSpend;
        uint32 _reserved;
    }

    /// @dev Aggregate variables tracked for the entire market
    uint64 internal baseSupplyIndex;
    uint64 internal baseBorrowIndex;
    uint64 internal trackingSupplyIndex;
    uint64 internal trackingBorrowIndex;
    uint104 internal totalSupplyBase;
    uint104 internal totalBorrowBase;
    uint40 internal lastAccrualTime;
    uint8 internal pauseFlags;

    /// @notice Aggregate variables tracked for each collateral asset
    mapping(address => TotalsCollateral) public totalsCollateral;

    /// @notice Mapping of users to accounts which may be permitted to manage the user account
    mapping(address => mapping(address => bool)) public isAllowed;

    /// @notice The next expected nonce for an address, for validating authorizations via signature
    mapping(address => uint) public userNonce;

    /// @notice Mapping of users to base principal and other basic data
    mapping(address => UserBasic) public userBasic;

    /// @notice Mapping of users to collateral data per collateral asset
    mapping(address => mapping(address => UserCollateral)) public userCollateral;

    /// @notice Mapping of magic liquidator points
    mapping(address => LiquidatorPoints) public liquidatorPoints;
}

File 9 of 10 : IERC20NonStandard.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
 * @title IERC20NonStandard
 * @dev Version of ERC20 with no return values for `approve`, `transfer`, and `transferFrom`
 *  See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
 */
interface IERC20NonStandard {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (-1 means infinite)
     */
    function approve(address spender, uint256 amount) external;

    /**
     * @notice Transfer `value` tokens from `msg.sender` to `to`
     * @param to The address of the destination account
     * @param value The number of tokens to transfer
     */
    function transfer(address to, uint256 value) external;

    /**
     * @notice Transfer `value` tokens from `from` to `to`
     * @param from The address of the source account
     * @param to The address of the destination account
     * @param value The number of tokens to transfer
     */
    function transferFrom(address from, address to, uint256 value) external;

    /**
     * @notice Gets the balance of the specified address
     * @param account The address from which the balance will be retrieved
     */
    function balanceOf(address account) external view returns (uint256);
}

File 10 of 10 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)

pragma solidity 0.8.15;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the Merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates Merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     *@dev The multiproof provided is not valid.
     */
    error MerkleProofInvalidMultiproof();

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Sorts the pair (a, b) and hashes the result.
     */
    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1,
    "details": {
      "yulDetails": {
        "optimizerSteps": "dhfoDgvulfnTUtnIf [xa[r]scLM cCTUtTOntnfDIul Lcul Vcul [j] Tpeul xa[rul] xa[r]cL gvif CTUca[r]LsTOtfDnca[r]Iulc] jmul[jul] VcTOcul jmul"
      }
    }
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "viaIR": true,
  "libraries": {}
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"governor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadData","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"CampaignEnded","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"InvalidUint128","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"NotANewMember","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"NotPermitted","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"NotSupported","type":"error"},{"inputs":[],"name":"NullGovernor","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":true,"internalType":"address","name":"comet","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"ConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernor","type":"address"}],"name":"GovernorTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"comet","type":"address"},{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"NewCampaign","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"comet","type":"address"},{"indexed":false,"internalType":"bytes32","name":"finishRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"NewCampaignFinishRoot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":true,"internalType":"address","name":"comet","type":"address"},{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"comet","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimedSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferOutFailed","type":"event"},{"inputs":[],"name":"MAX_CAMPAIGN_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"campaigns","outputs":[{"internalType":"bytes32","name":"startRoot","type":"bytes32"},{"internalType":"bytes32","name":"finishRoot","type":"bytes32"},{"internalType":"uint256","name":"finishTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs","name":"proofs","type":"tuple"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIds","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[]","name":"proofs","type":"tuple[]"}],"name":"claimBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIDs","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2][]","name":"neighbors","type":"address[2][]"},{"components":[{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"}],"internalType":"struct CometRewardsV2.MultiProofs[]","name":"multiProofs","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof[]","name":"finishProofs","type":"tuple[]"}],"name":"claimBatchForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2]","name":"neighbors","type":"address[2]"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof","name":"finishProof","type":"tuple"}],"name":"claimForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs","name":"proofs","type":"tuple"}],"name":"claimTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIds","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[]","name":"proofs","type":"tuple[]"}],"name":"claimToBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIDs","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2][]","name":"neighbors","type":"address[2][]"},{"components":[{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"}],"internalType":"struct CometRewardsV2.MultiProofs[]","name":"multiProofs","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof[]","name":"finishProofs","type":"tuple[]"}],"name":"claimToBatchForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2]","name":"neighbors","type":"address[2]"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof","name":"finishProof","type":"tuple"}],"name":"claimToForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"}],"name":"getCometCampaignsInfo","outputs":[{"internalType":"bytes32[]","name":"startRoots","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishRoots","type":"bytes32[]"},{"internalType":"address[][]","name":"assets","type":"address[][]"},{"internalType":"uint256[]","name":"finishTimestamps","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bool","name":"shouldAccrue","type":"bool"}],"name":"getRewardsOwed","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"owed","type":"uint256"}],"internalType":"struct CometRewardsV2.RewardOwed","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bool","name":"shouldAccrue","type":"bool"}],"name":"getRewardsOwedBatch","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"owed","type":"uint256"}],"internalType":"struct CometRewardsV2.RewardOwed[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"rewardConfig","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"components":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint128","name":"rescaleFactor","type":"uint128"},{"internalType":"bool","name":"shouldUpscale","type":"bool"}],"internalType":"struct CometRewardsV2.AssetConfig[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"rewardConfigForToken","outputs":[{"components":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint128","name":"rescaleFactor","type":"uint128"},{"internalType":"bool","name":"shouldUpscale","type":"bool"}],"internalType":"struct CometRewardsV2.AssetConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"rewardsClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"bytes32","name":"finishRoot","type":"bytes32"}],"name":"setCampaignFinishRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"bytes32","name":"startRoot","type":"bytes32"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setNewCampaign","outputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"bytes32","name":"startRoot","type":"bytes32"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"multiplier","type":"uint256"}],"internalType":"struct CometRewardsV2.TokenMultiplier[]","name":"assets","type":"tuple[]"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setNewCampaignWithCustomTokenMultiplier","outputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"address[][]","name":"tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"claimedAmounts","type":"uint256[][]"}],"name":"setRewardsClaimed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernor","type":"address"}],"name":"transferGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"bytes32[]","name":"proofs","type":"bytes32[]"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"accrued","type":"uint256"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608080604052346200009757601f620032a338819003918201601f19168301916001600160401b038311848410176200009c578084926020946040528339810103126200009757516001600160a01b03811690819003620000975780156200008557600080546001600160a01b0319169190911790556040516131f09081620000b38239f35b604051630d804a6760e41b8152600490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c90816301e3366714611a8557508063099cc91d146119555780630c340a241461192e57806311555dbc146118c05780631ae8b385146117b95780631d68b74d146116e25780632b8bbd0c1461160d5780634a18481a146115305780635e59ea90146113445780636a775f4f146110ea57806389a3284a146110445780638c7bc838146110265780639880dec214610fa3578063a62f91a614610f1e578063a9cdc9ee14610ce9578063ac80075014610c1e578063b8cc9ce614610b99578063bea0981214610af2578063c126fabe14610a82578063c7b33f4014610878578063d91c8e59146106b3578063e03e2f0014610573578063f1871f24146104495763ff5ad3991461012957600080fd5b346104465760c0366003190112610446576004356001600160a01b0381169003610441576044356024356001600160a01b03821682036104415760a435151560a43503610441576004356001600160a01b03168352600160205260408320541561041f576004356001600160a01b031683526001602052604083205481101561040d576004356001600160a01b031683526001602052604083206101cd9190611b5d565b50906002820154916101f76101e184611bf8565b936101ef6040519586611bbf565b808552611bf8565b601f1901845b8181106103e6575050600181015415806103dd575b610366575b60028101549160643591608435865b85811061027e578688604051918291602083016020845282518091526020604085019301915b81811061025a575050500390f35b9193509160206040826102706001948851611cc1565b01940191019184939261024c565b8061028f6103599260028601611d6a565b90549060039160018060a01b0391831b1c1690816000528501602052604060002060ff6001604051926102c3606085611bbf565b80548452015460018060801b038116602084015260801c161515604082015260018060a01b0387166000526004860160205260406000208260005260205261031660406000205491868a8a600435612f64565b908082111561035e5761032891611cf8565b60405191610337604084611bbf565b82526020820152610348828a611d28565b526103538189611d28565b50611d19565b610226565b505089610328565b6004356001600160a01b03163b156103ce578360405163bfe69c8d60e01b815260018060a01b038416600482015281816024818360018060a01b03600435165af180156103d2576103b9575b5050610217565b816103c391611bbf565b6103ce5783386103b2565b8380fd5b6040513d84823e3d90fd5b5060a435610212565b6020906040516103f7604082611bbf565b60008152600083820152828288010152016101fd565b60405163a554dcdf60e01b8152600490fd5b60405163a034dbb160e01b81528061043d8560048035908401612241565b0390fd5b600080fd5b80fd5b50346104465760c0366003190112610446576004356001600160a01b0380821690818303610441576001600160401b039160243583811161056f57610492903690600401611c0f565b604435928084168403610441576064359081168103610441576084359485151586036104415760a43590811161056b576104d0903690600401611b8f565b9490936020604051809263cde6804160e01b825281806104f4338860048401612241565b03915afa908115610560578991610532575b501561051a5761051596612dfa565b604051f35b6040516319b1d90760e31b8152336004820152602490fd5b610553915060203d8111610559575b61054b8183611bbf565b8101906122c4565b38610506565b503d610541565b6040513d8b823e3d90fd5b8780fd5b8580fd5b503461044657600319610120368201126106af576004356001600160a01b0381811692908383036104415760243590604435818116810361044157606435918216820361044157608435938415158503610441573660e41161056b5760e435966001600160401b03918289116106ab573660448a01116106ab57610104359283116106ab5760609083360301126106a757808952600160205260408920541561068b576020604051809263cde6804160e01b82528180610637338960048401612241565b03915afa90811561056057899161066d575b501561051a576106636105159760040160a486858a61255b565b50600401946127b8565b610685915060203d81116105595761054b8183611bbf565b38610649565b60405163a034dbb160e01b81528061043d8b8a60048401612241565b8880fd5b8980fd5b5080fd5b5034610446576040366003190112610446576001600160a01b039060043582811690819003610441578192915260016020928184526106f760243560408320611b5d565b509160028301805461070881611bf8565b946107166040519687611bbf565b818652601f1961072583611bf8565b01855b818110610853575050600390810190855b8381106107dd575050505061074d906122fd565b604051958695604087019060408852835180925260609183838a0195019187905b8282106107c3575050505086830382880152818087519485815201960194905b83821061079b5787870388f35b9185975082876107b18799849895979951611c9d565b0197019201879695939194929461078e565b8351811687528b9a5095850195928501929087019061076e565b80896107f161084993889d999b9c9d611d6a565b905490851b1c16600052838752604060002060ff8a60405192610815606085611bbf565b8054845201546001600160801b0381168a84015260801c161515604082015261083e828c611d28565b52610353818b611d28565b9897969498610739565b9880959798996108649493946122dc565b82828c010152019897969498929192610728565b50346104465760e036600319011261044657600435906001600160a01b03908183169081840361044157602435936044359380851694858103610441576064359182168083036104415760c43595861515870361044157604051966108de604089611bbf565b60008852600060208099015281875260018852604087205415610a66578187526001885260408720548a101561040d5761092360019a8389528b8a5260408920611b5d565b509389600052600385018952604060002060ff6040519c8d92610947606085611bbf565b80549384905201546001600160801b0381168c8f015260801c16151560408d015215610a4857506001840154159081610a40575b506109ec575b50916004604098926109b0946000520186528760002087600052865287600020549360a4359160843591612f64565b818111156109e4576109c29250611cf8565b905b8351926109d18585611bbf565b83528201526109e282518092611cc1565bf35b5050906109c4565b803b1561056f5785809160246040518094819363bfe69c8d60e01b83528760048401525af18015610a35571561098157610a27868092611bbf565b610a315738610981565b8480fd5b6040513d88823e3d90fd5b90503861097b565b60405163a034dbb160e01b815290819061043d908960048401612241565b60405163a034dbb160e01b81528061043d898960048401612241565b50346104465760031960a0368201126106af576004356001600160a01b0380821682036104415760443590811681036104415760643591821515830361044157608435936001600160401b03851161056f5760c0908536030112610a315761051593600401918060243592612a8b565b50346104465760a0366003190112610446576024356001600160401b0381116106af57610b23903690600401611b8f565b604435906001600160a01b038216820361044157602092610b8f92604051610b6881610b5a8882019460843590606435908761250d565b03601f198101835282611bbf565b519020604051858101918252858152610b82604082611bbf565b519020916004359161313c565b6040519015158152f35b5034610446576020366003190112610446576001600160a01b03600435818116908190036104415782549182169182330361051a578115610c0c5781604051937f6fadb1c244276388aee22be93b919985a18748c021e5d48553957a48101a25608686a36001600160a01b031916178255f35b604051630d804a6760e41b8152600490fd5b503461044657600319610100368201126106af576004356001600160a01b03808216908183036104415760243590604435908116810361044157606435928315158403610441573660c411610ce5576001600160401b039560c43591908783116106a7573660448401116106a75760e4359788116106a757606090883603011261056b5787526001602052604087205415610cc957610515956106638392600401608486858a61255b565b60405163a034dbb160e01b81528061043d898860048401612241565b8680fd5b50346104465760a0366003190112610446576004356001600160a01b0381168103610441576001600160401b03906044358281116103ce57610d2f903690600401611b8f565b909260643581811161056f57610d49903690600401611b8f565b9091608435908111610ce557610d63903690600401611b8f565b8754919690916001600160a01b0316330361051a5781850361040d5781830361040d576001600160a01b0386168852600160205260408820610da89060243590611b5d565b509188975b818910610dba5789604051f35b9091929394959697986002850154610dd38b8585612226565b9050810361040d57610de68b888a612226565b9190500361040d57805b610dfb8b8585612226565b9050811015610f045780898982610eed8f8f818e60048f8f8f8f86610eff9f808f8f9c610ecb96610e5196610e519f9e610ede9f610e628f610ebb99610e5c8f610e5193610e56610e518c610e5c9e81956121cd565b6121dd565b96612226565b906121cd565b7fa56b67569cae558523428bceed457ecebd24ee97a55b8161266bbf9d23c8e6026040610e948a610e5c8a8a8a612226565b81516024358152903560208201526001600160a01b039384169584169490931692a4612226565b359d6001600160a01b03946121cd565b1660005201602052604060002096612226565b6001600160a01b0394916121cd565b16600052602052604060002055611d19565b610df0565b5098610f1890989796959493929198611d19565b97610dad565b50346104465760a0366003190112610446576001600160a01b036004358181168103610441576001600160401b0391602435838111610a3157610f65903690600401611c0f565b916044359182168203610441576064359283151584036104415760843594851161056f5782610f9b610515963690600401611b8f565b949093612dfa565b5034610446576080366003190112610446576001600160a01b03906004358281169081900361044157604435908382168092036104415760643593841680940361044157826110019160049452600160205260406024359120611b5d565b5090600052016020526040600020906000526020526020604060002054604051908152f35b5034610446578060031936011261044657602060405162ed4e008152f35b5034610446576060366003190112610446576001600160a01b0360043581811690819003610441576044359182168092036104415760039261109c916110886122dc565b508152600160205260406024359120611b5d565b5090600052016020526060604060002060ff6001604051926110be8585611bbf565b80548452015460018060801b038116602084015260801c16151560408201526109e26040518092611c9d565b503461044657610100366003190112610446576001600160a01b036004358082169003610441576001600160401b036024358181116103ce57611131903690600401611c0f565b9082604435166044350361044157826064351660643503610441576084351515608435036104415760a435818111610a3157611171903690600401611c6d565b949060c4358381116113405761118b903690600401611b8f565b91909360e4359081116103ce576111a6903690600401611b8f565b90948887510361040d578387510361040d578187510361040d57876004351685526001602052604085205415611322576084356112c9575b845b87518110156112c35760405163cde6804160e01b81526020818061120a3360443560048401612241565b03818d600435165afa9081156112b8578791611299575b501561051a57806112658b6112458361123d611294968e611d28565b51928961225b565b611259611253858b8961226b565b8061228d565b9160443560043561255b565b5061128f611273828b611d28565b518861128084888d6122a2565b916064356044356004356127b8565b611d19565b6111e0565b6112b2915060203d6020116105595761054b8183611bbf565b38611221565b6040513d89823e3d90fd5b85604051f35b87600435163b15610a315760405163bfe69c8d60e01b8152886044351660048201528581602481838d600435165af18015610a355790869161130d575b50506111de565b8161131791611bbf565b610a31578438611306565b60405163a034dbb160e01b81528061043d8760048035908401612241565b8280fd5b50346104465760e0366003190112610446576004356001600160a01b03818116918281036103ce576001600160401b039260243584811161056f5761138d903690600401611c0f565b92604435908116808203610ce55760643594851515860361056b576084358781116106a7576113c0903690600401611c6d565b60a43589811161152c576113d8903690600401611b8f565b91909960c435908111611528576113f3903690600401611b8f565b9590978286510361040d578386510361040d578686510361040d578c9a818c52604060019c8d60205220541561150a57908d92916114b4575b5050508a8981905b61143f575b50604051f35b85518110156114af5761128f8a6114a7938b8f8c6114a1878e61149a8f8f908f8f889987948a8f9361125388611494976114888261148e95611481828e611d28565b519861225b565b9661226b565b9361255b565b50611d28565b51956122a2565b946127b8565b8b908a611434565b611439565b803b156113405760248392604051948593849263bfe69c8d60e01b845260048401525af180156114ff576114eb575b808c9161142c565b8b6114f8919c929c611bbf565b99386114e3565b6040513d8e823e3d90fd5b6044828f6040519163a034dbb160e01b835260048301526024820152fd5b8b80fd5b8a80fd5b5034610446576080366003190112610446576001600160a01b036004358181168103611340576044356001600160401b0381116103ce57366023820112156103ce5780600401359061158182611bf8565b9161158f6040519384611bbf565b80835260209460248685019260061b8401019236841161056b57602401915b8383106115ce57866115c6606435876024358a611d9d565b604051908152f35b60408336031261056b57604051906115e7604083611bbf565b83359083821682036106ab578289926040945282860135838201528152019201916115ae565b50346104465760031960c0368201126106af576004356001600160a01b0381811691828103610a315760443591808316830361056f57606435908116810361056f57608435938415158503610ce55760a435956001600160401b03871161056b5760c0908736030112610ce5576020604051809263cde6804160e01b8252818061169b338a60048401612241565b03915afa9081156112b85787916116c4575b501561051a57610515946004019260243592612a8b565b6116dc915060203d81116105595761054b8183611bbf565b386116ad565b5034610446576060366003190112610446576001600160a01b0360043581811690819003611340576024359060443592845416330361051a57821561040d57808452600160205260408420541561179b578084526001602052604084205482101561040d57600191611793917f86dc3da9b2bb25c8eea35197f01417ff78934ff53c99d1ace0375462e9c46c496060604051838152876020820152846040820152a185528260205260408520611b5d565b500155604051f35b604490846040519163a034dbb160e01b835260048301526024820152fd5b503461044657608036600319011261044657600435906001600160a01b0380831683036106af576044356001600160401b038111611340576117ff903690600401611b8f565b61180b81939293611bf8565b936118196040519586611bbf565b818552601f1961182883611bf8565b01815b81811061189b5750505b81811061184e5760206115c6606435876024358a611d9d565b80611860610e516118969385886121cd565b8460405191611870604084611bbf565b168152670de0b6b3a7640000602082015261188b8288611d28565b526103538187611d28565b611835565b6020906040516118ac604082611bbf565b848152828581830152828a0101520161182b565b5034610446576040366003190112610446576004356001600160a01b03811691908290036104465760243591815260016020526040812090815483101561044657606061190d8484611b5d565b50805490600560018201549101549060405192835260208301526040820152f35b5034610446578060031936011261044657546040516001600160a01b039091168152602090f35b50346104465760209081600319360112610446576001600160a01b0391600435838116810361134057916119b761198f6119aa9594612389565b9592969160409491945198899860808a5260808a0190611b29565b90888203858a0152611b29565b868103604088015283519081815283810184808460051b84010196019387925b848410611a1f5750505050505084820360608601528080855193848152019401925b828110611a0857505050500390f35b8351855286955093810193928101926001016119f9565b919395979688919395999a50601f1983820301855289519082808351928381520192019089905b808210611a6a5750505090806001929a0194019401918a99989697959394916119d7565b9193806001929488875116815201940192018a939291611a46565b9050346106af5760603660031901126106af576004356001600160a01b0381811691828103610a31576024359082821694858303610ce557604435938754163303611b145750611ad6918391613059565b611ae1575b83604051f35b60207f8210728e7c071f615b840ee026032693858fbcd5e5359e67e438c890f59e562091604051908152a3388080611adb565b6319b1d90760e31b8152336004820152602490fd5b90815180825260208080930193019160005b828110611b49575050505090565b835185529381019392810192600101611b3b565b8054821015611b79576000526006602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b9181601f84011215610441578235916001600160401b038311610441576020808501948460051b01011161044157565b601f909101601f19168101906001600160401b03821190821017611be257604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111611be25760051b60200190565b81601f8201121561044157803591611c2683611bf8565b92611c346040519485611bbf565b808452602092838086019260051b820101928311610441578301905b828210611c5e575050505090565b81358152908301908301611c50565b9181601f84011215610441578235916001600160401b038311610441576020808501948460061b01011161044157565b805182526020808201516001600160801b0316908301526040908101511515910152565b80516001600160a01b03168252602090810151910152565b9081602091031261044157516001600160401b03811681036104415790565b818110611d03570390565b634e487b7160e01b600052601160045260246000fd5b6000198114611d035760010190565b8051821015611b795760209160051b010190565b6001600160801b0391821691908215611d5457160490565b634e487b7160e01b600052601260045260246000fd5b8054821015611b795760005260206000200190600090565b6001600160a01b039091168152602081019190915260400190565b91909260018060a01b0390600082815416330361051a57851561040d5783511561040d5762ed4e00821161040d57604080516351076acb60e11b815296909486851694600492916020808b86818b5afa9a8b156121c357869b612194575b5087865260019a8b8252898720805490600160401b8210156121815790611e26918e82018155611b5d565b50988088528c83528a882054958d871061216e578a556000199095019b9487865b611eaf575b5050505050505082194211611e9c5750504201600590910155517fc0b232d318f3e59a207ea5731c6a79d5ae9dd78078bad277630b16a59f797422918190611e9690859083611d82565b0390a190565b634e487b7160e01b825260119052602490fd5b84518110156121695783611ec38287611d28565b510151156121595787848d88611ed9858a611d28565b51511690519283809263313ce56760e01b82525afa801561214f578a90612117575b60ff915016604d8111612104576001600160801b0390600a0a8181116120ee578f91898f8f818f8d928d8b7f809f126df209d3752da0eebe9cd87056d63a3cd3297d3a8756a8b630dc5578c88f9b978d988d80611f6a879f8f169c8c611f61828b611d28565b51511698611d28565b510151908351928352820152a36001600160401b038c1693878a8c8b8989111561207a5791611fa260039798999a92611fab94611d28565b51015198611d3c565b9a865197611fba60608a611bbf565b885287019a168a52611fd28b8688019a868c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b161790555b856120138287611d28565b51511660028c01805490600160401b82101561206757916120428261205d948c809b9a99989795018155611d6a565b819291549060031b8b811b9283911b16911916179055611d19565b9091929394611e47565b634e487b7160e01b8c5260418b5260248cfd5b91611fa260039798999261208d94611d28565b9a86519761209c60608a611bbf565b885287019a168a526120b48b8688019a898c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b16179055612008565b896024918f51916352a4b44160e01b8352820152fd5b634e487b7160e01b8a526011895260248afd5b508481813d8311612148575b61212d8183611bbf565b810103126106ab575160ff811681036106ab5760ff90611efb565b503d612123565b8d513d8c823e3d90fd5b8b5163a554dcdf60e01b81528890fd5b611e4c565b634e487b7160e01b895260118852602489fd5b634e487b7160e01b895260418852602489fd5b816121b5929c503d8d116121bc575b6121ad8183611bbf565b810190611cd9565b9938611dfb565b503d6121a3565b89513d88823e3d90fd5b9190811015611b795760051b0190565b356001600160a01b03811681036104415790565b903590601e198136030182121561044157018035906001600160401b03821161044157602001918160051b3603831361044157565b90821015611b795761223d9160051b8101906121f1565b9091565b6001600160a01b0391821681529116602082015260400190565b9190811015611b795760061b0190565b9190811015611b795760051b81013590601e1981360301821215610441570190565b903590603e1981360301821215610441570190565b9190811015611b795760051b81013590605e1981360301821215610441570190565b90816020910312610441575180151581036104415790565b604051906122eb606083611bbf565b60006040838281528260208201520152565b9060405191828154918282526020928383019160005283600020936000905b8282106123345750505061233292500383611bbf565b565b85546001600160a01b03168452600195860195889550938101939091019061231c565b9061236182611bf8565b61236e6040519182611bbf565b828152809261237f601f1991611bf8565b0190602036910137565b60018060a01b031660009181835260019160209183835260409384862054156124fd578286528084526124056123c186882054612357565b968481528286526123d487822054612357565b809786835284885280832054926123ea84611bf8565b936123f783519586611bbf565b808552601f19958691611bf8565b0189825b8281106124ea575050508398888252868152828220549561244161242c88611bf8565b976124398651998a611bbf565b808952611bf8565b01368288013785988c8884905b61245f575b50505050505050505050565b828552898452858520548110156124e55760056124dc928b9885885289875261248a848a8a20611b5d565b509161249885845492611d28565b526124a7848b84015492611d28565b526124b4600282016122fd565b6124be848c611d28565b526124c9838b611d28565b5001546124d6828b611d28565b52611d19565b8d908d9661244e565b612453565b60608782018301528c95508b9101612409565b5060609450849350839250829150565b604091949392606082019560018060a01b0316825260208201520152565b90359060be1981360301821215610441570190565b6002821015611b79576125589160051b81019061252b565b90565b939092919360018060a01b0380911694600090868252600196602093888552604097888520541561277a5782855289865288852054841015612769578190816125a38a6121dd565b911691829116109182612752575b50501561271a576125c28886612540565b356125cd8487612540565b35108061272b575b1561271a57906125ec918352878452868320611b5d565b50926126756126086125fe8484612540565b60808101906121f1565b95548096612615896121dd565b8a61262b6126238989612540565b359888612540565b0135966126408c519889928b8401948561250d565b0396612654601f1998898101835282611bbf565b5190208a5188810191825288815261266c8c82611bbf565b5190209261313c565b1561270957918091836126d761269f6126966125fe8c6126f09b9a99612540565b969098016121dd565b92896126b68c6126af8187612540565b3595612540565b0135926126cb8b51948592888401978861250d565b03908101835282611bbf565b51902090865190808201928352815261266c8782611bbf565b156126f9575090565b516309bde33960e01b8152600490fd5b85516309bde33960e01b8152600490fd5b865163a554dcdf60e01b8152600490fd5b508761274c61273a8288612540565b356127458689612540565b3590611cf8565b146125d5565b9091506127608689016121dd565b161138806125b1565b885163a554dcdf60e01b8152600490fd5b604483868b519163a034dbb160e01b835260048301526024820152fd5b9081526001600160a01b039091166020820152604081019190915260600190565b929095949193600060018060a01b03851681526001956020928784526127e18560408520611b5d565b508881018054919290918c8115612a615761283e91612824898c61280860408201826121f1565b939095610b5a604051938492868401968201359135908761250d565b5190206040518b81019182528b815261266c604082611bbf565b15612a4f575b6129d9575b88999a84995b612861575b5050505050505050505050565b6002830180548b10156129d3578a8a8a8a8f9e8f8a8a8a8f948f948c8c6128e98461294c9f6129359661289391611d6a565b9390549360039460018060a01b0391861b1c166000528389018c5260ff604060002096604051976128c560608a611bbf565b8054895201546001600160801b0381168e89015260801c1615156040870152611d6a565b60018060a09493941b039254911b1c16968860018060a01b0383169b8c60005260048801825260406000208a6000528252604060002054965415156000146129ca570135915b8c612f64565b90808211612952575b505050505050505050611d19565b9961284f565b61295c9082611cf8565b90612968828587613059565b1561293e5760008051602061319b8339815191529560046129b9948a600052018152604060002090866000525260406000205560405193849360018060a01b03169860018060a01b03169684612797565b0390a48a388a8a828a8a828061293e565b5050809161292f565b50612854565b6001600160a01b0388163b156103ce5760405163bfe69c8d60e01b81526001600160a01b03808d166004830152909b9085908d90602490829084908e165af19b8c15612a44578a9b9c612a30575b509a9950612849565b85612a3d91969296611bbf565b9338612a27565b6040513d87823e3d90fd5b6040516309bde33960e01b8152600490fd5b505060058301544211156128445760405163e8c6942b60e01b81528061043d898c60048401611d82565b6001600160a01b038116600090815260016020526040812054929591949193909215612dd2576001600160a01b03851683526001602052604083205482101561040d576001600160a01b0385168352600160205260408320612aee908390611b5d565b5096612b51612b0060808701876121f1565b91908a54604051938b85612b218c602083019360408201359135908561250d565b0395612b35601f1997888101835282611bbf565b519020604051602081019182526020815261266c604082611bbf565b15612a4f576001890154908115612da857612b9a91612b358a6126cb612b7a60a08c018c6121f1565b9390958c604051938491602083019660206060830135920135908861250d565b15612a4f575b612d3c575b825b6002880154811015612d32578087878a87612bc8612c899660028401611d6a565b92905460039160018060a01b038286851b1c16600052828101602052612c738d60406000209060ff600160405193612c01606086611bbf565b80548552015460018060801b038116602085015260801c161515604083015260018060a01b038a1660005260048401602052604060002060018060a01b03868a891b1c166000526020526040600020549660018501541515600014612d29575060406060820135915b01358a8a612f64565b93808511612c8e575b5050505050505050611d19565b612ba7565b612c989085611cf8565b612cb1818c88871b86901c6001600160a01b0316613059565b15612c7c576001600160a01b039788166000818152600493909301602090815260408085209890961b9490941c891680845296909352908390209390935590518886169591949091169260008051602061319b833981519152928291612d1991908c84612797565b0390a48787388080808e81612c7c565b60409091612c6a565b5050505050505050565b6001600160a01b0385163b156113405760405163bfe69c8d60e01b81526001600160a01b03878116600483015284908290602490829084908b165af18015612d9d57612d89575b50612ba5565b83612d9691949294611bbf565b9138612d83565b6040513d86823e3d90fd5b50506005880154421115612ba05760405163e8c6942b60e01b81528061043d858960048401611d82565b60405163a034dbb160e01b81526001600160a01b038616600482015260248101849052604490fd5b93959492958387510361040d5760009660018060a01b0396878716808a526001986020908a8252604093848d205415612f3457908b9291612edc575b5090508a8a5b612e4f575b505050505050505050505050565b8451811015612ed757612e628186611d28565b51838d528b8352848d20541115612ec657612e7d8186611d28565b5189821015612eb2578161128f8e8d8f9695948d8d612ea58e612eab9960051b81019061252b565b93612a8b565b9091612e3c565b634e487b7160e01b8d52603260045260248dfd5b835163a554dcdf60e01b8152600490fd5b612e41565b909150823b1561152857835163bfe69c8d60e01b815290871660048201528b8160248183875af18015612f2a57612f16575b908a91612e36565b9a612f23818c939d611bbf565b9a90612f0e565b84513d8e823e3d90fd5b6044848e87519163a034dbb160e01b835260048301526024820152fd5b8060001904821181151516611d03570290565b9092908115612fdd5750612f789250611cf8565b604082015115612fb357670de0b6b3a764000091612fa6612faf9260018060801b0360208401511690612f51565b905b5190612f51565b0490565b60208201516001600160801b0316918215611d5457670de0b6b3a764000092612faf920490612fa8565b604051632ae6e9fd60e21b81526001600160a01b039485166004820152936020925084916024918391165afa801561304d5761302a9260009161302f575b506001600160401b0316611cf8565b612f78565b613047915060203d81116121bc576121ad8183611bbf565b3861301b565b6040513d6000823e3d90fd5b9192909260009260009081958315613132576001600160a01b0391821692833b156104465760405163a9059cbb60e01b815281818061309c898760048401611d82565b038183895af180156103d25761311c575b50503d8060001461310c576020146130c3578680fd5b909192939495602081803e515b613104577f8cdf3b7225378a44288992d46fdd440ed9c8fc556b68962dfc6de79ae7b7c631916020916040519586521693a3565b509193505050565b50909192939495506000196130d0565b819298509061312a91611bbf565b9538806130ad565b5050925050915090565b9192916000915b808310613151575050501490565b90919261315f8483856121cd565b3590600082821015613188575060005260205261318160406000205b93611d19565b9190613143565b6040916131819382526020522061317b56fe66d900e943b127cf94bd5fbf6b921691d1993cceda8ba20d63b1cd54b7e1af8aa2646970667358221220cf6a1b672c491a6072444dad943ac842312614d03dd61da465d4c3236e9220d364736f6c634300080f003300000000000000000000000005ed81814be2d9731c8906133236ffe9c62b013e

Deployed Bytecode

0x608080604052600436101561001357600080fd5b600090813560e01c90816301e3366714611a8557508063099cc91d146119555780630c340a241461192e57806311555dbc146118c05780631ae8b385146117b95780631d68b74d146116e25780632b8bbd0c1461160d5780634a18481a146115305780635e59ea90146113445780636a775f4f146110ea57806389a3284a146110445780638c7bc838146110265780639880dec214610fa3578063a62f91a614610f1e578063a9cdc9ee14610ce9578063ac80075014610c1e578063b8cc9ce614610b99578063bea0981214610af2578063c126fabe14610a82578063c7b33f4014610878578063d91c8e59146106b3578063e03e2f0014610573578063f1871f24146104495763ff5ad3991461012957600080fd5b346104465760c0366003190112610446576004356001600160a01b0381169003610441576044356024356001600160a01b03821682036104415760a435151560a43503610441576004356001600160a01b03168352600160205260408320541561041f576004356001600160a01b031683526001602052604083205481101561040d576004356001600160a01b031683526001602052604083206101cd9190611b5d565b50906002820154916101f76101e184611bf8565b936101ef6040519586611bbf565b808552611bf8565b601f1901845b8181106103e6575050600181015415806103dd575b610366575b60028101549160643591608435865b85811061027e578688604051918291602083016020845282518091526020604085019301915b81811061025a575050500390f35b9193509160206040826102706001948851611cc1565b01940191019184939261024c565b8061028f6103599260028601611d6a565b90549060039160018060a01b0391831b1c1690816000528501602052604060002060ff6001604051926102c3606085611bbf565b80548452015460018060801b038116602084015260801c161515604082015260018060a01b0387166000526004860160205260406000208260005260205261031660406000205491868a8a600435612f64565b908082111561035e5761032891611cf8565b60405191610337604084611bbf565b82526020820152610348828a611d28565b526103538189611d28565b50611d19565b610226565b505089610328565b6004356001600160a01b03163b156103ce578360405163bfe69c8d60e01b815260018060a01b038416600482015281816024818360018060a01b03600435165af180156103d2576103b9575b5050610217565b816103c391611bbf565b6103ce5783386103b2565b8380fd5b6040513d84823e3d90fd5b5060a435610212565b6020906040516103f7604082611bbf565b60008152600083820152828288010152016101fd565b60405163a554dcdf60e01b8152600490fd5b60405163a034dbb160e01b81528061043d8560048035908401612241565b0390fd5b600080fd5b80fd5b50346104465760c0366003190112610446576004356001600160a01b0380821690818303610441576001600160401b039160243583811161056f57610492903690600401611c0f565b604435928084168403610441576064359081168103610441576084359485151586036104415760a43590811161056b576104d0903690600401611b8f565b9490936020604051809263cde6804160e01b825281806104f4338860048401612241565b03915afa908115610560578991610532575b501561051a5761051596612dfa565b604051f35b6040516319b1d90760e31b8152336004820152602490fd5b610553915060203d8111610559575b61054b8183611bbf565b8101906122c4565b38610506565b503d610541565b6040513d8b823e3d90fd5b8780fd5b8580fd5b503461044657600319610120368201126106af576004356001600160a01b0381811692908383036104415760243590604435818116810361044157606435918216820361044157608435938415158503610441573660e41161056b5760e435966001600160401b03918289116106ab573660448a01116106ab57610104359283116106ab5760609083360301126106a757808952600160205260408920541561068b576020604051809263cde6804160e01b82528180610637338960048401612241565b03915afa90811561056057899161066d575b501561051a576106636105159760040160a486858a61255b565b50600401946127b8565b610685915060203d81116105595761054b8183611bbf565b38610649565b60405163a034dbb160e01b81528061043d8b8a60048401612241565b8880fd5b8980fd5b5080fd5b5034610446576040366003190112610446576001600160a01b039060043582811690819003610441578192915260016020928184526106f760243560408320611b5d565b509160028301805461070881611bf8565b946107166040519687611bbf565b818652601f1961072583611bf8565b01855b818110610853575050600390810190855b8381106107dd575050505061074d906122fd565b604051958695604087019060408852835180925260609183838a0195019187905b8282106107c3575050505086830382880152818087519485815201960194905b83821061079b5787870388f35b9185975082876107b18799849895979951611c9d565b0197019201879695939194929461078e565b8351811687528b9a5095850195928501929087019061076e565b80896107f161084993889d999b9c9d611d6a565b905490851b1c16600052838752604060002060ff8a60405192610815606085611bbf565b8054845201546001600160801b0381168a84015260801c161515604082015261083e828c611d28565b52610353818b611d28565b9897969498610739565b9880959798996108649493946122dc565b82828c010152019897969498929192610728565b50346104465760e036600319011261044657600435906001600160a01b03908183169081840361044157602435936044359380851694858103610441576064359182168083036104415760c43595861515870361044157604051966108de604089611bbf565b60008852600060208099015281875260018852604087205415610a66578187526001885260408720548a101561040d5761092360019a8389528b8a5260408920611b5d565b509389600052600385018952604060002060ff6040519c8d92610947606085611bbf565b80549384905201546001600160801b0381168c8f015260801c16151560408d015215610a4857506001840154159081610a40575b506109ec575b50916004604098926109b0946000520186528760002087600052865287600020549360a4359160843591612f64565b818111156109e4576109c29250611cf8565b905b8351926109d18585611bbf565b83528201526109e282518092611cc1565bf35b5050906109c4565b803b1561056f5785809160246040518094819363bfe69c8d60e01b83528760048401525af18015610a35571561098157610a27868092611bbf565b610a315738610981565b8480fd5b6040513d88823e3d90fd5b90503861097b565b60405163a034dbb160e01b815290819061043d908960048401612241565b60405163a034dbb160e01b81528061043d898960048401612241565b50346104465760031960a0368201126106af576004356001600160a01b0380821682036104415760443590811681036104415760643591821515830361044157608435936001600160401b03851161056f5760c0908536030112610a315761051593600401918060243592612a8b565b50346104465760a0366003190112610446576024356001600160401b0381116106af57610b23903690600401611b8f565b604435906001600160a01b038216820361044157602092610b8f92604051610b6881610b5a8882019460843590606435908761250d565b03601f198101835282611bbf565b519020604051858101918252858152610b82604082611bbf565b519020916004359161313c565b6040519015158152f35b5034610446576020366003190112610446576001600160a01b03600435818116908190036104415782549182169182330361051a578115610c0c5781604051937f6fadb1c244276388aee22be93b919985a18748c021e5d48553957a48101a25608686a36001600160a01b031916178255f35b604051630d804a6760e41b8152600490fd5b503461044657600319610100368201126106af576004356001600160a01b03808216908183036104415760243590604435908116810361044157606435928315158403610441573660c411610ce5576001600160401b039560c43591908783116106a7573660448401116106a75760e4359788116106a757606090883603011261056b5787526001602052604087205415610cc957610515956106638392600401608486858a61255b565b60405163a034dbb160e01b81528061043d898860048401612241565b8680fd5b50346104465760a0366003190112610446576004356001600160a01b0381168103610441576001600160401b03906044358281116103ce57610d2f903690600401611b8f565b909260643581811161056f57610d49903690600401611b8f565b9091608435908111610ce557610d63903690600401611b8f565b8754919690916001600160a01b0316330361051a5781850361040d5781830361040d576001600160a01b0386168852600160205260408820610da89060243590611b5d565b509188975b818910610dba5789604051f35b9091929394959697986002850154610dd38b8585612226565b9050810361040d57610de68b888a612226565b9190500361040d57805b610dfb8b8585612226565b9050811015610f045780898982610eed8f8f818e60048f8f8f8f86610eff9f808f8f9c610ecb96610e5196610e519f9e610ede9f610e628f610ebb99610e5c8f610e5193610e56610e518c610e5c9e81956121cd565b6121dd565b96612226565b906121cd565b7fa56b67569cae558523428bceed457ecebd24ee97a55b8161266bbf9d23c8e6026040610e948a610e5c8a8a8a612226565b81516024358152903560208201526001600160a01b039384169584169490931692a4612226565b359d6001600160a01b03946121cd565b1660005201602052604060002096612226565b6001600160a01b0394916121cd565b16600052602052604060002055611d19565b610df0565b5098610f1890989796959493929198611d19565b97610dad565b50346104465760a0366003190112610446576001600160a01b036004358181168103610441576001600160401b0391602435838111610a3157610f65903690600401611c0f565b916044359182168203610441576064359283151584036104415760843594851161056f5782610f9b610515963690600401611b8f565b949093612dfa565b5034610446576080366003190112610446576001600160a01b03906004358281169081900361044157604435908382168092036104415760643593841680940361044157826110019160049452600160205260406024359120611b5d565b5090600052016020526040600020906000526020526020604060002054604051908152f35b5034610446578060031936011261044657602060405162ed4e008152f35b5034610446576060366003190112610446576001600160a01b0360043581811690819003610441576044359182168092036104415760039261109c916110886122dc565b508152600160205260406024359120611b5d565b5090600052016020526060604060002060ff6001604051926110be8585611bbf565b80548452015460018060801b038116602084015260801c16151560408201526109e26040518092611c9d565b503461044657610100366003190112610446576001600160a01b036004358082169003610441576001600160401b036024358181116103ce57611131903690600401611c0f565b9082604435166044350361044157826064351660643503610441576084351515608435036104415760a435818111610a3157611171903690600401611c6d565b949060c4358381116113405761118b903690600401611b8f565b91909360e4359081116103ce576111a6903690600401611b8f565b90948887510361040d578387510361040d578187510361040d57876004351685526001602052604085205415611322576084356112c9575b845b87518110156112c35760405163cde6804160e01b81526020818061120a3360443560048401612241565b03818d600435165afa9081156112b8578791611299575b501561051a57806112658b6112458361123d611294968e611d28565b51928961225b565b611259611253858b8961226b565b8061228d565b9160443560043561255b565b5061128f611273828b611d28565b518861128084888d6122a2565b916064356044356004356127b8565b611d19565b6111e0565b6112b2915060203d6020116105595761054b8183611bbf565b38611221565b6040513d89823e3d90fd5b85604051f35b87600435163b15610a315760405163bfe69c8d60e01b8152886044351660048201528581602481838d600435165af18015610a355790869161130d575b50506111de565b8161131791611bbf565b610a31578438611306565b60405163a034dbb160e01b81528061043d8760048035908401612241565b8280fd5b50346104465760e0366003190112610446576004356001600160a01b03818116918281036103ce576001600160401b039260243584811161056f5761138d903690600401611c0f565b92604435908116808203610ce55760643594851515860361056b576084358781116106a7576113c0903690600401611c6d565b60a43589811161152c576113d8903690600401611b8f565b91909960c435908111611528576113f3903690600401611b8f565b9590978286510361040d578386510361040d578686510361040d578c9a818c52604060019c8d60205220541561150a57908d92916114b4575b5050508a8981905b61143f575b50604051f35b85518110156114af5761128f8a6114a7938b8f8c6114a1878e61149a8f8f908f8f889987948a8f9361125388611494976114888261148e95611481828e611d28565b519861225b565b9661226b565b9361255b565b50611d28565b51956122a2565b946127b8565b8b908a611434565b611439565b803b156113405760248392604051948593849263bfe69c8d60e01b845260048401525af180156114ff576114eb575b808c9161142c565b8b6114f8919c929c611bbf565b99386114e3565b6040513d8e823e3d90fd5b6044828f6040519163a034dbb160e01b835260048301526024820152fd5b8b80fd5b8a80fd5b5034610446576080366003190112610446576001600160a01b036004358181168103611340576044356001600160401b0381116103ce57366023820112156103ce5780600401359061158182611bf8565b9161158f6040519384611bbf565b80835260209460248685019260061b8401019236841161056b57602401915b8383106115ce57866115c6606435876024358a611d9d565b604051908152f35b60408336031261056b57604051906115e7604083611bbf565b83359083821682036106ab578289926040945282860135838201528152019201916115ae565b50346104465760031960c0368201126106af576004356001600160a01b0381811691828103610a315760443591808316830361056f57606435908116810361056f57608435938415158503610ce55760a435956001600160401b03871161056b5760c0908736030112610ce5576020604051809263cde6804160e01b8252818061169b338a60048401612241565b03915afa9081156112b85787916116c4575b501561051a57610515946004019260243592612a8b565b6116dc915060203d81116105595761054b8183611bbf565b386116ad565b5034610446576060366003190112610446576001600160a01b0360043581811690819003611340576024359060443592845416330361051a57821561040d57808452600160205260408420541561179b578084526001602052604084205482101561040d57600191611793917f86dc3da9b2bb25c8eea35197f01417ff78934ff53c99d1ace0375462e9c46c496060604051838152876020820152846040820152a185528260205260408520611b5d565b500155604051f35b604490846040519163a034dbb160e01b835260048301526024820152fd5b503461044657608036600319011261044657600435906001600160a01b0380831683036106af576044356001600160401b038111611340576117ff903690600401611b8f565b61180b81939293611bf8565b936118196040519586611bbf565b818552601f1961182883611bf8565b01815b81811061189b5750505b81811061184e5760206115c6606435876024358a611d9d565b80611860610e516118969385886121cd565b8460405191611870604084611bbf565b168152670de0b6b3a7640000602082015261188b8288611d28565b526103538187611d28565b611835565b6020906040516118ac604082611bbf565b848152828581830152828a0101520161182b565b5034610446576040366003190112610446576004356001600160a01b03811691908290036104465760243591815260016020526040812090815483101561044657606061190d8484611b5d565b50805490600560018201549101549060405192835260208301526040820152f35b5034610446578060031936011261044657546040516001600160a01b039091168152602090f35b50346104465760209081600319360112610446576001600160a01b0391600435838116810361134057916119b761198f6119aa9594612389565b9592969160409491945198899860808a5260808a0190611b29565b90888203858a0152611b29565b868103604088015283519081815283810184808460051b84010196019387925b848410611a1f5750505050505084820360608601528080855193848152019401925b828110611a0857505050500390f35b8351855286955093810193928101926001016119f9565b919395979688919395999a50601f1983820301855289519082808351928381520192019089905b808210611a6a5750505090806001929a0194019401918a99989697959394916119d7565b9193806001929488875116815201940192018a939291611a46565b9050346106af5760603660031901126106af576004356001600160a01b0381811691828103610a31576024359082821694858303610ce557604435938754163303611b145750611ad6918391613059565b611ae1575b83604051f35b60207f8210728e7c071f615b840ee026032693858fbcd5e5359e67e438c890f59e562091604051908152a3388080611adb565b6319b1d90760e31b8152336004820152602490fd5b90815180825260208080930193019160005b828110611b49575050505090565b835185529381019392810192600101611b3b565b8054821015611b79576000526006602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b9181601f84011215610441578235916001600160401b038311610441576020808501948460051b01011161044157565b601f909101601f19168101906001600160401b03821190821017611be257604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111611be25760051b60200190565b81601f8201121561044157803591611c2683611bf8565b92611c346040519485611bbf565b808452602092838086019260051b820101928311610441578301905b828210611c5e575050505090565b81358152908301908301611c50565b9181601f84011215610441578235916001600160401b038311610441576020808501948460061b01011161044157565b805182526020808201516001600160801b0316908301526040908101511515910152565b80516001600160a01b03168252602090810151910152565b9081602091031261044157516001600160401b03811681036104415790565b818110611d03570390565b634e487b7160e01b600052601160045260246000fd5b6000198114611d035760010190565b8051821015611b795760209160051b010190565b6001600160801b0391821691908215611d5457160490565b634e487b7160e01b600052601260045260246000fd5b8054821015611b795760005260206000200190600090565b6001600160a01b039091168152602081019190915260400190565b91909260018060a01b0390600082815416330361051a57851561040d5783511561040d5762ed4e00821161040d57604080516351076acb60e11b815296909486851694600492916020808b86818b5afa9a8b156121c357869b612194575b5087865260019a8b8252898720805490600160401b8210156121815790611e26918e82018155611b5d565b50988088528c83528a882054958d871061216e578a556000199095019b9487865b611eaf575b5050505050505082194211611e9c5750504201600590910155517fc0b232d318f3e59a207ea5731c6a79d5ae9dd78078bad277630b16a59f797422918190611e9690859083611d82565b0390a190565b634e487b7160e01b825260119052602490fd5b84518110156121695783611ec38287611d28565b510151156121595787848d88611ed9858a611d28565b51511690519283809263313ce56760e01b82525afa801561214f578a90612117575b60ff915016604d8111612104576001600160801b0390600a0a8181116120ee578f91898f8f818f8d928d8b7f809f126df209d3752da0eebe9cd87056d63a3cd3297d3a8756a8b630dc5578c88f9b978d988d80611f6a879f8f169c8c611f61828b611d28565b51511698611d28565b510151908351928352820152a36001600160401b038c1693878a8c8b8989111561207a5791611fa260039798999a92611fab94611d28565b51015198611d3c565b9a865197611fba60608a611bbf565b885287019a168a52611fd28b8688019a868c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b161790555b856120138287611d28565b51511660028c01805490600160401b82101561206757916120428261205d948c809b9a99989795018155611d6a565b819291549060031b8b811b9283911b16911916179055611d19565b9091929394611e47565b634e487b7160e01b8c5260418b5260248cfd5b91611fa260039798999261208d94611d28565b9a86519761209c60608a611bbf565b885287019a168a526120b48b8688019a898c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b16179055612008565b896024918f51916352a4b44160e01b8352820152fd5b634e487b7160e01b8a526011895260248afd5b508481813d8311612148575b61212d8183611bbf565b810103126106ab575160ff811681036106ab5760ff90611efb565b503d612123565b8d513d8c823e3d90fd5b8b5163a554dcdf60e01b81528890fd5b611e4c565b634e487b7160e01b895260118852602489fd5b634e487b7160e01b895260418852602489fd5b816121b5929c503d8d116121bc575b6121ad8183611bbf565b810190611cd9565b9938611dfb565b503d6121a3565b89513d88823e3d90fd5b9190811015611b795760051b0190565b356001600160a01b03811681036104415790565b903590601e198136030182121561044157018035906001600160401b03821161044157602001918160051b3603831361044157565b90821015611b795761223d9160051b8101906121f1565b9091565b6001600160a01b0391821681529116602082015260400190565b9190811015611b795760061b0190565b9190811015611b795760051b81013590601e1981360301821215610441570190565b903590603e1981360301821215610441570190565b9190811015611b795760051b81013590605e1981360301821215610441570190565b90816020910312610441575180151581036104415790565b604051906122eb606083611bbf565b60006040838281528260208201520152565b9060405191828154918282526020928383019160005283600020936000905b8282106123345750505061233292500383611bbf565b565b85546001600160a01b03168452600195860195889550938101939091019061231c565b9061236182611bf8565b61236e6040519182611bbf565b828152809261237f601f1991611bf8565b0190602036910137565b60018060a01b031660009181835260019160209183835260409384862054156124fd578286528084526124056123c186882054612357565b968481528286526123d487822054612357565b809786835284885280832054926123ea84611bf8565b936123f783519586611bbf565b808552601f19958691611bf8565b0189825b8281106124ea575050508398888252868152828220549561244161242c88611bf8565b976124398651998a611bbf565b808952611bf8565b01368288013785988c8884905b61245f575b50505050505050505050565b828552898452858520548110156124e55760056124dc928b9885885289875261248a848a8a20611b5d565b509161249885845492611d28565b526124a7848b84015492611d28565b526124b4600282016122fd565b6124be848c611d28565b526124c9838b611d28565b5001546124d6828b611d28565b52611d19565b8d908d9661244e565b612453565b60608782018301528c95508b9101612409565b5060609450849350839250829150565b604091949392606082019560018060a01b0316825260208201520152565b90359060be1981360301821215610441570190565b6002821015611b79576125589160051b81019061252b565b90565b939092919360018060a01b0380911694600090868252600196602093888552604097888520541561277a5782855289865288852054841015612769578190816125a38a6121dd565b911691829116109182612752575b50501561271a576125c28886612540565b356125cd8487612540565b35108061272b575b1561271a57906125ec918352878452868320611b5d565b50926126756126086125fe8484612540565b60808101906121f1565b95548096612615896121dd565b8a61262b6126238989612540565b359888612540565b0135966126408c519889928b8401948561250d565b0396612654601f1998898101835282611bbf565b5190208a5188810191825288815261266c8c82611bbf565b5190209261313c565b1561270957918091836126d761269f6126966125fe8c6126f09b9a99612540565b969098016121dd565b92896126b68c6126af8187612540565b3595612540565b0135926126cb8b51948592888401978861250d565b03908101835282611bbf565b51902090865190808201928352815261266c8782611bbf565b156126f9575090565b516309bde33960e01b8152600490fd5b85516309bde33960e01b8152600490fd5b865163a554dcdf60e01b8152600490fd5b508761274c61273a8288612540565b356127458689612540565b3590611cf8565b146125d5565b9091506127608689016121dd565b161138806125b1565b885163a554dcdf60e01b8152600490fd5b604483868b519163a034dbb160e01b835260048301526024820152fd5b9081526001600160a01b039091166020820152604081019190915260600190565b929095949193600060018060a01b03851681526001956020928784526127e18560408520611b5d565b508881018054919290918c8115612a615761283e91612824898c61280860408201826121f1565b939095610b5a604051938492868401968201359135908761250d565b5190206040518b81019182528b815261266c604082611bbf565b15612a4f575b6129d9575b88999a84995b612861575b5050505050505050505050565b6002830180548b10156129d3578a8a8a8a8f9e8f8a8a8a8f948f948c8c6128e98461294c9f6129359661289391611d6a565b9390549360039460018060a01b0391861b1c166000528389018c5260ff604060002096604051976128c560608a611bbf565b8054895201546001600160801b0381168e89015260801c1615156040870152611d6a565b60018060a09493941b039254911b1c16968860018060a01b0383169b8c60005260048801825260406000208a6000528252604060002054965415156000146129ca570135915b8c612f64565b90808211612952575b505050505050505050611d19565b9961284f565b61295c9082611cf8565b90612968828587613059565b1561293e5760008051602061319b8339815191529560046129b9948a600052018152604060002090866000525260406000205560405193849360018060a01b03169860018060a01b03169684612797565b0390a48a388a8a828a8a828061293e565b5050809161292f565b50612854565b6001600160a01b0388163b156103ce5760405163bfe69c8d60e01b81526001600160a01b03808d166004830152909b9085908d90602490829084908e165af19b8c15612a44578a9b9c612a30575b509a9950612849565b85612a3d91969296611bbf565b9338612a27565b6040513d87823e3d90fd5b6040516309bde33960e01b8152600490fd5b505060058301544211156128445760405163e8c6942b60e01b81528061043d898c60048401611d82565b6001600160a01b038116600090815260016020526040812054929591949193909215612dd2576001600160a01b03851683526001602052604083205482101561040d576001600160a01b0385168352600160205260408320612aee908390611b5d565b5096612b51612b0060808701876121f1565b91908a54604051938b85612b218c602083019360408201359135908561250d565b0395612b35601f1997888101835282611bbf565b519020604051602081019182526020815261266c604082611bbf565b15612a4f576001890154908115612da857612b9a91612b358a6126cb612b7a60a08c018c6121f1565b9390958c604051938491602083019660206060830135920135908861250d565b15612a4f575b612d3c575b825b6002880154811015612d32578087878a87612bc8612c899660028401611d6a565b92905460039160018060a01b038286851b1c16600052828101602052612c738d60406000209060ff600160405193612c01606086611bbf565b80548552015460018060801b038116602085015260801c161515604083015260018060a01b038a1660005260048401602052604060002060018060a01b03868a891b1c166000526020526040600020549660018501541515600014612d29575060406060820135915b01358a8a612f64565b93808511612c8e575b5050505050505050611d19565b612ba7565b612c989085611cf8565b612cb1818c88871b86901c6001600160a01b0316613059565b15612c7c576001600160a01b039788166000818152600493909301602090815260408085209890961b9490941c891680845296909352908390209390935590518886169591949091169260008051602061319b833981519152928291612d1991908c84612797565b0390a48787388080808e81612c7c565b60409091612c6a565b5050505050505050565b6001600160a01b0385163b156113405760405163bfe69c8d60e01b81526001600160a01b03878116600483015284908290602490829084908b165af18015612d9d57612d89575b50612ba5565b83612d9691949294611bbf565b9138612d83565b6040513d86823e3d90fd5b50506005880154421115612ba05760405163e8c6942b60e01b81528061043d858960048401611d82565b60405163a034dbb160e01b81526001600160a01b038616600482015260248101849052604490fd5b93959492958387510361040d5760009660018060a01b0396878716808a526001986020908a8252604093848d205415612f3457908b9291612edc575b5090508a8a5b612e4f575b505050505050505050505050565b8451811015612ed757612e628186611d28565b51838d528b8352848d20541115612ec657612e7d8186611d28565b5189821015612eb2578161128f8e8d8f9695948d8d612ea58e612eab9960051b81019061252b565b93612a8b565b9091612e3c565b634e487b7160e01b8d52603260045260248dfd5b835163a554dcdf60e01b8152600490fd5b612e41565b909150823b1561152857835163bfe69c8d60e01b815290871660048201528b8160248183875af18015612f2a57612f16575b908a91612e36565b9a612f23818c939d611bbf565b9a90612f0e565b84513d8e823e3d90fd5b6044848e87519163a034dbb160e01b835260048301526024820152fd5b8060001904821181151516611d03570290565b9092908115612fdd5750612f789250611cf8565b604082015115612fb357670de0b6b3a764000091612fa6612faf9260018060801b0360208401511690612f51565b905b5190612f51565b0490565b60208201516001600160801b0316918215611d5457670de0b6b3a764000092612faf920490612fa8565b604051632ae6e9fd60e21b81526001600160a01b039485166004820152936020925084916024918391165afa801561304d5761302a9260009161302f575b506001600160401b0316611cf8565b612f78565b613047915060203d81116121bc576121ad8183611bbf565b3861301b565b6040513d6000823e3d90fd5b9192909260009260009081958315613132576001600160a01b0391821692833b156104465760405163a9059cbb60e01b815281818061309c898760048401611d82565b038183895af180156103d25761311c575b50503d8060001461310c576020146130c3578680fd5b909192939495602081803e515b613104577f8cdf3b7225378a44288992d46fdd440ed9c8fc556b68962dfc6de79ae7b7c631916020916040519586521693a3565b509193505050565b50909192939495506000196130d0565b819298509061312a91611bbf565b9538806130ad565b5050925050915090565b9192916000915b808310613151575050501490565b90919261315f8483856121cd565b3590600082821015613188575060005260205261318160406000205b93611d19565b9190613143565b6040916131819382526020522061317b56fe66d900e943b127cf94bd5fbf6b921691d1993cceda8ba20d63b1cd54b7e1af8aa2646970667358221220cf6a1b672c491a6072444dad943ac842312614d03dd61da465d4c3236e9220d364736f6c634300080f0033

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

00000000000000000000000005ed81814be2d9731c8906133236ffe9c62b013e

-----Decoded View---------------
Arg [0] : governor_ (address): 0x05ED81814BE2D9731c8906133236FFE9C62B013E

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000005ed81814be2d9731c8906133236ffe9c62b013e


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
[ Download: CSV Export  ]

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