BNB Price: $616.27 (+2.75%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Harvest Pool593051372025-08-29 14:19:42227 days ago1756477182IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool557445062025-07-29 16:26:10258 days ago1753806370IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool544028512025-07-18 0:53:43270 days ago1752800023IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool536035372025-07-11 2:21:27277 days ago1752200487IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool521923472025-06-27 14:00:40290 days ago1751032840IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool521078132025-06-26 2:47:18292 days ago1750906038IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool520746822025-06-25 12:59:01293 days ago1750856341IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool518697912025-06-21 23:36:35296 days ago1750548995IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool518435922025-06-21 12:41:37297 days ago1750509697IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool518192992025-06-21 2:34:16297 days ago1750473256IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517873142025-06-20 13:14:38297 days ago1750425278IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517830172025-06-20 11:27:12298 days ago1750418832IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517650992025-06-20 3:56:57298 days ago1750391817IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517335912025-06-19 14:49:14298 days ago1750344554IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517335352025-06-19 14:47:50298 days ago1750344470IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517126632025-06-19 6:05:58299 days ago1750313158IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517046162025-06-19 2:44:47299 days ago1750301087IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool517044462025-06-19 2:40:32299 days ago1750300832IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool516995982025-06-19 0:39:19299 days ago1750293559IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool516797302025-06-18 16:22:37299 days ago1750263757IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool516791902025-06-18 16:09:07299 days ago1750262947IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool516770062025-06-18 15:14:31299 days ago1750259671IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool516764622025-06-18 15:00:53299 days ago1750258853IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool516764462025-06-18 15:00:29299 days ago1750258829IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
Harvest Pool516762852025-06-18 14:56:27299 days ago1750258587IN
0xae8476D2...4e7A4F800
0 BNB0.000009790.11
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
593051372025-08-29 14:19:42227 days ago1756477182
0xae8476D2...4e7A4F800
2.98824515 BNB
557445062025-07-29 16:26:10258 days ago1753806370
0xae8476D2...4e7A4F800
2.98824515 BNB
544028512025-07-18 0:53:43270 days ago1752800023
0xae8476D2...4e7A4F800
2.98824515 BNB
536035372025-07-11 2:21:27277 days ago1752200487
0xae8476D2...4e7A4F800
2.98824515 BNB
521923472025-06-27 14:00:40290 days ago1751032840
0xae8476D2...4e7A4F800
1.45055118 BNB
521078132025-06-26 2:47:18292 days ago1750906038
0xae8476D2...4e7A4F800
2.98824515 BNB
520746822025-06-25 12:59:01293 days ago1750856341
0xae8476D2...4e7A4F800
2.98824515 BNB
518697912025-06-21 23:36:35296 days ago1750548995
0xae8476D2...4e7A4F800
0.00137719 BNB
518435922025-06-21 12:41:37297 days ago1750509697
0xae8476D2...4e7A4F800
2.98824515 BNB
518192992025-06-21 2:34:16297 days ago1750473256
0xae8476D2...4e7A4F800
2.98824515 BNB
517873142025-06-20 13:14:38297 days ago1750425278
0xae8476D2...4e7A4F800
2.98824515 BNB
517830172025-06-20 11:27:12298 days ago1750418832
0xae8476D2...4e7A4F800
2.98824515 BNB
517650992025-06-20 3:56:57298 days ago1750391817
0xae8476D2...4e7A4F800
2.98724143 BNB
517335912025-06-19 14:49:14298 days ago1750344554
0xae8476D2...4e7A4F800
0.01052719 BNB
517335352025-06-19 14:47:50298 days ago1750344470
0xae8476D2...4e7A4F800
2.98824515 BNB
517126632025-06-19 6:05:58299 days ago1750313158
0xae8476D2...4e7A4F800
2.98824515 BNB
517046162025-06-19 2:44:47299 days ago1750301087
0xae8476D2...4e7A4F800
2.98824515 BNB
517044462025-06-19 2:40:32299 days ago1750300832
0xae8476D2...4e7A4F800
2.97848853 BNB
516995982025-06-19 0:39:19299 days ago1750293559
0xae8476D2...4e7A4F800
2.98824515 BNB
516797302025-06-18 16:22:37299 days ago1750263757
0xae8476D2...4e7A4F800
2.98824515 BNB
516791902025-06-18 16:09:07299 days ago1750262947
0xae8476D2...4e7A4F800
2.98824515 BNB
516770062025-06-18 15:14:31299 days ago1750259671
0xae8476D2...4e7A4F800
2.98824515 BNB
516764622025-06-18 15:00:53299 days ago1750258853
0xae8476D2...4e7A4F800
2.98824515 BNB
516764462025-06-18 15:00:29299 days ago1750258829
0xae8476D2...4e7A4F800
2.98824515 BNB
516762852025-06-18 14:56:27299 days ago1750258587
0xae8476D2...4e7A4F800
2.98824515 BNB
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

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

Contract Name:
IDOInitializableV3

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin-4.5.0/contracts/access/Ownable.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {SafeCastLib} from "solmate/src/utils/SafeCastLib.sol";
import {ECDSA} from "@openzeppelin-4.5.0/contracts/utils/cryptography/ECDSA.sol";
import {ReentrancyGuardTransient} from "../base/ReentrancyGuardTransient.sol";

/**
 * @title IDOInitializableV3
 * @notice IDOv3 supports 1 or 2 pools -- each pool can raise in their own lpToken (eg. BNB or CAKE)
 */
contract IDOInitializableV3 is Ownable, ReentrancyGuardTransient {
    using SafeTransferLib for ERC20;
    using SafeTransferLib for address;
    using SafeCastLib for uint256;

    // Whether it is initialized
    bool private isInitialized;

    // all the addresses
    // [0] lpToken0 [1] lpToken1 [2] offeringToken [3] adminAddress
    address[4] public addresses;

    // The timestamp when IDO starts
    uint256 public startTimestamp;

    // The timestamp when IDO ends
    uint256 public endTimestamp;

    // Max buffer seconds (for sanity checks)
    uint256 public MAX_BUFFER_SECONDS;

    // Max pool id (0 if only 1 pool, 1 if theres 2 pools)
    uint8 public MAX_POOL_ID;

    // Minimum amount for each user to deposit into the pool
    uint256[2] public MIN_DEPOSIT_AMOUNTS;

    // Total tokens distributed across the pools
    uint256 public totalTokensOffered;

    // Struct that contains pool's information
    struct PoolInformation {
        uint128 raisingAmountPool; // amount of tokens raised for the pool (in LP tokens)
        uint128 offeringAmountPool; // amount of tokens offered for the pool (in offeringTokens)
        uint128 capPerUserInLP; // cap of tokens per user (if 0, it is ignored)
        uint128 totalAmountPool; // total amount pool deposited (in LP tokens)
    }

    // Array of PoolInformation of size NUMBER_POOLS
    PoolInformation[2] public _poolInformation;

    // Struct that contains each user information for both pools
    struct UserInfo {
        uint128 amountPool; // How many tokens the user has provided for pool
        bool claimedPool; // Whether the user has claimed (default: false) for pool
    }

    // It maps the address to pool id to UserInfo
    mapping(address => mapping(uint8 => UserInfo)) private _userInfo;

    // An address for the signer of the signature
    address public signerAddress;

    // Admin withdraw events
    event AdminWithdraw(uint256 amountLP0, uint256 amountLP1, uint256 amountOfferingToken);

    // Admin recovers token
    event AdminTokenRecovery(address tokenAddress, uint256 amountTokens);

    // Deposit event
    event Deposit(address indexed user, uint256 amount, uint8 indexed pid);

    // Harvest event
    event Harvest(address indexed user, uint256 offeringAmount, uint256 excessAmount, uint8 indexed pid);

    // Event for new start & end timestamps
    event NewStartAndEndTimestamps(uint256 startTimestamp, uint256 endTimestamp);

    // Event when parameters are set for one of the pools
    event PoolParametersSet(uint256 offeringAmountPool, uint256 raisingAmountPool, uint8 indexed pid);

    // Event when MIN_DEPOSIT_AMOUNT is updated
    event UpdatedMinDepositAmount(uint256 minAmount, uint8 indexed pid);

    // Event when signer address update
    event UpdatedSignerAddress(address indexed signerAddr);

    error MaxPoolIdNotValid();
    error PoolIdNotValid();
    error SignatureVerifyFailed();
    error SignerAddressZero();
    error EndTimeTooFar();
    error StartTimeMustInferiorToEndTime();
    error AlreadyInitialized();
    error AddressesLengthNotCorrect();
    error StartAndEndTimestampsLengthNotCorrect();
    error TokensNotDepositedProperly();
    error NewAmountAboveUserCap();
    error CanNotBeLPToken();
    error CanNotBeOfferingToken();
    error PoolNotSet();
    error TooEarly();
    error TooLate();
    error AmountMustBeZero();
    error AmountMustExceedZero();
    error AmountMustExceedMinimum();
    error DidNotParticipate();
    error AlreadyHarvested();
    error NotEnoughLPTokens();
    error NotEnoughOfferingTokens();
    error IDOHasStarted();

    /**
     * @notice Constructor
     */
    constructor() {
        MIN_DEPOSIT_AMOUNTS[0] = 1000000;
        MIN_DEPOSIT_AMOUNTS[1] = 1000000;
    }

    /**
     * @notice It initializes the contract
     * @dev It can only be called once.
     * @dev no caller check as this method is called immediately after contract is created
     * @param _addresses: [0] lpToken0 [1] lpToken1 [2] offeringToken [3] adminAddress
     * @param _startAndEndTimestamps: [0] startTimestamp [1] endTimestamp
     * @param _maxBufferSeconds: maximum buffer of blocks from the current block number
     * @param _maxPoolId: maximum id of pools, if it is 0 means 1 pool, and 1 means 2 pools
     */
    function initialize(
        address[] calldata _addresses,
        uint256[] calldata _startAndEndTimestamps,
        uint256 _maxBufferSeconds,
        uint8 _maxPoolId
    ) public {
        if (isInitialized) {
            revert AlreadyInitialized();
        }

        if (_addresses.length != 4) {
            revert AddressesLengthNotCorrect();
        }

        if (_startAndEndTimestamps.length != 2) {
            revert StartAndEndTimestampsLengthNotCorrect();
        }

        // Make this contract initialized
        isInitialized = true;

        // [0] lpToken0
        // [1] lpToken1
        // [2] offeringToken
        // [3] adminAddress
        for (uint8 i = 0; i < _addresses.length; i++) {
            addresses[i] = _addresses[i];
        }

        startTimestamp = _startAndEndTimestamps[0];
        endTimestamp = _startAndEndTimestamps[1];

        MAX_BUFFER_SECONDS = _maxBufferSeconds;

        if (_maxPoolId <= 1) {
            MAX_POOL_ID = _maxPoolId;
        } else {
            revert MaxPoolIdNotValid();
        }

        // Transfer ownership to admin
        transferOwnership(_addresses[3]);
    }

    /**
     * @notice It allows users to deposit LP tokens to pool
     * @dev if the LP address is Zero, means user should deposit Native token instead of ERC20
     * @param _amount: the number of LP token used (18 decimals) - if address[0] == address(0), IDO is raising in native token, thus this parameter will not be used
     * @param _pid: pool id
     * @param _expiredAt: the expire timestamp at
     * @param _signature: the signature string to verify it is from msg.sender
     */
    function depositPool(uint256 _amount, uint8 _pid, uint256 _expiredAt, bytes memory _signature)
        external
        payable
        nonReentrant
    {
        _checkPid(_pid);

        // Checks signature is correct
        // we don't use chainId so can be replayed on multiple chains if the address is the same,
        // but that is quite unlikely since the salt should be different for different ido sale tokens
        bytes32 msgHash = keccak256(abi.encode(address(this), "VerifyAddress", msg.sender, _expiredAt));
        address addr = ECDSA.recover(ECDSA.toEthSignedMessageHash(msgHash), _signature);
        if (block.timestamp > _expiredAt || addr != signerAddress) {
            revert SignatureVerifyFailed();
        }

        // Checks that pool was set
        if (_poolInformation[_pid].offeringAmountPool == 0 || _poolInformation[_pid].raisingAmountPool == 0) {
            revert PoolNotSet();
        }

        // Checks whether the timestamp is not too early
        if (block.timestamp < startTimestamp) {
            revert TooEarly();
        }

        // Checks whether the timestamp is not too late
        if (block.timestamp > endTimestamp) {
            revert TooLate();
        }

        // Verify tokens were deposited properly
        if (ERC20(addresses[2]).balanceOf(address(this)) < totalTokensOffered) {
            revert TokensNotDepositedProperly();
        }

        uint128 transferAmount;

        // Checks that the amount deposited is not inferior to 0
        if (addresses[_pid] == address(0)) {
            if (msg.value == 0) {
                revert AmountMustExceedZero();
            }

            transferAmount = msg.value.safeCastTo128();
        } else {
            if (msg.value != 0) {
                revert AmountMustBeZero();
            }

            if (_amount == 0) {
                revert AmountMustExceedZero();
            }

            // Transfers funds to this contract
            ERC20(addresses[_pid]).safeTransferFrom(msg.sender, address(this), _amount);

            transferAmount = _amount.safeCastTo128();
        }

        // Update the user status
        _userInfo[msg.sender][_pid].amountPool = _userInfo[msg.sender][_pid].amountPool + transferAmount;

        if (_userInfo[msg.sender][_pid].amountPool < MIN_DEPOSIT_AMOUNTS[_pid]) {
            revert AmountMustExceedMinimum();
        }

        // Check if the pool has a cap per user
        if (_poolInformation[_pid].capPerUserInLP > 0) {
            // Checks whether the cap has been reached
            if (_userInfo[msg.sender][_pid].amountPool > _poolInformation[_pid].capPerUserInLP) {
                revert NewAmountAboveUserCap();
            }
        }

        // Updates the totalAmount for pool
        _poolInformation[_pid].totalAmountPool = _poolInformation[_pid].totalAmountPool + transferAmount;

        emit Deposit(msg.sender, transferAmount, _pid);
    }

    /**
     * @notice It allows users to harvest from pool
     * @param _pid: pool id
     */
    function harvestPool(uint8 _pid) external nonReentrant {
        _checkPid(_pid);

        // Checks whether pool id is valid
        if (block.timestamp <= endTimestamp) {
            revert TooEarly();
        }

        // Checks whether the user has participated
        if (_userInfo[msg.sender][_pid].amountPool == 0) {
            revert DidNotParticipate();
        }

        // Checks whether the user has already harvested
        if (_userInfo[msg.sender][_pid].claimedPool) {
            revert AlreadyHarvested();
        }

        // Updates the harvest status
        _userInfo[msg.sender][_pid].claimedPool = true;

        (uint256 offeringTokenAmount, uint256 refundingTokenAmount) =
            _calculateOfferingAndRefundingAmountsPool(msg.sender, _pid);

        // Transfer these tokens back to the user if quantity > 0
        if (offeringTokenAmount > 0) {
            // Transfer the tokens at TGE
            ERC20(addresses[2]).safeTransfer(msg.sender, offeringTokenAmount);
        }

        if (refundingTokenAmount > 0) {
            if (addresses[_pid] == address(0)) {
                msg.sender.safeTransferETH(refundingTokenAmount);
            } else {
                ERC20(addresses[_pid]).safeTransfer(msg.sender, refundingTokenAmount);
            }
        }

        emit Harvest(msg.sender, offeringTokenAmount, refundingTokenAmount, _pid);
    }

    /**
     * @notice It allows the admin to withdraw funds
     * @param _lpAmount0: the number of LP token0 to withdraw (18 decimals)
     * @param _lpAmount1: the number of LP token1 to withdraw (18 decimals)
     * @param _offerAmount: the number of offering amount to withdraw
     * @dev This function is only callable by admin.
     */
    function finalWithdraw(uint256 _lpAmount0, uint256 _lpAmount1, uint256 _offerAmount) external onlyOwner {
        if (_lpAmount0 > 0) {
            if (addresses[0] == address(0)) {
                msg.sender.safeTransferETH(_lpAmount0);
            } else {
                _safeTransferLpToken(msg.sender, _lpAmount0, 0);
            }
        }

        if (_lpAmount1 > 0) {
            if (addresses[1] == address(0)) {
                msg.sender.safeTransferETH(_lpAmount1);
            } else {
                _safeTransferLpToken(msg.sender, _lpAmount1, 1);
            }
        }

        if (_offerAmount > 0) {
            ERC20(addresses[2]).safeTransfer(msg.sender, _offerAmount);
        }

        emit AdminWithdraw(_lpAmount0, _lpAmount1, _offerAmount);
    }

    /**
     * @notice It allows the admin to recover wrong tokens sent to the contract
     * @param _tokenAddress: the address of the token to withdraw (18 decimals)
     * @param _tokenAmount: the number of token amount to withdraw
     * @dev This function is only callable by admin.
     */
    function recoverWrongTokens(address _tokenAddress, uint256 _tokenAmount) external onlyOwner {
        if (_tokenAddress == addresses[0]) {
            revert CanNotBeLPToken();
        }

        if (_tokenAddress == addresses[1]) {
            revert CanNotBeLPToken();
        }

        if (_tokenAddress == addresses[2]) {
            revert CanNotBeOfferingToken();
        }

        ERC20(_tokenAddress).safeTransfer(msg.sender, _tokenAmount);

        emit AdminTokenRecovery(_tokenAddress, _tokenAmount);
    }

    /**
     * @notice It sets parameters for pool
     * @param _offeringAmountPool: offering amount (in tokens)
     * @param _raisingAmountPool: raising amount (in LP tokens)
     * @param _limitPerUserInLP: limit per user (in LP tokens)
     * @param _pid: pool id
     */
    function setPool(uint256 _offeringAmountPool, uint256 _raisingAmountPool, uint256 _limitPerUserInLP, uint8 _pid)
        external
        onlyOwner
    {
        _checkPid(_pid);

        if (block.timestamp >= startTimestamp) {
            revert IDOHasStarted();
        }

        _poolInformation[_pid].offeringAmountPool = _offeringAmountPool.safeCastTo128();
        _poolInformation[_pid].raisingAmountPool = _raisingAmountPool.safeCastTo128();
        _poolInformation[_pid].capPerUserInLP = _limitPerUserInLP.safeCastTo128();

        uint256 tokensDistributedAcrossPools;

        for (uint8 i = 0; i <= MAX_POOL_ID; i++) {
            tokensDistributedAcrossPools = tokensDistributedAcrossPools + _poolInformation[i].offeringAmountPool;
        }

        // Update totalTokensOffered
        totalTokensOffered = tokensDistributedAcrossPools;

        emit PoolParametersSet(_offeringAmountPool, _raisingAmountPool, _pid);
    }

    /**
     * @notice It allows the admin to update start and end blocks
     * @param _startAndEndTimestamps: [0] startTimestamp [1] endTimestamp
     * @dev This function is only callable by admin.
     */
    function updateStartAndEndTimestamps(uint256[] calldata _startAndEndTimestamps) external onlyOwner {
        if (_startAndEndTimestamps.length != 2) {
            revert StartAndEndTimestampsLengthNotCorrect();
        }

        if (endTimestamp >= (block.timestamp + MAX_BUFFER_SECONDS)) revert EndTimeTooFar();
        if (startTimestamp >= endTimestamp) revert StartTimeMustInferiorToEndTime();
        if (block.timestamp >= startTimestamp) revert IDOHasStarted();

        startTimestamp = _startAndEndTimestamps[0];
        endTimestamp = _startAndEndTimestamps[1];

        emit NewStartAndEndTimestamps(_startAndEndTimestamps[0], _startAndEndTimestamps[1]);
    }

    /**
     * @notice It allows the admin to update MIN_DEPOSIT_AMOUNT
     * @param _newAmount The new value of minimum amount
     * @param _pid: pool id
     * @dev This function is only callable by admin.
     */
    function updateMinDepositAmount(uint256 _newAmount, uint8 _pid) external onlyOwner {
        _checkPid(_pid);

        MIN_DEPOSIT_AMOUNTS[_pid] = _newAmount;
        emit UpdatedMinDepositAmount(_newAmount, _pid);
    }

    /**
     * @notice It allows the admin to update the signer address
     * @param _signerAddr: the signer address for the signature verification
     * @dev This function is only callable by admin.
     */
    function updateSignerAddress(address _signerAddr) external onlyOwner {
        if (_signerAddr == address(0)) revert SignerAddressZero();
        signerAddress = _signerAddr;
        emit UpdatedSignerAddress(_signerAddr);
    }

    /**
     * @notice External view function to see user allocations for pool
     * @param _user: user address
     * @param _pids[]: array of pids
     * @return
     */
    function viewUserAllocationPools(address _user, uint8[] calldata _pids) public view returns (uint256[] memory) {
        uint256[] memory allocationPools = new uint256[](_pids.length);
        for (uint8 i = 0; i < _pids.length; i++) {
            allocationPools[i] = _getUserAllocationPool(_user, _pids[i]);
        }
        return allocationPools;
    }

    /**
     * @notice External view function to see user information
     * @param _user: user address
     * @param _pids[]: array of pids
     */
    function viewUserInfo(address _user, uint8[] calldata _pids)
        external
        view
        returns (uint256[] memory, bool[] memory)
    {
        uint256[] memory amountPools = new uint256[](_pids.length);
        bool[] memory statusPools = new bool[](_pids.length);

        for (uint8 i = 0; i < _pids.length; i++) {
            uint8 pid = _pids[i];
            if (pid <= MAX_POOL_ID) {
                amountPools[i] = _userInfo[_user][pid].amountPool;
                statusPools[i] = _userInfo[_user][pid].claimedPool;
            }
        }
        return (amountPools, statusPools);
    }

    /**
     * @notice External view function to see user offering and refunding amounts for pool
     * @param _user: user address
     * @param _pids: array of pids
     */
    function viewUserOfferingAndRefundingAmountsForPools(address _user, uint8[] calldata _pids)
        public
        view
        returns (uint256[2][] memory)
    {
        uint256[2][] memory amountPools = new uint256[2][](_pids.length);

        for (uint8 i = 0; i < _pids.length; i++) {
            uint256 userOfferingAmountPool;
            uint256 userRefundingAmountPool;

            if (_poolInformation[_pids[i]].raisingAmountPool > 0) {
                (userOfferingAmountPool, userRefundingAmountPool) =
                    _calculateOfferingAndRefundingAmountsPool(_user, _pids[i]);
            }

            amountPools[i] = [userOfferingAmountPool, userRefundingAmountPool];
        }
        return amountPools;
    }

    /**
     * @notice It calculates the offering amount for a user and the number of LP tokens to transfer back.
     * @param _user: user address
     * @param _pid: pool id
     * @return userOfferingAmount the amount of offering tokens user will get
     * @return userRefundingAmount the amount of refunding (eg. BNB) token user will get
     */
    function _calculateOfferingAndRefundingAmountsPool(address _user, uint8 _pid)
        internal
        view
        returns (uint256 userOfferingAmount, uint256 userRefundingAmount)
    {
        uint256 userAmountInPool = _userInfo[_user][_pid].amountPool;
        uint256 raisingAmountInPool = _poolInformation[_pid].raisingAmountPool;
        if (_poolInformation[_pid].totalAmountPool > raisingAmountInPool) {
            // Calculate allocation for the user
            uint256 allocation = _getUserAllocationPool(_user, _pid);

            // Calculate the offering amount for the user based on the offeringAmount for the pool
            userOfferingAmount = (_poolInformation[_pid].offeringAmountPool * allocation) / 1e12;

            // Calculate the payAmount
            uint256 payAmount = (raisingAmountInPool * allocation) / 1e12;

            // Calculate the pre-tax refunding amount
            userRefundingAmount = userAmountInPool - payAmount;
        } else {
            // _userInfo[_user] / (raisingAmount / offeringAmount)
            userOfferingAmount = (userAmountInPool * _poolInformation[_pid].offeringAmountPool) / raisingAmountInPool;

            if (userOfferingAmount == 0 && userAmountInPool > 0) {
                userRefundingAmount = userAmountInPool;
            }
        }
    }

    /**
     * @notice It returns the user allocation for pool
     * @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%)
     * @param _user: user address
     * @param _pid: pool id
     * @return It returns the user's share of pool
     */
    function _getUserAllocationPool(address _user, uint8 _pid) internal view returns (uint256) {
        if (_pid > MAX_POOL_ID) {
            return 0;
        }

        if (_poolInformation[_pid].totalAmountPool > 0) {
            return (_userInfo[_user][_pid].amountPool * 1e12) / _poolInformation[_pid].totalAmountPool;
        } else {
            return 0;
        }
    }

    function _checkPid(uint8 _pid) internal view {
        if (_pid > MAX_POOL_ID) {
            revert PoolIdNotValid();
        }
    }

    function _checkLpTokenBalance(uint256 _amount, uint256 _balance) internal pure {
        if (_amount > _balance) {
            revert NotEnoughLPTokens();
        }
    }

    function _safeTransferLpToken(address _to, uint256 _amount, uint8 _pid) internal {
        _checkPid(_pid);
        ERC20(addresses[_pid]).safeTransfer(_to, _amount);
    }
}

// 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);
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

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

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            success := call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)

            // Set success to whether the call reverted, if not we check it either
            // returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
            if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
                success := iszero(or(iszero(extcodesize(token)), returndatasize())) 
            }
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)

            // Set success to whether the call reverted, if not we check it either
            // returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
            if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
                success := iszero(or(iszero(extcodesize(token)), returndatasize())) 
            }
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)

            // Set success to whether the call reverted, if not we check it either
            // returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
            if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
                success := iszero(or(iszero(extcodesize(token)), returndatasize())) 
            }
        }

        require(success, "APPROVE_FAILED");
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Safe unsigned integer casting library that reverts on overflow.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
    function safeCastTo248(uint256 x) internal pure returns (uint248 y) {
        require(x < 1 << 248);

        y = uint248(x);
    }

    function safeCastTo240(uint256 x) internal pure returns (uint240 y) {
        require(x < 1 << 240);

        y = uint240(x);
    }

    function safeCastTo232(uint256 x) internal pure returns (uint232 y) {
        require(x < 1 << 232);

        y = uint232(x);
    }

    function safeCastTo224(uint256 x) internal pure returns (uint224 y) {
        require(x < 1 << 224);

        y = uint224(x);
    }

    function safeCastTo216(uint256 x) internal pure returns (uint216 y) {
        require(x < 1 << 216);

        y = uint216(x);
    }

    function safeCastTo208(uint256 x) internal pure returns (uint208 y) {
        require(x < 1 << 208);

        y = uint208(x);
    }

    function safeCastTo200(uint256 x) internal pure returns (uint200 y) {
        require(x < 1 << 200);

        y = uint200(x);
    }

    function safeCastTo192(uint256 x) internal pure returns (uint192 y) {
        require(x < 1 << 192);

        y = uint192(x);
    }

    function safeCastTo184(uint256 x) internal pure returns (uint184 y) {
        require(x < 1 << 184);

        y = uint184(x);
    }

    function safeCastTo176(uint256 x) internal pure returns (uint176 y) {
        require(x < 1 << 176);

        y = uint176(x);
    }

    function safeCastTo168(uint256 x) internal pure returns (uint168 y) {
        require(x < 1 << 168);

        y = uint168(x);
    }

    function safeCastTo160(uint256 x) internal pure returns (uint160 y) {
        require(x < 1 << 160);

        y = uint160(x);
    }

    function safeCastTo152(uint256 x) internal pure returns (uint152 y) {
        require(x < 1 << 152);

        y = uint152(x);
    }

    function safeCastTo144(uint256 x) internal pure returns (uint144 y) {
        require(x < 1 << 144);

        y = uint144(x);
    }

    function safeCastTo136(uint256 x) internal pure returns (uint136 y) {
        require(x < 1 << 136);

        y = uint136(x);
    }

    function safeCastTo128(uint256 x) internal pure returns (uint128 y) {
        require(x < 1 << 128);

        y = uint128(x);
    }

    function safeCastTo120(uint256 x) internal pure returns (uint120 y) {
        require(x < 1 << 120);

        y = uint120(x);
    }

    function safeCastTo112(uint256 x) internal pure returns (uint112 y) {
        require(x < 1 << 112);

        y = uint112(x);
    }

    function safeCastTo104(uint256 x) internal pure returns (uint104 y) {
        require(x < 1 << 104);

        y = uint104(x);
    }

    function safeCastTo96(uint256 x) internal pure returns (uint96 y) {
        require(x < 1 << 96);

        y = uint96(x);
    }

    function safeCastTo88(uint256 x) internal pure returns (uint88 y) {
        require(x < 1 << 88);

        y = uint88(x);
    }

    function safeCastTo80(uint256 x) internal pure returns (uint80 y) {
        require(x < 1 << 80);

        y = uint80(x);
    }

    function safeCastTo72(uint256 x) internal pure returns (uint72 y) {
        require(x < 1 << 72);

        y = uint72(x);
    }

    function safeCastTo64(uint256 x) internal pure returns (uint64 y) {
        require(x < 1 << 64);

        y = uint64(x);
    }

    function safeCastTo56(uint256 x) internal pure returns (uint56 y) {
        require(x < 1 << 56);

        y = uint56(x);
    }

    function safeCastTo48(uint256 x) internal pure returns (uint48 y) {
        require(x < 1 << 48);

        y = uint48(x);
    }

    function safeCastTo40(uint256 x) internal pure returns (uint40 y) {
        require(x < 1 << 40);

        y = uint40(x);
    }

    function safeCastTo32(uint256 x) internal pure returns (uint32 y) {
        require(x < 1 << 32);

        y = uint32(x);
    }

    function safeCastTo24(uint256 x) internal pure returns (uint24 y) {
        require(x < 1 << 24);

        y = uint24(x);
    }

    function safeCastTo16(uint256 x) internal pure returns (uint16 y) {
        require(x < 1 << 16);

        y = uint16(x);
    }

    function safeCastTo8(uint256 x) internal pure returns (uint8 y) {
        require(x < 1 << 8);

        y = uint8(x);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 7 of 9 : ReentrancyGuardTransient.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @notice Using transient storage slot for the lock status
/// @dev credit to https://github.com/Vectorized/solady/blob/main/src/utils/ReentrancyGuardTransient.sol
abstract contract ReentrancyGuardTransient {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to: `uint32(bytes4(keccak256("Reentrancy()"))) | 1 << 71`.
    /// 9 bytes is large enough to avoid collisions in practice,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x8000000000ab143c06;

    modifier nonReentrant() {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            tstore(_REENTRANCY_GUARD_SLOT, address())
        }

        _;

        /// @solidity memory-safe-assembly
        assembly {
            tstore(_REENTRANCY_GUARD_SLOT, 0)
        }
    }
}

