ETH Price: $3,836.52 (+6.05%)

Contract

0x800E48366b3dc4D93114246D52B98Adb48aD83CB
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Age:24H
Amount:Between 0-1
Reset Filter

Transaction Hash
Method
Block
From
To

There are no matching entries

Update your filters to view other transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MerkleDistributor

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 12 : MerkleDistributor.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import { IERC20Mintable } from "./interfaces/IERC20Mintable.sol";
import { IILVPool } from "./interfaces/IILVPool.sol";
import { IFactory } from "./interfaces/IFactory.sol";

error AlreadyClaimed();
error AlreadyPaused();
error InvalidProof();
error IsPaused();
error NotFactoryController();
error ZeroAddress();
error ZeroBytes();

/**
 * @title MerkleDistributor
 *
 * @dev Contract used to rewards users with their missing ILV rewards.
 * @dev Serves as "virtual" pool with 0 weight to be registered via PoolFactory.registerPool()
 *      so that the users can claim their rewards via ILVPool.stakeAsPool().
 * @dev This contract can be paused by the owner, for example when staking program finishes.
 */
contract MerkleDistributor {
    // This is a packed array of booleans for the Merkle Tree
    mapping(uint256 => uint256) private _claimedBitMap;

    // Address of the factory contract, used to check if the caller is the owner
    IFactory private immutable _factory;

    // Address of the ILV pool contract, used to call stakeAsPool()
    IILVPool public immutable ilvPool;

    // Whether the contract is paused so that new claims are not allowed
    bool public isPaused;

    // Merkle root used for the distribution
    bytes32 public merkleRoot;

    // below fields make this contract compatible with ILVPool.stakeAsPool()
    address public immutable poolToken; // ILV token address
    bool public constant isFlashPool = false;
    uint32 public constant weight = 0; // needs to be 0 so pool weights are not altered when registering

    // Claimed is emitted whenever a call to claim() succeeds
    event Claimed(uint256 index, address indexed account, uint256 amount);

    // SetMerkleRoot is emitted whenever the merkle root is set
    event SetMerkleRoot(address by, bytes32 merkleRoot);

    // Paused/Unpaused are emitted whenever the contract is paused/unpaused
    event Paused(address by);
    event Unpaused(address by);

    /**
     * @dev modifier to check if the caller is the factory controller
     */
    modifier isFactoryController() {
        if (msg.sender != _factory.owner()) revert NotFactoryController();
        _;
    }

    /**
     * @dev validate and set required parameters
     * @param factory_ factory address used for access control, must be non-zero
     * @param ilv_ ILV address used as poolToken, must be non-zero
     * @param ilvPool_ ILV pool address used to call stakeAsPool(), must be non-zero
     * @param merkleRoot_ merkle root, must be non-zero
     */
    constructor(IFactory factory_, address ilv_, IILVPool ilvPool_, bytes32 merkleRoot_) {
        if (address(factory_) == address(0)) revert ZeroAddress();
        if (ilv_ == address(0)) revert ZeroAddress();
        if (address(ilvPool_) == address(0)) revert ZeroAddress();
        if (merkleRoot_ == bytes32(0)) revert ZeroBytes();
        _factory = factory_;
        poolToken = ilv_;
        ilvPool = ilvPool_;
        merkleRoot = merkleRoot_;
        emit SetMerkleRoot(msg.sender, merkleRoot_);
    }

    /**
     * @dev checks whether an index have been already claimed
     * @param index index to be checked
     * @return boolean claim status
     */
    function isClaimed(uint256 index) public view returns (bool) {
        uint256 claimedWordIndex = index / 256;
        uint256 claimedBitIndex = index % 256;
        uint256 claimedWord = _claimedBitMap[claimedWordIndex];
        uint256 mask = (1 << claimedBitIndex);
        return claimedWord & mask == mask;
    }

    /**
     * @dev mark the index as claimed in a gas-efficient way
     * @param index index to be marked
     */
    function _setClaimed(uint256 index) private {
        uint256 claimedWordIndex = index / 256;
        uint256 claimedBitIndex = index % 256;
        _claimedBitMap[claimedWordIndex] = _claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);
    }

    /**
     * @dev Set paused/unpaused state in the contract
     * @notice Can only be called by the owner
     * @param shouldPause whether the contract should be paused/unpausd
     */
    function pause(bool shouldPause) external isFactoryController {
        if ((isPaused && shouldPause) || (!isPaused && !shouldPause)) revert AlreadyPaused();
        if (shouldPause) {
            isPaused = true;
            emit Paused(msg.sender);
        } else {
            isPaused = false;
            emit Unpaused(msg.sender);
        }
    }

    /**
     * @dev Sets the yield weight tree root
     * @notice Can only be called by the owner
     * @param merkleRoot_ 32 bytes tree root, must be non-zero
     */
    function setMerkleRoot(bytes32 merkleRoot_) external isFactoryController {
        if (merkleRoot_ == bytes32(0)) revert ZeroBytes();
        merkleRoot = merkleRoot_;
        emit SetMerkleRoot(msg.sender, merkleRoot_);
    }

    /**
     * @dev verifies the parameters and stakes the ILV if not yet claimed
     * @param index index used for claiming
     * @param amount amount of tokens to be claimed and staked
     * @param proof bytes32 array with the merkle proof generated off-chain
     */
    function claim(uint256 index, uint256 amount, bytes32[] calldata proof) external virtual {
        // Revert if the contract is paused
        if (isPaused) revert IsPaused();
        // Revert if already claimed
        if (isClaimed(index)) revert AlreadyClaimed();

        // Verify the merkle proof
        bytes32 node = keccak256(abi.encodePacked(index, msg.sender, amount));
        if (!MerkleProof.verify(proof, merkleRoot, node)) revert InvalidProof();

        // Mark it claimed and stake claimed ILV
        _setClaimed(index);
        ilvPool.stakeAsPool(msg.sender, amount);

        emit Claimed(index, msg.sender, amount);
    }
}

