ETH Price: $3,067.49 (+1.38%)
Gas: 6 Gwei

Contract

0x3f257f1749E10edFA24087ecDa5fbedBCb7D5c2E
 

Overview

ETH Balance

176 wei

Eth Value

Less Than $0.01 (@ $3,067.49/ETH)

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Transfer Ownersh...156398582022-09-29 15:21:11649 days ago1664464871IN
0x3f257f17...BCb7D5c2E
0 ETH0.0006270821.92533241
Withdraw And Cla...151672082022-07-18 14:33:49722 days ago1658154829IN
0x3f257f17...BCb7D5c2E
0 ETH0.008450156.81889368
Cache151558052022-07-16 20:16:28724 days ago1658002588IN
0x3f257f17...BCb7D5c2E
0 ETH0.0024993914.49041793
Add Eth Rewards151558012022-07-16 20:14:39724 days ago1658002479IN
0x3f257f17...BCb7D5c2E
0.01 ETH0.0004002911.82298091
Withdraw And Cla...151557852022-07-16 20:11:59724 days ago1658002319IN
0x3f257f17...BCb7D5c2E
0 ETH0.0016191913.33981271
Cache151557472022-07-16 20:03:58724 days ago1658001838IN
0x3f257f17...BCb7D5c2E
0 ETH0.0027828216.13364436
Withdraw And Cla...151557382022-07-16 20:02:32724 days ago1658001752IN
0x3f257f17...BCb7D5c2E
0 ETH0.0039454821.33734581
Set Prime Token ...151556832022-07-16 19:49:26724 days ago1658000966IN
0x3f257f17...BCb7D5c2E
0 ETH0.0010458321.66599114
Set Eth Rewards151546112022-07-16 15:44:22724 days ago1657986262IN
0x3f257f17...BCb7D5c2E
0.01 ETH0.0810708119.17082647
Set Eth Timed Ca...151545342022-07-16 15:28:19724 days ago1657985299IN
0x3f257f17...BCb7D5c2E
0 ETH0.0022054546.64464854
Set Prime Per Se...151545332022-07-16 15:28:12724 days ago1657985292IN
0x3f257f17...BCb7D5c2E
0 ETH0.049525141.5764411
Cache151543932022-07-16 14:53:18724 days ago1657983198IN
0x3f257f17...BCb7D5c2E
0 ETH0.0053163934.93422863
Add Pool151466102022-07-15 10:04:34725 days ago1657879474IN
0x3f257f17...BCb7D5c2E
0 ETH0.0199595312.87202158
Add Pool151466092022-07-15 10:04:13725 days ago1657879453IN
0x3f257f17...BCb7D5c2E
0 ETH0.018166111.77635636
Add Pool151466062022-07-15 10:03:53725 days ago1657879433IN
0x3f257f17...BCb7D5c2E
0 ETH0.019972713.01519643
Add Pool151466032022-07-15 10:03:15725 days ago1657879395IN
0x3f257f17...BCb7D5c2E
0 ETH0.0182113211.92976509
Add Pool151466012022-07-15 10:03:06725 days ago1657879386IN
0x3f257f17...BCb7D5c2E
0 ETH0.0198777413.09019155
Add Pool151465992022-07-15 10:02:43725 days ago1657879363IN
0x3f257f17...BCb7D5c2E
0 ETH0.0202303713.39317317
Add Pool151465982022-07-15 10:02:37725 days ago1657879357IN
0x3f257f17...BCb7D5c2E
0 ETH0.0207061513.78135514
Add Pool151465972022-07-15 10:02:33725 days ago1657879353IN
0x3f257f17...BCb7D5c2E
0 ETH0.0222599814.89507265
Add Pool151465952022-07-15 10:02:06725 days ago1657879326IN
0x3f257f17...BCb7D5c2E
0 ETH0.0223477315.03448865
Add Pool151465942022-07-15 10:01:49725 days ago1657879309IN
0x3f257f17...BCb7D5c2E
0 ETH0.0213581314.44671237
Add Pool151465932022-07-15 10:01:28725 days ago1657879288IN
0x3f257f17...BCb7D5c2E
0 ETH0.0207060414.08205641
Add Pool151465922022-07-15 10:01:24725 days ago1657879284IN
0x3f257f17...BCb7D5c2E
0 ETH0.0196181213.41535861
Add Pool151465902022-07-15 10:01:02725 days ago1657879262IN
0x3f257f17...BCb7D5c2E
0 ETH0.0212455514.60838065
View all transactions

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Block From To Value
151672082022-07-18 14:33:49722 days ago1658154829
0x3f257f17...BCb7D5c2E
0.01 ETH
151557382022-07-16 20:02:32724 days ago1658001752
0x3f257f17...BCb7D5c2E
0.01 ETH
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x89Bb49d0...e5177f3D0
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
TimedCacheEthAndPrimeRewards

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : TimedCacheEthAndPrimeRewards.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.7;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./PrimeRewards.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

/// @title The TimedCacheEthAndPrimeRewards caching contract
/// @notice Caching contract for Masterpieces. It allows for a fixed PRIME token
/// rewards distributed evenly across all cached tokens per second.
contract TimedCacheEthAndPrimeRewards is PrimeRewards, ReentrancyGuard {
    /// @notice Timed Cache Info per user per pool/Masterpiece
    struct TimedCacheInfo {
        uint256 lastCacheTimestamp;
    }

    /// @notice Eth Info of each pool.
    /// Contains the total amount of Eth rewarded and total amount of Eth claimed.
    struct EthPoolInfo {
        uint256 ethReward;
        uint256 ethClaimed;
    }

    /// @notice Pool id to Masterpiece
    mapping(uint256 => EthPoolInfo) public ethPoolInfo;
    /// @notice TimedCache info for each user that caches a Masterpiece
    /// poolID(per masterpiece) => user address => timedCache info
    mapping(uint256 => mapping(address => TimedCacheInfo))
        public timedCacheInfo;

    /// @notice Minimum number of timed cache seconds per ETH
    uint256 public ethTimedCachePeriod;
    
    /// @dev Fire when eth rewards are added to a Pool Id's eth rewards
    /// @param _tokenIds The Pool Id where Eth rewards have been added 
    /// @param _ethRewards Amount of Eth rewards added to that Pool Id
    event EthRewardsAdded(uint256[] _tokenIds, uint256[] _ethRewards);


    /// @dev Fire when eth rewards are set for a Pool Id
    /// @param _tokenIds The Pool Id of Eth rewards set 
    /// @param _ethRewards Amount of Eth to be distributed as rewards
    event EthRewardsSet(uint256[] _tokenIds, uint256[] _ethRewards);

    /// @dev Fire when there has been a change made to timedCacheperiod for either 
    ///  ETH or PRIME
    /// @param timedCachePeriod Length of time in seconds that rewards will be distributed in 
    /// @param currencyId Reward currency - 1 = ETH, 2 = PRIME
    event TimedCachePeriodUpdated(
        uint256 timedCachePeriod,
        uint256 indexed currencyId
    );

    /// @param _prime The PRIME token contract address.
    /// @param _parallelAlpha The Parallel Alpha contract address.
    constructor(IERC20 _prime, IERC1155 _parallelAlpha)
        PrimeRewards(_prime, _parallelAlpha)
    {}

    /// @notice Set the timedCachePeriod
    /// @param _ethTimedCachePeriod Minimum number of timedCache seconds per ETH
    function setEthTimedCachePeriod(uint256 _ethTimedCachePeriod)
        external
        onlyOwner
    {
        ethTimedCachePeriod = _ethTimedCachePeriod;
        emit TimedCachePeriodUpdated(_ethTimedCachePeriod, ID_ETH);
    }

    /// @notice Add ETH rewards for the specified Masterpiece pools
    /// @param _pids List of specified pools/Masterpieces
    /// @param _ethRewards List of ETH values for corresponding _pids
    function addEthRewards(uint256[] memory _pids, uint256[] memory _ethRewards)
        external
        payable
        onlyOwner
    {
        require(
            _pids.length == _ethRewards.length,
            "token ids and eth rewards lengths aren't the same"
        );
        uint256 totalEthRewards = 0;
        for (uint256 i = 0; i < _pids.length; i++) {
            uint256 pid = _pids[i];
            uint256 ethReward = _ethRewards[i];
            ethPoolInfo[pid].ethReward += ethReward;
            totalEthRewards += ethReward;
        }
        require(msg.value >= totalEthRewards, "Not enough eth sent");
        emit EthRewardsAdded(_pids, _ethRewards);
    }

    /// @notice Set ETH rewards for the specified Masterpiece pools
    /// @param _pids List of specified pools/Masterpieces
    /// @param _ethRewards List of ETH values for corresponding _pids
    function setEthRewards(uint256[] memory _pids, uint256[] memory _ethRewards)
        public
        payable
        onlyOwner
    {
        require(
            _pids.length == _ethRewards.length,
            "token ids and eth rewards lengths aren't the same"
        );
        uint256 currentTotalEth = 0;
        uint256 newTotalEth = 0;
        for (uint256 i = 0; i < _pids.length; i++) {
            uint256 pid = _pids[i];
            uint256 ethReward = _ethRewards[i];
            EthPoolInfo storage _ethPoolInfo = ethPoolInfo[pid];
            // new eth reward - old eth reward
            currentTotalEth += _ethPoolInfo.ethReward;
            newTotalEth += ethReward;
            _ethPoolInfo.ethReward = ethReward;
        }
        if (newTotalEth > currentTotalEth) {
            require(
                msg.value >= (newTotalEth - currentTotalEth),
                "Not enough eth sent"
            );
        }
        emit EthRewardsSet(_pids, _ethRewards);
    }

    /// @notice View function to see pending ETH on frontend.
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _user Address of user.
    /// @return pending ETH reward for a given user.
    function pendingEth(uint256 _pid, address _user)
        external
        view
        returns (uint256 pending)
    {
        CacheInfo storage _cache = cacheInfo[_pid][_user];
        EthPoolInfo storage _ethPoolInfo = ethPoolInfo[_pid];
        TimedCacheInfo storage _timedCache = timedCacheInfo[_pid][_user];

        if (_ethPoolInfo.ethClaimed < _ethPoolInfo.ethReward) {
            uint256 remainingRewards = _ethPoolInfo.ethReward -
                _ethPoolInfo.ethClaimed;

            uint256 vestedAmount = _cache.amount *
                (((block.timestamp - _timedCache.lastCacheTimestamp) *
                    1 ether) / ethTimedCachePeriod);

            pending = Math.min(vestedAmount, remainingRewards);
        }
    }

    /// @notice Cache nfts for PRIME allocation.
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _amount Amount of prime sets to cache for _pid.
    function cache(uint256 _pid, uint256 _amount) public override {
        TimedCacheInfo storage _timedCache = timedCacheInfo[_pid][msg.sender];

        _timedCache.lastCacheTimestamp = block.timestamp;

        PrimeRewards.cache(_pid, _amount);
    }

    /// @notice Claim eth for transaction sender.
    /// @param _pid Token id to claim.
    function claimEth(uint256 _pid) public nonReentrant {
        CacheInfo memory _cache = cacheInfo[_pid][msg.sender];
        EthPoolInfo storage _ethPoolInfo = ethPoolInfo[_pid];
        TimedCacheInfo storage _timedCache = timedCacheInfo[_pid][msg.sender];
        require(
            _ethPoolInfo.ethClaimed < _ethPoolInfo.ethReward,
            "Already claimed all eth"
        );

        uint256 remainingRewards = _ethPoolInfo.ethReward -
            _ethPoolInfo.ethClaimed;

        uint256 vestedAmount = _cache.amount *
            (((block.timestamp - _timedCache.lastCacheTimestamp) * 1 ether) /
                ethTimedCachePeriod);

        uint256 pendingEthReward = Math.min(vestedAmount, remainingRewards);
        _ethPoolInfo.ethClaimed += pendingEthReward;
        _timedCache.lastCacheTimestamp = block.timestamp;

        if (pendingEthReward > 0) {
            (bool sent, ) = msg.sender.call{ value: pendingEthReward }("");
            require(sent, "Failed to send Ether");
        }
        emit Claim(msg.sender, _pid, pendingEthReward, ID_ETH);
    }

    /// @notice Claim eth and PRIME for transaction sender.
    /// @param _pid Pool id to claim.
    function claimPrimeAndEth(uint256 _pid) public {
        claimPrime(_pid);
        claimEth(_pid);
    }

    /// @notice Claim multiple pools
    /// @param _pids Pool IDs of all to be claimed
    function claimPoolsPrimeAndEth(uint256[] calldata _pids) external {
        for (uint256 i = 0; i < _pids.length; ++i) {
            claimPrimeAndEth(_pids[i]);
        }
    }

    /// @notice Withdraw Masterpiece and claim eth for transaction sender.
    /// @param _pid Token id to withdraw.
    /// @param _amount Amount to withdraw.
    function withdrawAndClaimEth(uint256 _pid, uint256 _amount) external {
        claimEth(_pid);
        withdraw(_pid, _amount);
    }

    /// @notice Withdraw Masterpiece and claim eth and prime for transaction sender.
    /// @param _pid Token id to withdraw.
    /// @param _amount Amount to withdraw.
    function withdrawAndClaimPrimeAndEth(uint256 _pid, uint256 _amount)
        external
    {
        claimEth(_pid);
        withdrawAndClaimPrime(_pid, _amount);
    }

    /// @notice Sweep function to transfer ETH out of contract.
    /// @param to address to sweep to
    /// @param amount Amount to withdraw
    function sweepETH(address payable to, uint256 amount) external onlyOwner {
        (bool sent, ) = to.call{ value: amount }("");
        require(sent, "Failed to send Ether");
    }
}