// 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;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

Settings
{
  "remappings": [
    "@openzeppelin-4.5.0/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/",
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressesLengthNotCorrect","type":"error"},{"inputs":[],"name":"AlreadyHarvested","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AmountMustBeZero","type":"error"},{"inputs":[],"name":"AmountMustExceedMinimum","type":"error"},{"inputs":[],"name":"AmountMustExceedZero","type":"error"},{"inputs":[],"name":"CanNotBeLPToken","type":"error"},{"inputs":[],"name":"CanNotBeOfferingToken","type":"error"},{"inputs":[],"name":"DidNotParticipate","type":"error"},{"inputs":[],"name":"EndTimeTooFar","type":"error"},{"inputs":[],"name":"IDOHasStarted","type":"error"},{"inputs":[],"name":"MaxPoolIdNotValid","type":"error"},{"inputs":[],"name":"NewAmountAboveUserCap","type":"error"},{"inputs":[],"name":"NotEnoughLPTokens","type":"error"},{"inputs":[],"name":"NotEnoughOfferingTokens","type":"error"},{"inputs":[],"name":"PoolIdNotValid","type":"error"},{"inputs":[],"name":"PoolNotSet","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SignatureVerifyFailed","type":"error"},{"inputs":[],"name":"SignerAddressZero","type":"error"},{"inputs":[],"name":"StartAndEndTimestampsLengthNotCorrect","type":"error"},{"inputs":[],"name":"StartTimeMustInferiorToEndTime","type":"error"},{"inputs":[],"name":"TokensNotDepositedProperly","type":"error"},{"inputs":[],"name":"TooEarly","type":"error"},{"inputs":[],"name":"TooLate","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokens","type":"uint256"}],"name":"AdminTokenRecovery","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountLP0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLP1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfferingToken","type":"uint256"}],"name":"AdminWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"offeringAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"excessAmount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"NewStartAndEndTimestamps","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":"offeringAmountPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"raisingAmountPool","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"PoolParametersSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minAmount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"UpdatedMinDepositAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signerAddr","type":"address"}],"name":"UpdatedSignerAddress","type":"event"},{"inputs":[],"name":"MAX_BUFFER_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POOL_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MIN_DEPOSIT_AMOUNTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_poolInformation","outputs":[{"internalType":"uint128","name":"raisingAmountPool","type":"uint128"},{"internalType":"uint128","name":"offeringAmountPool","type":"uint128"},{"internalType":"uint128","name":"capPerUserInLP","type":"uint128"},{"internalType":"uint128","name":"totalAmountPool","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"addresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"},{"internalType":"uint256","name":"_expiredAt","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"depositPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"endTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpAmount0","type":"uint256"},{"internalType":"uint256","name":"_lpAmount1","type":"uint256"},{"internalType":"uint256","name":"_offerAmount","type":"uint256"}],"name":"finalWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"harvestPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256[]","name":"_startAndEndTimestamps","type":"uint256[]"},{"internalType":"uint256","name":"_maxBufferSeconds","type":"uint256"},{"internalType":"uint8","name":"_maxPoolId","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverWrongTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offeringAmountPool","type":"uint256"},{"internalType":"uint256","name":"_raisingAmountPool","type":"uint256"},{"internalType":"uint256","name":"_limitPerUserInLP","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensOffered","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":"_newAmount","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"updateMinDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signerAddr","type":"address"}],"name":"updateSignerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_startAndEndTimestamps","type":"uint256[]"}],"name":"updateStartAndEndTimestamps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserAllocationPools","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserInfo","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserOfferingAndRefundingAmountsForPools","outputs":[{"internalType":"uint256[2][]","name":"","type":"uint256[2][]"}],"stateMutability":"view","type":"function"}]