File 2 of 12 : IERC20Mintable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

interface IERC20Mintable is IERC20Upgradeable {
    function mint(address _to, uint256 _value) external;
}

File 3 of 12 : IILVPool.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

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

interface IILVPool is ICorePool {
    function stakeAsPool(address _staker, uint256 _value) external;
}

File 4 of 12 : IFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

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

interface IFactory {
    function owner() external view returns (address);

    function ilvPerSecond() external view returns (uint192);

    function totalWeight() external view returns (uint32);

    function secondsPerUpdate() external view returns (uint32);

    function endTime() external view returns (uint32);

    function lastRatioUpdate() external view returns (uint32);

    function pools(address _poolToken) external view returns (ICorePool);

    function poolExists(address _poolAddress) external view returns (bool);

    function getPoolAddress(address poolToken) external view returns (address);

    function getPoolData(address _poolToken)
        external
        view
        returns (
            address,
            address,
            uint32,
            bool
        );

    function shouldUpdateRatio() external view returns (bool);

    function registerPool(ICorePool pool) external;

    function updateILVPerSecond() external;

    function mintYieldTo(
        address _to,
        uint256 _value,
        bool _useSILV
    ) external;

    function changePoolWeight(address pool, uint32 weight) external;
}

File 5 of 12 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 6 of 12 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The proofs can be generated using the JavaScript library
 * https://github.com/miguelmota/merkletreejs[merkletreejs].
 * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
 *
 * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

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

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

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

    /**
     * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * _Available since v4.7._
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * _Available since v4.7._
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,
     * consuming from one or the other at each step according to the instructions given by
     * `proofFlags`.
     *
     * _Available since v4.7._
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

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

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}
     *
     * _Available since v4.7._
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

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

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 7 of 12 : IERC20Upgradeable.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 IERC20Upgradeable {
    /**
     * @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 8 of 12 : ICorePool.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

import { Stake } from "../libraries/Stake.sol";

interface ICorePool {
    function users(address _user)
        external
        view
        returns (
            uint128,
            uint128,
            uint128,
            uint248,
            uint8,
            uint256,
            uint256
        );

    function poolToken() external view returns (address);

    function isFlashPool() external view returns (bool);

    function weight() external view returns (uint32);

    function lastYieldDistribution() external view returns (uint64);

    function yieldRewardsPerWeight() external view returns (uint256);

    function globalWeight() external view returns (uint256);

    function pendingRewards(address _user) external view returns (uint256, uint256);

    function poolTokenReserve() external view returns (uint256);

    function balanceOf(address _user) external view returns (uint256);

    function getTotalReserves() external view returns (uint256);

    function getStake(address _user, uint256 _stakeId) external view returns (Stake.Data memory);

    function getStakesLength(address _user) external view returns (uint256);

    function sync() external;

    function setWeight(uint32 _weight) external;

    function receiveVaultRewards(uint256 value) external;
}

File 9 of 12 : Stake.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;

/**
 * @dev Stake library used by ILV pool and Sushi LP Pool.
 *
 * @dev Responsible to manage weight calculation and store important constants
 *      related to stake period, base weight and multipliers utilized.
 */
