ETH Price: $2,881.98 (-1.60%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim243195862026-01-26 14:25:239 mins ago1769437523IN
0x66666666...6360f919c
0 ETH0.000011350.22237665
Claim With Callb...243193292026-01-26 13:33:231 hr ago1769434403IN
0x66666666...6360f919c
0 ETH0.00031822.16338038
Claim With Callb...243186602026-01-26 11:18:593 hrs ago1769426339IN
0x66666666...6360f919c
0 ETH0.000010110.06930804
Claim243179522026-01-26 8:56:475 hrs ago1769417807IN
0x66666666...6360f919c
0 ETH0.000002950.04338483
Claim With Callb...243173652026-01-26 6:59:117 hrs ago1769410751IN
0x66666666...6360f919c
0 ETH0.000007350.05970728
Claim With Callb...243162292026-01-26 3:11:3511 hrs ago1769397095IN
0x66666666...6360f919c
0 ETH0.00037522.23122379
Claim243161412026-01-26 2:53:5911 hrs ago1769396039IN
0x66666666...6360f919c
0 ETH0.00000320.04699481
Claim243157242026-01-26 1:30:1113 hrs ago1769391011IN
0x66666666...6360f919c
0 ETH0.000005490.08060887
Claim With Callb...243144292026-01-25 21:10:4717 hrs ago1769375447IN
0x66666666...6360f919c
0 ETH0.000027290.16746427
Claim243140252026-01-25 19:48:5918 hrs ago1769370539IN
0x66666666...6360f919c
0 ETH0.000152252.23347854
Claim With Callb...243126352026-01-25 15:10:3523 hrs ago1769353835IN
0x66666666...6360f919c
0 ETH0.000010350.06354438
Claim With Callb...243114952026-01-25 11:22:1127 hrs ago1769340131IN
0x66666666...6360f919c
0 ETH0.00000680.04662584
Claim243106112026-01-25 8:24:3530 hrs ago1769329475IN
0x66666666...6360f919c
0 ETH0.00013892.03755013
Claim243087082026-01-25 2:02:3536 hrs ago1769306555IN
0x66666666...6360f919c
0 ETH0.000002120.0311057
Claim243084252026-01-25 1:05:5937 hrs ago1769303159IN
0x66666666...6360f919c
0 ETH0.000002440.03589614
Claim243079692026-01-24 23:33:5939 hrs ago1769297639IN
0x66666666...6360f919c
0 ETH0.000002470.03634281
Claim With Callb...243078092026-01-24 23:01:4739 hrs ago1769295707IN
0x66666666...6360f919c
0 ETH0.000004340.03527981
Redeem243078042026-01-24 23:00:4739 hrs ago1769295647IN
0x66666666...6360f919c
0 ETH0.000001860.03509838
Claim243077942026-01-24 22:58:3539 hrs ago1769295515IN
0x66666666...6360f919c
0 ETH0.000001760.03462828
Claim With Callb...243065872026-01-24 18:56:4743 hrs ago1769281007IN
0x66666666...6360f919c
0 ETH0.0002722.09257746
Claim243031902026-01-24 7:34:232 days ago1769240063IN
0x66666666...6360f919c
0 ETH0.000103872.03394615
Claim243021032026-01-24 3:55:592 days ago1769226959IN
0x66666666...6360f919c
0 ETH0.000004720.06927
Claim243020792026-01-24 3:51:112 days ago1769226671IN
0x66666666...6360f919c
0 ETH0.000005180.06927
Claim243007722026-01-23 23:28:592 days ago1769210939IN
0x66666666...6360f919c
0 ETH0.000003290.04829323
Claim242996352026-01-23 19:40:112 days ago1769197211IN
0x66666666...6360f919c
0 ETH0.000145252.130726
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x61018080220348632025-03-13 2:08:11319 days ago1741831691  Contract Creation0 ETH
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
VestManager

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import { VestManagerBase } from "./VestManagerBase.sol";

interface IGovToken is IERC20 {
    function INITIAL_SUPPLY() external view returns (uint256);
}

contract VestManager is VestManagerBase {
    uint256 constant PRECISION = 1e18;
    address immutable public prisma;
    address immutable public yprisma;
    address immutable public cvxprisma;
    uint256 public immutable INITIAL_SUPPLY;
    address public immutable BURN_ADDRESS;
    
    bool public initialized;
    uint256 public redemptionRatio;
    mapping(AllocationType => uint256) public allocationByType;
    mapping(AllocationType => uint256) public durationByType;
    mapping(AllocationType => bytes32) public merkleRootByType;
    mapping(address account => mapping(AllocationType => bool hasClaimed)) public hasClaimed; // used for airdrops only

    enum AllocationType {
        PERMA_STAKE,
        LICENSING,
        TREASURY,
        REDEMPTIONS,
        AIRDROP_TEAM,
        AIRDROP_VICTIMS,
        AIRDROP_LOCK_PENALTY
    }

    event TokenRedeemed(address indexed token, address indexed redeemer, address indexed recipient, uint256 amount);
    event MerkleRootSet(AllocationType indexed allocationType, bytes32 root);
    event AirdropClaimed(AllocationType indexed allocationType, address indexed account, address indexed recipient, uint256 amount);
    event InitializationParamsSet();

    constructor(
        address _core,
        address _token,
        address _burnAddress,
        address[3] memory _redemptionTokens // PRISMA, yPRISMA, cvxPRISMA
    ) VestManagerBase(_core, _token) {
        INITIAL_SUPPLY = IGovToken(_token).INITIAL_SUPPLY();
        require(IERC20(_token).balanceOf(address(this)) == INITIAL_SUPPLY, "VestManager not funded");
        BURN_ADDRESS = _burnAddress;
        prisma = _redemptionTokens[0];
        yprisma = _redemptionTokens[1];
        cvxprisma = _redemptionTokens[2];
    }

    /**
        @notice Set the initialization parameters for the vesting contract
        @dev All values must be set in the same order as the AllocationType enum
        @param _maxRedeemable   Maximum amount of PRISMA/yPRISMA/cvxPRISMA that can be redeemed
        @param _merkleRoots     Merkle roots for the airdrop allocations
        @param _nonUserTargets  Addresses to receive the non-user allocations
        @param _vestDurations  Durations of the vesting periods for each type
        @param _allocPercentages Percentages of the initial supply allocated to each type,  
            the first two values being perma-stakers, followed by all other allocation types in order of 
            AllocationType enum.
    */
    function setInitializationParams(
        uint256 _maxRedeemable,
        bytes32[3] memory _merkleRoots,
        address[4] memory _nonUserTargets,
        uint256[8] memory _vestDurations,
        uint256[8] memory _allocPercentages
    ) external onlyOwner {
        require(!initialized, "params already set");
        initialized = true;

        uint256 totalPctAllocated;
        uint256 airdropIndex;
        require(_vestDurations[0] == _vestDurations[1], "perma-staker durations must match");
        for (uint256 i = 0; i < _allocPercentages.length; i++) {
            AllocationType allocType = i == 0 ? AllocationType(i) : AllocationType(i-1); // First two are same type
            require(_vestDurations[i] > 0 && _vestDurations[i] <= type(uint32).max, "invalid duration");
            durationByType[allocType] = uint32(_vestDurations[i]);
            totalPctAllocated += _allocPercentages[i];
            uint256 allocation = _allocPercentages[i] * INITIAL_SUPPLY / PRECISION;
            allocationByType[allocType] += allocation;
            
            if (i < _nonUserTargets.length) { 
                _createVest(
                    _nonUserTargets[i], 
                    uint32(_vestDurations[i]), 
                    uint112(allocation)
                );
                continue;
            }
            if (
                allocType == AllocationType.AIRDROP_TEAM ||
                allocType == AllocationType.AIRDROP_VICTIMS ||
                allocType == AllocationType.AIRDROP_LOCK_PENALTY
            ) {
                // Set merkle roots for airdrop allocations
                merkleRootByType[allocType] = _merkleRoots[airdropIndex];
                emit MerkleRootSet(allocType, _merkleRoots[airdropIndex++]);
            }
        }

        // Set the redemption ratio to be used for all PRISMA/yPRISMA/cvxPRISMA redemptions
        uint256 _redemptionRatio = (
            allocationByType[AllocationType.REDEMPTIONS] * 1e18 / _maxRedeemable
        );
        redemptionRatio = _redemptionRatio;
        require(_redemptionRatio != 0, "ratio is 0");
        require(totalPctAllocated == PRECISION, "Total not 100%");
        emit InitializationParamsSet();
    }

    /**
        @notice Set the merkle root for the lock penalty airdrop
        @dev This root must be set later after lock penalty data is finalized
        @param _root Merkle root for the lock penalty airdrop
        @param _allocation Allocation for the lock penalty airdrop
    */
    function setLockPenaltyMerkleRoot(bytes32 _root, uint256 _allocation) external onlyOwner {
        require(initialized, "init params not set");
        require(merkleRootByType[AllocationType.AIRDROP_LOCK_PENALTY] == bytes32(0), "root already set");
        merkleRootByType[AllocationType.AIRDROP_LOCK_PENALTY] = _root;
        emit MerkleRootSet(AllocationType.AIRDROP_LOCK_PENALTY, _root);
        allocationByType[AllocationType.AIRDROP_LOCK_PENALTY] = _allocation;
    }

    function merkleClaim(
        address _account,
        address _recipient,
        uint256 _amount,
        AllocationType _type,
        bytes32[] calldata _proof,
        uint256 _index
    ) external callerOrDelegated(_account) {
        require(
            _type == AllocationType.AIRDROP_TEAM || 
            _type == AllocationType.AIRDROP_LOCK_PENALTY || 
            _type == AllocationType.AIRDROP_VICTIMS, 
            "invalid type"
        );

        bytes32 _root = merkleRootByType[_type];
        require(_root != bytes32(0), "root not set");

        require(!hasClaimed[_account][_type], "already claimed");
        bytes32 node = keccak256(abi.encodePacked(_account, _index, _amount));
        require(MerkleProof.verifyCalldata(
            _proof, 
            _root, 
            node
        ), "invalid proof");

        _createVest(
            _recipient,
            uint32(durationByType[_type]),
            uint112(_amount)
        );
        hasClaimed[_account][_type] = true;
        emit AirdropClaimed(_type, _account, _recipient, _amount);
    }

    /**
        @notice Redeem PRISMA tokens for RSUP tokens
        @param _token    Token to redeem (PRISMA, yPRISMA or cvxPRISMA)
        @param _recipient Address to receive the RSUP tokens
        @param _amount   Amount of tokens to redeem
        @dev This function allows users to convert their PRISMA tokens to RSUP tokens
             at the redemption ratio. The input tokens are burned in the process.
    */
    function redeem(address _token, address _recipient, uint256 _amount) external {
        require(
            _token == address(prisma) || 
            _token == address(yprisma) || 
            _token == address(cvxprisma), 
            "invalid token"
        );
        require(_amount > 0, "amount too low");
        uint256 _ratio = redemptionRatio;
        require(_ratio != 0, "ratio not set");
        IERC20(_token).transferFrom(msg.sender, BURN_ADDRESS, _amount);
        _createVest(
            _recipient,
            uint32(durationByType[AllocationType.REDEMPTIONS]),
            uint112(_amount * _ratio / 1e18)
        );
        emit TokenRedeemed(_token, msg.sender, _recipient, _amount);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MerkleProof.sol)
// This file was procedurally generated from scripts/generate/templates/MerkleProof.js.

pragma solidity ^0.8.20;

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

/**
 * @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.
 *
 * IMPORTANT: Consider memory side-effects when using custom hashing functions
 * that access memory in an unsafe way.
 *
 * NOTE: This library supports proof verification for merkle trees built using
 * custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving
 * leaf inclusion in trees built using non-commutative hashing functions requires
 * additional logic that is not supported by this library.
 */
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.
     *
     * This version handles proofs in memory with the default hashing function.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(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 leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in memory with the default hashing function.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @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.
     *
     * This version handles proofs in memory with a custom hashing function.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processProof(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in memory with a custom hashing function.
     */
    function processProof(
        bytes32[] memory proof,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = hasher(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @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.
     *
     * This version handles proofs in calldata with the default hashing function.
     */
    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 leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in calldata with the default hashing function.
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @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.
     *
     * This version handles proofs in calldata with a custom hashing function.
     */
    function verifyCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processProofCalldata(proof, leaf, hasher) == 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 leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in calldata with a custom hashing function.
     */
    function processProofCalldata(
        bytes32[] calldata proof,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = hasher(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}.
     *
     * This version handles multiproofs in memory with the default hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProof}.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(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.
     *
     * This version handles multiproofs in memory with the default hashing function.
     *
     * 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).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    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 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
        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 < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = Hashes.commutativeKeccak256(a, b);
        }

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

    /**
     * @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}.
     *
     * This version handles multiproofs in memory with a custom hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProof}.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processMultiProof(proof, proofFlags, leaves, hasher) == 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.
     *
     * This version handles multiproofs in memory with a custom hashing function.
     *
     * 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).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view 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 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
        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 < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = hasher(a, b);
        }

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

    /**
     * @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}.
     *
     * This version handles multiproofs in calldata with the default hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProofCalldata}.
     */
    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.
     *
     * This version handles multiproofs in calldata with the default hashing function.
     *
     * 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).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    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 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
        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 < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = Hashes.commutativeKeccak256(a, b);
        }

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

    /**
     * @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}.
     *
     * This version handles multiproofs in calldata with a custom hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProofCalldata}.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == 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.
     *
     * This version handles multiproofs in calldata with a custom hashing function.
     *
     * 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).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view 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 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 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[](proofFlagsLen);
        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 < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = hasher(a, b);
        }

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

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { DelegatedOps } from '../../dependencies/DelegatedOps.sol';
import { CoreOwnable } from '../../dependencies/CoreOwnable.sol';
import { IVestClaimCallback } from 'src/interfaces/IVestClaimCallback.sol';

contract VestManagerBase is CoreOwnable, DelegatedOps {
    uint256 public immutable VEST_GLOBAL_START_TIME;
    IERC20 public immutable token;

    mapping(address => Vest[]) public userVests;
    mapping(address => ClaimSettings) public claimSettings;

    struct Vest {
        uint32 duration; // max of ~56k days
        uint112 amount;
        uint112 claimed;
    }

    struct ClaimSettings {
        bool allowPermissionlessClaims;
        address recipient;
    }

    event VestCreated(address indexed account, uint256 indexed duration, uint256 amount);
    event Claimed(address indexed account, uint256 amount);
    event ClaimSettingsSet(address indexed account, bool indexed allowPermissionlessClaims, address indexed recipient);

    constructor(address _core, address _token) CoreOwnable(_core) {
        token = IERC20(_token);
        VEST_GLOBAL_START_TIME = block.timestamp;
    }

    /// @notice Creates or adds to a vesting instance for an account
    /// @param _account The address to create the vest for
    /// @param _duration The duration of the vesting period in seconds
    /// @param _amount The amount of tokens to vest
    /// @return The total number of vesting instances for the account
    function _createVest(
        address _account,
        uint32 _duration,
        uint112 _amount
    ) internal returns (uint256) {
        require(_account != address(0), "zero address");
        require(_amount > 0, "Amount must be greater than zero");

        uint256 length = numAccountVests(_account);

        // If a vest with matching duration already exists, simply add to its amount
        for (uint256 i = 0; i < length; i++) {
            if (userVests[_account][i].duration == _duration) {
                userVests[_account][i].amount += _amount;
                return length;
            }
        }

        // If the duration does not exist, create a new vest
        userVests[_account].push(Vest(
            _duration,
            _amount,
            0
        ));

        emit VestCreated(_account, _duration, _amount);
        return length + 1;
    }

    function numAccountVests(address _account) public view returns (uint256) {
        return userVests[_account].length;
    }

    /**
     * @notice Claims all available vested tokens for an account
     * @param _account Address to claim tokens for
     * @return _claimed Total amount of tokens claimed
     * @dev Any caller can claim on behalf of an account, unless explicitly blocked via account's claimSettings
     */
    function claim(address _account) external returns (uint256 _claimed) {
        address recipient = _enforceClaimSettings(_account);
        _claimed = _claim(_account);
        if (_claimed > 0) {
            token.transfer(recipient, _claimed);
            emit Claimed(_account, _claimed);
        }
    }

    /**
     * @notice Claims all available vested tokens for an account, and calls a callback to handle the tokens
     * @dev Important: the claimed tokens are transferred to the callback contract for handling, not the recipient
     * @dev Restricted to the account or a delegated caller
     * @param _account Address to claim tokens for
     * @param _callback Address of the callback contract to use
     * @return _claimed Total amount of tokens claimed
     */
    function claimWithCallback(
        address _account, 
        address _callback
    ) external callerOrDelegated(_account) returns (uint256 _claimed) {
        address recipient = _enforceClaimSettings(_account);
        _claimed = _claim(_account);
        if (_claimed > 0) {
            token.transfer(_callback, _claimed);
            require(IVestClaimCallback(_callback).onClaim(_account, recipient, _claimed), "callback failed");
            emit Claimed(_account, _claimed);
        }
    }

    function _claim(address _account) internal returns (uint256 _claimed) {
        Vest[] storage vests = userVests[_account];
        uint256 length = vests.length;
        require(length > 0, "No vests to claim");

        for (uint256 i = 0; i < length; i++) {
            uint112 claimable = _claimableAmount(vests[i]);
            if (claimable > 0) {
                vests[i].claimed += claimable;
                _claimed += claimable;
            }
        }
    }

    function _enforceClaimSettings(address _account) internal view returns (address) {
        ClaimSettings memory settings = claimSettings[_account];
        if (!settings.allowPermissionlessClaims) {
            require(msg.sender == _account, "!authorized");
        }
        return settings.recipient != address(0) ? settings.recipient : _account;
    }

    /**
     * @notice Get aggregated vesting data for an account. Includes all vests for the account.
     * @param _account Address of the account to query
     * @return _totalAmount Total amount of tokens in all vests for the account
     * @return _totalClaimable Amount of tokens that can be claimed by the account
     * @return _totalClaimed Amount of tokens already claimed by the account
     * @dev Iterates through all vests for the account to calculate totals
     */
    function getAggregateVestData(address _account) external view returns (
        uint256 _totalAmount,
        uint256 _totalClaimable,
        uint256 _totalClaimed
    ) {
        uint256 length = numAccountVests(_account);
        for (uint256 i = 0; i < length; i++) {
            (uint256 _total, uint256 _claimable, uint256 _claimed,) = _vestData(userVests[_account][i]);
            _totalAmount += _total;
            _totalClaimable += _claimable;
            _totalClaimed += _claimed;
        }
    }

    /**
     * @notice Get single vest data for an account
     * @param _account Address of the account to query
     * @param index Index of the vest to query
     * @return _total Total amount of tokens in the vest
     * @return _claimable Amount of tokens that can be claimed for the vest
     * @return _claimed Amount of tokens already claimed for the vest
     * @return _timeRemaining Time remaining until vesting is complete
     */
    function getSingleVestData(address _account, uint256 index) external view returns (
        uint256 _total,
        uint256 _claimable,
        uint256 _claimed,
        uint256 _timeRemaining
    ) {
        return _vestData(userVests[_account][index]);
    }

    function _vestData(Vest memory vest) internal view returns (
        uint256 _total,
        uint256 _claimable,
        uint256 _claimed,
        uint256 _timeRemaining
    ){
        uint256 vested = _vestedAmount(vest);
        _total = vest.amount;
        _claimable = vested - vest.claimed;
        _claimed = vest.claimed;
        uint256 elapsed = block.timestamp - VEST_GLOBAL_START_TIME;
        _timeRemaining = elapsed > vest.duration ? 0 : vest.duration - elapsed;
    }

    function _claimableAmount(Vest storage vest) internal view returns (uint112) {
        return uint112(_vestedAmount(vest) - vest.claimed);
    }

    function _vestedAmount(Vest memory vest) internal view returns (uint256) {
        if (block.timestamp < VEST_GLOBAL_START_TIME) {
            return 0;
        } else if (block.timestamp >= VEST_GLOBAL_START_TIME + vest.duration) {
            return vest.amount;
        } else {
            return (vest.amount * (block.timestamp - VEST_GLOBAL_START_TIME)) / vest.duration;
        }
    }

    function setClaimSettings( 
        bool _allowPermissionlessClaims, 
        address _recipient
    ) external {
        claimSettings[msg.sender] = ClaimSettings(_allowPermissionlessClaims, _recipient);
        emit ClaimSettingsSet(msg.sender, _allowPermissionlessClaims, _recipient);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/Hashes.sol)

pragma solidity ^0.8.20;

/**
 * @dev Library of standard hash functions.
 *
 * _Available since v5.1._
 */
library Hashes {
    /**
     * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.
     *
     * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
     */
    function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {
        return a < b ? _efficientKeccak256(a, b) : _efficientKeccak256(b, a);
    }

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

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

/**
    @title Delegated Operations
    @author Prisma Finance (with edits by Resupply Finance)
    @notice Allows delegation to specific contract functionality. Useful for creating
            wrapper contracts to bundle multiple interactions into a single call.
 */
contract DelegatedOps {
    event DelegateApprovalSet(address indexed account, address indexed delegate, bool isApproved);

    mapping(address owner => mapping(address caller => bool isApproved)) public isApprovedDelegate;

    modifier callerOrDelegated(address _account) {
        require(msg.sender == _account || isApprovedDelegate[_account][msg.sender], "!CallerOrDelegated");
        _;
    }

    function setDelegateApproval(address _delegate, bool _isApproved) external {
        isApprovedDelegate[msg.sender][_delegate] = _isApproved;
        emit DelegateApprovalSet(msg.sender, _delegate, _isApproved);
    }
}

File 7 of 11 : CoreOwnable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

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

/**
    @title Core Ownable
    @author Prisma Finance (with edits by Resupply Finance)
    @notice Contracts inheriting `CoreOwnable` have the same owner as `Core`.
            The ownership cannot be independently modified or renounced.
 */
contract CoreOwnable {
    ICore public immutable core;

    constructor(address _core) {
        core = ICore(_core);
    }

    modifier onlyOwner() {
        require(msg.sender == address(core), "!core");
        _;
    }

    function owner() public view returns (address) {
        return address(core);
    }
}

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

import { IGovStaker } from "./IGovStaker.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IVestClaimCallback {
    event RecoveredERC20(address indexed token, address indexed recipient, uint256 amount);

    function govStaker() external view returns (IGovStaker);
    function vestManager() external view returns (address);
    function token() external view returns (IERC20);
    
    function onClaim(
        address account,
        address recipient,
        uint256 amount
    ) external returns (bool success);
    
    function recoverERC20(address token, address recipient, uint256 amount) external;
}

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

import { IAuthHook } from './IAuthHook.sol';

interface ICore {
    struct OperatorAuth {
        bool authorized;
        IAuthHook hook;
    }

    event VoterSet(address indexed newVoter);
    event OperatorExecuted(address indexed caller, address indexed target, bytes data);
    event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);

    function execute(address target, bytes calldata data) external returns (bytes memory);
    function epochLength() external view returns (uint256);
    function startTime() external view returns (uint256);
    function voter() external view returns (address);
    function ownershipTransferDeadline() external view returns (uint256);
    function pendingOwner() external view returns (address);
    function setOperatorPermissions(
        address caller,
        address target,
        bytes4 selector,
        bool authorized,
        IAuthHook authHook
    ) external;
    function setVoter(address newVoter) external;
    function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);
}

File 10 of 11 : IGovStaker.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IGovStaker {
    /* ========== EVENTS ========== */
    event RewardAdded(address indexed rewardToken, uint256 amount);
    event RewardTokenAdded(address indexed rewardsToken, address indexed rewardsDistributor, uint256 rewardsDuration);
    event Recovered(address indexed token, uint256 amount);
    event RewardsDurationUpdated(address indexed rewardsToken, uint256 duration);
    event RewardPaid(address indexed user, address indexed rewardToken, uint256 reward);
    event Staked(address indexed account, uint indexed epoch, uint amount);
    event Unstaked(address indexed account, uint amount);
    event Cooldown(address indexed account, uint amount, uint end);
    event CooldownEpochsUpdated(uint24 newDuration);

    /* ========== STRUCTS ========== */
    struct Reward {
        address rewardsDistributor;
        uint256 rewardsDuration;
        uint256 periodFinish;
        uint256 rewardRate;
        uint256 lastUpdateTime;
        uint256 rewardPerTokenStored;
    }

    struct AccountData {
        uint120 realizedStake; // Amount of stake that has fully realized weight.
        uint120 pendingStake; // Amount of stake that has not yet fully realized weight.
        uint16 lastUpdateEpoch;
    }

    struct UserCooldown {
        uint104 end;
        uint152 amount;
    }

    enum ApprovalStatus {
        None, // 0. Default value, indicating no approval
        StakeOnly, // 1. Approved for stake only
        UnstakeOnly, // 2. Approved for unstake only
        StakeAndUnstake // 3. Approved for both stake and unstake
    }

    /* ========== STATE VARIABLES ========== */
    function rewardTokens(uint256 index) external view returns (address);
    function rewardData(address token) external view returns (Reward memory);
    function rewards(address account, address token) external view returns (uint256);
    function userRewardPerTokenPaid(address account, address token) external view returns (uint256);
    function CORE() external view returns (address);
    function PRECISION() external view returns (uint256);
    function ESCROW() external view returns (address);
    function MAX_COOLDOWN_DURATION() external view returns (uint24);
    function totalPending() external view returns (uint120);
    function totalLastUpdateEpoch() external view returns (uint16);
    function cooldownEpochs() external view returns (uint256);
    function decimals() external view returns (uint8);
    function approvedCaller(address account, address caller) external view returns (ApprovalStatus);

    /* ========== EXTERNAL FUNCTIONS ========== */
    function accountData(address account) external view returns (AccountData memory);
    function stakeToken() external view returns (address);
    function balanceOf(address account) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function getReward() external;
    function getOneReward(address rewardsToken) external;
    function addReward(address rewardsToken, address rewardsDistributor, uint256 rewardsDuration) external;
    function notifyRewardAmount(address rewardsToken, uint256 rewardAmount) external;
    function setRewardsDistributor(address rewardsToken, address rewardsDistributor) external;
    function setRewardsDuration(address rewardsToken, uint256 rewardsDuration) external;
    function recoverERC20(address tokenAddress, uint256 tokenAmount) external;
    function stake(address account, uint amount) external returns (uint);
    function stakeFor(address account, uint amount) external returns (uint);
    function cooldown(address account, uint amount) external returns (uint);
    function cooldowns(address account) external view returns (UserCooldown memory);
    function cooldownFor(address account, uint amount) external returns (uint);
    function exit(address account) external returns (uint);
    function exitFor(address account) external returns (uint);
    function unstake(address account, address receiver) external returns (uint);
    function unstakeFor(address account, address receiver) external returns (uint);
    function checkpointAccount(address account) external returns (AccountData memory, uint weight);
    function checkpointAccountWithLimit(address account, uint epoch) external returns (AccountData memory, uint weight);
    function checkpointTotal() external returns (uint);
    function setApprovedCaller(address caller, ApprovalStatus status) external;
    function setCooldownEpochs(uint24 epochs) external;
    function getAccountWeight(address account) external view returns (uint);
    function getAccountWeightAt(address account, uint epoch) external view returns (uint);
    function getTotalWeight() external view returns (uint);
    function getTotalWeightAt(uint epoch) external view returns (uint);
    function getUnstakableAmount(address account) external view returns (uint);
    function isCooldownEnabled() external view returns (bool);
    function rewardTokensLength() external view returns (uint256);
    function earned(address account, address rewardsToken) external view returns (uint256 pending);
    function earnedMulti(address account) external view returns (uint256[] memory pending);
    function rewardPerToken(address rewardsToken) external view returns (uint256 rewardAmount);
    function lastTimeRewardApplicable(address rewardsToken) external view returns (uint256);
    function getRewardForDuration(address rewardsToken) external view returns (uint256);
    function owner() external view returns (address);
    function guardian() external view returns (address);
    function getEpoch() external view returns (uint);
    function epochLength() external view returns (uint);
    function startTime() external view returns (uint);
    function irreversiblyCommitAccountAsPermanentStaker(address account) external;
    function onPermaStakeMigrate(address account) external;
    function migrateStake() external returns (uint amount);
    function setDelegateApproval(address delegate, bool approved) external;
}

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

interface IAuthHook {
    function preHook(address operator, address target, bytes calldata data) external returns (bool);
    function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);
}