0x6080604052348015600e575f80fd5b506016336026565b620f42406009819055600a556075565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6126fe806100825f395ff3fe608060405260043610610147575f3560e01c8063a85adeab116100b3578063dfd2bb551161006d578063dfd2bb55146103c8578063e6fd48bc146103e7578063edf26d9b146103fc578063f2fde38b1461041b578063f93bf8331461043a578063f9cd5c1214610459575f80fd5b8063a85adeab146102d8578063b1ced5e7146102ed578063c8aa65c114610318578063ca463ca41461032b578063caa7f23214610357578063ce3f5e4b14610376575f80fd5b80635b7633d0116101045780635b7633d01461021e578063715018a614610255578063760b31801461026957806376920d081461027e5780638da5cb5b1461029d5780638fa2a9f0146102b9575f80fd5b80630f0b7a2b1461014b5780632374876c1461017d5780632937049e1461019e5780633f138d4b146101bd5780634af3c9b7146101dc57806354070e3914610209575b5f80fd5b348015610156575f80fd5b5061016a6101653660046120c8565b610485565b6040519081526020015b60405180910390f35b348015610188575f80fd5b5061019c6101973660046120f4565b61049b565b005b3480156101a9575f80fd5b5061019c6101b8366004612114565b610681565b3480156101c8575f80fd5b5061019c6101d7366004612153565b61076e565b3480156101e7575f80fd5b506101fb6101f63660046121bc565b61087f565b604051610174929190612245565b348015610214575f80fd5b5061016a60075481565b348015610229575f80fd5b5060115461023d906001600160a01b031681565b6040516001600160a01b039091168152602001610174565b348015610260575f80fd5b5061019c610a26565b348015610274575f80fd5b5061016a600b5481565b348015610289575f80fd5b5061019c61029836600461229f565b610a5a565b3480156102a8575f80fd5b505f546001600160a01b031661023d565b3480156102c4575f80fd5b5061019c6102d33660046122db565b610c20565b3480156102e3575f80fd5b5061016a60065481565b3480156102f8575f80fd5b506008546103069060ff1681565b60405160ff9091168152602001610174565b61019c610326366004612308565b610cb9565b348015610336575f80fd5b5061034a6103453660046121bc565b61121e565b60405161017491906123de565b348015610362575f80fd5b5061019c610371366004612447565b611365565b348015610381575f80fd5b506103956103903660046120c8565b6114c9565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610174565b3480156103d3575f80fd5b5061019c6103e2366004612486565b611506565b3480156103f2575f80fd5b5061016a60055481565b348015610407575f80fd5b5061023d6104163660046120c8565b6116ae565b348015610426575f80fd5b5061019c6104353660046122db565b6116cd565b348015610445575f80fd5b5061019c61045436600461250d565b611767565b348015610464575f80fd5b506104786104733660046121bc565b6117ee565b6040516101749190612537565b60098160028110610494575f80fd5b0154905081565b688000000000ab143c065c156104b85763ab143c065f526004601cfd5b30688000000000ab143c065d6104cd816118a8565b60065442116104ef5760405163085de62560e01b815260040160405180910390fd5b335f90815260106020908152604080832060ff851684529091528120546001600160801b03169003610534576040516337191a8560e21b815260040160405180910390fd5b335f90815260106020908152604080832060ff8086168552925290912054600160801b90041615610578576040516302cce53760e21b815260040160405180910390fd5b335f81815260106020908152604080832060ff861684529091528120805460ff60801b1916600160801b1790559081906105b290846118d2565b909250905081156105d9576105d93383600160025b01546001600160a01b03169190611a58565b8015610630575f600160ff8516600481106105f6576105f6612549565b01546001600160a01b031603610615576106103382611ae7565b610630565b610630338260018660ff16600481106105c7576105c7612549565b604080518381526020810183905260ff85169133917f51524c2e5edfedf8b01b29719c661e4fbe27e71734e7cd773dabb7cb712fb3b3910160405180910390a350505f688000000000ab143c065d50565b5f546001600160a01b031633146106b35760405162461bcd60e51b81526004016106aa9061255d565b60405180910390fd5b82156106e3576001546001600160a01b03166106d8576106d33384611ae7565b6106e3565b6106e333845f611b3a565b8115610714576002546001600160a01b0316610708576107033383611ae7565b610714565b61071433836001611b3a565b8015610728576107283382600160026105c7565b60408051848152602081018490529081018290527f5cba002c3841a6704789c1f41f4dab171dc5a8c972c928498c961665cdecf41b9060600160405180910390a1505050565b5f546001600160a01b031633146107975760405162461bcd60e51b81526004016106aa9061255d565b6001546001600160a01b03908116908316036107c6576040516310da472360e01b815260040160405180910390fd5b6002546001600160a01b03908116908316036107f5576040516310da472360e01b815260040160405180910390fd5b6003546001600160a01b03908116908316036108245760405163a8dfadb960e01b815260040160405180910390fd5b6108386001600160a01b0383163383611a58565b604080516001600160a01b0384168152602081018390527f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab7812991015b60405180910390a15050565b6060805f8367ffffffffffffffff81111561089c5761089c6122f4565b6040519080825280602002602001820160405280156108c5578160200160208202803683370190505b5090505f8467ffffffffffffffff8111156108e2576108e26122f4565b60405190808252806020026020018201604052801561090b578160200160208202803683370190505b5090505f5b60ff8116861115610a19575f87878360ff1681811061093157610931612549565b905060200201602081019061094691906120f4565b60085490915060ff90811690821611610a06576001600160a01b0389165f90815260106020908152604080832060ff808616855292529091205485516001600160801b039091169186919085169081106109a2576109a2612549565b6020908102919091018101919091526001600160a01b038a165f90815260108252604080822060ff808616845293529020548451600160801b90910482169185919085169081106109f5576109f5612549565b911515602092830291909101909101525b5080610a11816125a6565b915050610910565b5090969095509350505050565b5f546001600160a01b03163314610a4f5760405162461bcd60e51b81526004016106aa9061255d565b610a585f611b5e565b565b5f546001600160a01b03163314610a835760405162461bcd60e51b81526004016106aa9061255d565b610a8c816118a8565b6005544210610aae57604051630eac48e360e01b815260040160405180910390fd5b610ab784611bad565b600c8260ff1660028110610acd57610acd612549565b6002020180546001600160801b03928316600160801b029216919091179055610af583611bad565b600c8260ff1660028110610b0b57610b0b612549565b6002020180546001600160801b0319166001600160801b0392909216919091179055610b3682611bad565b600c8260ff1660028110610b4c57610b4c612549565b600202016001015f6101000a8154816001600160801b0302191690836001600160801b031602179055505f805f90505b60085460ff90811690821611610bd557600c8160ff1660028110610ba257610ba2612549565b6002020154610bc190600160801b90046001600160801b0316836125c4565b915080610bcd816125a6565b915050610b7c565b50600b819055604080518681526020810186905260ff8416917fddaf243a142670be60c19ff7116b5d8b124717b29bb4cc03cead42161614105b910160405180910390a25050505050565b5f546001600160a01b03163314610c495760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b038116610c7057604051632b561add60e01b815260040160405180910390fd5b601180546001600160a01b0319166001600160a01b0383169081179091556040517fa7f36ce0102fe26e2c05a5883f82aac2cee294dd4aec8da709ec986aa16e2b7a905f90a250565b688000000000ab143c065c15610cd65763ab143c065f526004601cfd5b30688000000000ab143c065d610ceb836118a8565b604080513060208201526080918101829052600d60a08201526c5665726966794164647265737360981b60c08201523360608201529081018390525f9060e0016040516020818303038152906040528051906020012090505f610da3610d9d836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018290525f90605c01604051602081830303815290604052805190602001209050919050565b84611bc1565b905083421180610dc157506011546001600160a01b03828116911614155b15610ddf5760405163112d49d360e01b815260040160405180910390fd5b600c8560ff1660028110610df557610df5612549565b6002020154600160801b90046001600160801b03161580610e375750600c8560ff1660028110610e2757610e27612549565b60020201546001600160801b0316155b15610e5557604051633c67586360e01b815260040160405180910390fd5b600554421015610e785760405163085de62560e01b815260040160405180910390fd5b600654421115610e9b5760405163ecdd1c2960e01b815260040160405180910390fd5b600b546003546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610ee4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0891906125d7565b1015610f275760405163726da7d560e11b815260040160405180910390fd5b5f80600160ff881660048110610f3f57610f3f612549565b01546001600160a01b031603610f7f57345f03610f6f57604051639e6c689560e01b815260040160405180910390fd5b610f7834611bad565b9050610ff9565b3415610f9e5760405163ac1cb9c960e01b815260040160405180910390fd5b865f03610fbe57604051639e6c689560e01b815260040160405180910390fd5b610fed33308960018a60ff1660048110610fda57610fda612549565b01546001600160a01b0316929190611be5565b610ff687611bad565b90505b335f90815260106020908152604080832060ff8a16845290915290205461102a9082906001600160801b03166125ee565b335f90815260106020908152604080832060ff8b16808552925290912080546001600160801b0319166001600160801b0393909316929092179091556009906002811061107957611079612549565b0154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b031610156110c057604051632fb20d4560e21b815260040160405180910390fd5b5f600c8760ff16600281106110d7576110d7612549565b60020201600101546001600160801b0316111561115557600c8660ff166002811061110457611104612549565b6002020160010154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b03918216911611156111555760405163017976fb60e61b815260040160405180910390fd5b80600c8760ff166002811061116c5761116c612549565b6002020160010160109054906101000a90046001600160801b031661119191906125ee565b600c8760ff16600281106111a7576111a7612549565b6001600291909102919091010180546001600160801b03928316600160801b02908316179055604051908216815260ff87169033907ff763e680fce25a97ffd55d8b705370c98b47b2285f7b3b2900c43606fd4180459060200160405180910390a35050505f688000000000ab143c065d50505050565b60605f8267ffffffffffffffff81111561123a5761123a6122f4565b60405190808252806020026020018201604052801561127357816020015b6112606120aa565b8152602001906001900390816112585790505b5090505f5b60ff811684111561135c575f805f600c88888660ff1681811061129d5761129d612549565b90506020020160208101906112b291906120f4565b60ff16600281106112c5576112c5612549565b60020201546001600160801b031611156113125761130c8888888660ff168181106112f2576112f2612549565b905060200201602081019061130791906120f4565b6118d2565b90925090505b604051806040016040528083815260200182815250848460ff168151811061133c5761133c612549565b602002602001018190525050508080611354906125a6565b915050611278565b50949350505050565b5f546001600160a01b0316331461138e5760405162461bcd60e51b81526004016106aa9061255d565b600281146113af57604051631397ee3560e31b815260040160405180910390fd5b6007546113bc90426125c4565b600654106113dd5760405163eb47c4f360e01b815260040160405180910390fd5b60065460055410611401576040516311af708560e21b815260040160405180910390fd5b600554421061142357604051630eac48e360e01b815260040160405180910390fd5b81815f81811061143557611435612549565b6020029190910135600555508181600181811061145457611454612549565b6020029190910135600655507f57df350cfad05a64accd73700fee8a7febd6d8430e035e45f0599ca62494aa8b82825f8161149157611491612549565b90506020020135838360018181106114ab576114ab612549565b90506020020135604051610873929190918252602082015260400190565b600c81600281106114d8575f80fd5b6002020180546001909101546001600160801b038083169350600160801b9283900481169282821692041684565b5f54600160a01b900460ff161561152f5760405162dc149f60e41b815260040160405180910390fd5b6004851461155057604051633b9b621f60e01b815260040160405180910390fd5b6002831461157157604051631397ee3560e31b815260040160405180910390fd5b5f805460ff60a01b1916600160a01b1781555b60ff81168611156116005786868260ff168181106115a4576115a4612549565b90506020020160208101906115b991906122db565b60018260ff16600481106115cf576115cf612549565b0180546001600160a01b0319166001600160a01b0392909216919091179055806115f8816125a6565b915050611584565b5083835f81811061161357611613612549565b6020029190910135600555508383600181811061163257611632612549565b6020029190910135600655506007829055600160ff821611611662576008805460ff191660ff831617905561167b565b604051633f0e260960e11b815260040160405180910390fd5b6116a68686600381811061169157611691612549565b905060200201602081019061043591906122db565b505050505050565b600181600481106116bd575f80fd5b01546001600160a01b0316905081565b5f546001600160a01b031633146116f65760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b03811661175b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106aa565b61176481611b5e565b50565b5f546001600160a01b031633146117905760405162461bcd60e51b81526004016106aa9061255d565b611799816118a8565b8160098260ff16600281106117b0576117b0612549565b015560405182815260ff8216907fefb6532c118ca8bcccd1ad6718d9e3d5f439d4176953ba393f110d80a192182b9060200160405180910390a25050565b60605f8267ffffffffffffffff81111561180a5761180a6122f4565b604051908082528060200260200182016040528015611833578160200160208202803683370190505b5090505f5b60ff811684111561135c576118768686868460ff1681811061185c5761185c612549565b905060200201602081019061187191906120f4565b611c89565b828260ff168151811061188b5761188b612549565b6020908102919091010152806118a0816125a6565b915050611838565b60085460ff908116908216111561176457604051630a26ca2560e31b815260040160405180910390fd5b6001600160a01b0382165f90815260106020908152604080832060ff8516808552925282205482916001600160801b03909116908290600c906002811061191b5761191b612549565b600290810291909101546001600160801b031691508190600c9060ff881690811061194857611948612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b031611156119f7575f61197d8787611c89565b905064e8d4a5100081600c8860ff166002811061199c5761199c612549565b60020201546119bb9190600160801b90046001600160801b031661260d565b6119c59190612638565b94505f64e8d4a510006119d8838561260d565b6119e29190612638565b90506119ee818561264b565b94505050611a4f565b80600c8660ff1660028110611a0e57611a0e612549565b6002020154611a2d90600160801b90046001600160801b03168461260d565b611a379190612638565b935083158015611a4657505f82115b15611a4f578192505b50509250929050565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f511416151615611aa25750823b153d17155b80611ae15760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016106aa565b50505050565b5f805f805f85875af1905080611b355760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b60448201526064016106aa565b505050565b611b43816118a8565b611b35838360018460ff16600481106105c7576105c7612549565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f600160801b8210611bbd575f80fd5b5090565b5f805f611bce8585611d6d565b91509150611bdb81611dd8565b5090505b92915050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af191505080601f3d1160015f511416151615611c3e5750833b153d17155b80611c825760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016106aa565b5050505050565b6008545f9060ff9081169083161115611ca357505f611bdf565b5f600c8360ff1660028110611cba57611cba612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b03161115611d6657600c8260ff1660028110611cfa57611cfa612549565b60020201600101546001600160a01b0384165f90815260106020908152604080832060ff87168452909152902054600160801b9091046001600160801b0390811691611d4c911664e8d4a5100061265e565b611d569190612687565b6001600160801b03169050611bdf565b505f611bdf565b5f808251604103611da1576020830151604084015160608501515f1a611d9587828585611f8d565b94509450505050611dd1565b8251604003611dca5760208301516040840151611dbf868383612072565b935093505050611dd1565b505f905060025b9250929050565b5f816004811115611deb57611deb6126b4565b03611df35750565b6001816004811115611e0757611e076126b4565b03611e545760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016106aa565b6002816004811115611e6857611e686126b4565b03611eb55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016106aa565b6003816004811115611ec957611ec96126b4565b03611f215760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016106aa565b6004816004811115611f3557611f356126b4565b036117645760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016106aa565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611fc257505f90506003612069565b8460ff16601b14158015611fda57508460ff16601c14155b15611fea57505f90506004612069565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561203b573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612063575f60019250925050612069565b91505f90505b94509492505050565b5f806001600160ff1b0383168161208e60ff86901c601b6125c4565b905061209c87828885611f8d565b935093505050935093915050565b60405180604001604052806002906020820280368337509192915050565b5f602082840312156120d8575f80fd5b5035919050565b803560ff811681146120ef575f80fd5b919050565b5f60208284031215612104575f80fd5b61210d826120df565b9392505050565b5f805f60608486031215612126575f80fd5b505081359360208301359350604090920135919050565b80356001600160a01b03811681146120ef575f80fd5b5f8060408385031215612164575f80fd5b61216d8361213d565b946020939093013593505050565b5f8083601f84011261218b575f80fd5b50813567ffffffffffffffff8111156121a2575f80fd5b6020830191508360208260051b8501011115611dd1575f80fd5b5f805f604084860312156121ce575f80fd5b6121d78461213d565b9250602084013567ffffffffffffffff8111156121f2575f80fd5b6121fe8682870161217b565b9497909650939450505050565b5f8151808452602084019350602083015f5b8281101561223b57815186526020958601959091019060010161221d565b5093949350505050565b604081525f612257604083018561220b565b82810360208401528084518083526020830191506020860192505f5b818110156122935783511515835260209384019390920191600101612273565b50909695505050505050565b5f805f80608085870312156122b2575f80fd5b8435935060208501359250604085013591506122d0606086016120df565b905092959194509250565b5f602082840312156122eb575f80fd5b61210d8261213d565b634e487b7160e01b5f52604160045260245ffd5b5f805f806080858703121561231b575f80fd5b8435935061232b602086016120df565b925060408501359150606085013567ffffffffffffffff81111561234d575f80fd5b8501601f8101871361235d575f80fd5b803567ffffffffffffffff811115612377576123776122f4565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156123a6576123a66122f4565b6040528181528282016020018910156123bd575f80fd5b816020840160208301375f6020838301015280935050505092959194509250565b602080825282518282018190525f918401906040840190835b8181101561243c578351835f5b6002811015612423578251825260209283019290910190600101612404565b50505060209390930192604092909201916001016123f7565b509095945050505050565b5f8060208385031215612458575f80fd5b823567ffffffffffffffff81111561246e575f80fd5b61247a8582860161217b565b90969095509350505050565b5f805f805f806080878903121561249b575f80fd5b863567ffffffffffffffff8111156124b1575f80fd5b6124bd89828a0161217b565b909750955050602087013567ffffffffffffffff8111156124dc575f80fd5b6124e889828a0161217b565b90955093505060408701359150612501606088016120df565b90509295509295509295565b5f806040838503121561251e575f80fd5b8235915061252e602084016120df565b90509250929050565b602081525f61210d602083018461220b565b634e487b7160e01b5f52603260045260245ffd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036125bb576125bb612592565b60010192915050565b80820180821115611bdf57611bdf612592565b5f602082840312156125e7575f80fd5b5051919050565b6001600160801b038181168382160190811115611bdf57611bdf612592565b8082028115828204841417611bdf57611bdf612592565b634e487b7160e01b5f52601260045260245ffd5b5f8261264657612646612624565b500490565b81810381811115611bdf57611bdf612592565b6001600160801b03818116838216029081169081811461268057612680612592565b5092915050565b5f6001600160801b0383168061269f5761269f612624565b806001600160801b0384160491505092915050565b634e487b7160e01b5f52602160045260245ffdfea26469706673582212205864efc2ee04fd64cfdbff5bfe2642175d283afd0e057a2a78b8223f1c406b2364736f6c634300081a0033