library Stake {
    struct Data {
        /// @dev token amount staked
        uint120 value;
        /// @dev locking period - from
        uint64 lockedFrom;
        /// @dev locking period - until
        uint64 lockedUntil;
        /// @dev indicates if the stake was created as a yield reward
        bool isYield;
    }

    /**
     * @dev Stake weight is proportional to stake value and time locked, precisely
     *      "stake value wei multiplied by (fraction of the year locked plus one)".
     * @dev To avoid significant precision loss due to multiplication by "fraction of the year" [0, 1],
     *      weight is stored multiplied by 1e6 constant, as an integer.
     * @dev Corner case 1: if time locked is zero, weight is stake value multiplied by 1e6 + base weight
     * @dev Corner case 2: if time locked is two years, division of
            (lockedUntil - lockedFrom) / MAX_STAKE_PERIOD is 1e6, and
     *      weight is a stake value multiplied by 2 * 1e6.
     */
    uint256 internal constant WEIGHT_MULTIPLIER = 1e6;

    /**
     * @dev Minimum weight value, if result of multiplication using WEIGHT_MULTIPLIER
     *      is 0 (e.g stake flexible), then BASE_WEIGHT is used.
     */
    uint256 internal constant BASE_WEIGHT = 1e6;
    /**
     * @dev Minimum period that someone can lock a stake for.
     */
    uint256 internal constant MIN_STAKE_PERIOD = 30 days;

    /**
     * @dev Maximum period that someone can lock a stake for.
     */
    uint256 internal constant MAX_STAKE_PERIOD = 365 days;

    /**
     * @dev Rewards per weight are stored multiplied by 1e20 as uint.
     */
    uint256 internal constant REWARD_PER_WEIGHT_MULTIPLIER = 1e20;

    /**
     * @dev When we know beforehand that staking is done for yield instead of
     *      executing `weight()` function we use the following constant.
     */
    uint256 internal constant YIELD_STAKE_WEIGHT_MULTIPLIER = 2 * 1e6;

    function weight(Data storage _self) internal view returns (uint256) {
        return
            uint256(
                (((_self.lockedUntil - _self.lockedFrom) * WEIGHT_MULTIPLIER) / MAX_STAKE_PERIOD + BASE_WEIGHT) *
                    _self.value
            );
    }

    /**
     * @dev Converts stake weight (not to be mixed with the pool weight) to
     *      ILV reward value, applying the 10^12 division on weight
     *
     * @param _weight stake weight
     * @param _rewardPerWeight ILV reward per weight
     * @param _rewardPerWeightPaid last reward per weight value used for user earnings
     * @return reward value normalized to 10^12
     */
    function earned(
        uint256 _weight,
        uint256 _rewardPerWeight,
        uint256 _rewardPerWeightPaid
    ) internal pure returns (uint256) {
        // apply the formula and return
        return (_weight * (_rewardPerWeight - _rewardPerWeightPaid)) / REWARD_PER_WEIGHT_MULTIPLIER;
    }

    /**
     * @dev Converts reward ILV value to stake weight (not to be mixed with the pool weight),
     *      applying the 10^12 multiplication on the reward.
     *      - OR -
     * @dev Converts reward ILV value to reward/weight if stake weight is supplied as second
     *      function parameter instead of reward/weight.
     *
     * @param _reward yield reward
     * @param _globalWeight total weight in the pool
     * @return reward per weight value
     */
    function getRewardPerWeight(uint256 _reward, uint256 _globalWeight) internal pure returns (uint256) {
        // apply the reverse formula and return
        return (_reward * REWARD_PER_WEIGHT_MULTIPLIER) / _globalWeight;
    }
}