File 2 of 16 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 3 of 16 : PrimeRewards.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.7;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

/// @title The PrimeRewards caching contract
/// @notice Caching for PrimeKey, PrimeSets, CatalystDrive. It allows for a fixed PRIME token
/// rewards distributed evenly across all cached tokens per second.
contract PrimeRewards is Ownable, ERC1155Holder {
    using SafeERC20 for IERC20;
    using SafeCast for uint256;
    using SafeCast for int256;

    /// @notice Info of each Cache.
    /// `amount` Number of NFT sets the user has provided.
    /// `rewardDebt` The amount of PRIME the user is not eligible for either from
    ///  having already harvesting or from not caching in the past.
    struct CacheInfo {
        uint256 amount;
        int256 rewardDebt;
    }

    /// @notice Info of each pool.
    /// Contains the weighted allocation of the reward pool
    /// as well as the ParallelAlpha tokenIds required to cache in the pool
    struct PoolInfo {
        uint256 accPrimePerShare; // The amount of accumulated PRIME per share
        uint256 allocPoint; // share of the contract's per second rewards to that pool
        uint256 lastRewardTimestamp; // last time stamp at which rewards were assigned  
        uint256[] tokenIds; // ParallelAlpha tokenIds required to cache in the pool
        uint256 totalSupply; // Total number of cached sets in pool
    }

    /// @notice Address of PRIME contract.
    IERC20 public PRIME;

    /// @notice Address of Parallel Alpha erc1155
    IERC1155 public immutable parallelAlpha;

    /// @notice Info of each pool.
    PoolInfo[] public poolInfo;

    /// @notice Cache info of each user that caches NFT sets.
    // poolID(per set) => user address => cache info
    mapping(uint256 => mapping(address => CacheInfo)) public cacheInfo;

    /// @notice Prime amount distributed for given period. primeAmountPerSecond = primeAmount / (endTimestamp - startTimestamp)
    uint256 public startTimestamp; // caching start timestamp.
    uint256 public endTimestamp; // caching end timestamp.
    uint256 public primeAmount; // the amount of PRIME to give out as rewards.
    uint256 public primeAmountPerSecond; // the amount of PRIME to give out as rewards per second.
    uint256 public constant primeAmountPerSecondPrecision = 1e18; // primeAmountPerSecond is carried around with extra precision to reduce rounding errors

    /// @dev PRIME token will be minted after this contract is deployed, but should not be changeable forever
    uint256 public primeUpdateCutoff = 1667304000;

    /// @dev Limit number of pools that can be added
    uint256 public maxNumPools = 500;

    /// @dev Total allocation points. Must be the sum of all allocation points (i.e. multipliers) in all pools.
    uint256 public totalAllocPoint;

    /// @dev Caching functionality flag
    bool public cachingPaused;

    /// @dev Constants passed into event data
    uint256 public constant ID_PRIME = 0;
    uint256 public constant ID_ETH = 1;

    /// @dev internal lock for receiving ERC1155 tokens. Only allow during cache calls
    bool public onReceiveLocked = true;

     // @dev Fire when user has cached an asset (or set of assets) to the contract
    // @param user Address that has cached an asset
    // @param pid Pool ID that the user has caches assets to
    // @param amount Number of assets cached
    event Cache(address indexed user, uint256 indexed pid, uint256 amount);

    // @dev Fire when user withdraws asset (or set of assets) from contract
    // @param user Address that has withdrawn an asset
    // @param pid Pool ID of the withdrawn assets
    // @param amount Number of assets withdrawn
    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);

    // @dev Fire if an emergency withdrawal of assets occurs
    // @param user Address that has withdrawn an asset
    // @param pid Pool ID of the withdrawn assets
    // @param amount Number of assets withdrawn
    event EmergencyWithdraw(
        address indexed user,
        uint256 indexed pid,
        uint256 amount
    );

    // @dev Fire when user claims their rewards from the contract 
    // @param user Address claiming rewards
    // @param pid Pool ID from which the user has claimed rewards
    // @param amount Amount of rewards claimed
    // @param currencyId Reward currency - 1 = ETH, 2 = PRIME
    event Claim(
        address indexed user,
        uint256 indexed pid,
        uint256 amount,
        uint256 indexed currencyId
    );

    // @dev Fire when a new pool is added to the contract 
    // @param pid Pool ID of the new pool
    // @param tokenIds ERC1155 token ids of pool assets
    event LogPoolAddition(uint256 indexed pid, uint256[] tokenIds);

    // @dev Fire when the end of a rewards regime has been updated 
    // @param endTimestamp New end time for a pool rewards
    // @param currencyId Reward currency - 1 = ETH, 2 = PRIME
    event EndTimestampUpdated(uint256 endTimestamp, uint256 indexed currencyID);

    // @dev Fire when additional rewards are added to a pool's rewards regime 
    // @param amount Amount of new rewards added
    // @param currencyID Reward currency - 1 = ETH, 2 = PRIME
    event RewardIncrease(uint256 amount, uint256 indexed currencyID);

    // @dev Fire when rewards are removed from a pool's rewards regime 
    // @param amount Amount of new rewards added
    // @param currencyID Reward currency - 1 = ETH, 2 = PRIME
    event RewardDecrease(uint256 amount, uint256 indexed currencyID);

    // @dev Fire when caching is paused for the contract 
    // @param cachingPaused True if caching is paused
    event CachingPaused(bool cachingPaused);

    // @dev Fire when there has been a change to the allocation points of a pool
    // @param pid Pool ID for which the allocation points have changed
    // @param totalAllocPoint the new total allocation points of all pools
    // @param currencyID Reward currency - 1 = ETH, 2 = PRIME
    event LogPoolSetAllocPoint(
        uint256 indexed pid,
        uint256 allocPoint,
        uint256 totalAllocPoint,
        uint256 indexed currencyId
    );


    // @dev Fire when rewards are recalculated in the pool
    // @param pid Pool ID for which the update occurred
    // @param lastRewardTimestamp The timestamp at which rewards have been recalculated for
    // @param supply The amount of assets staked to that pool
    // @param currencyID Reward currency - 1 = ETH, 2 = PRIME
    event LogUpdatePool(
        uint256 indexed pid,
        uint256 lastRewardTimestamp,
        uint256 supply,
        uint256 accPerShare,
        uint256 indexed currencyId
    );

    // @dev Fire when the rewards rate has been changed
    // @param amount Amount of rewards
    // @param startTimestamp Begin time of the reward period
    // @param startTimestamp End time of the reward period
    // @param currencyID Reward currency - 1 = ETH, 2 = PRIME
    event LogSetPerSecond(
        uint256 amount,
        uint256 startTimestamp,
        uint256 endTimestamp,
        uint256 indexed currencyId
    );

    /// @param _prime The PRIME token contract address.
    /// @param _parallelAlpha The Parallel Alpha contract address.
    constructor(IERC20 _prime, IERC1155 _parallelAlpha) {
        parallelAlpha = _parallelAlpha;
        PRIME = _prime;
    }

    /// @notice Sets new prime token address
    /// @param _prime The PRIME token contract address.
    function setPrimeTokenAddress(IERC20 _prime) external onlyOwner {
        require(
            block.timestamp < primeUpdateCutoff,
            "PRIME address update window has has passed"
        );
        PRIME = _prime;
    }

    /// @notice Sets new max number of pools. New max cannot be less than
    /// current number of pools.
    /// @param _maxNumPools The new max number of pools.
    function setMaxNumPools(uint256 _maxNumPools) external onlyOwner {
        require(
            _maxNumPools >= poolLength(),
            "Can't set maxNumPools less than poolLength"
        );
        maxNumPools = _maxNumPools;
    }

    /// @notice Returns the number of pools.
    function poolLength() public view returns (uint256 pools) {
        pools = poolInfo.length;
    }

    /// @param _pid Pool to get IDs for
    function getPoolTokenIds(uint256 _pid)
        external
        view
        returns (uint256[] memory)
    {
        return poolInfo[_pid].tokenIds;
    }

    function updateAllPools() internal {
        uint256 len = poolLength();
        for (uint256 i = 0; i < len; ++i) {
            updatePool(i);
        }
    }

    /// @notice Add a new set of tokenIds as a new pool. Can only be called by the owner.
    /// DO NOT add the same token id more than once or rewards will be inaccurate.
    /// @param _allocPoint Allocation Point (i.e. multiplier) of the new pool.
    /// @param _tokenIds TokenIds for ParallelAlpha ERC1155, set of tokenIds for pool.
    function addPool(uint256 _allocPoint, uint256[] memory _tokenIds)
        public
        virtual
        onlyOwner
    {
        require(poolInfo.length < maxNumPools, "Max num pools reached");
        require(_tokenIds.length > 0, "TokenIds cannot be empty");
        require(_allocPoint > 0, "Allocation point cannot be 0 or negative");
        // Update all pool information before adding the AllocPoint for new pool
        for (uint256 i = 0; i < poolInfo.length; ++i) {
            updatePool(i);
            require(
                keccak256(abi.encodePacked(poolInfo[i].tokenIds)) !=
                    keccak256(abi.encodePacked(_tokenIds)),
                "Pool with same tokenIds exists"
            );
        }
        totalAllocPoint += _allocPoint;
        poolInfo.push(
            PoolInfo({
                accPrimePerShare: 0,
                allocPoint: _allocPoint,
                lastRewardTimestamp: Math.max(block.timestamp, startTimestamp),
                tokenIds: _tokenIds,
                totalSupply: 0
            })
        );
        emit LogPoolAddition(poolInfo.length - 1, _tokenIds);
        emit LogPoolSetAllocPoint(
            poolInfo.length - 1,
            _allocPoint,
            totalAllocPoint,
            ID_PRIME
        );
    }

    /// @notice Set new period to distribute rewards between endTimestamp-startTimestamp
    /// evenly per second. primeAmountPerSecond = _primeAmount / (_endTimestamp - _startTimestamp)
    /// Can only be set once any existing setPrimePerSecond regime has concluded (ethEndTimestamp < block.timestamp)
    /// @param _startTimestamp Timestamp for caching period to start at
    /// @param _endTimestamp Timestamp for caching period to end at
    /// @param _primeAmount Amount of Prime to distribute evenly across whole period
    function setPrimePerSecond(
        uint256 _startTimestamp,
        uint256 _endTimestamp,
        uint256 _primeAmount
    ) external onlyOwner {
        require(
            _startTimestamp < _endTimestamp,
            "endTimestamp cant be less than startTimestamp"
        );
        require(
            block.timestamp < startTimestamp || endTimestamp < block.timestamp,
            "Only updates after endTimestamp or before startTimestamp"
        );

        // Update all pools, ensure rewards are calculated up to this timestamp
        for (uint256 i = 0; i < poolInfo.length; ++i) {
            updatePool(i);
            poolInfo[i].lastRewardTimestamp = _startTimestamp;
        }
        primeAmount = _primeAmount;
        startTimestamp = _startTimestamp;
        endTimestamp = _endTimestamp;
        primeAmountPerSecond =
            (_primeAmount * primeAmountPerSecondPrecision) /
            (_endTimestamp - _startTimestamp);
        emit LogSetPerSecond(
            _primeAmount,
            _startTimestamp,
            _endTimestamp,
            ID_PRIME
        );
    }

    /// @notice Update endTimestamp, only possible to call this when caching for
    /// a period has already begun. New endTimestamp must be in the future
    /// @param _endTimestamp New timestamp for caching period to end at
    function setEndTimestamp(uint256 _endTimestamp) external onlyOwner {
        require(
            startTimestamp < block.timestamp,
            "caching period has not started yet"
        );
        require(block.timestamp < _endTimestamp, "invalid end timestamp");
        updateAllPools();

        // Update primeAmountPerSecond based on the new endTimestamp
        startTimestamp = block.timestamp;
        endTimestamp = _endTimestamp;
        primeAmountPerSecond =
            (primeAmount * primeAmountPerSecondPrecision) /
            (endTimestamp - startTimestamp);
        emit EndTimestampUpdated(_endTimestamp, ID_PRIME);
    }

    /// @notice Function for 'Top Ups', adds additional prime to distribute for remaining time
    /// in the period.
    /// @param _addPrimeAmount Amount of Prime to add to the reward pool
    function addPrimeAmount(uint256 _addPrimeAmount) external onlyOwner {
        require(
            startTimestamp < block.timestamp && block.timestamp < endTimestamp,
            "Can only addPrimeAmount during period"
        );
        // Update all pools
        updateAllPools();
        // Top up current period's PRIME
        primeAmount += _addPrimeAmount;
        primeAmountPerSecond =
            (primeAmount * primeAmountPerSecondPrecision) /
            (endTimestamp - block.timestamp);
        emit RewardIncrease(_addPrimeAmount, ID_PRIME);
    }

    /// @notice Function for 'Top Downs', removes prime distributed for remaining time
    /// in the period.
    /// @param _removePrimeAmount Amount of Prime to remove from the remaining reward pool
    function removePrimeAmount(uint256 _removePrimeAmount) external onlyOwner {
        require(
            startTimestamp < block.timestamp && block.timestamp < endTimestamp,
            "Can only removePrimeAmount during a period"
        );

        // Update all pools
        updateAllPools();

        // Adjust current period's PRIME
        // Using min to make sure primeAmount can only be reduced to zero
        _removePrimeAmount = Math.min(_removePrimeAmount, primeAmount);
        primeAmount -= _removePrimeAmount;
        primeAmountPerSecond =
            (primeAmount * primeAmountPerSecondPrecision) /
            (endTimestamp - block.timestamp);
        emit RewardDecrease(_removePrimeAmount, ID_PRIME);
    }

    /// @notice Update the given pool's PRIME allocation point (i.e. multiplier). Only owner.
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _allocPoint New allocation point (i.e. multiplier) of the pool.
    function setPoolAllocPoint(uint256 _pid, uint256 _allocPoint)
        external
        onlyOwner
    {
        // Update all pools
        updateAllPools();
        totalAllocPoint =
            totalAllocPoint -
            poolInfo[_pid].allocPoint +
            _allocPoint;
        poolInfo[_pid].allocPoint = _allocPoint;
        emit LogPoolSetAllocPoint(_pid, _allocPoint, totalAllocPoint, ID_PRIME);
    }

    /// @notice Enable/disable caching for pools. Only owner.
    /// @param _cachingPaused boolean value to set
    function setCachingPaused(bool _cachingPaused) external onlyOwner {
        cachingPaused = _cachingPaused;
        emit CachingPaused(cachingPaused);
    }

    /// @notice View function to see cache amounts for pools.
    /// @param _pids List of pool index ids. See `poolInfo`.
    /// @param _addresses List of user addresses.
    /// @return amounts List of cache amounts.
    function getPoolCacheAmounts(
        uint256[] calldata _pids,
        address[] calldata _addresses
    ) external view returns (uint256[] memory) {
        require(
            _pids.length == _addresses.length,
            "pids and addresses length mismatch"
        );

        uint256[] memory amounts = new uint256[](_pids.length);
        for (uint256 i = 0; i < _pids.length; ++i) {
            amounts[i] = cacheInfo[_pids[i]][_addresses[i]].amount;
        }

        return amounts;
    }

    /// @notice View function to see pending PRIME on frontend.
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _user Address of user.
    /// @return pending PRIME reward for a given user.
    function pendingPrime(uint256 _pid, address _user)
        external
        view
        returns (uint256 pending)
    {
        PoolInfo memory pool = poolInfo[_pid];
        CacheInfo storage _cache = cacheInfo[_pid][_user];
        uint256 accPrimePerShare = pool.accPrimePerShare;
        uint256 totalSupply = pool.totalSupply;

        if (
            startTimestamp <= block.timestamp &&
            pool.lastRewardTimestamp < block.timestamp &&
            totalSupply > 0
        ) {
            uint256 updateToTimestamp = Math.min(block.timestamp, endTimestamp);
            uint256 seconds_ = updateToTimestamp - pool.lastRewardTimestamp;
            uint256 primeReward = (seconds_ *
                primeAmountPerSecond *
                pool.allocPoint) / totalAllocPoint;
            accPrimePerShare += primeReward / totalSupply;
        }
        pending =
            ((_cache.amount * accPrimePerShare).toInt256() - _cache.rewardDebt)
                .toUint256() /
            primeAmountPerSecondPrecision;
    }

    /// @notice Update reward variables for all pools. Be careful of gas required.
    /// @param _pids Pool IDs of all to be updated. Make sure to update all active pools.
    function massUpdatePools(uint256[] calldata _pids) external {
        uint256 len = _pids.length;
        for (uint256 i = 0; i < len; ++i) {
            updatePool(_pids[i]);
        }
    }

    /// @notice Update reward variables for the given pool.
    /// @param _pid The index of the pool. See `poolInfo`.
    function updatePool(uint256 _pid) public {
        PoolInfo storage pool = poolInfo[_pid];
        if (
            startTimestamp > block.timestamp ||
            pool.lastRewardTimestamp >= block.timestamp ||
            (startTimestamp == 0 && endTimestamp == 0)
        ) {
            return;
        }

        uint256 updateToTimestamp = Math.min(block.timestamp, endTimestamp);
        uint256 totalSupply = pool.totalSupply;
        uint256 seconds_ = updateToTimestamp - pool.lastRewardTimestamp;
        uint256 primeReward = (seconds_ *
            primeAmountPerSecond *
            pool.allocPoint) / totalAllocPoint;
        primeAmount -= primeReward / primeAmountPerSecondPrecision;
        if (totalSupply > 0) {
            pool.accPrimePerShare += primeReward / totalSupply;
        }
        pool.lastRewardTimestamp = updateToTimestamp;
        emit LogUpdatePool(
            _pid,
            pool.lastRewardTimestamp,
            totalSupply,
            pool.accPrimePerShare,
            ID_PRIME
        );
    }

    /// @notice Cache NFTs for PRIME rewards.
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _amount Amount of 'tokenIds sets' to cache for _pid.
    function cache(uint256 _pid, uint256 _amount) public virtual {
        require(!cachingPaused, "Caching is paused");
        require(_amount > 0, "Specify valid amount to cache");
        updatePool(_pid);
        CacheInfo storage _cache = cacheInfo[_pid][msg.sender];

        // Create amounts array for tokenIds BatchTransfer
        uint256[] memory amounts = new uint256[](
            poolInfo[_pid].tokenIds.length
        );
        for (uint256 i = 0; i < amounts.length; i++) {
            amounts[i] = _amount;
        }

        // Effects
        poolInfo[_pid].totalSupply += _amount;
        _cache.amount += _amount;
        _cache.rewardDebt += (_amount * poolInfo[_pid].accPrimePerShare)
            .toInt256();

        onReceiveLocked = false;
        parallelAlpha.safeBatchTransferFrom(
            msg.sender,
            address(this),
            poolInfo[_pid].tokenIds,
            amounts,
            bytes("")
        );
        onReceiveLocked = true;

        emit Cache(msg.sender, _pid, _amount);
    }

    /// @notice Withdraw from pool
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _amount Amount of tokenId sets to withdraw from the pool
    function withdraw(uint256 _pid, uint256 _amount) public virtual {
        updatePool(_pid);
        CacheInfo storage _cache = cacheInfo[_pid][msg.sender];

        // Create amounts array for tokenIds BatchTransfer
        uint256[] memory amounts = new uint256[](
            poolInfo[_pid].tokenIds.length
        );
        for (uint256 i = 0; i < amounts.length; i++) {
            amounts[i] = _amount;
        }

        // Effects
        poolInfo[_pid].totalSupply -= _amount;
        _cache.rewardDebt -= (_amount * poolInfo[_pid].accPrimePerShare)
            .toInt256();
        _cache.amount -= _amount;

        parallelAlpha.safeBatchTransferFrom(
            address(this),
            msg.sender,
            poolInfo[_pid].tokenIds,
            amounts,
            bytes("")
        );

        emit Withdraw(msg.sender, _pid, _amount);
    }

    /// @notice Claim accumulated PRIME rewards.
    /// @param _pid The index of the pool. See `poolInfo`.
    function claimPrime(uint256 _pid) public {
        updatePool(_pid);
        CacheInfo storage _cache = cacheInfo[_pid][msg.sender];
        int256 accumulatedPrime = (_cache.amount *
            poolInfo[_pid].accPrimePerShare).toInt256();
        uint256 _pendingPrime = (accumulatedPrime - _cache.rewardDebt)
            .toUint256() / primeAmountPerSecondPrecision;

        // Effects
        _cache.rewardDebt = accumulatedPrime;

        // Interactions
        if (_pendingPrime != 0) {
            PRIME.safeTransfer(msg.sender, _pendingPrime);
        }

        emit Claim(msg.sender, _pid, _pendingPrime, ID_PRIME);
    }

    /// @notice claimPrime multiple pools
    /// @param _pids Pool IDs of all to be claimed
    function claimPrimePools(uint256[] calldata _pids) external virtual {
        for (uint256 i = 0; i < _pids.length; ++i) {
            claimPrime(_pids[i]);
        }
    }

    /// @notice Withdraw and claim PRIME rewards.
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _amount Amount of tokenId sets to withdraw.
    function withdrawAndClaimPrime(uint256 _pid, uint256 _amount)
        public
        virtual
    {
        updatePool(_pid);
        CacheInfo storage _cache = cacheInfo[_pid][msg.sender];
        int256 accumulatedPrime = (_cache.amount *
            poolInfo[_pid].accPrimePerShare).toInt256();
        uint256 _pendingPrime = (accumulatedPrime - _cache.rewardDebt)
            .toUint256() / primeAmountPerSecondPrecision;

        // Create amounts array for tokenIds BatchTransfer
        uint256[] memory amounts = new uint256[](
            poolInfo[_pid].tokenIds.length
        );
        for (uint256 i = 0; i < amounts.length; i++) {
            amounts[i] = _amount;
        }

        // Effects
        poolInfo[_pid].totalSupply -= _amount;
        _cache.rewardDebt =
            accumulatedPrime -
            (_amount * poolInfo[_pid].accPrimePerShare).toInt256();
        _cache.amount -= _amount;

        if (_pendingPrime != 0) {
            PRIME.safeTransfer(msg.sender, _pendingPrime);
        }

        parallelAlpha.safeBatchTransferFrom(
            address(this),
            msg.sender,
            poolInfo[_pid].tokenIds,
            amounts,
            bytes("")
        );

        emit Withdraw(msg.sender, _pid, _amount);
        emit Claim(msg.sender, _pid, _pendingPrime, ID_PRIME);
    }

    /// @notice Withdraw and forgo rewards. EMERGENCY ONLY.
    /// @param _pid The index of the pool. See `poolInfo`.
    function emergencyWithdraw(uint256 _pid) public virtual {
        CacheInfo storage _cache = cacheInfo[_pid][msg.sender];

        uint256 amount = _cache.amount;
        // Create amounts array for tokenIds BatchTransfer
        uint256[] memory amounts = new uint256[](
            poolInfo[_pid].tokenIds.length
        );
        for (uint256 i = 0; i < amounts.length; i++) {
            amounts[i] = amount;
        }

        // Effects
        poolInfo[_pid].totalSupply -= amount;
        _cache.rewardDebt = 0;
        _cache.amount = 0;

        parallelAlpha.safeBatchTransferFrom(
            address(this),
            msg.sender,
            poolInfo[_pid].tokenIds,
            amounts,
            bytes("")
        );

        emit EmergencyWithdraw(msg.sender, _pid, amount);
    }

    /// @notice Sweep function to transfer erc20 tokens out of contract. Only owner.
    /// @param erc20 Token to transfer out
    /// @param to address to sweep to
    /// @param amount Amount to withdraw
    function sweepERC20(
        IERC20 erc20,
        address to,
        uint256 amount
    ) external onlyOwner {
        erc20.transfer(to, amount);
    }

    /// @notice Disable renounceOwnership. Only callable by owner.
    function renounceOwnership() public virtual override onlyOwner {
        revert("Ownership cannot be renounced");
    }

    /// @notice Revert for calls outside of cache method
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        require(onReceiveLocked == false, "onReceive is locked");
        return this.onERC1155Received.selector;
    }

    /// @notice Revert for calls outside of cache method
    function onERC1155BatchReceived(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) public virtual override returns (bytes4) {
        require(onReceiveLocked == false, "onReceive is locked");
        return this.onERC1155BatchReceived.selector;
    }
}