Deployed Bytecode

0x608060405260043610610147575f3560e01c8063a85adeab116100b3578063dfd2bb551161006d578063dfd2bb55146103c8578063e6fd48bc146103e7578063edf26d9b146103fc578063f2fde38b1461041b578063f93bf8331461043a578063f9cd5c1214610459575f80fd5b8063a85adeab146102d8578063b1ced5e7146102ed578063c8aa65c114610318578063ca463ca41461032b578063caa7f23214610357578063ce3f5e4b14610376575f80fd5b80635b7633d0116101045780635b7633d01461021e578063715018a614610255578063760b31801461026957806376920d081461027e5780638da5cb5b1461029d5780638fa2a9f0146102b9575f80fd5b80630f0b7a2b1461014b5780632374876c1461017d5780632937049e1461019e5780633f138d4b146101bd5780634af3c9b7146101dc57806354070e3914610209575b5f80fd5b348015610156575f80fd5b5061016a6101653660046120c8565b610485565b6040519081526020015b60405180910390f35b348015610188575f80fd5b5061019c6101973660046120f4565b61049b565b005b3480156101a9575f80fd5b5061019c6101b8366004612114565b610681565b3480156101c8575f80fd5b5061019c6101d7366004612153565b61076e565b3480156101e7575f80fd5b506101fb6101f63660046121bc565b61087f565b604051610174929190612245565b348015610214575f80fd5b5061016a60075481565b348015610229575f80fd5b5060115461023d906001600160a01b031681565b6040516001600160a01b039091168152602001610174565b348015610260575f80fd5b5061019c610a26565b348015610274575f80fd5b5061016a600b5481565b348015610289575f80fd5b5061019c61029836600461229f565b610a5a565b3480156102a8575f80fd5b505f546001600160a01b031661023d565b3480156102c4575f80fd5b5061019c6102d33660046122db565b610c20565b3480156102e3575f80fd5b5061016a60065481565b3480156102f8575f80fd5b506008546103069060ff1681565b60405160ff9091168152602001610174565b61019c610326366004612308565b610cb9565b348015610336575f80fd5b5061034a6103453660046121bc565b61121e565b60405161017491906123de565b348015610362575f80fd5b5061019c610371366004612447565b611365565b348015610381575f80fd5b506103956103903660046120c8565b6114c9565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610174565b3480156103d3575f80fd5b5061019c6103e2366004612486565b611506565b3480156103f2575f80fd5b5061016a60055481565b348015610407575f80fd5b5061023d6104163660046120c8565b6116ae565b348015610426575f80fd5b5061019c6104353660046122db565b6116cd565b348015610445575f80fd5b5061019c61045436600461250d565b611767565b348015610464575f80fd5b506104786104733660046121bc565b6117ee565b6040516101749190612537565b60098160028110610494575f80fd5b0154905081565b688000000000ab143c065c156104b85763ab143c065f526004601cfd5b30688000000000ab143c065d6104cd816118a8565b60065442116104ef5760405163085de62560e01b815260040160405180910390fd5b335f90815260106020908152604080832060ff851684529091528120546001600160801b03169003610534576040516337191a8560e21b815260040160405180910390fd5b335f90815260106020908152604080832060ff8086168552925290912054600160801b90041615610578576040516302cce53760e21b815260040160405180910390fd5b335f81815260106020908152604080832060ff861684529091528120805460ff60801b1916600160801b1790559081906105b290846118d2565b909250905081156105d9576105d93383600160025b01546001600160a01b03169190611a58565b8015610630575f600160ff8516600481106105f6576105f6612549565b01546001600160a01b031603610615576106103382611ae7565b610630565b610630338260018660ff16600481106105c7576105c7612549565b604080518381526020810183905260ff85169133917f51524c2e5edfedf8b01b29719c661e4fbe27e71734e7cd773dabb7cb712fb3b3910160405180910390a350505f688000000000ab143c065d50565b5f546001600160a01b031633146106b35760405162461bcd60e51b81526004016106aa9061255d565b60405180910390fd5b82156106e3576001546001600160a01b03166106d8576106d33384611ae7565b6106e3565b6106e333845f611b3a565b8115610714576002546001600160a01b0316610708576107033383611ae7565b610714565b61071433836001611b3a565b8015610728576107283382600160026105c7565b60408051848152602081018490529081018290527f5cba002c3841a6704789c1f41f4dab171dc5a8c972c928498c961665cdecf41b9060600160405180910390a1505050565b5f546001600160a01b031633146107975760405162461bcd60e51b81526004016106aa9061255d565b6001546001600160a01b03908116908316036107c6576040516310da472360e01b815260040160405180910390fd5b6002546001600160a01b03908116908316036107f5576040516310da472360e01b815260040160405180910390fd5b6003546001600160a01b03908116908316036108245760405163a8dfadb960e01b815260040160405180910390fd5b6108386001600160a01b0383163383611a58565b604080516001600160a01b0384168152602081018390527f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab7812991015b60405180910390a15050565b6060805f8367ffffffffffffffff81111561089c5761089c6122f4565b6040519080825280602002602001820160405280156108c5578160200160208202803683370190505b5090505f8467ffffffffffffffff8111156108e2576108e26122f4565b60405190808252806020026020018201604052801561090b578160200160208202803683370190505b5090505f5b60ff8116861115610a19575f87878360ff1681811061093157610931612549565b905060200201602081019061094691906120f4565b60085490915060ff90811690821611610a06576001600160a01b0389165f90815260106020908152604080832060ff808616855292529091205485516001600160801b039091169186919085169081106109a2576109a2612549565b6020908102919091018101919091526001600160a01b038a165f90815260108252604080822060ff808616845293529020548451600160801b90910482169185919085169081106109f5576109f5612549565b911515602092830291909101909101525b5080610a11816125a6565b915050610910565b5090969095509350505050565b5f546001600160a01b03163314610a4f5760405162461bcd60e51b81526004016106aa9061255d565b610a585f611b5e565b565b5f546001600160a01b03163314610a835760405162461bcd60e51b81526004016106aa9061255d565b610a8c816118a8565b6005544210610aae57604051630eac48e360e01b815260040160405180910390fd5b610ab784611bad565b600c8260ff1660028110610acd57610acd612549565b6002020180546001600160801b03928316600160801b029216919091179055610af583611bad565b600c8260ff1660028110610b0b57610b0b612549565b6002020180546001600160801b0319166001600160801b0392909216919091179055610b3682611bad565b600c8260ff1660028110610b4c57610b4c612549565b600202016001015f6101000a8154816001600160801b0302191690836001600160801b031602179055505f805f90505b60085460ff90811690821611610bd557600c8160ff1660028110610ba257610ba2612549565b6002020154610bc190600160801b90046001600160801b0316836125c4565b915080610bcd816125a6565b915050610b7c565b50600b819055604080518681526020810186905260ff8416917fddaf243a142670be60c19ff7116b5d8b124717b29bb4cc03cead42161614105b910160405180910390a25050505050565b5f546001600160a01b03163314610c495760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b038116610c7057604051632b561add60e01b815260040160405180910390fd5b601180546001600160a01b0319166001600160a01b0383169081179091556040517fa7f36ce0102fe26e2c05a5883f82aac2cee294dd4aec8da709ec986aa16e2b7a905f90a250565b688000000000ab143c065c15610cd65763ab143c065f526004601cfd5b30688000000000ab143c065d610ceb836118a8565b604080513060208201526080918101829052600d60a08201526c5665726966794164647265737360981b60c08201523360608201529081018390525f9060e0016040516020818303038152906040528051906020012090505f610da3610d9d836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018290525f90605c01604051602081830303815290604052805190602001209050919050565b84611bc1565b905083421180610dc157506011546001600160a01b03828116911614155b15610ddf5760405163112d49d360e01b815260040160405180910390fd5b600c8560ff1660028110610df557610df5612549565b6002020154600160801b90046001600160801b03161580610e375750600c8560ff1660028110610e2757610e27612549565b60020201546001600160801b0316155b15610e5557604051633c67586360e01b815260040160405180910390fd5b600554421015610e785760405163085de62560e01b815260040160405180910390fd5b600654421115610e9b5760405163ecdd1c2960e01b815260040160405180910390fd5b600b546003546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610ee4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0891906125d7565b1015610f275760405163726da7d560e11b815260040160405180910390fd5b5f80600160ff881660048110610f3f57610f3f612549565b01546001600160a01b031603610f7f57345f03610f6f57604051639e6c689560e01b815260040160405180910390fd5b610f7834611bad565b9050610ff9565b3415610f9e5760405163ac1cb9c960e01b815260040160405180910390fd5b865f03610fbe57604051639e6c689560e01b815260040160405180910390fd5b610fed33308960018a60ff1660048110610fda57610fda612549565b01546001600160a01b0316929190611be5565b610ff687611bad565b90505b335f90815260106020908152604080832060ff8a16845290915290205461102a9082906001600160801b03166125ee565b335f90815260106020908152604080832060ff8b16808552925290912080546001600160801b0319166001600160801b0393909316929092179091556009906002811061107957611079612549565b0154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b031610156110c057604051632fb20d4560e21b815260040160405180910390fd5b5f600c8760ff16600281106110d7576110d7612549565b60020201600101546001600160801b0316111561115557600c8660ff166002811061110457611104612549565b6002020160010154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b03918216911611156111555760405163017976fb60e61b815260040160405180910390fd5b80600c8760ff166002811061116c5761116c612549565b6002020160010160109054906101000a90046001600160801b031661119191906125ee565b600c8760ff16600281106111a7576111a7612549565b6001600291909102919091010180546001600160801b03928316600160801b02908316179055604051908216815260ff87169033907ff763e680fce25a97ffd55d8b705370c98b47b2285f7b3b2900c43606fd4180459060200160405180910390a35050505f688000000000ab143c065d50505050565b60605f8267ffffffffffffffff81111561123a5761123a6122f4565b60405190808252806020026020018201604052801561127357816020015b6112606120aa565b8152602001906001900390816112585790505b5090505f5b60ff811684111561135c575f805f600c88888660ff1681811061129d5761129d612549565b90506020020160208101906112b291906120f4565b60ff16600281106112c5576112c5612549565b60020201546001600160801b031611156113125761130c8888888660ff168181106112f2576112f2612549565b905060200201602081019061130791906120f4565b6118d2565b90925090505b604051806040016040528083815260200182815250848460ff168151811061133c5761133c612549565b602002602001018190525050508080611354906125a6565b915050611278565b50949350505050565b5f546001600160a01b0316331461138e5760405162461bcd60e51b81526004016106aa9061255d565b600281146113af57604051631397ee3560e31b815260040160405180910390fd5b6007546113bc90426125c4565b600654106113dd5760405163eb47c4f360e01b815260040160405180910390fd5b60065460055410611401576040516311af708560e21b815260040160405180910390fd5b600554421061142357604051630eac48e360e01b815260040160405180910390fd5b81815f81811061143557611435612549565b6020029190910135600555508181600181811061145457611454612549565b6020029190910135600655507f57df350cfad05a64accd73700fee8a7febd6d8430e035e45f0599ca62494aa8b82825f8161149157611491612549565b90506020020135838360018181106114ab576114ab612549565b90506020020135604051610873929190918252602082015260400190565b600c81600281106114d8575f80fd5b6002020180546001909101546001600160801b038083169350600160801b9283900481169282821692041684565b5f54600160a01b900460ff161561152f5760405162dc149f60e41b815260040160405180910390fd5b6004851461155057604051633b9b621f60e01b815260040160405180910390fd5b6002831461157157604051631397ee3560e31b815260040160405180910390fd5b5f805460ff60a01b1916600160a01b1781555b60ff81168611156116005786868260ff168181106115a4576115a4612549565b90506020020160208101906115b991906122db565b60018260ff16600481106115cf576115cf612549565b0180546001600160a01b0319166001600160a01b0392909216919091179055806115f8816125a6565b915050611584565b5083835f81811061161357611613612549565b6020029190910135600555508383600181811061163257611632612549565b6020029190910135600655506007829055600160ff821611611662576008805460ff191660ff831617905561167b565b604051633f0e260960e11b815260040160405180910390fd5b6116a68686600381811061169157611691612549565b905060200201602081019061043591906122db565b505050505050565b600181600481106116bd575f80fd5b01546001600160a01b0316905081565b5f546001600160a01b031633146116f65760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b03811661175b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106aa565b61176481611b5e565b50565b5f546001600160a01b031633146117905760405162461bcd60e51b81526004016106aa9061255d565b611799816118a8565b8160098260ff16600281106117b0576117b0612549565b015560405182815260ff8216907fefb6532c118ca8bcccd1ad6718d9e3d5f439d4176953ba393f110d80a192182b9060200160405180910390a25050565b60605f8267ffffffffffffffff81111561180a5761180a6122f4565b604051908082528060200260200182016040528015611833578160200160208202803683370190505b5090505f5b60ff811684111561135c576118768686868460ff1681811061185c5761185c612549565b905060200201602081019061187191906120f4565b611c89565b828260ff168151811061188b5761188b612549565b6020908102919091010152806118a0816125a6565b915050611838565b60085460ff908116908216111561176457604051630a26ca2560e31b815260040160405180910390fd5b6001600160a01b0382165f90815260106020908152604080832060ff8516808552925282205482916001600160801b03909116908290600c906002811061191b5761191b612549565b600290810291909101546001600160801b031691508190600c9060ff881690811061194857611948612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b031611156119f7575f61197d8787611c89565b905064e8d4a5100081600c8860ff166002811061199c5761199c612549565b60020201546119bb9190600160801b90046001600160801b031661260d565b6119c59190612638565b94505f64e8d4a510006119d8838561260d565b6119e29190612638565b90506119ee818561264b565b94505050611a4f565b80600c8660ff1660028110611a0e57611a0e612549565b6002020154611a2d90600160801b90046001600160801b03168461260d565b611a379190612638565b935083158015611a4657505f82115b15611a4f578192505b50509250929050565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f511416151615611aa25750823b153d17155b80611ae15760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016106aa565b50505050565b5f805f805f85875af1905080611b355760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b60448201526064016106aa565b505050565b611b43816118a8565b611b35838360018460ff16600481106105c7576105c7612549565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f600160801b8210611bbd575f80fd5b5090565b5f805f611bce8585611d6d565b91509150611bdb81611dd8565b5090505b92915050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af191505080601f3d1160015f511416151615611c3e5750833b153d17155b80611c825760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016106aa565b5050505050565b6008545f9060ff9081169083161115611ca357505f611bdf565b5f600c8360ff1660028110611cba57611cba612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b03161115611d6657600c8260ff1660028110611cfa57611cfa612549565b60020201600101546001600160a01b0384165f90815260106020908152604080832060ff87168452909152902054600160801b9091046001600160801b0390811691611d4c911664e8d4a5100061265e565b611d569190612687565b6001600160801b03169050611bdf565b505f611bdf565b5f808251604103611da1576020830151604084015160608501515f1a611d9587828585611f8d565b94509450505050611dd1565b8251604003611dca5760208301516040840151611dbf868383612072565b935093505050611dd1565b505f905060025b9250929050565b5f816004811115611deb57611deb6126b4565b03611df35750565b6001816004811115611e0757611e076126b4565b03611e545760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016106aa565b6002816004811115611e6857611e686126b4565b03611eb55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016106aa565b6003816004811115611ec957611ec96126b4565b03611f215760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016106aa565b6004816004811115611f3557611f356126b4565b036117645760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016106aa565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611fc257505f90506003612069565b8460ff16601b14158015611fda57508460ff16601c14155b15611fea57505f90506004612069565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561203b573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612063575f60019250925050612069565b91505f90505b94509492505050565b5f806001600160ff1b0383168161208e60ff86901c601b6125c4565b905061209c87828885611f8d565b935093505050935093915050565b60405180604001604052806002906020820280368337509192915050565b5f602082840312156120d8575f80fd5b5035919050565b803560ff811681146120ef575f80fd5b919050565b5f60208284031215612104575f80fd5b61210d826120df565b9392505050565b5f805f60608486031215612126575f80fd5b505081359360208301359350604090920135919050565b80356001600160a01b03811681146120ef575f80fd5b5f8060408385031215612164575f80fd5b61216d8361213d565b946020939093013593505050565b5f8083601f84011261218b575f80fd5b50813567ffffffffffffffff8111156121a2575f80fd5b6020830191508360208260051b8501011115611dd1575f80fd5b5f805f604084860312156121ce575f80fd5b6121d78461213d565b9250602084013567ffffffffffffffff8111156121f2575f80fd5b6121fe8682870161217b565b9497909650939450505050565b5f8151808452602084019350602083015f5b8281101561223b57815186526020958601959091019060010161221d565b5093949350505050565b604081525f612257604083018561220b565b82810360208401528084518083526020830191506020860192505f5b818110156122935783511515835260209384019390920191600101612273565b50909695505050505050565b5f805f80608085870312156122b2575f80fd5b8435935060208501359250604085013591506122d0606086016120df565b905092959194509250565b5f602082840312156122eb575f80fd5b61210d8261213d565b634e487b7160e01b5f52604160045260245ffd5b5f805f806080858703121561231b575f80fd5b8435935061232b602086016120df565b925060408501359150606085013567ffffffffffffffff81111561234d575f80fd5b8501601f8101871361235d575f80fd5b803567ffffffffffffffff811115612377576123776122f4565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156123a6576123a66122f4565b6040528181528282016020018910156123bd575f80fd5b816020840160208301375f6020838301015280935050505092959194509250565b602080825282518282018190525f918401906040840190835b8181101561243c578351835f5b6002811015612423578251825260209283019290910190600101612404565b50505060209390930192604092909201916001016123f7565b509095945050505050565b5f8060208385031215612458575f80fd5b823567ffffffffffffffff81111561246e575f80fd5b61247a8582860161217b565b90969095509350505050565b5f805f805f806080878903121561249b575f80fd5b863567ffffffffffffffff8111156124b1575f80fd5b6124bd89828a0161217b565b909750955050602087013567ffffffffffffffff8111156124dc575f80fd5b6124e889828a0161217b565b90955093505060408701359150612501606088016120df565b90509295509295509295565b5f806040838503121561251e575f80fd5b8235915061252e602084016120df565b90509250929050565b602081525f61210d602083018461220b565b634e487b7160e01b5f52603260045260245ffd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036125bb576125bb612592565b60010192915050565b80820180821115611bdf57611bdf612592565b5f602082840312156125e7575f80fd5b5051919050565b6001600160801b038181168382160190811115611bdf57611bdf612592565b8082028115828204841417611bdf57611bdf612592565b634e487b7160e01b5f52601260045260245ffd5b5f8261264657612646612624565b500490565b81810381811115611bdf57611bdf612592565b6001600160801b03818116838216029081169081811461268057612680612592565b5092915050565b5f6001600160801b0383168061269f5761269f612624565b806001600160801b0384160491505092915050565b634e487b7160e01b5f52602160045260245ffdfea26469706673582212205864efc2ee04fd64cfdbff5bfe2642175d283afd0e057a2a78b8223f1c406b2364736f6c634300081a0033

Block Transaction Gas Used Reward
view all blocks produced
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
View All Validatorset

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.