File 10 of 12 : 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 11 of 12 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IFactory","name":"factory_","type":"address"},{"internalType":"address","name":"ilv_","type":"address"},{"internalType":"contract IILVPool","name":"ilvPool_","type":"address"},{"internalType":"bytes32","name":"merkleRoot_","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"AlreadyPaused","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"IsPaused","type":"error"},{"inputs":[],"name":"NotFactoryController","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroBytes","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"by","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"SetMerkleRoot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"by","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ilvPool","outputs":[{"internalType":"contract IILVPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFlashPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"shouldPause","type":"bool"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot_","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weight","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}]

60e060405234801561001057600080fd5b50604051610a63380380610a6383398101604081905261002f9161012b565b6001600160a01b0384166100565760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03831661007d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382166100a45760405163d92e233d60e01b815260040160405180910390fd5b806100c2576040516325898e1760e11b815260040160405180910390fd5b6001600160601b0319606085811b821660805284811b821660c05283901b1660a052600281905560408051338152602081018390527f8c20d275fe64865598ebdb3edb3a618f781cd951ac8ec5b911ddd5c72a4fb8b0910160405180910390a150505050610195565b60008060008060808587031215610140578384fd5b845161014b8161017d565b602086015190945061015c8161017d565b604086015190935061016d8161017d565b6060959095015193969295505050565b6001600160a01b038116811461019257600080fd5b50565b60805160601c60a05160601c60c05160601c6108886101db600039600061019301526000818161015401526105b20152600081816101b7015261034001526108886000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063a1aab33f11610066578063a1aab33f14610112578063ae0b51df1461012f578063b187bd2614610142578063c4131f5e1461014f578063cbdf382c1461018e57600080fd5b806302329a29146100a35780631da10d91146100b85780632eb4a7ab146100d55780637cb64759146100ec5780639e34070f146100ff575b600080fd5b6100b66100b1366004610760565b6101b5565b005b6100c0600081565b60405190151581526020015b60405180910390f35b6100de60025481565b6040519081526020016100cc565b6100b66100fa366004610780565b61033e565b6100c061010d366004610780565b610459565b61011a600081565b60405163ffffffff90911681526020016100cc565b6100b661013d366004610798565b61049a565b6001546100c09060ff1681565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100cc565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561020e57600080fd5b505afa158015610222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102469190610739565b6001600160a01b0316336001600160a01b031614610277576040516310b400d760e31b815260040160405180910390fd5b60015460ff1680156102865750805b8061029d575060015460ff1615801561029d575080155b156102bb57604051631785c68160e01b815260040160405180910390fd5b8015610304576001805460ff1916811790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020015b60405180910390a150565b6001805460ff191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020016102f9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561039757600080fd5b505afa1580156103ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cf9190610739565b6001600160a01b0316336001600160a01b031614610400576040516310b400d760e31b815260040160405180910390fd5b8061041e576040516325898e1760e11b815260040160405180910390fd5b600281905560408051338152602081018390527f8c20d275fe64865598ebdb3edb3a618f781cd951ac8ec5b911ddd5c72a4fb8b091016102f9565b60008061046861010084610816565b9050600061047861010085610851565b60009283526020839052604090922054600190921b9182169091149392505050565b60015460ff16156104be57604051631309a56360e01b815260040160405180910390fd5b6104c784610459565b156104e557604051630c8d9eab60e31b815260040160405180910390fd5b60408051602081018690526bffffffffffffffffffffffff193360601b169181019190915260548101849052600090607401604051602081830303815290604052805190602001209050610570838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506002549150849050610658565b61058d576040516309bde33960e01b815260040160405180910390fd5b6105968561066e565b6040516344cc892d60e01b8152336004820152602481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906344cc892d90604401600060405180830381600087803b1580156105fe57600080fd5b505af1158015610612573d6000803e3d6000fd5b505060408051888152602081018890523393507f4ec90e965519d92681267467f775ada5bd214aa92c0dc93d90a5e880ce9ed02692500160405180910390a25050505050565b60008261066585846106ac565b14949350505050565b600061067c61010083610816565b9050600061068c61010084610851565b6000928352602083905260409092208054600190931b9092179091555050565b600081815b84518110156106ff576106eb828683815181106106de57634e487b7160e01b600052603260045260246000fd5b6020026020010151610707565b9150806106f78161082a565b9150506106b1565b509392505050565b6000818310610723576000828152602084905260409020610732565b60008381526020839052604090205b9392505050565b60006020828403121561074a578081fd5b81516001600160a01b0381168114610732578182fd5b600060208284031215610771578081fd5b81358015158114610732578182fd5b600060208284031215610791578081fd5b5035919050565b600080600080606085870312156107ad578283fd5b8435935060208501359250604085013567ffffffffffffffff808211156107d2578384fd5b818701915087601f8301126107e5578384fd5b8135818111156107f3578485fd5b8860208260051b8501011115610807578485fd5b95989497505060200194505050565b60008261082557610825610865565b500490565b600060001982141561084a57634e487b7160e01b81526011600452602481fd5b5060010190565b60008261086057610860610865565b500690565b634e487b7160e01b600052601260045260246000fdfea164736f6c6343000804000a0000000000000000000000009dca38d109c6c69790fb70bcfdeaf27c4394597c0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291d0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291dd340b175529489304ea0ea0635356c5bbb59df9847ae1cfec156e3b52fe4e404

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061009e5760003560e01c8063a1aab33f11610066578063a1aab33f14610112578063ae0b51df1461012f578063b187bd2614610142578063c4131f5e1461014f578063cbdf382c1461018e57600080fd5b806302329a29146100a35780631da10d91146100b85780632eb4a7ab146100d55780637cb64759146100ec5780639e34070f146100ff575b600080fd5b6100b66100b1366004610760565b6101b5565b005b6100c0600081565b60405190151581526020015b60405180910390f35b6100de60025481565b6040519081526020016100cc565b6100b66100fa366004610780565b61033e565b6100c061010d366004610780565b610459565b61011a600081565b60405163ffffffff90911681526020016100cc565b6100b661013d366004610798565b61049a565b6001546100c09060ff1681565b6101767f0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291d81565b6040516001600160a01b0390911681526020016100cc565b6101767f0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291d81565b7f0000000000000000000000009dca38d109c6c69790fb70bcfdeaf27c4394597c6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561020e57600080fd5b505afa158015610222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102469190610739565b6001600160a01b0316336001600160a01b031614610277576040516310b400d760e31b815260040160405180910390fd5b60015460ff1680156102865750805b8061029d575060015460ff1615801561029d575080155b156102bb57604051631785c68160e01b815260040160405180910390fd5b8015610304576001805460ff1916811790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020015b60405180910390a150565b6001805460ff191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020016102f9565b7f0000000000000000000000009dca38d109c6c69790fb70bcfdeaf27c4394597c6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561039757600080fd5b505afa1580156103ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cf9190610739565b6001600160a01b0316336001600160a01b031614610400576040516310b400d760e31b815260040160405180910390fd5b8061041e576040516325898e1760e11b815260040160405180910390fd5b600281905560408051338152602081018390527f8c20d275fe64865598ebdb3edb3a618f781cd951ac8ec5b911ddd5c72a4fb8b091016102f9565b60008061046861010084610816565b9050600061047861010085610851565b60009283526020839052604090922054600190921b9182169091149392505050565b60015460ff16156104be57604051631309a56360e01b815260040160405180910390fd5b6104c784610459565b156104e557604051630c8d9eab60e31b815260040160405180910390fd5b60408051602081018690526bffffffffffffffffffffffff193360601b169181019190915260548101849052600090607401604051602081830303815290604052805190602001209050610570838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506002549150849050610658565b61058d576040516309bde33960e01b815260040160405180910390fd5b6105968561066e565b6040516344cc892d60e01b8152336004820152602481018590527f0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291d6001600160a01b0316906344cc892d90604401600060405180830381600087803b1580156105fe57600080fd5b505af1158015610612573d6000803e3d6000fd5b505060408051888152602081018890523393507f4ec90e965519d92681267467f775ada5bd214aa92c0dc93d90a5e880ce9ed02692500160405180910390a25050505050565b60008261066585846106ac565b14949350505050565b600061067c61010083610816565b9050600061068c61010084610851565b6000928352602083905260409092208054600190931b9092179091555050565b600081815b84518110156106ff576106eb828683815181106106de57634e487b7160e01b600052603260045260246000fd5b6020026020010151610707565b9150806106f78161082a565b9150506106b1565b509392505050565b6000818310610723576000828152602084905260409020610732565b60008381526020839052604090205b9392505050565b60006020828403121561074a578081fd5b81516001600160a01b0381168114610732578182fd5b600060208284031215610771578081fd5b81358015158114610732578182fd5b600060208284031215610791578081fd5b5035919050565b600080600080606085870312156107ad578283fd5b8435935060208501359250604085013567ffffffffffffffff808211156107d2578384fd5b818701915087601f8301126107e5578384fd5b8135818111156107f3578485fd5b8860208260051b8501011115610807578485fd5b95989497505060200194505050565b60008261082557610825610865565b500490565b600060001982141561084a57634e487b7160e01b81526011600452602481fd5b5060010190565b60008261086057610860610865565b500690565b634e487b7160e01b600052601260045260246000fdfea164736f6c6343000804000a

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

0000000000000000000000009dca38d109c6c69790fb70bcfdeaf27c4394597c0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291d0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291dd340b175529489304ea0ea0635356c5bbb59df9847ae1cfec156e3b52fe4e404

-----Decoded View---------------
Arg [0] : factory_ (address): 0x9DcA38D109c6c69790Fb70BCfDEAF27C4394597c
Arg [1] : ilv_ (address): 0x7f5f854FfB6b7701540a00C69c4AB2De2B34291D
Arg [2] : ilvPool_ (address): 0x7f5f854FfB6b7701540a00C69c4AB2De2B34291D
Arg [3] : merkleRoot_ (bytes32): 0xd340b175529489304ea0ea0635356c5bbb59df9847ae1cfec156e3b52fe4e404

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000009dca38d109c6c69790fb70bcfdeaf27c4394597c
Arg [1] : 0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291d
Arg [2] : 0000000000000000000000007f5f854ffb6b7701540a00c69c4ab2de2b34291d
Arg [3] : d340b175529489304ea0ea0635356c5bbb59df9847ae1cfec156e3b52fe4e404


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

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.