File 4 of 16 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}

File 5 of 16 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 6 of 16 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

File 7 of 16 : ERC1155Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol)

pragma solidity ^0.8.0;

import "./ERC1155Receiver.sol";

/**
 * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
 *
 * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
 * stuck.
 *
 * @dev _Available since v3.1._
 */
contract ERC1155Holder is ERC1155Receiver {
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155BatchReceived.selector;
    }
}

File 8 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

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

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

File 9 of 16 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 10 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 12 of 16 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 13 of 16 : ERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../IERC1155Receiver.sol";
import "../../../utils/introspection/ERC165.sol";

/**
 * @dev _Available since v3.1._
 */
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
    }
}

File 14 of 16 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 15 of 16 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

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

pragma solidity ^0.8.0;

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

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

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IERC20","name":"_prime","type":"address"},{"internalType":"contract IERC1155","name":"_parallelAlpha","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Cache","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"cachingPaused","type":"bool"}],"name":"CachingPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyID","type":"uint256"}],"name":"EndTimestampUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"_ethRewards","type":"uint256[]"}],"name":"EthRewardsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"_ethRewards","type":"uint256[]"}],"name":"EthRewardsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"LogPoolAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalAllocPoint","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"LogPoolSetAllocPoint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"LogSetPerSecond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastRewardTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accPerShare","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"LogUpdatePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyID","type":"uint256"}],"name":"RewardDecrease","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyID","type":"uint256"}],"name":"RewardIncrease","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timedCachePeriod","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"currencyId","type":"uint256"}],"name":"TimedCachePeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"ID_ETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ID_PRIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRIME","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"},{"internalType":"uint256[]","name":"_ethRewards","type":"uint256[]"}],"name":"addEthRewards","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_addPrimeAmount","type":"uint256"}],"name":"addPrimeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"cache","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"cacheInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"int256","name":"rewardDebt","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cachingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"claimEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"}],"name":"claimPoolsPrimeAndEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"claimPrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"claimPrimeAndEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"}],"name":"claimPrimePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ethPoolInfo","outputs":[{"internalType":"uint256","name":"ethReward","type":"uint256"},{"internalType":"uint256","name":"ethClaimed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethTimedCachePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"},{"internalType":"address[]","name":"_addresses","type":"address[]"}],"name":"getPoolCacheAmounts","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getPoolTokenIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"}],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxNumPools","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onReceiveLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"parallelAlpha","outputs":[{"internalType":"contract IERC1155","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingEth","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingPrime","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"uint256","name":"accPrimePerShare","type":"uint256"},{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"uint256","name":"lastRewardTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"pools","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primeAmountPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primeAmountPerSecondPrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primeUpdateCutoff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_removePrimeAmount","type":"uint256"}],"name":"removePrimeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_cachingPaused","type":"bool"}],"name":"setCachingPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_endTimestamp","type":"uint256"}],"name":"setEndTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"},{"internalType":"uint256[]","name":"_ethRewards","type":"uint256[]"}],"name":"setEthRewards","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethTimedCachePeriod","type":"uint256"}],"name":"setEthTimedCachePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxNumPools","type":"uint256"}],"name":"setMaxNumPools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"}],"name":"setPoolAllocPoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startTimestamp","type":"uint256"},{"internalType":"uint256","name":"_endTimestamp","type":"uint256"},{"internalType":"uint256","name":"_primeAmount","type":"uint256"}],"name":"setPrimePerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_prime","type":"address"}],"name":"setPrimeTokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"erc20","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sweepERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sweepETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"timedCacheInfo","outputs":[{"internalType":"uint256","name":"lastCacheTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawAndClaimEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawAndClaimPrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawAndClaimPrimeAndEth","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x6080604052600436106103745760003560e01c80638c272e46116101d1578063cc8ba18811610102578063e7bcdafd116100a0578063f2fde38b1161006f578063f2fde38b14610a69578063f928603e14610a89578063f9a3bfe114610aa9578063fc8e917714610ac957600080fd5b8063e7bcdafd146109f6578063edc7a35f14610a16578063f15d6f9d14610a29578063f23a6e6114610a4957600080fd5b8063ddcb4b68116100dc578063ddcb4b681461098b578063e1df480f146109ab578063e4f3ae43146109cb578063e6fd48bc146109e057600080fd5b8063cc8ba1881461091e578063cdeccabf1461093e578063dc628aa41461096b57600080fd5b8063bdc158801161016f578063c9af39e211610149578063c9af39e21461088a578063c9ffdfb2146108aa578063ca7238f2146108ca578063cbd99868146108fe57600080fd5b8063bdc1588014610841578063bec4d45414610854578063bee208851461086a57600080fd5b8063a85adeab116101ab578063a85adeab146107bd578063ae1f071d146107d3578063b588d1c9146107e8578063bc197c811461080857600080fd5b80638c272e46146107485780638da5cb5b14610780578063a339bb461461079e57600080fd5b8063446a3c1f116102ab5780635c5709ca11610249578063719931301161022357806371993130146106d25780637943dca4146106e85780637df6a6c814610708578063811822e61461072857600080fd5b80635c5709ca1461065e5780636af84fc01461069d578063715018a6146106bd57600080fd5b806351eb05a61161028557806351eb05a6146105de5780635312ea8e146105fe57806357a5b58c1461061e5780635b116ab81461063e57600080fd5b8063446a3c1f1461057e5780634f94a8cd1461059e578063503690d1146105be57600080fd5b80631cb819ad1161031857806333b1a24a116102f257806333b1a24a1461050a5780633f3a1f501461052c57806340fe03a714610548578063441a3e701461055e57600080fd5b80631cb819ad146104ba5780632138c1aa146104d45780632fee4c87146104f457600080fd5b8063081e3eda11610354578063081e3eda1461042f57806312446f491461044e5780631526fe271461046457806317caf6f1146104a457600080fd5b806217cd8b146103795780626d0c1a146103b657806301ffc9a7146103ff575b600080fd5b34801561038557600080fd5b50600154610399906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103c257600080fd5b506103ea6103d1366004613a55565b600d602052600090815260409020805460019091015482565b604080519283526020830191909152016103ad565b34801561040b57600080fd5b5061041f61041a3660046139ea565b610ae9565b60405190151581526020016103ad565b34801561043b57600080fd5b506002545b6040519081526020016103ad565b34801561045a57600080fd5b5061044060085481565b34801561047057600080fd5b5061048461047f366004613a55565b610b20565b6040805194855260208501939093529183015260608201526080016103ad565b3480156104b057600080fd5b50610440600a5481565b3480156104c657600080fd5b50600b5461041f9060ff1681565b3480156104e057600080fd5b506104406104ef366004613a6e565b610b5a565b34801561050057600080fd5b5061044060095481565b34801561051657600080fd5b5061052a6105253660046138a1565b610c10565b005b34801561053857600080fd5b50610440670de0b6b3a764000081565b34801561055457600080fd5b50610440600f5481565b34801561056a57600080fd5b5061052a610579366004613ada565b610c51565b34801561058a57600080fd5b50610440610599366004613a6e565b610ebb565b3480156105aa57600080fd5b5061052a6105b9366004613ada565b611071565b3480156105ca57600080fd5b5061052a6105d9366004613a14565b611392565b3480156105ea57600080fd5b5061052a6105f9366004613a55565b61144d565b34801561060a57600080fd5b5061052a610619366004613a55565b6115a5565b34801561062a57600080fd5b5061052a6106393660046138a1565b6117a2565b34801561064a57600080fd5b5061052a610659366004613760565b6117df565b34801561066a57600080fd5b506103ea610679366004613a6e565b60036020908152600092835260408084209091529082529020805460019091015482565b3480156106a957600080fd5b5061052a6106b8366004613a55565b6118a3565b3480156106c957600080fd5b5061052a6119c3565b3480156106de57600080fd5b5061044060075481565b3480156106f457600080fd5b5061052a610703366004613ada565b611a35565b34801561071457600080fd5b5061052a610723366004613a55565b611a4c565b34801561073457600080fd5b5061052a610743366004613a55565b611b8c565b34801561075457600080fd5b50610440610763366004613a6e565b600e60209081526000928352604080842090915290825290205481565b34801561078c57600080fd5b506000546001600160a01b0316610399565b3480156107aa57600080fd5b50600b5461041f90610100900460ff1681565b3480156107c957600080fd5b5061044060055481565b3480156107df57600080fd5b50610440600181565b3480156107f457600080fd5b5061052a610803366004613743565b611c20565b34801561081457600080fd5b5061082861082336600461378c565b611cd0565b6040516001600160e01b031990911681526020016103ad565b61052a61084f36600461394d565b611d33565b34801561086057600080fd5b5061044060065481565b34801561087657600080fd5b5061052a610885366004613a9e565b611ea6565b34801561089657600080fd5b5061052a6108a53660046138a1565b6121f7565b3480156108b657600080fd5b5061052a6108c5366004613a55565b612233565b3480156108d657600080fd5b506103997f00000000000000000000000076be3b62873462d2142405439777e971754e8e7781565b34801561090a57600080fd5b5061052a610919366004613a55565b612248565b34801561092a57600080fd5b5061052a610939366004613afc565b6124ab565b34801561094a57600080fd5b5061095e6109593660046138e2565b61268d565b6040516103ad9190613ca1565b34801561097757600080fd5b5061052a610986366004613ada565b6127e9565b34801561099757600080fd5b5061052a6109a63660046139b0565b6128c6565b3480156109b757600080fd5b5061052a6109c6366004613ada565b61293d565b3480156109d757600080fd5b50610440600081565b3480156109ec57600080fd5b5061044060045481565b348015610a0257600080fd5b5061052a610a11366004613a55565b612963565b61052a610a2436600461394d565b612a3d565b348015610a3557600080fd5b5061095e610a44366004613a55565b612ba3565b348015610a5557600080fd5b50610828610a64366004613839565b612c1f565b348015610a7557600080fd5b5061052a610a84366004613743565b612c82565b348015610a9557600080fd5b5061052a610aa4366004613a55565b612d1a565b348015610ab557600080fd5b5061052a610ac4366004613ada565b612e46565b348015610ad557600080fd5b5061052a610ae4366004613a55565b612e59565b60006001600160e01b03198216630271189760e51b1480610b1a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60028181548110610b3057600080fd5b60009182526020909120600590910201805460018201546002830154600490930154919350919084565b60008281526003602090815260408083206001600160a01b038516808552908352818420868552600d8452828520600e855283862092865291909352908320815460018301541015610c075760018201548254600091610bb991613e84565b600f548354919250600091610bce9042613e84565b610be090670de0b6b3a7640000613e26565b610bea9190613e04565b8554610bf69190613e26565b9050610c028183612ebb565b955050505b50505092915050565b60005b81811015610c4c57610c3c838383818110610c3057610c30613ef8565b90506020020135612233565b610c4581613ec7565b9050610c13565b505050565b610c5a8261144d565b600082815260036020908152604080832033845290915281206002805491929185908110610c8a57610c8a613ef8565b9060005260206000209060050201600301805490506001600160401b03811115610cb657610cb6613f0e565b604051908082528060200260200182016040528015610cdf578160200160208202803683370190505b50905060005b8151811015610d1e5783828281518110610d0157610d01613ef8565b602090810291909101015280610d1681613ec7565b915050610ce5565b508260028581548110610d3357610d33613ef8565b90600052602060002090600502016004016000828254610d539190613e84565b92505081905550610d9260028581548110610d7057610d70613ef8565b90600052602060002090600502016000015484610d8d9190613e26565b612ed3565b826001016000828254610da59190613e45565b9091555050815483908390600090610dbe908490613e84565b925050819055507f00000000000000000000000076be3b62873462d2142405439777e971754e8e776001600160a01b0316632eb2c2d6303360028881548110610e0957610e09613ef8565b906000526020600020906005020160030185604051806020016040528060008152506040518663ffffffff1660e01b8152600401610e4b959493929190613c12565b600060405180830381600087803b158015610e6557600080fd5b505af1158015610e79573d6000803e3d6000fd5b50506040518581528692503391507ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568906020015b60405180910390a350505050565b60008060028481548110610ed157610ed1613ef8565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201805480602002602001604051908101604052809291908181526020018280548015610f5757602002820191906000526020600020905b815481526020019060010190808311610f43575b505050918352505060049182015460209182015260008781526003825260408082206001600160a01b03891683529092522082516080840151925493945090929091904210801590610fac5750428460400151105b8015610fb85750600081115b15611029576000610fcb42600554612ebb565b90506000856040015182610fdf9190613e84565b90506000600a54876020015160075484610ff99190613e26565b6110039190613e26565b61100d9190613e04565b90506110198482613e04565b6110239086613dec565b94505050505b670de0b6b3a764000061105c846001015461104d858760000154610d8d9190613e26565b6110579190613e45565b612f41565b6110669190613e04565b979650505050505050565b61107a8261144d565b60008281526003602090815260408083203384529091528120600280549192916110cc9190869081106110af576110af613ef8565b60009182526020909120600590910201548354610d8d9190613e26565b90506000670de0b6b3a76400006110ec8460010154846110579190613e45565b6110f69190613e04565b905060006002868154811061110d5761110d613ef8565b9060005260206000209060050201600301805490506001600160401b0381111561113957611139613f0e565b604051908082528060200260200182016040528015611162578160200160208202803683370190505b50905060005b81518110156111a1578582828151811061118457611184613ef8565b60209081029190910101528061119981613ec7565b915050611168565b5084600287815481106111b6576111b6613ef8565b906000526020600020906005020160040160008282546111d69190613e84565b92505081905550611210600287815481106111f3576111f3613ef8565b90600052602060002090600502016000015486610d8d9190613e26565b61121a9084613e45565b6001850155835485908590600090611233908490613e84565b9091555050811561125557600154611255906001600160a01b03163384612f93565b7f00000000000000000000000076be3b62873462d2142405439777e971754e8e776001600160a01b0316632eb2c2d6303360028a8154811061129957611299613ef8565b906000526020600020906005020160030185604051806020016040528060008152506040518663ffffffff1660e01b81526004016112db959493929190613c12565b600060405180830381600087803b1580156112f557600080fd5b505af1158015611309573d6000803e3d6000fd5b50506040518781528892503391507ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a3600086336001600160a01b03167f45c072aa05b9853b5a993de7a28bc332ee01404a628cec1a23ce0f659f842ef18560405161138291815260200190565b60405180910390a4505050505050565b6000546001600160a01b031633146113c55760405162461bcd60e51b81526004016113bc90613d46565b60405180910390fd5b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b15801561140f57600080fd5b505af1158015611423573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144791906139cd565b50505050565b60006002828154811061146257611462613ef8565b90600052602060002090600502019050426004541180611486575042816002015410155b8061149c575060045415801561149c5750600554155b156114a5575050565b60006114b342600554612ebb565b60048301546002840154919250906000906114ce9084613e84565b90506000600a548560010154600754846114e89190613e26565b6114f29190613e26565b6114fc9190613e04565b9050611510670de0b6b3a764000082613e04565b600660008282546115219190613e84565b9091555050821561154f576115368382613e04565b8560000160008282546115499190613dec565b90915550505b6002850184905584546040805186815260208101869052808201929092525160009188917fc75b283f14d0a806c63b93a3659ed39c43a20bf0fff8030465e93d79e91ca40f9181900360600190a3505050505050565b6000818152600360209081526040808320338452909152812080546002805492939192859081106115d8576115d8613ef8565b9060005260206000209060050201600301805490506001600160401b0381111561160457611604613f0e565b60405190808252806020026020018201604052801561162d578160200160208202803683370190505b50905060005b815181101561166c578282828151811061164f5761164f613ef8565b60209081029190910101528061166481613ec7565b915050611633565b50816002858154811061168157611681613ef8565b906000526020600020906005020160040160008282546116a19190613e84565b90915550506000600184018190558355600280546001600160a01b037f00000000000000000000000076be3b62873462d2142405439777e971754e8e771691632eb2c2d69130913391899081106116fa576116fa613ef8565b906000526020600020906005020160030185604051806020016040528060008152506040518663ffffffff1660e01b815260040161173c959493929190613c12565b600060405180830381600087803b15801561175657600080fd5b505af115801561176a573d6000803e3d6000fd5b50506040518481528692503391507fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae059590602001610ead565b8060005b81811015611447576117cf8484838181106117c3576117c3613ef8565b9050602002013561144d565b6117d881613ec7565b90506117a6565b6000546001600160a01b031633146118095760405162461bcd60e51b81526004016113bc90613d46565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611856576040519150601f19603f3d011682016040523d82523d6000602084013e61185b565b606091505b5050905080610c4c5760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016113bc565b6000546001600160a01b031633146118cd5760405162461bcd60e51b81526004016113bc90613d46565b426004541080156118df575060055442105b6119395760405162461bcd60e51b815260206004820152602560248201527f43616e206f6e6c79206164645072696d65416d6f756e7420647572696e672070604482015264195c9a5bd960da1b60648201526084016113bc565b611941612fe5565b80600660008282546119539190613dec565b9091555050600554611966904290613e84565b670de0b6b3a764000060065461197c9190613e26565b6119869190613e04565b6007556040518181526000907f4dffb45d6f962f8af66e8c830a9a6027cea8919fd29147db4be34dadb0fb5f1e906020015b60405180910390a250565b6000546001600160a01b031633146119ed5760405162461bcd60e51b81526004016113bc90613d46565b60405162461bcd60e51b815260206004820152601d60248201527f4f776e6572736869702063616e6e6f742062652072656e6f756e63656400000060448201526064016113bc565b611a3e82612248565b611a488282611071565b5050565b6000546001600160a01b03163314611a765760405162461bcd60e51b81526004016113bc90613d46565b4260045410611ad25760405162461bcd60e51b815260206004820152602260248201527f63616368696e6720706572696f6420686173206e6f7420737461727465642079604482015261195d60f21b60648201526084016113bc565b804210611b195760405162461bcd60e51b81526020600482015260156024820152740696e76616c696420656e642074696d657374616d7605c1b60448201526064016113bc565b611b21612fe5565b4260048190556005829055611b369082613e84565b670de0b6b3a7640000600654611b4c9190613e26565b611b569190613e04565b6007556040518181526000907f7e9fbea655506e5a9e67dca69341fadbddee58b360cc1e2f888d0b5576febb84906020016119b8565b6000546001600160a01b03163314611bb65760405162461bcd60e51b81526004016113bc90613d46565b600254811015611c1b5760405162461bcd60e51b815260206004820152602a60248201527f43616e277420736574206d61784e756d506f6f6c73206c657373207468616e206044820152690e0deded898cadccee8d60b31b60648201526084016113bc565b600955565b6000546001600160a01b03163314611c4a5760405162461bcd60e51b81526004016113bc90613d46565b6008544210611cae5760405162461bcd60e51b815260206004820152602a60248201527f5052494d452061646472657373207570646174652077696e646f7720686173206044820152691a185cc81c185cdcd95960b21b60648201526084016113bc565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b600b54600090610100900460ff1615611d215760405162461bcd60e51b81526020600482015260136024820152721bdb949958d95a5d99481a5cc81b1bd8dad959606a1b60448201526064016113bc565b5063bc197c8160e01b95945050505050565b6000546001600160a01b03163314611d5d5760405162461bcd60e51b81526004016113bc90613d46565b8051825114611d7e5760405162461bcd60e51b81526004016113bc90613cf5565b60008060005b8451811015611e0f576000858281518110611da157611da1613ef8565b602002602001015190506000858381518110611dbf57611dbf613ef8565b6020908102919091018101516000848152600d9092526040909120805491925090611dea9087613dec565b9550611df68286613dec565b9190559250819050611e0781613ec7565b915050611d84565b5081811115611e6757611e228282613e84565b341015611e675760405162461bcd60e51b8152602060048201526013602482015272139bdd08195b9bdd59da08195d1a081cd95b9d606a1b60448201526064016113bc565b7f512952600b6e98be68b7c8b5a19a1689a79f9abe676fa394588b94d2559896ea8484604051611e98929190613cb4565b60405180910390a150505050565b6000546001600160a01b03163314611ed05760405162461bcd60e51b81526004016113bc90613d46565b60095460025410611f1b5760405162461bcd60e51b815260206004820152601560248201527413585e081b9d5b481c1bdbdb1cc81c995858da1959605a1b60448201526064016113bc565b6000815111611f6c5760405162461bcd60e51b815260206004820152601860248201527f546f6b656e4964732063616e6e6f7420626520656d707479000000000000000060448201526064016113bc565b60008211611fcd5760405162461bcd60e51b815260206004820152602860248201527f416c6c6f636174696f6e20706f696e742063616e6e6f742062652030206f72206044820152676e6567617469766560c01b60648201526084016113bc565b60005b6002548110156120b257611fe38161144d565b81604051602001611ff49190613b8f565b604051602081830303815290604052805190602001206002828154811061201d5761201d613ef8565b906000526020600020906005020160030160405160200161203e9190613bc5565b6040516020818303038152906040528051906020012014156120a25760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c20776974682073616d6520746f6b656e49647320657869737473000060448201526064016113bc565b6120ab81613ec7565b9050611fd0565b5081600a60008282546120c59190613dec565b9250508190555060026040518060a00160405280600081526020018481526020016120f242600454613016565b815260208082018590526000604092830181905284546001818101875595825290829020845160059092020190815583820151948101949094559082015160028401556060820151805192939261214f92600385019201906135ad565b506080919091015160049091015560025461216c90600190613e84565b7f433d962a500f8c767748676218e15a2c52504785df1e3ea4a25d04926140609c8260405161219b9190613ca1565b60405180910390a26002546000906121b590600190613e84565b600a546040805186815260208101929092527fc12a6201c487829aaa17c8698145154b8fb8c84945e43430f08a08b385ffa8e391015b60405180910390a35050565b60005b81811015610c4c5761222383838381811061221757612217613ef8565b90506020020135612963565b61222c81613ec7565b90506121fa565b61223c81612963565b61224581612248565b50565b6002600c54141561229b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016113bc565b6002600c55600081815260036020908152604080832033808552908352818420825180840184528154815260019182015481860152868652600d8552838620600e865284872093875292909452919093208354918401549293929091116123445760405162461bcd60e51b815260206004820152601760248201527f416c726561647920636c61696d656420616c6c2065746800000000000000000060448201526064016113bc565b6001820154825460009161235791613e84565b600f54835491925060009161236c9042613e84565b61237e90670de0b6b3a7640000613e26565b6123889190613e04565b85516123949190613e26565b905060006123a28284612ebb565b9050808560010160008282546123b89190613dec565b9091555050428455801561245757604051600090339083908381818185875af1925050503d8060008114612408576040519150601f19603f3d011682016040523d82523d6000602084013e61240d565b606091505b50509050806124555760405162461bcd60e51b81526020600482015260146024820152732330b4b632b2103a379039b2b7321022ba3432b960611b60448201526064016113bc565b505b600187336001600160a01b03167f45c072aa05b9853b5a993de7a28bc332ee01404a628cec1a23ce0f659f842ef18460405161249591815260200190565b60405180910390a450506001600c555050505050565b6000546001600160a01b031633146124d55760405162461bcd60e51b81526004016113bc90613d46565b81831061253a5760405162461bcd60e51b815260206004820152602d60248201527f656e6454696d657374616d702063616e74206265206c657373207468616e207360448201526c07461727454696d657374616d7609c1b60648201526084016113bc565b60045442108061254b575042600554105b6125bd5760405162461bcd60e51b815260206004820152603860248201527f4f6e6c79207570646174657320616674657220656e6454696d657374616d702060448201527f6f72206265666f726520737461727454696d657374616d70000000000000000060648201526084016113bc565b60005b60025481101561260b576125d38161144d565b83600282815481106125e7576125e7613ef8565b600091825260209091206002600590920201015561260481613ec7565b90506125c0565b506006819055600483905560058290556126258383613e84565b612637670de0b6b3a764000083613e26565b6126419190613e04565b60075560408051828152602081018590529081018390526000907f72bb6e826d1a04bd8fa5fdde85546e3b9eb8e95d8500eec20f4c0124edcb422b9060600160405180910390a2505050565b60608382146126e95760405162461bcd60e51b815260206004820152602260248201527f7069647320616e6420616464726573736573206c656e677468206d69736d61746044820152610c6d60f31b60648201526084016113bc565b6000846001600160401b0381111561270357612703613f0e565b60405190808252806020026020018201604052801561272c578160200160208202803683370190505b50905060005b858110156127df576003600088888481811061275057612750613ef8565b905060200201358152602001908152602001600020600086868481811061277957612779613ef8565b905060200201602081019061278e9190613743565b6001600160a01b03166001600160a01b03168152602001908152602001600020600001548282815181106127c4576127c4613ef8565b60209081029190910101526127d881613ec7565b9050612732565b5095945050505050565b6000546001600160a01b031633146128135760405162461bcd60e51b81526004016113bc90613d46565b61281b612fe5565b806002838154811061282f5761282f613ef8565b906000526020600020906005020160010154600a5461284e9190613e84565b6128589190613dec565b600a81905550806002838154811061287257612872613ef8565b9060005260206000209060050201600101819055506000827fc12a6201c487829aaa17c8698145154b8fb8c84945e43430f08a08b385ffa8e383600a546040516121eb929190918252602082015260400190565b6000546001600160a01b031633146128f05760405162461bcd60e51b81526004016113bc90613d46565b600b805460ff191682151590811790915560405160ff909116151581527f066381685e9b988004d0190e3e15af3526943a03d13d8a917b38b77f45d0a4d89060200160405180910390a150565b6000828152600e602090815260408083203384529091529020428155610c4c8383613026565b61296c8161144d565b60008181526003602090815260408083203384529091528120600280549192916129a19190859081106110af576110af613ef8565b90506000670de0b6b3a76400006129c18460010154846110579190613e45565b6129cb9190613e04565b60018401839055905080156129f1576001546129f1906001600160a01b03163383612f93565b600084336001600160a01b03167f45c072aa05b9853b5a993de7a28bc332ee01404a628cec1a23ce0f659f842ef184604051612a2f91815260200190565b60405180910390a450505050565b6000546001600160a01b03163314612a675760405162461bcd60e51b81526004016113bc90613d46565b8051825114612a885760405162461bcd60e51b81526004016113bc90613cf5565b6000805b8351811015612b1e576000848281518110612aa957612aa9613ef8565b602002602001015190506000848381518110612ac757612ac7613ef8565b6020026020010151905080600d60008481526020019081526020016000206000016000828254612af79190613dec565b90915550612b0790508185613dec565b935050508080612b1690613ec7565b915050612a8c565b5080341015612b655760405162461bcd60e51b8152602060048201526013602482015272139bdd08195b9bdd59da08195d1a081cd95b9d606a1b60448201526064016113bc565b7f51b9b52ec210cd9a34deb653c9f15ceec56d47ef15357b06d7c2a422d178a8228383604051612b96929190613cb4565b60405180910390a1505050565b606060028281548110612bb857612bb8613ef8565b9060005260206000209060050201600301805480602002602001604051908101604052809291908181526020018280548015612c1357602002820191906000526020600020905b815481526020019060010190808311612bff575b50505050509050919050565b600b54600090610100900460ff1615612c705760405162461bcd60e51b81526020600482015260136024820152721bdb949958d95a5d99481a5cc81b1bd8dad959606a1b60448201526064016113bc565b5063f23a6e6160e01b95945050505050565b6000546001600160a01b03163314612cac5760405162461bcd60e51b81526004016113bc90613d46565b6001600160a01b038116612d115760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016113bc565b6122458161331a565b6000546001600160a01b03163314612d445760405162461bcd60e51b81526004016113bc90613d46565b42600454108015612d56575060055442105b612db55760405162461bcd60e51b815260206004820152602a60248201527f43616e206f6e6c792072656d6f76655072696d65416d6f756e7420647572696e60448201526919c818481c195c9a5bd960b21b60648201526084016113bc565b612dbd612fe5565b612dc981600654612ebb565b90508060066000828254612ddd9190613e84565b9091555050600554612df0904290613e84565b670de0b6b3a7640000600654612e069190613e26565b612e109190613e04565b6007556040518181526000907fb8f9e0ef8f651eda7570ff1a8ebe8a2acf07d57f7c18a9184d8e4395c2c82aa5906020016119b8565b612e4f82612248565b611a488282610c51565b6000546001600160a01b03163314612e835760405162461bcd60e51b81526004016113bc90613d46565b600f8190556040518181526001907f9767f99212eabcf230ccbba205c91de15b83afb35b16fb6adae11c8951c582df906020016119b8565b6000818310612eca5781612ecc565b825b9392505050565b60006001600160ff1b03821115612f3d5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016113bc565b5090565b600080821215612f3d5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f73697469766560448201526064016113bc565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610c4c90849061336a565b6000612ff060025490565b905060005b81811015611a48576130068161144d565b61300f81613ec7565b9050612ff5565b600081831015612eca5781612ecc565b600b5460ff161561306d5760405162461bcd60e51b815260206004820152601160248201527010d858da1a5b99c81a5cc81c185d5cd959607a1b60448201526064016113bc565b600081116130bd5760405162461bcd60e51b815260206004820152601d60248201527f537065636966792076616c696420616d6f756e7420746f20636163686500000060448201526064016113bc565b6130c68261144d565b6000828152600360209081526040808320338452909152812060028054919291859081106130f6576130f6613ef8565b9060005260206000209060050201600301805490506001600160401b0381111561312257613122613f0e565b60405190808252806020026020018201604052801561314b578160200160208202803683370190505b50905060005b815181101561318a578382828151811061316d5761316d613ef8565b60209081029190910101528061318281613ec7565b915050613151565b50826002858154811061319f5761319f613ef8565b906000526020600020906005020160040160008282546131bf9190613dec565b90915550508154839083906000906131d8908490613dec565b925050819055506131f560028581548110610d7057610d70613ef8565b8260010160008282546132089190613dab565b9091555050600b805461ff0019169055600280546001600160a01b037f00000000000000000000000076be3b62873462d2142405439777e971754e8e771691632eb2c2d691339130918990811061326157613261613ef8565b906000526020600020906005020160030185604051806020016040528060008152506040518663ffffffff1660e01b81526004016132a3959493929190613c12565b600060405180830381600087803b1580156132bd57600080fd5b505af11580156132d1573d6000803e3d6000fd5b5050600b805461ff0019166101001790555050604051849033907fa1e3bbbdbb1b06b4311536b4174ea3f26a13cacad3a75aaada060941a0c9ab1790610ead9087815260200190565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006133bf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661343c9092919063ffffffff16565b805190915015610c4c57808060200190518101906133dd91906139cd565b610c4c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016113bc565b606061344b8484600085613453565b949350505050565b6060824710156134b45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016113bc565b6001600160a01b0385163b61350b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016113bc565b600080866001600160a01b031685876040516135279190613bf6565b60006040518083038185875af1925050503d8060008114613564576040519150601f19603f3d011682016040523d82523d6000602084013e613569565b606091505b509150915061106682828660608315613583575081612ecc565b8251156135935782518084602001fd5b8160405162461bcd60e51b81526004016113bc9190613ce2565b8280548282559060005260206000209081019282156135e8579160200282015b828111156135e85782518255916020019190600101906135cd565b50612f3d9291505b80821115612f3d57600081556001016135f0565b60008083601f84011261361657600080fd5b5081356001600160401b0381111561362d57600080fd5b6020830191508360208260051b850101111561364857600080fd5b9250929050565b600082601f83011261366057600080fd5b813560206001600160401b0382111561367b5761367b613f0e565b8160051b61368a828201613d7b565b8381528281019086840183880185018910156136a557600080fd5b600093505b858410156136c85780358352600193909301929184019184016136aa565b50979650505050505050565b600082601f8301126136e557600080fd5b81356001600160401b038111156136fe576136fe613f0e565b613711601f8201601f1916602001613d7b565b81815284602083860101111561372657600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561375557600080fd5b8135612ecc81613f24565b6000806040838503121561377357600080fd5b823561377e81613f24565b946020939093013593505050565b600080600080600060a086880312156137a457600080fd5b85356137af81613f24565b945060208601356137bf81613f24565b935060408601356001600160401b03808211156137db57600080fd5b6137e789838a0161364f565b945060608801359150808211156137fd57600080fd5b61380989838a0161364f565b9350608088013591508082111561381f57600080fd5b5061382c888289016136d4565b9150509295509295909350565b600080600080600060a0868803121561385157600080fd5b853561385c81613f24565b9450602086013561386c81613f24565b9350604086013592506060860135915060808601356001600160401b0381111561389557600080fd5b61382c888289016136d4565b600080602083850312156138b457600080fd5b82356001600160401b038111156138ca57600080fd5b6138d685828601613604565b90969095509350505050565b600080600080604085870312156138f857600080fd5b84356001600160401b038082111561390f57600080fd5b61391b88838901613604565b9096509450602087013591508082111561393457600080fd5b5061394187828801613604565b95989497509550505050565b6000806040838503121561396057600080fd5b82356001600160401b038082111561397757600080fd5b6139838683870161364f565b9350602085013591508082111561399957600080fd5b506139a68582860161364f565b9150509250929050565b6000602082840312156139c257600080fd5b8135612ecc81613f39565b6000602082840312156139df57600080fd5b8151612ecc81613f39565b6000602082840312156139fc57600080fd5b81356001600160e01b031981168114612ecc57600080fd5b600080600060608486031215613a2957600080fd5b8335613a3481613f24565b92506020840135613a4481613f24565b929592945050506040919091013590565b600060208284031215613a6757600080fd5b5035919050565b60008060408385031215613a8157600080fd5b823591506020830135613a9381613f24565b809150509250929050565b60008060408385031215613ab157600080fd5b8235915060208301356001600160401b03811115613ace57600080fd5b6139a68582860161364f565b60008060408385031215613aed57600080fd5b50508035926020909101359150565b600080600060608486031215613b1157600080fd5b505081359360208301359350604090920135919050565b600081518084526020808501945080840160005b83811015613b5857815187529582019590820190600101613b3c565b509495945050505050565b60008151808452613b7b816020860160208601613e9b565b601f01601f19169290920160200192915050565b815160009082906020808601845b83811015613bb957815185529382019390820190600101613b9d565b50929695505050505050565b60008183548391508460005260208060002060005b83811015613bb957815485529382019360019182019101613bda565b60008251613c08818460208701613e9b565b9190910192915050565b6001600160a01b038681168252851660208083019190915260a060408301819052855490830181905260008681528281209092909160c085019190845b81811015613c6b57845484526001948501949383019301613c4f565b5050508381036060850152613c808187613b28565b9150508281036080840152613c958185613b63565b98975050505050505050565b602081526000612ecc6020830184613b28565b604081526000613cc76040830185613b28565b8281036020840152613cd98185613b28565b95945050505050565b602081526000612ecc6020830184613b63565b60208082526031908201527f746f6b656e2069647320616e64206574682072657761726473206c656e67746860408201527073206172656e2774207468652073616d6560781b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b604051601f8201601f191681016001600160401b0381118282101715613da357613da3613f0e565b604052919050565b600080821280156001600160ff1b0384900385131615613dcd57613dcd613ee2565b600160ff1b8390038412811615613de657613de6613ee2565b50500190565b60008219821115613dff57613dff613ee2565b500190565b600082613e2157634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615613e4057613e40613ee2565b500290565b60008083128015600160ff1b850184121615613e6357613e63613ee2565b6001600160ff1b0384018313811615613e7e57613e7e613ee2565b50500390565b600082821015613e9657613e96613ee2565b500390565b60005b83811015613eb6578181015183820152602001613e9e565b838111156114475750506000910152565b6000600019821415613edb57613edb613ee2565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461224557600080fd5b801515811461224557600080fdfea2646970667358221220e4c8e593b2252bc2ad44e6f4055e6d13933f2593ce9ed730387ebc9fb9f5026064736f6c63430008070033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.