Settings
{
  "remappings": [
    "ds-test/=node_modules/ds-test/src/",
    "forge-std/=node_modules/forge-std/src/",
    "frax-std/=node_modules/frax-standard-solidity/src/",
    "@axelar-network/=node_modules/@axelar-network/",
    "@chainlink/=node_modules/@chainlink/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@layerzerolabs/=node_modules/@layerzerolabs/",
    "@mean-finance/=node_modules/@mean-finance/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@rari-capital/=node_modules/@rari-capital/",
    "@uniswap/=node_modules/@uniswap/",
    "base64-sol/=node_modules/base64-sol/",
    "frax-standard-solidity/=node_modules/frax-standard-solidity/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
    "solidity-stringutils/=lib/surl/lib/solidity-stringutils/",
    "surl/=lib/surl/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_burnAddress","type":"address"},{"internalType":"address[3]","name":"_redemptionTokens","type":"address[3]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum VestManager.AllocationType","name":"allocationType","type":"uint8"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AirdropClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"allowPermissionlessClaims","type":"bool"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"ClaimSettingsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"DelegateApprovalSet","type":"event"},{"anonymous":false,"inputs":[],"name":"InitializationParamsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum VestManager.AllocationType","name":"allocationType","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"MerkleRootSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VestCreated","type":"event"},{"inputs":[],"name":"BURN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VEST_GLOBAL_START_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"allocationByType","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"claim","outputs":[{"internalType":"uint256","name":"_claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimSettings","outputs":[{"internalType":"bool","name":"allowPermissionlessClaims","type":"bool"},{"internalType":"address","name":"recipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_callback","type":"address"}],"name":"claimWithCallback","outputs":[{"internalType":"uint256","name":"_claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cvxprisma","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"durationByType","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getAggregateVestData","outputs":[{"internalType":"uint256","name":"_totalAmount","type":"uint256"},{"internalType":"uint256","name":"_totalClaimable","type":"uint256"},{"internalType":"uint256","name":"_totalClaimed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getSingleVestData","outputs":[{"internalType":"uint256","name":"_total","type":"uint256"},{"internalType":"uint256","name":"_claimable","type":"uint256"},{"internalType":"uint256","name":"_claimed","type":"uint256"},{"internalType":"uint256","name":"_timeRemaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"hasClaimed","outputs":[{"internalType":"bool","name":"hasClaimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"isApprovedDelegate","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"enum VestManager.AllocationType","name":"_type","type":"uint8"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"merkleClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum VestManager.AllocationType","name":"","type":"uint8"}],"name":"merkleRootByType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"numAccountVests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prisma","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowPermissionlessClaims","type":"bool"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"setClaimSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"bool","name":"_isApproved","type":"bool"}],"name":"setDelegateApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxRedeemable","type":"uint256"},{"internalType":"bytes32[3]","name":"_merkleRoots","type":"bytes32[3]"},{"internalType":"address[4]","name":"_nonUserTargets","type":"address[4]"},{"internalType":"uint256[8]","name":"_vestDurations","type":"uint256[8]"},{"internalType":"uint256[8]","name":"_allocPercentages","type":"uint256[8]"}],"name":"setInitializationParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_root","type":"bytes32"},{"internalType":"uint256","name":"_allocation","type":"uint256"}],"name":"setLockPenaltyMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userVests","outputs":[{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint112","name":"amount","type":"uint112"},{"internalType":"uint112","name":"claimed","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yprisma","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

610180806040523461024a57612176803803809161001d82856102c0565b8339810160c08282031261024a57610034826102e3565b610040602084016102e3565b9061004d604085016102e3565b9280607f8601121561024a5760405194606086016001600160401b038111878210176102ac57604052859060c0810192831161024a57606001905b828210610294575050506001600160a01b039081166080521660c08190524260a052604051630bfcba7760e21b8152602081600481855afa908115610256575f91610261575b50610140526040516370a0823160e01b815230600482015290602090829060249082905afa908115610256575f91610220575b5061014051036101db576101605280516001600160a01b0390811660e0526020820151811661010052604091820151166101205251611e7e90816102f882396080518181816101fc01528181610ad80152611237015260a0518181816109d801528181611da50152611de7015260c0518181816101b8015281816102c0015261110d015260e0518181816113d201526116680152610100518181816115e0015261162401526101205181818161106f01526115ae015261014051818181610b330152611037015261016051818181610170015261142b0152f35b60405162461bcd60e51b815260206004820152601660248201527f566573744d616e61676572206e6f742066756e646564000000000000000000006044820152606490fd5b90506020813d60201161024e575b8161023b602093836102c0565b8101031261024a57515f610101565b5f80fd5b3d915061022e565b6040513d5f823e3d90fd5b90506020813d60201161028c575b8161027c602093836102c0565b8101031261024a575160246100ce565b3d915061026f565b602080916102a1846102e3565b815201910190610088565b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b038211908210176102ac57604052565b51906001600160a01b038216820361024a5756fe6080806040526004361015610012575f80fd5b5f3560e01c9081630449c4ab14611697575080630a3266b0146116535780630d4b95161461160f5780630e6dfcd51461139e578063158ef93e1461137c5780631633ec361461121d5780631930e825146111c757806319c21b0a1461119f5780631e83409a1461109e5780632abb7e661461105a5780632ff2e9dc1461102057806348f5eaf914610fac5780634b7b8ef714610f845780634e47d71414610f4c5780638156145d146109fb578063826160fc146109c157806384063c6c146109905780638da5cb5b146101e7578063a42a29a614610938578063c3c854b6146108a4578063c9ea23031461059f578063d338edf31461054e578063d698715514610501578063dc9b52b414610459578063de987d501461043c578063f10549f61461022b578063f2f4eb26146101e7578063fc0c546a146101a35763fccc28131461015b575f80fd5b3461019f575f36600319011261019f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b3461019f575f36600319011261019f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461019f575f36600319011261019f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461019f57604036600319011261019f5761024461175e565b61024c611748565b6001600160a01b03821691338314801561041c575b61026a90611940565b61027381611bb8565b9061027d81611c5e565b928361028f575b602084604051908152f35b60405163a9059cbb60e01b81526001600160a01b03821660048201526024810185905290602082806044810103815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19384156103f6575f602094879461033b97610401575b50604051631005f04960e21b81526001600160a01b039182166004820152921660248301526044820193909352938492839182906064820190565b03926001600160a01b03165af19081156103f6575f916103c7575b5015610390576020917fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a83604051848152a2828080610284565b60405162461bcd60e51b815260206004820152600f60248201526e18d85b1b189858dac819985a5b1959608a1b6044820152606490fd5b6103e9915060203d6020116103ef575b6103e18183611830565b810190611852565b83610356565b503d6103d7565b6040513d5f823e3d90fd5b61041790873d89116103ef576103e18183611830565b610300565b505f8381526020818152604080832033845290915290205460ff16610261565b3461019f575f36600319011261019f576020600454604051908152f35b3461019f57602036600319011261019f5761047261175e565b5f5f5f9260018060a01b0316805f52600160205260405f20545f915b8183106104ac57606085878660405192835260208301526040820152f35b909192936104f76104eb6104f1600193855f52846020526104e16104dc6104d68a60405f206117cf565b5061190b565b611d64565b50949190926118ed565b986118ed565b976118ed565b959301919061048e565b3461019f57602036600319011261019f576001600160a01b0361052261175e565b165f5260026020526040805f205481519060ff81161515825260018060a01b039060081c166020820152f35b3461019f57604036600319011261019f5761056761175e565b602435600781101561019f5761059360ff9160209360018060a01b03165f526008845260405f206117b9565b54166040519015158152f35b3461019f5760c036600319011261019f576105b861175e565b6105c0611748565b60643590604435600783101561019f576084359167ffffffffffffffff831161019f573660238401121561019f5782600401359367ffffffffffffffff851161019f573660248660051b8601011161019f576001600160a01b038616913383148015610884575b61063090611940565b5f600483148015610878575b818115610868575b5015610834576106538361178b565b5497881561080057845f52600860205260ff6106728560405f206117b9565b54166107c95760405160208101916bffffffffffffffffffffffff199060601b16825260a4356034820152866054820152605481526106b2607482611830565b519020975f985b888a10156106fa5760248a60051b89010135908181105f146106e9575f52602052600160405f205b9901986106b9565b905f52602052600160405f206106e1565b036107945761072363ffffffff61071085611774565b54166001600160701b03871690846119a1565b50835f5260086020526107398360405f206117b9565b805460ff19166001179055610780576040519384526001600160a01b0316927f55230c7d73ba193bcb70f278e7f5657a2520e8112f3bed52e55ce7eb93982bcc90602090a4005b634e487b7160e01b5f52602160045260245ffd5b60405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b1c9bdbdd081b9bdd081cd95d60a21b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b696e76616c6964207479706560a01b6044820152606490fd5b9050610780576005831481610644565b50505f6006831461063c565b505f8381526020818152604080832033845290915290205460ff16610627565b3461019f57604036600319011261019f576108bd61175e565b602435908115159182810361019f576108fe90335f525f60205260405f2060018060a01b0384165f5260205260405f209060ff801983541691151516179055565b6040519182526001600160a01b03169033907f92d241afb0a1a9b3441bf1bd6bea0f9164cf5a2562cbe4bcc34ab943b246560890602090a3005b3461019f57604036600319011261019f576001600160a01b0361095961175e565b165f52600160205260806109786104dc6104d660243560405f206117cf565b91604051938452602084015260408301526060820152f35b3461019f57602036600319011261019f57600435600781101561019f576109b86020916117a2565b54604051908152f35b3461019f575f36600319011261019f5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461019f5761030036600319011261019f57366043121561019f57604051610a24606082611830565b803660841161019f576024905b60848210610f3c57823660a3121561019f5760405190610a52608083611830565b81366101041161019f576084905b6101048210610f1c57505036610123121561019f5760405191610100610a868185611830565b83366102041161019f57610104905b6102048210610f0c57505036610223121561019f57610ab76040519182611830565b80366103041161019f57610204905b6103048210610efc5750610b069050337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461189b565b60035460ff8116610ec25760019060ff1916176003555f935f908051602082015103610e73579392905f947f0000000000000000000000000000000000000000000000000000000000000000925b60088710610c52578760035f52600560205260405f2054670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610c3e57610b99906004359061187d565b8060045515610c0c57670de0b6b3a764000003610bd6577fc4af3af2e2df2bca7e41e8da8c822b5e33dab57063450f96219db777481efabb5f80a1005b60405162461bcd60e51b815260206004820152600e60248201526d546f74616c206e6f74203130302560901b6044820152606490fd5b60405162461bcd60e51b815260206004820152600a6024820152690726174696f20697320360b41b6044820152606490fd5b634e487b7160e01b5f52601160045260245ffd5b9091929394959687155f14610e595760078810156107805787905b610c7789856118cf565b51151580610e41575b15610e0957610cb59063ffffffff610c988b876118cf565b5116610ca384611774565b55610cae8a896118cf565b51906118ed565b97670de0b6b3a7640000610cd387610ccd848b6118cf565b5161186a565b04610cdd836117a2565b610ce88282546118ed565b90556004821080610dad5750506007821015918261078057600481148015610da0575b838115610d90575b50610d2b575b50600191505b01959493929190610b54565b610d35868a6118fa565b51610d3f8261178b565b55855f198114610c3e576001610d579101968a6118fa565b5192610780577fc1e85192bb4dc49db867f1ac46b02d377f7e2bd38caacd2c19ff453935ebd4c06020600194604051908152a289610d19565b9050610780576006811483610d13565b505f925060058114610d0b565b90925015610df557600581901b830151600192610def916001600160a01b0316906001600160701b0363ffffffff610de5868a6118cf565b51169116916119a1565b50610d1f565b634e487b7160e01b5f52603260045260245ffd5b60405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606490fd5b5063ffffffff610e518a866118cf565b511115610c80565b5f198801888111610c3e5760078110156107805790610c6d565b60405162461bcd60e51b815260206004820152602160248201527f7065726d612d7374616b6572206475726174696f6e73206d757374206d6174636044820152600d60fb1b6064820152608490fd5b60405162461bcd60e51b81526020600482015260126024820152711c185c985b5cc8185b1c9958591e481cd95d60721b6044820152606490fd5b8135815260209182019101610ac6565b8135815260209182019101610a95565b81356001600160a01b038116810361019f57815260209182019101610a60565b8135815260209182019101610a31565b3461019f57602036600319011261019f576001600160a01b03610f6d61175e565b165f526001602052602060405f2054604051908152f35b3461019f57602036600319011261019f57600435600781101561019f576109b860209161178b565b3461019f57604036600319011261019f57610fc561175e565b6001600160a01b03165f9081526001602052604090208054602435919082101561019f57606091610ff5916117cf565b50546040519063ffffffff811682526001600160701b038160201c16602083015260901c6040820152f35b3461019f575f36600319011261019f5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461019f575f36600319011261019f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461019f57602036600319011261019f576110b761175e565b6110c081611bb8565b906110ca81611c5e565b90816110dc575b602082604051908152f35b60405163a9059cbb60e01b81526001600160a01b03909316600484015260248301829052602083806044810103815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19283156103f657602093611184575b506040518281526001600160a01b03909116907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a908490a2826110d1565b61119a90843d86116103ef576103e18183611830565b611146565b3461019f57602036600319011261019f57600435600781101561019f576109b8602091611774565b3461019f57604036600319011261019f576111e061175e565b6111e8611748565b9060018060a01b03165f525f60205260405f209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461019f57604036600319011261019f57600435611265337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461189b565b60ff60035416156113415760065f5260076020527f55c5b153ab560fcde54a63b18c7f53d75501706907cef8767fbded79ab9997c754611309577fc1e85192bb4dc49db867f1ac46b02d377f7e2bd38caacd2c19ff453935ebd4c06020600692835f52600782528060405f2055604051908152a260065f5260056020526024357f069400f22b28c6c362558d92f66163cec5671cba50b61abd2eecfcd0eaeac51855005b60405162461bcd60e51b815260206004820152601060248201526f1c9bdbdd08185b1c9958591e481cd95d60821b6044820152606490fd5b60405162461bcd60e51b81526020600482015260136024820152721a5b9a5d081c185c985b5cc81b9bdd081cd95d606a1b6044820152606490fd5b3461019f575f36600319011261019f57602060ff600354166040519015158152f35b3461019f57606036600319011261019f576113b761175e565b6113bf611748565b6001600160a01b039182169160443591907f000000000000000000000000000000000000000000000000000000000000000016831480156115dd575b80156115ab575b1561157657811561154057600454801561150b576040516323b872dd60e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602482015260448101849052906020826064815f895af19182156103f6576114b3926114ee575b5060035f5260066020526001600160701b03670de0b6b3a76400006114aa63ffffffff60405f205416938761186a565b041690836119a1565b506040519182526001600160a01b03169133917f0c139059c3dc33b2bf39a13d853d8f16f0ee4c6d4076eef665b063b44518e59490602090a4005b6115069060203d6020116103ef576103e18183611830565b61147a565b60405162461bcd60e51b815260206004820152600d60248201526c1c985d1a5bc81b9bdd081cd95d609a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d616d6f756e7420746f6f206c6f7760901b6044820152606490fd5b60405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606490fd5b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168314611402565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031683146113fb565b3461019f575f36600319011261019f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461019f575f36600319011261019f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461019f57604036600319011261019f5760043580151580910361019f576116bd611748565b916116c7816117e4565b818152602081019260018060a01b031692838152335f52600260205261170060405f2092511515839060ff801983541691151516179055565b518154610100600160a81b03191660089190911b610100600160a81b0316179055337fd600d35401e5ac794858fa031a56d9a11286fb0577b9d560b781b91b4984766c5f80a4005b602435906001600160a01b038216820361019f57565b600435906001600160a01b038216820361019f57565b6007811015610780575f52600660205260405f2090565b6007811015610780575f52600760205260405f2090565b6007811015610780575f52600560205260405f2090565b906007811015610780575f5260205260405f2090565b8054821015610df5575f5260205f2001905f90565b6040810190811067ffffffffffffffff82111761180057604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761180057604052565b90601f8019910116810190811067ffffffffffffffff82111761180057604052565b9081602091031261019f5751801515810361019f5790565b81810292918115918404141715610c3e57565b8115611887570490565b634e487b7160e01b5f52601260045260245ffd5b156118a257565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b906008811015610df55760051b0190565b91908203918211610c3e57565b91908201809211610c3e57565b906003811015610df55760051b0190565b9060405161191881611814565b604081935463ffffffff811683526001600160701b038160201c16602084015260901c910152565b1561194757565b60405162461bcd60e51b81526020600482015260126024820152710850d85b1b195c93dc91195b1959d85d195960721b6044820152606490fd5b906001600160701b03809116911601906001600160701b038211610c3e57565b6001600160a01b03168015611b84576001600160701b038316918215611b4057815f52600160205260405f2054935f5b858110611ab1575050815f52600160205260405f2063ffffffff604051926119f884611814565b16938483526020830181815260408401925f845280546801000000000000000081101561180057611a2e916001820181556117cf565b611a9e5793519051925160901b6001600160901b031916640100000000600160901b03602094851b1663ffffffff90921691909117179092557f941051f5740326e2299731cca609f60c53e8302c775962e529bb902465620ddc91604051908152a360018101809111610c3e5790565b634e487b7160e01b5f525f60045260245ffd5b835f52600160205263ffffffff611acb8260405f206117cf565b50541663ffffffff841614611ae2576001016119d1565b611b3d9450611b169250611b0191935f52600160205260405f206117cf565b50916001600160701b03835460201c16611981565b640100000000600160901b0382549160201b1690640100000000600160901b031916179055565b90565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b60405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b6044820152606490fd5b6001600160a01b0381165f818152600260205260409081902090519190611bde836117e4565b5460ff8116158015845260089190911c6001600160a01b03166020909301928352611c1f575b50516001600160a01b0316908115611c1a575090565b905090565b3303611c2b575f611c04565b60405162461bcd60e51b815260206004820152600b60248201526a08585d5d1a1bdc9a5e995960aa1b6044820152606490fd5b6001600160a01b03165f9081526001602052604081208054919291908115611d2b575f5b828110611c8e57505050565b6001600160701b03611cc0611ca383856117cf565b50611cb5611cb08261190b565b611de5565b905460901c906118e0565b1680611cd0575b50600101611c82565b611d24908296611d1f611ce5600195876117cf565b50611cf484825460901c611981565b815471ffffffffffffffffffffffffffffffffffff1660909190911b6001600160901b031916179055565b6118ed565b9490611cc7565b60405162461bcd60e51b81526020600482015260116024820152704e6f20766573747320746f20636c61696d60781b6044820152606490fd5b611d6d81611de5565b906001600160701b03602082015116926001600160701b03611d97604084019482865116906118e0565b9351169163ffffffff611dca7f0000000000000000000000000000000000000000000000000000000000000000426118e0565b9151169081811115611ddc5750505f90565b611b3d916118e0565b7f00000000000000000000000000000000000000000000000000000000000000008042105f14611e155750505f90565b611e2663ffffffff835116826118ed565b4210611e3d5750602001516001600160701b031690565b9063ffffffff611e68611b3d93611e626001600160701b0360208601511691426118e0565b9061186a565b9151169061187d56fea164736f6c634300081c000a000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f726000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000da47862a83dac0c112ba89c6abc2159b95afd71c000000000000000000000000e3668873d944e4a949da05fc8bde419eff54388200000000000000000000000034635280737b5bfe6c7dc2fc3065d60d66e78185

Deployed Bytecode

0x6080806040526004361015610012575f80fd5b5f3560e01c9081630449c4ab14611697575080630a3266b0146116535780630d4b95161461160f5780630e6dfcd51461139e578063158ef93e1461137c5780631633ec361461121d5780631930e825146111c757806319c21b0a1461119f5780631e83409a1461109e5780632abb7e661461105a5780632ff2e9dc1461102057806348f5eaf914610fac5780634b7b8ef714610f845780634e47d71414610f4c5780638156145d146109fb578063826160fc146109c157806384063c6c146109905780638da5cb5b146101e7578063a42a29a614610938578063c3c854b6146108a4578063c9ea23031461059f578063d338edf31461054e578063d698715514610501578063dc9b52b414610459578063de987d501461043c578063f10549f61461022b578063f2f4eb26146101e7578063fc0c546a146101a35763fccc28131461015b575f80fd5b3461019f575f36600319011261019f576040517f000000000000000000000000000000000000000000000000000000000000dead6001600160a01b03168152602090f35b5f80fd5b3461019f575f36600319011261019f576040517f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7266001600160a01b03168152602090f35b3461019f575f36600319011261019f576040517f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03168152602090f35b3461019f57604036600319011261019f5761024461175e565b61024c611748565b6001600160a01b03821691338314801561041c575b61026a90611940565b61027381611bb8565b9061027d81611c5e565b928361028f575b602084604051908152f35b60405163a9059cbb60e01b81526001600160a01b03821660048201526024810185905290602082806044810103815f7f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7266001600160a01b03165af19384156103f6575f602094879461033b97610401575b50604051631005f04960e21b81526001600160a01b039182166004820152921660248301526044820193909352938492839182906064820190565b03926001600160a01b03165af19081156103f6575f916103c7575b5015610390576020917fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a83604051848152a2828080610284565b60405162461bcd60e51b815260206004820152600f60248201526e18d85b1b189858dac819985a5b1959608a1b6044820152606490fd5b6103e9915060203d6020116103ef575b6103e18183611830565b810190611852565b83610356565b503d6103d7565b6040513d5f823e3d90fd5b61041790873d89116103ef576103e18183611830565b610300565b505f8381526020818152604080832033845290915290205460ff16610261565b3461019f575f36600319011261019f576020600454604051908152f35b3461019f57602036600319011261019f5761047261175e565b5f5f5f9260018060a01b0316805f52600160205260405f20545f915b8183106104ac57606085878660405192835260208301526040820152f35b909192936104f76104eb6104f1600193855f52846020526104e16104dc6104d68a60405f206117cf565b5061190b565b611d64565b50949190926118ed565b986118ed565b976118ed565b959301919061048e565b3461019f57602036600319011261019f576001600160a01b0361052261175e565b165f5260026020526040805f205481519060ff81161515825260018060a01b039060081c166020820152f35b3461019f57604036600319011261019f5761056761175e565b602435600781101561019f5761059360ff9160209360018060a01b03165f526008845260405f206117b9565b54166040519015158152f35b3461019f5760c036600319011261019f576105b861175e565b6105c0611748565b60643590604435600783101561019f576084359167ffffffffffffffff831161019f573660238401121561019f5782600401359367ffffffffffffffff851161019f573660248660051b8601011161019f576001600160a01b038616913383148015610884575b61063090611940565b5f600483148015610878575b818115610868575b5015610834576106538361178b565b5497881561080057845f52600860205260ff6106728560405f206117b9565b54166107c95760405160208101916bffffffffffffffffffffffff199060601b16825260a4356034820152866054820152605481526106b2607482611830565b519020975f985b888a10156106fa5760248a60051b89010135908181105f146106e9575f52602052600160405f205b9901986106b9565b905f52602052600160405f206106e1565b036107945761072363ffffffff61071085611774565b54166001600160701b03871690846119a1565b50835f5260086020526107398360405f206117b9565b805460ff19166001179055610780576040519384526001600160a01b0316927f55230c7d73ba193bcb70f278e7f5657a2520e8112f3bed52e55ce7eb93982bcc90602090a4005b634e487b7160e01b5f52602160045260245ffd5b60405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b1c9bdbdd081b9bdd081cd95d60a21b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b696e76616c6964207479706560a01b6044820152606490fd5b9050610780576005831481610644565b50505f6006831461063c565b505f8381526020818152604080832033845290915290205460ff16610627565b3461019f57604036600319011261019f576108bd61175e565b602435908115159182810361019f576108fe90335f525f60205260405f2060018060a01b0384165f5260205260405f209060ff801983541691151516179055565b6040519182526001600160a01b03169033907f92d241afb0a1a9b3441bf1bd6bea0f9164cf5a2562cbe4bcc34ab943b246560890602090a3005b3461019f57604036600319011261019f576001600160a01b0361095961175e565b165f52600160205260806109786104dc6104d660243560405f206117cf565b91604051938452602084015260408301526060820152f35b3461019f57602036600319011261019f57600435600781101561019f576109b86020916117a2565b54604051908152f35b3461019f575f36600319011261019f5760206040517f0000000000000000000000000000000000000000000000000000000067d23e0b8152f35b3461019f5761030036600319011261019f57366043121561019f57604051610a24606082611830565b803660841161019f576024905b60848210610f3c57823660a3121561019f5760405190610a52608083611830565b81366101041161019f576084905b6101048210610f1c57505036610123121561019f5760405191610100610a868185611830565b83366102041161019f57610104905b6102048210610f0c57505036610223121561019f57610ab76040519182611830565b80366103041161019f57610204905b6103048210610efc5750610b069050337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03161461189b565b60035460ff8116610ec25760019060ff1916176003555f935f908051602082015103610e73579392905f947f00000000000000000000000000000000000000000031a17e847807b1bc000000925b60088710610c52578760035f52600560205260405f2054670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610c3e57610b99906004359061187d565b8060045515610c0c57670de0b6b3a764000003610bd6577fc4af3af2e2df2bca7e41e8da8c822b5e33dab57063450f96219db777481efabb5f80a1005b60405162461bcd60e51b815260206004820152600e60248201526d546f74616c206e6f74203130302560901b6044820152606490fd5b60405162461bcd60e51b815260206004820152600a6024820152690726174696f20697320360b41b6044820152606490fd5b634e487b7160e01b5f52601160045260245ffd5b9091929394959687155f14610e595760078810156107805787905b610c7789856118cf565b51151580610e41575b15610e0957610cb59063ffffffff610c988b876118cf565b5116610ca384611774565b55610cae8a896118cf565b51906118ed565b97670de0b6b3a7640000610cd387610ccd848b6118cf565b5161186a565b04610cdd836117a2565b610ce88282546118ed565b90556004821080610dad5750506007821015918261078057600481148015610da0575b838115610d90575b50610d2b575b50600191505b01959493929190610b54565b610d35868a6118fa565b51610d3f8261178b565b55855f198114610c3e576001610d579101968a6118fa565b5192610780577fc1e85192bb4dc49db867f1ac46b02d377f7e2bd38caacd2c19ff453935ebd4c06020600194604051908152a289610d19565b9050610780576006811483610d13565b505f925060058114610d0b565b90925015610df557600581901b830151600192610def916001600160a01b0316906001600160701b0363ffffffff610de5868a6118cf565b51169116916119a1565b50610d1f565b634e487b7160e01b5f52603260045260245ffd5b60405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606490fd5b5063ffffffff610e518a866118cf565b511115610c80565b5f198801888111610c3e5760078110156107805790610c6d565b60405162461bcd60e51b815260206004820152602160248201527f7065726d612d7374616b6572206475726174696f6e73206d757374206d6174636044820152600d60fb1b6064820152608490fd5b60405162461bcd60e51b81526020600482015260126024820152711c185c985b5cc8185b1c9958591e481cd95d60721b6044820152606490fd5b8135815260209182019101610ac6565b8135815260209182019101610a95565b81356001600160a01b038116810361019f57815260209182019101610a60565b8135815260209182019101610a31565b3461019f57602036600319011261019f576001600160a01b03610f6d61175e565b165f526001602052602060405f2054604051908152f35b3461019f57602036600319011261019f57600435600781101561019f576109b860209161178b565b3461019f57604036600319011261019f57610fc561175e565b6001600160a01b03165f9081526001602052604090208054602435919082101561019f57606091610ff5916117cf565b50546040519063ffffffff811682526001600160701b038160201c16602083015260901c6040820152f35b3461019f575f36600319011261019f5760206040517f00000000000000000000000000000000000000000031a17e847807b1bc0000008152f35b3461019f575f36600319011261019f576040517f00000000000000000000000034635280737b5bfe6c7dc2fc3065d60d66e781856001600160a01b03168152602090f35b3461019f57602036600319011261019f576110b761175e565b6110c081611bb8565b906110ca81611c5e565b90816110dc575b602082604051908152f35b60405163a9059cbb60e01b81526001600160a01b03909316600484015260248301829052602083806044810103815f7f000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f7266001600160a01b03165af19283156103f657602093611184575b506040518281526001600160a01b03909116907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a908490a2826110d1565b61119a90843d86116103ef576103e18183611830565b611146565b3461019f57602036600319011261019f57600435600781101561019f576109b8602091611774565b3461019f57604036600319011261019f576111e061175e565b6111e8611748565b9060018060a01b03165f525f60205260405f209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461019f57604036600319011261019f57600435611265337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03161461189b565b60ff60035416156113415760065f5260076020527f55c5b153ab560fcde54a63b18c7f53d75501706907cef8767fbded79ab9997c754611309577fc1e85192bb4dc49db867f1ac46b02d377f7e2bd38caacd2c19ff453935ebd4c06020600692835f52600782528060405f2055604051908152a260065f5260056020526024357f069400f22b28c6c362558d92f66163cec5671cba50b61abd2eecfcd0eaeac51855005b60405162461bcd60e51b815260206004820152601060248201526f1c9bdbdd08185b1c9958591e481cd95d60821b6044820152606490fd5b60405162461bcd60e51b81526020600482015260136024820152721a5b9a5d081c185c985b5cc81b9bdd081cd95d606a1b6044820152606490fd5b3461019f575f36600319011261019f57602060ff600354166040519015158152f35b3461019f57606036600319011261019f576113b761175e565b6113bf611748565b6001600160a01b039182169160443591907f000000000000000000000000da47862a83dac0c112ba89c6abc2159b95afd71c16831480156115dd575b80156115ab575b1561157657811561154057600454801561150b576040516323b872dd60e01b81523360048201527f000000000000000000000000000000000000000000000000000000000000dead6001600160a01b0316602482015260448101849052906020826064815f895af19182156103f6576114b3926114ee575b5060035f5260066020526001600160701b03670de0b6b3a76400006114aa63ffffffff60405f205416938761186a565b041690836119a1565b506040519182526001600160a01b03169133917f0c139059c3dc33b2bf39a13d853d8f16f0ee4c6d4076eef665b063b44518e59490602090a4005b6115069060203d6020116103ef576103e18183611830565b61147a565b60405162461bcd60e51b815260206004820152600d60248201526c1c985d1a5bc81b9bdd081cd95d609a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d616d6f756e7420746f6f206c6f7760901b6044820152606490fd5b60405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606490fd5b507f00000000000000000000000034635280737b5bfe6c7dc2fc3065d60d66e781856001600160a01b03168314611402565b507f000000000000000000000000e3668873d944e4a949da05fc8bde419eff5438826001600160a01b031683146113fb565b3461019f575f36600319011261019f576040517f000000000000000000000000e3668873d944e4a949da05fc8bde419eff5438826001600160a01b03168152602090f35b3461019f575f36600319011261019f576040517f000000000000000000000000da47862a83dac0c112ba89c6abc2159b95afd71c6001600160a01b03168152602090f35b3461019f57604036600319011261019f5760043580151580910361019f576116bd611748565b916116c7816117e4565b818152602081019260018060a01b031692838152335f52600260205261170060405f2092511515839060ff801983541691151516179055565b518154610100600160a81b03191660089190911b610100600160a81b0316179055337fd600d35401e5ac794858fa031a56d9a11286fb0577b9d560b781b91b4984766c5f80a4005b602435906001600160a01b038216820361019f57565b600435906001600160a01b038216820361019f57565b6007811015610780575f52600660205260405f2090565b6007811015610780575f52600760205260405f2090565b6007811015610780575f52600560205260405f2090565b906007811015610780575f5260205260405f2090565b8054821015610df5575f5260205f2001905f90565b6040810190811067ffffffffffffffff82111761180057604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761180057604052565b90601f8019910116810190811067ffffffffffffffff82111761180057604052565b9081602091031261019f5751801515810361019f5790565b81810292918115918404141715610c3e57565b8115611887570490565b634e487b7160e01b5f52601260045260245ffd5b156118a257565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b906008811015610df55760051b0190565b91908203918211610c3e57565b91908201809211610c3e57565b906003811015610df55760051b0190565b9060405161191881611814565b604081935463ffffffff811683526001600160701b038160201c16602084015260901c910152565b1561194757565b60405162461bcd60e51b81526020600482015260126024820152710850d85b1b195c93dc91195b1959d85d195960721b6044820152606490fd5b906001600160701b03809116911601906001600160701b038211610c3e57565b6001600160a01b03168015611b84576001600160701b038316918215611b4057815f52600160205260405f2054935f5b858110611ab1575050815f52600160205260405f2063ffffffff604051926119f884611814565b16938483526020830181815260408401925f845280546801000000000000000081101561180057611a2e916001820181556117cf565b611a9e5793519051925160901b6001600160901b031916640100000000600160901b03602094851b1663ffffffff90921691909117179092557f941051f5740326e2299731cca609f60c53e8302c775962e529bb902465620ddc91604051908152a360018101809111610c3e5790565b634e487b7160e01b5f525f60045260245ffd5b835f52600160205263ffffffff611acb8260405f206117cf565b50541663ffffffff841614611ae2576001016119d1565b611b3d9450611b169250611b0191935f52600160205260405f206117cf565b50916001600160701b03835460201c16611981565b640100000000600160901b0382549160201b1690640100000000600160901b031916179055565b90565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b60405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b6044820152606490fd5b6001600160a01b0381165f818152600260205260409081902090519190611bde836117e4565b5460ff8116158015845260089190911c6001600160a01b03166020909301928352611c1f575b50516001600160a01b0316908115611c1a575090565b905090565b3303611c2b575f611c04565b60405162461bcd60e51b815260206004820152600b60248201526a08585d5d1a1bdc9a5e995960aa1b6044820152606490fd5b6001600160a01b03165f9081526001602052604081208054919291908115611d2b575f5b828110611c8e57505050565b6001600160701b03611cc0611ca383856117cf565b50611cb5611cb08261190b565b611de5565b905460901c906118e0565b1680611cd0575b50600101611c82565b611d24908296611d1f611ce5600195876117cf565b50611cf484825460901c611981565b815471ffffffffffffffffffffffffffffffffffff1660909190911b6001600160901b031916179055565b6118ed565b9490611cc7565b60405162461bcd60e51b81526020600482015260116024820152704e6f20766573747320746f20636c61696d60781b6044820152606490fd5b611d6d81611de5565b906001600160701b03602082015116926001600160701b03611d97604084019482865116906118e0565b9351169163ffffffff611dca7f0000000000000000000000000000000000000000000000000000000067d23e0b426118e0565b9151169081811115611ddc5750505f90565b611b3d916118e0565b7f0000000000000000000000000000000000000000000000000000000067d23e0b8042105f14611e155750505f90565b611e2663ffffffff835116826118ed565b4210611e3d5750602001516001600160701b031690565b9063ffffffff611e68611b3d93611e626001600160701b0360208601511691426118e0565b9061186a565b9151169061187d56fea164736f6c634300081c000a

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

000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f726000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000da47862a83dac0c112ba89c6abc2159b95afd71c000000000000000000000000e3668873d944e4a949da05fc8bde419eff54388200000000000000000000000034635280737b5bfe6c7dc2fc3065d60d66e78185

-----Decoded View---------------
Arg [0] : _core (address): 0xc07e000044F95655c11fda4cD37F70A94d7e0a7d
Arg [1] : _token (address): 0x419905009e4656fdC02418C7Df35B1E61Ed5F726
Arg [2] : _burnAddress (address): 0x000000000000000000000000000000000000dEaD
Arg [3] : _redemptionTokens (address[3]): 0xdA47862a83dac0c112BA89c6abC2159b95afd71C,0xe3668873D944E4A949DA05fc8bDE419eFF543882,0x34635280737b5BFe6c7DC2FC3065D60d66e78185

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d
Arg [1] : 000000000000000000000000419905009e4656fdc02418c7df35b1e61ed5f726
Arg [2] : 000000000000000000000000000000000000000000000000000000000000dead
Arg [3] : 000000000000000000000000da47862a83dac0c112ba89c6abc2159b95afd71c
Arg [4] : 000000000000000000000000e3668873d944e4a949da05fc8bde419eff543882
Arg [5] : 00000000000000000000000034635280737b5bfe6c7dc2fc3065d60d66e78185


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

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