ETH Price: $1,876.24 (+0.53%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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

Contract Name:
Claiming

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-10-31
*/

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;


library AddressUpgradeable {
    
    function isContract(address account) internal view returns (bool) {
        
        
        

        return account.code.length > 0;
    }

    
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

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

    
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

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

    
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

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

    
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            
            if (returndata.length > 0) {
                

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

abstract contract Initializable {
    
    bool private _initialized;

    
    bool private _initializing;

    
    modifier initializer() {
        
        
        
        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    function _isConstructor() private view returns (bool) {
        return !AddressUpgradeable.isContract(address(this));
    }
}

library MerkleProofUpgradeable {
    
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
                
                computedHash = _efficientHash(computedHash, proofElement);
            } else {
                
                computedHash = _efficientHash(proofElement, computedHash);
            }
        }
        return computedHash;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

library StringsUpgradeable {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    
    function toString(uint256 value) internal pure returns (string memory) {
        
        

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

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

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

interface IERC20Upgradeable {
    
    function totalSupply() external view returns (uint256);

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

    
    function transfer(address to, uint256 amount) external returns (bool);

    
    function allowance(address owner, address spender) external view returns (uint256);

    
    function approve(address spender, uint256 amount) external returns (bool);

    
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

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

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

abstract contract ReentrancyGuardUpgradeable is Initializable {
    
    
    
    
    

    
    
    
    
    
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    
    modifier nonReentrant() {
        
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        
        _status = _ENTERED;

        _;

        
        
        _status = _NOT_ENTERED;
    }

    
    uint256[49] private __gap;
}

abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    
    uint256[50] private __gap;
}

abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    
    event Paused(address account);

    
    event Unpaused(address account);

    bool private _paused;

    
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

    
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    
    uint256[49] private __gap;
}

abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

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

    
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    
    uint256[49] private __gap;
}

interface IAccessControlUpgradeable {
    
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    
    function hasRole(bytes32 role, address account) external view returns (bool);

    
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    
    function grantRole(bytes32 role, address account) external;

    
    function revokeRole(bytes32 role, address account) external;

    
    function renounceRole(bytes32 role, address account) external;
}

interface IERC165Upgradeable {
    
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    
    uint256[50] private __gap;
}

abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
    }

    
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        StringsUpgradeable.toHexString(uint160(account), 20),
                        " is missing role ",
                        StringsUpgradeable.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }

    
    uint256[49] private __gap;
}

library EnumerableSetUpgradeable {
    
    
    
    
    
    
    
    

    struct Set {
        
        bytes32[] _values;
        
        
        mapping(bytes32 => uint256) _indexes;
    }

    
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            
            
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            
            
            
            

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastvalue = set._values[lastIndex];

                
                set._values[toDeleteIndex] = lastvalue;
                
                set._indexes[lastvalue] = valueIndex; 
            }

            
            set._values.pop();

            
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    

    struct Bytes32Set {
        Set _inner;
    }

    
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        return _values(set._inner);
    }

    

    struct AddressSet {
        Set _inner;
    }

    
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly {
            result := store
        }

        return result;
    }

    

    struct UintSet {
        Set _inner;
    }

    
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly {
            result := store
        }

        return result;
    }
}

contract Claiming is Initializable, ContextUpgradeable, OwnableUpgradeable, AccessControlUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable {
    using StringsUpgradeable for uint16;
    using StringsUpgradeable for uint256;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    bytes32 public constant LOCKER_ROLE = keccak256("LOCKER_ROLE");
    uint256 public constant denominator = 100000000;
    bool public isAllowedWithdraw;

    struct DistributorSettings {
        bytes32 claimingWalletsMerkleRoot; 
        uint256 unlocksNumber; 
        uint256 lastRootUpdate;
        bool paused;
    }

    struct UnlockPeriod {
        uint256 startDate; 
        uint256 totalPercentage; 
        uint256 endDate; 
        uint256 periodUnit;
        bool isUnlockedBeforeStart;
    }

    struct Claim {
        uint256 totalClaimed;
    }

    struct Wallet {
        bool isGraylisted;
        uint256 lastWalletUpdate;
    }

    address distributorAddress;
    DistributorSettings distributorSetting; 
    mapping(uint256 => UnlockPeriod) unlocks;
    mapping(address => Claim) claims; 
    mapping(address => Wallet) wallets; 
    mapping(address => address) walletInfo; 
    uint256 public stoppedTime;
    uint256 public totalAmount;
    uint256 public totalClaimedAmount;

    uint256 public refundDate;
    EnumerableSetUpgradeable.AddressSet private refundRequested;
    EnumerableSetUpgradeable.AddressSet private refunded;

    event UnlockPeriodChanged(uint256 indexed _periodIndex, uint256 _vestingStartDate, uint256 _totalPercentage, uint256 _cliffEndDate, uint256 _periodUnit, bool _isUnlocked);
    event Claimed(address indexed sender, uint256 _amount);
    event TokensWithdrawn(uint256 _amount);
    event MerkleRootUpdated(bytes32 _merkleRoot);
    event DistributionPaused(bool _paused);
    event WalletUpdated(address indexed _existingWallet, address indexed _newWallet);
    event CancelVesting(uint256 _stoppedTime, uint256 _withdrawnAmount);

    function initialize() public initializer {
        __Ownable_init();
        __Pausable_init();
        __ReentrancyGuard_init();
        __AccessControl_init();
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(LOCKER_ROLE, _msgSender());
        isAllowedWithdraw = true;
    }

    function setRoot(address _distributorAddress, bytes32 _merkleRoot) public onlyRole(LOCKER_ROLE) {
        _setRoot(_distributorAddress, _merkleRoot);
    }

    function setPause(bool _paused) public onlyRole(LOCKER_ROLE) {
        distributorSetting.paused = _paused;
        emit DistributionPaused(_paused);
    }

    function setRefundDate(uint256 _refundDate) public onlyRole(LOCKER_ROLE) {
        refundDate = _refundDate;
    }

    function withdrawEmergency(address _to, uint256 _amount) public onlyRole(LOCKER_ROLE) {
        require(isAllowedWithdraw, "emgergeny withdraw stopped");
        IERC20Upgradeable _token = IERC20Upgradeable(distributorAddress);
        require(_token.balanceOf(address(this)) >= _amount, "insufficient balance");
        _token.transfer(_to, _amount);
        emit TokensWithdrawn(_amount);
    }

    function lock(
        address _distributorAddress,
        bytes32 _merkleRoot,
        uint256 _totalAmount,
        UnlockPeriod[] calldata _periods,
        uint256 _refundDate
    ) public onlyRole(LOCKER_ROLE) {
        require(_totalAmount > 0, "total amount can't be 0");
        _setRoot(_distributorAddress, _merkleRoot);
        setUnlockPeriods(_periods);
        totalAmount = _totalAmount;
        refundDate = _refundDate;
    }

    function stopEmergencyWithdraw() public onlyRole(LOCKER_ROLE) {
        isAllowedWithdraw = false;
    }

    function updateWallet(
        uint256 _totalAllocation,
        address _newWallet,
        bytes32[] calldata _merkleProof
    ) public nonReentrant {
        require(!distributorSetting.paused, "distribution paused");

        _validateProof(_totalAllocation, _msgSender(), distributorSetting.claimingWalletsMerkleRoot, _merkleProof);

        wallets[_msgSender()].isGraylisted = true;
        wallets[_msgSender()].lastWalletUpdate = block.timestamp;
        wallets[_newWallet].isGraylisted = false;
        wallets[_newWallet].lastWalletUpdate = block.timestamp;
        if (walletInfo[_msgSender()] == address(0))
            walletInfo[_newWallet] = _msgSender();
        else
            walletInfo[_newWallet] = walletInfo[_msgSender()];
        walletInfo[_msgSender()] = address(0);

        claims[_newWallet].totalClaimed = claims[_msgSender()].totalClaimed;

        if (refundRequested.contains(_msgSender())) {
            refundRequested.remove(_msgSender());
            refundRequested.add(_newWallet);
        }

        if (refunded.contains(_msgSender())) {
            refunded.remove(_msgSender());
            refunded.add(_newWallet);
        }

        emit WalletUpdated(_msgSender(), _newWallet);
    }

    function claim(
        uint256 _totalAllocation,
        bytes32[] calldata _merkleProof
    ) public nonReentrant {

        require(!distributorSetting.paused, "distribution paused");

        require(!wallets[_msgSender()].isGraylisted, "wallet greylisted");

        if (refundDate > 0) {
            require(!refunded.contains(_msgSender()), "wallet refunded");

            if (block.timestamp > refundDate) {
                require(!refundRequested.contains(_msgSender()), "refund requested");
            }
            else {
                refundRequested.remove(_msgSender());
            }
        }
        
        _validateProof(_totalAllocation, _msgSender(), distributorSetting.claimingWalletsMerkleRoot, _merkleProof);

        uint256 totalToClaim = getAvailableTokens(_totalAllocation, _msgSender(), _merkleProof);

        require(totalToClaim > 0, "nothing to claim");

        _transfer(totalToClaim);

        claims[_msgSender()].totalClaimed += totalToClaim;
        totalClaimedAmount += totalToClaim;

        emit Claimed(_msgSender(), totalToClaim);
    }

    function requestRefund() external refundEnabled {
        require(claims[_msgSender()].totalClaimed == 0, "already claimed");
        refundRequested.add(_msgSender());
    }

    function revokeRefund() external refundEnabled {
        refundRequested.remove(_msgSender());
    }

    function isRefundRequested() external view returns (bool) {
        return refundRequested.contains(_msgSender());
    }

    function isRefunded() external view returns (bool) {
        return refunded.contains(_msgSender());
    }

    function getRefundRequested() public view onlyRole(LOCKER_ROLE) returns (address[] memory) {
        return _addressSetToArray(refundRequested);
    }

    function getRefunded() public view onlyRole(LOCKER_ROLE) returns (address[] memory) {
        return _addressSetToArray(refunded);
    }

    function addRefunded(address[] memory users) public onlyRole(LOCKER_ROLE) {
        for (uint256 i = 0; i < users.length; i++) {
            refunded.add(users[i]);
        }
    }

    function removeRefunded(address[] memory users) public onlyRole(LOCKER_ROLE) {
        for (uint256 i = 0; i < users.length; i++) {
            refunded.remove(users[i]);
        }
    }

    function stopVesting() public nonReentrant onlyRole(LOCKER_ROLE) {
        require(stoppedTime == 0, "Vesting was already stopped");
        stoppedTime = block.timestamp;

        uint256 percentageBeforeStopped = 0;
        for (uint256 _periodIndex = 0; _periodIndex < distributorSetting.unlocksNumber; _periodIndex++) {
            UnlockPeriod memory _unlockPeriod = unlocks[_periodIndex];
            if (_unlockPeriod.startDate >= stoppedTime) {
                break;
            }
            if (_unlockPeriod.isUnlockedBeforeStart) {
                continue;
            }
            percentageBeforeStopped += _unlockPeriod.totalPercentage;
        }
        uint256 leftAmount = totalAmount * percentageBeforeStopped / (denominator * 100) - totalClaimedAmount;

        IERC20Upgradeable _token = IERC20Upgradeable(distributorAddress);
        uint256 currentLockedAmount = _token.balanceOf(address(this));

        uint256 withdrawnAmount = 0;
        if (currentLockedAmount > leftAmount) {
            withdrawnAmount = currentLockedAmount - leftAmount;
            _transfer(withdrawnAmount);
        }
        emit CancelVesting(stoppedTime, withdrawnAmount);

    }

    function getAvailableTokens(uint256 _totalAllocation, address _wallet, bytes32[] calldata _merkleProof) public view returns (uint256) {
        require(!wallets[_wallet].isGraylisted, "wallet greylisted");
        
        _validateProof(_totalAllocation, _wallet, distributorSetting.claimingWalletsMerkleRoot, _merkleProof);

        uint256 availableAmount = 0;
        uint256 unlocksNumber = distributorSetting.unlocksNumber;
        uint256 totalClaimed = claims[_wallet].totalClaimed;
        uint256 unlockedBefore = 0;

        for (uint256 _periodIndex = 0; _periodIndex < unlocksNumber; _periodIndex++) {
            UnlockPeriod memory _unlockPeriod = unlocks[_periodIndex];
            if (block.timestamp >= _unlockPeriod.startDate) {
                if (_unlockPeriod.startDate >= stoppedTime && stoppedTime > 0) {
                    break;
                }
                if (_unlockPeriod.totalPercentage == 0) {
                    continue;
                }
                if (_unlockPeriod.isUnlockedBeforeStart) {
                    
                    unlockedBefore += _unlockPeriod.totalPercentage;
                    continue;
                }
                if (_unlockPeriod.periodUnit == 0) {
                    availableAmount += _unlockPeriod.totalPercentage;
                } else {
                    if (block.timestamp >= _unlockPeriod.endDate) {
                        if (stoppedTime == 0 || stoppedTime >= _unlockPeriod.endDate)
                            availableAmount += _unlockPeriod.totalPercentage;
                        else {
                            availableAmount += (_unlockPeriod.totalPercentage / ((_unlockPeriod.endDate - _unlockPeriod.startDate) / _unlockPeriod.periodUnit + 1)) * ((stoppedTime - _unlockPeriod.startDate) / _unlockPeriod.periodUnit + 1);
                        }
                    } else {
                        uint256 _end = block.timestamp;
                        if (_end > stoppedTime && stoppedTime > _unlockPeriod.startDate) _end = stoppedTime;
                        availableAmount += (_unlockPeriod.totalPercentage / ((_unlockPeriod.endDate - _unlockPeriod.startDate) / _unlockPeriod.periodUnit + 1)) * ((_end - _unlockPeriod.startDate) / _unlockPeriod.periodUnit + 1);
                    }
                }
            } else {
                break;
            }
        }
        if ((availableAmount + unlockedBefore) > (100 * denominator)) availableAmount = 100 * denominator - unlockedBefore;
        uint256 _avail = _calculatePercentage(_totalAllocation, availableAmount);
        if (_avail >= totalClaimed)
            return _avail - totalClaimed;
        else
            return 0;
    }

    function verifyTotalPercentageUnlockPeriod(UnlockPeriod[] calldata _periods) public pure returns (bool) {
        uint256 _totalAmount = 0;
        for(uint256 _periodIndex = 0; _periodIndex < _periods.length; _periodIndex++) {
            _totalAmount += _periods[_periodIndex].totalPercentage;
        }
        return ((_totalAmount <= 100 * denominator) && (_totalAmount >= 99 * denominator));
    }

    function setUnlockPeriods(UnlockPeriod[] calldata _periods) public onlyRole(LOCKER_ROLE) {
        require(verifyTotalPercentageUnlockPeriod(_periods), "invalid unlock percentage");
        distributorSetting.unlocksNumber = _periods.length;

        for(uint256 _periodIndex = 0; _periodIndex < _periods.length; _periodIndex++) {

            unlocks[_periodIndex].startDate = _periods[_periodIndex].startDate;
            unlocks[_periodIndex].totalPercentage = _periods[_periodIndex].totalPercentage;
            unlocks[_periodIndex].endDate = _periods[_periodIndex].endDate;
            unlocks[_periodIndex].periodUnit = _periods[_periodIndex].periodUnit;
            unlocks[_periodIndex].isUnlockedBeforeStart = _periods[_periodIndex].isUnlockedBeforeStart;
            

            emit UnlockPeriodChanged(
                _periodIndex, 
                _periods[_periodIndex].startDate, 
                _periods[_periodIndex].totalPercentage, 
                _periods[_periodIndex].endDate,
                _periods[_periodIndex].periodUnit,
                _periods[_periodIndex].isUnlockedBeforeStart);
        }
    }

    function getTotalClaimedPerWallet(address _wallet, uint256 _totalAllocation, bytes32[] calldata _merkleProof) public view returns (uint256) {
        require(!wallets[_wallet].isGraylisted, "wallet greylisted");
        
        _validateProof(_totalAllocation, _wallet, distributorSetting.claimingWalletsMerkleRoot, _merkleProof);
        
        uint256 unlockedBefore = 0;
        uint256 unlocksNumber = distributorSetting.unlocksNumber;
        for (uint256 _periodIndex = 0; _periodIndex < unlocksNumber; _periodIndex++) {
            UnlockPeriod memory _unlockPeriod = unlocks[_periodIndex];
            if (_unlockPeriod.isUnlockedBeforeStart) {
                unlockedBefore += _unlockPeriod.totalPercentage;
                continue;
            } else {
                break;
            }
        }
        return claims[_wallet].totalClaimed + _calculatePercentage(_totalAllocation, unlockedBefore);
    }

    function isVestingStopped() public view returns (bool) {
        return stoppedTime > 0;
    }

    
    
    

    function _setRoot(address _distributorAddress, bytes32 _merkleRoot) internal {
        distributorAddress = _distributorAddress;
        distributorSetting.claimingWalletsMerkleRoot = _merkleRoot;
        distributorSetting.lastRootUpdate = block.timestamp;
        emit MerkleRootUpdated(_merkleRoot);
    }

    function _calculatePercentage(
        uint256 _amount,
        uint256 _percentage
    ) internal pure returns (uint256) {
        return (_amount * _percentage / (100 * denominator));
    }

    function _validateProof(
        uint256 _totalAllocation,
        address _wallet,
        bytes32 _merkleRoot,
        bytes32[] calldata _merkleProof
    ) internal view {
        address _origin = walletInfo[_wallet];
        if (_origin == address(0)) _origin = _wallet;
        bytes32 leaf = keccak256(abi.encode(_origin, _totalAllocation));
        require(MerkleProofUpgradeable.verify(_merkleProof, _merkleRoot, leaf), "invalid proof");
    }

    function _transfer(uint256 _amount) internal {
        IERC20Upgradeable _token = IERC20Upgradeable(distributorAddress);
        require(_token.balanceOf(address(this)) >= _amount, "insufficient balance");
        _token.transfer(_msgSender(), _amount);
    }

    function _addressSetToArray(EnumerableSetUpgradeable.AddressSet storage input) internal view returns (address[] memory) {
        address[] memory result = new address[](input.length());

        for (uint256 i = 0; i < result.length; i++) {
            result[i] = input.at(i);
        }

        return result;
    }

    modifier refundEnabled {
        require(block.timestamp <= refundDate, "Refund not enabled or expired");
        _;
    }
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_stoppedTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_withdrawnAmount","type":"uint256"}],"name":"CancelVesting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_paused","type":"bool"}],"name":"DistributionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"MerkleRootUpdated","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":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_periodIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_vestingStartDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalPercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_cliffEndDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_periodUnit","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_isUnlocked","type":"bool"}],"name":"UnlockPeriodChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_existingWallet","type":"address"},{"indexed":true,"internalType":"address","name":"_newWallet","type":"address"}],"name":"WalletUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCKER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],"name":"addRefunded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalAllocation","type":"uint256"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"denominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalAllocation","type":"uint256"},{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"}],"name":"getAvailableTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRefundRequested","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRefunded","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"uint256","name":"_totalAllocation","type":"uint256"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"}],"name":"getTotalClaimedPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAllowedWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRefundRequested","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRefunded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isVestingStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_distributorAddress","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"_totalAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"startDate","type":"uint256"},{"internalType":"uint256","name":"totalPercentage","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"uint256","name":"periodUnit","type":"uint256"},{"internalType":"bool","name":"isUnlockedBeforeStart","type":"bool"}],"internalType":"struct Claiming.UnlockPeriod[]","name":"_periods","type":"tuple[]"},{"internalType":"uint256","name":"_refundDate","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],"name":"removeRefunded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_refundDate","type":"uint256"}],"name":"setRefundDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_distributorAddress","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"startDate","type":"uint256"},{"internalType":"uint256","name":"totalPercentage","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"uint256","name":"periodUnit","type":"uint256"},{"internalType":"bool","name":"isUnlockedBeforeStart","type":"bool"}],"internalType":"struct Claiming.UnlockPeriod[]","name":"_periods","type":"tuple[]"}],"name":"setUnlockPeriods","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopEmergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stoppedTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalClaimedAmount","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":"_totalAllocation","type":"uint256"},{"internalType":"address","name":"_newWallet","type":"address"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"}],"name":"updateWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"startDate","type":"uint256"},{"internalType":"uint256","name":"totalPercentage","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"uint256","name":"periodUnit","type":"uint256"},{"internalType":"bool","name":"isUnlockedBeforeStart","type":"bool"}],"internalType":"struct Claiming.UnlockPeriod[]","name":"_periods","type":"tuple[]"}],"name":"verifyTotalPercentageUnlockPeriod","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102535760003560e01c806389dd916b11610146578063b3834ed4116100c3578063d5cef13311610087578063d5cef133146104a2578063d9ee6ec0146104aa578063f2fde38b146104b2578063f3621367146104c5578063f7487c98146104da578063fb1057cd146104ed57600080fd5b8063b3834ed41461044c578063b92d4dff14610461578063bedb86fb14610469578063c328474e1461047c578063d547741f1461048f57600080fd5b80639661cb0d1161010a5780639661cb0d1461041257806396ce07951461041c57806396efe078146104275780639ea59ccb14610431578063a217fddf1461044457600080fd5b806389dd916b146103c75780638b0ec37a146103d25780638da5cb5b146103da57806390e3340c146103f557806391d14854146103ff57600080fd5b8063553bccf1116101d4578063715018a611610198578063715018a614610389578063779cd083146103915780637cdd7935146103995780637f94f65d146103ac5780638129fc1c146103bf57600080fd5b8063553bccf11461034257806357971e78146103505780635c975abb146103635780636c3d7e1d1461036e57806371411dba1461038157600080fd5b80632f2ff15d1161021b5780632f2ff15d146102e35780632f52ebb7146102f657806335cc17781461030957806336568abe1461031c57806347ee951c1461032f57600080fd5b806301ffc9a7146102585780630e42ff131461028057806313303ddf146102955780631a39d8ef146102a8578063248a9ca3146102c0575b600080fd5b61026b610266366004612654565b6104f5565b60405190151581526020015b60405180910390f35b61029361028e3660046126ca565b61052c565b005b6102936102a336600461270c565b6107d1565b6102b26101375481565b604051908152602001610277565b6102b26102ce36600461270c565b60009081526097602052604090206001015490565b6102936102f1366004612741565b6107f1565b6102936103043660046127b2565b61081c565b6102936103173660046127fe565b610a6f565b61029361032a366004612741565b610afe565b6102b261033d36600461286e565b610b7c565b61012d5461026b9060ff1681565b6102b261035e3660046128c8565b610e9c565b60c95460ff1661026b565b61029361037c36600461290a565b610fb9565b6102936111aa565b610293611209565b61026b61126f565b6102936103a736600461294a565b61127f565b6102936103ba36600461290a565b6112e5565b610293611308565b61013654151561026b565b61026b611411565b6033546040516001600160a01b039091168152602001610277565b6102b26101365481565b61026b61040d366004612741565b61141c565b6102b26101385481565b6102b26305f5e10081565b6102b26101395481565b61029361043f36600461294a565b611447565b6102b2600081565b6104546114ad565b6040516102779190612a0f565b6102936114d9565b610293610477366004612a6a565b61173f565b61026b61048a3660046126ca565b6117a2565b61029361049d366004612741565b61181c565b610293611842565b6104546118f1565b6102936104c0366004612a87565b611917565b6102b2600080516020612d3e83398151915281565b6102936104e836600461286e565b6119df565b610293611be0565b60006001600160e01b03198216637965db0b60e01b148061052657506301ffc9a760e01b6001600160e01b03198316145b92915050565b600080516020612d3e8339815191526105458133611c07565b61054f83836117a2565b6105a05760405162461bcd60e51b815260206004820152601960248201527f696e76616c696420756e6c6f636b2070657263656e746167650000000000000060448201526064015b60405180910390fd5b61012f82905560005b828110156107cb578383828181106105c3576105c3612aa2565b60008481526101326020526040902060a09091029290920135909155508383828181106105f2576105f2612aa2565b905060a002016020013561013260008381526020019081526020016000206001018190555083838281811061062957610629612aa2565b905060a002016040013561013260008381526020019081526020016000206002018190555083838281811061066057610660612aa2565b905060a002016060013561013260008381526020019081526020016000206003018190555083838281811061069757610697612aa2565b905060a0020160800160208101906106af9190612a6a565b600082815261013260205260409020600401805460ff1916911515919091179055807f92c9de83f112173ee7e61902732a99242d514635be0257ace0761072c730633485858381811061070457610704612aa2565b905060a002016000013586868581811061072057610720612aa2565b905060a002016020013587878681811061073c5761073c612aa2565b905060a002016040013588888781811061075857610758612aa2565b905060a002016060013589898881811061077457610774612aa2565b905060a00201608001602081019061078c9190612a6a565b6040805195865260208601949094529284019190915260608301521515608082015260a00160405180910390a2806107c381612ace565b9150506105a9565b50505050565b600080516020612d3e8339815191526107ea8133611c07565b5061013955565b60008281526097602052604090206001015461080d8133611c07565b6108178383611c6b565b505050565b600260fb54141561083f5760405162461bcd60e51b815260040161059790612ae9565b600260fb556101315460ff161561088e5760405162461bcd60e51b8152602060048201526013602482015272191a5cdd1c9a589d5d1a5bdb881c185d5cd959606a1b6044820152606401610597565b336000908152610134602052604090205460ff16156108bf5760405162461bcd60e51b815260040161059790612b20565b6101395415610983576108d6335b61013c90611cf1565b156109155760405162461bcd60e51b815260206004820152600f60248201526e1dd85b1b195d081c99599d5b991959608a1b6044820152606401610597565b610139544211156109735761092e335b61013a90611cf1565b1561096e5760405162461bcd60e51b815260206004820152601060248201526f1c99599d5b99081c995c5d595cdd195960821b6044820152606401610597565b610983565b610981335b61013a90611d16565b505b61099483335b61012e548585611d2b565b60006109a284338585610b7c565b9050600081116109e75760405162461bcd60e51b815260206004820152601060248201526f6e6f7468696e6720746f20636c61696d60801b6044820152606401610597565b6109f081611e0b565b336000908152610133602052604081208054839290610a10908490612b4b565b92505081905550806101386000828254610a2a9190612b4b565b909155505060405181815233907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9060200160405180910390a25050600160fb555050565b600080516020612d3e833981519152610a888133611c07565b60008511610ad85760405162461bcd60e51b815260206004820152601760248201527f746f74616c20616d6f756e742063616e277420626520300000000000000000006044820152606401610597565b610ae28787611f64565b610aec848461052c565b50610137939093555050610139555050565b6001600160a01b0381163314610b6e5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610597565b610b788282611fc0565b5050565b6001600160a01b0383166000908152610134602052604081205460ff1615610bb65760405162461bcd60e51b815260040161059790612b20565b610bc9858561012e600001548686611d2b565b61012f546001600160a01b0385166000908152610133602052604081205490919082805b83811015610e225760008181526101326020908152604091829020825160a0810184528154808252600183015493820193909352600282015493810193909352600381015460608401526004015460ff16151560808301524210610e085761013654815110801590610c625750600061013654115b15610c6d5750610e22565b6020810151610c7c5750610e10565b806080015115610c9d576020810151610c959084612b4b565b925050610e10565b6060810151610cbc576020810151610cb59087612b4b565b9550610e0e565b80604001514210610d6a57610136541580610cde575080604001516101365410155b15610cf2576020810151610cb59087612b4b565b6060810151815161013654610d079190612b63565b610d119190612b7a565b610d1c906001612b4b565b606082015182516040840151610d329190612b63565b610d3c9190612b7a565b610d47906001612b4b565b8260200151610d569190612b7a565b610d609190612b9c565b610cb59087612b4b565b61013654429081118015610d815750815161013654115b15610d8c5750610136545b60608201518251610d9d9083612b63565b610da79190612b7a565b610db2906001612b4b565b606083015183516040850151610dc89190612b63565b610dd29190612b7a565b610ddd906001612b4b565b8360200151610dec9190612b7a565b610df69190612b9c565b610e009088612b4b565b965050610e0e565b50610e22565b505b80610e1a81612ace565b915050610bed565b50610e326305f5e1006064612b9c565b610e3c8286612b4b565b1115610e5f5780610e526305f5e1006064612b9c565b610e5c9190612b63565b93505b6000610e6b8a86612027565b9050828110610e8a57610e7e8382612b63565b95505050505050610e94565b6000955050505050505b949350505050565b6001600160a01b0384166000908152610134602052604081205460ff1615610ed65760405162461bcd60e51b815260040161059790612b20565b610ee9848661012e600001548686611d2b565b61012f54600090815b81811015610f7f5760008181526101326020908152604091829020825160a081018452815481526001820154928101929092526002810154928201929092526003820154606082015260049091015460ff161580156080830152610f67576020810151610f5f9085612b4b565b935050610f6d565b50610f7f565b80610f7781612ace565b915050610ef2565b50610f8a8683612027565b6001600160a01b03881660009081526101336020526040902054610fae9190612b4b565b979650505050505050565b600080516020612d3e833981519152610fd28133611c07565b61012d5460ff166110255760405162461bcd60e51b815260206004820152601a60248201527f656d67657267656e792077697468647261772073746f707065640000000000006044820152606401610597565b61012d546040516370a0823160e01b81523060048201526101009091046001600160a01b031690839082906370a082319060240160206040518083038186803b15801561107157600080fd5b505afa158015611085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a99190612bbb565b10156110ee5760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610597565b60405163a9059cbb60e01b81526001600160a01b0385811660048301526024820185905282169063a9059cbb90604401602060405180830381600087803b15801561113857600080fd5b505af115801561114c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111709190612bd4565b506040518381527f9c6393f251205f9e03559951cab4c9ae71767b6174f77944a5b0c2fa51fbda9f9060200160405180910390a150505050565b610139544211156111fd5760405162461bcd60e51b815260206004820152601d60248201527f526566756e64206e6f7420656e61626c6564206f7220657870697265640000006044820152606401610597565b61120633610978565b50565b6033546001600160a01b031633146112635760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610597565b61126d600061204c565b565b600061127a336108cd565b905090565b600080516020612d3e8339815191526112988133611c07565b60005b8251811015610817576112d28382815181106112b9576112b9612aa2565b602002602001015161013c61209e90919063ffffffff16565b50806112dd81612ace565b91505061129b565b600080516020612d3e8339815191526112fe8133611c07565b6108178383611f64565b600054610100900460ff166113235760005460ff1615611327565b303b155b61138a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610597565b600054610100900460ff161580156113ac576000805461ffff19166101011790555b6113b46120b3565b6113bc6120e2565b6113c4612111565b6113cc612140565b6113d7600033612167565b6113ef600080516020612d3e83398151915233612167565b61012d805460ff191660011790558015611206576000805461ff001916905550565b600061127a33610925565b60009182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600080516020612d3e8339815191526114608133611c07565b60005b82518110156108175761149a83828151811061148157611481612aa2565b602002602001015161013c611d1690919063ffffffff16565b50806114a581612ace565b915050611463565b6060600080516020612d3e8339815191526114c88133611c07565b6114d361013c612171565b91505090565b600260fb5414156114fc5760405162461bcd60e51b815260040161059790612ae9565b600260fb55600080516020612d3e83398151915261151a8133611c07565b610136541561156b5760405162461bcd60e51b815260206004820152601b60248201527f56657374696e672077617320616c72656164792073746f7070656400000000006044820152606401610597565b42610136556000805b61012f548110156116135760008181526101326020908152604091829020825160a0810184528154808252600183015493820193909352600282015493810193909352600381015460608401526004015460ff161515608083015261013654116115de5750611613565b8060800151156115ee5750611601565b60208101516115fd9084612b4b565b9250505b8061160b81612ace565b915050611574565b506101385460009061162a6305f5e1006064612b9c565b83610137546116399190612b9c565b6116439190612b7a565b61164d9190612b63565b61012d546040516370a0823160e01b815230600482015291925061010090046001600160a01b03169060009082906370a082319060240160206040518083038186803b15801561169c57600080fd5b505afa1580156116b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d49190612bbb565b90506000838211156116f5576116ea8483612b63565b90506116f581611e0b565b6101365460408051918252602082018390527ff89ed788b8b17dc6626f03e53e8d007e8e11591dbcedc2566f8bac50c4a08579910160405180910390a15050600160fb5550505050565b600080516020612d3e8339815191526117588133611c07565b610131805460ff19168315159081179091556040519081527f41cbf6951a9357698e34cd1b958ca104f937fcd0e1bee7b3c98552ad3b67394e906020015b60405180910390a15050565b600080805b838110156117ea578484828181106117c1576117c1612aa2565b905060a0020160200135826117d69190612b4b565b9150806117e281612ace565b9150506117a7565b506117fa6305f5e1006064612b9c565b8111158015610e9457506118136305f5e1006063612b9c565b11159392505050565b6000828152609760205260409020600101546118388133611c07565b6108178383611fc0565b610139544211156118955760405162461bcd60e51b815260206004820152601d60248201527f526566756e64206e6f7420656e61626c6564206f7220657870697265640000006044820152606401610597565b3360009081526101336020526040902054156118e55760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b6044820152606401610597565b61120661013a3361209e565b6060600080516020612d3e83398151915261190c8133611c07565b6114d361013a612171565b6033546001600160a01b031633146119715760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610597565b6001600160a01b0381166119d65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610597565b6112068161204c565b600260fb541415611a025760405162461bcd60e51b815260040161059790612ae9565b600260fb556101315460ff1615611a515760405162461bcd60e51b8152602060048201526013602482015272191a5cdd1c9a589d5d1a5bdb881c185d5cd959606a1b6044820152606401610597565b611a5b8433610989565b336000818152610134602090815260408083208054600160ff1991821681178355429281018390556001600160a01b038a811687528487208054909316835591019190915593835261013590915290205416611adf576001600160a01b03831660009081526101356020526040902080546001600160a01b03191633179055611b16565b3360009081526101356020526040808220546001600160a01b0386811684529190922080546001600160a01b031916919092161790555b3360008181526101356020908152604080832080546001600160a01b0319169055610133909152808220546001600160a01b0387168352912055611b5990610925565b15611b7657611b6733610978565b50611b7461013a8461209e565b505b611b7f336108cd565b15611b9f57611b9061013c33611d16565b50611b9d61013c8461209e565b505b6040516001600160a01b0384169033907f0f37c6733428a3a65d46b7f1853a5ce4bfa3cf92d25322507a50bf23a0b5a0a890600090a35050600160fb555050565b600080516020612d3e833981519152611bf98133611c07565b5061012d805460ff19169055565b611c11828261141c565b610b7857611c29816001600160a01b0316601461221b565b611c3483602061221b565b604051602001611c45929190612c1d565b60408051601f198184030181529082905262461bcd60e51b825261059791600401612c92565b611c75828261141c565b610b785760008281526097602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611cad3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000611d0f836001600160a01b0384166123b7565b6001600160a01b03808516600090815261013560205260409020541680611d4f5750835b604080516001600160a01b0383166020820152908101879052600090606001604051602081830303815290604052805190602001209050611dc68484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508992508591506124aa9050565b611e025760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610597565b50505050505050565b61012d546040516370a0823160e01b81523060048201526101009091046001600160a01b031690829082906370a082319060240160206040518083038186803b158015611e5757600080fd5b505afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f9190612bbb565b1015611ed45760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610597565b6001600160a01b03811663a9059cbb336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381600087803b158015611f2c57600080fd5b505af1158015611f40573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108179190612bd4565b61012d8054610100600160a81b0319166101006001600160a01b0385160217905561012e81905542610130556040518181527f90004c04698bc3322499a575ed3752dd4abf33e0a7294c06a787a0fe01bea94190602001611796565b611fca828261141c565b15610b785760008281526097602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006120386305f5e1006064612b9c565b6120428385612b9c565b611d0f9190612b7a565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000611d0f836001600160a01b0384166124c0565b600054610100900460ff166120da5760405162461bcd60e51b815260040161059790612cc5565b61126d61250f565b600054610100900460ff166121095760405162461bcd60e51b815260040161059790612cc5565b61126d61253f565b600054610100900460ff166121385760405162461bcd60e51b815260040161059790612cc5565b61126d612572565b600054610100900460ff1661126d5760405162461bcd60e51b815260040161059790612cc5565b610b788282611c6b565b6060600061217e836125a0565b67ffffffffffffffff81111561219657612196612934565b6040519080825280602002602001820160405280156121bf578160200160208202803683370190505b50905060005b8151811015612214576121d884826125aa565b8282815181106121ea576121ea612aa2565b6001600160a01b03909216602092830291909101909101528061220c81612ace565b9150506121c5565b5092915050565b6060600061222a836002612b9c565b612235906002612b4b565b67ffffffffffffffff81111561224d5761224d612934565b6040519080825280601f01601f191660200182016040528015612277576020820181803683370190505b509050600360fc1b8160008151811061229257612292612aa2565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106122c1576122c1612aa2565b60200101906001600160f81b031916908160001a90535060006122e5846002612b9c565b6122f0906001612b4b565b90505b6001811115612368576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061232457612324612aa2565b1a60f81b82828151811061233a5761233a612aa2565b60200101906001600160f81b031916908160001a90535060049490941c9361236181612d10565b90506122f3565b508315611d0f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610597565b600081815260018301602052604081205480156124a05760006123db600183612b63565b85549091506000906123ef90600190612b63565b905081811461245457600086600001828154811061240f5761240f612aa2565b906000526020600020015490508087600001848154811061243257612432612aa2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061246557612465612d27565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610526565b6000915050610526565b6000826124b785846125b6565b14949350505050565b600081815260018301602052604081205461250757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610526565b506000610526565b600054610100900460ff166125365760405162461bcd60e51b815260040161059790612cc5565b61126d3361204c565b600054610100900460ff166125665760405162461bcd60e51b815260040161059790612cc5565b60c9805460ff19169055565b600054610100900460ff166125995760405162461bcd60e51b815260040161059790612cc5565b600160fb55565b6000610526825490565b6000611d0f838361262a565b600081815b84518110156126225760008582815181106125d8576125d8612aa2565b602002602001015190508083116125fe576000838152602082905260409020925061260f565b600081815260208490526040902092505b508061261a81612ace565b9150506125bb565b509392505050565b600082600001828154811061264157612641612aa2565b9060005260206000200154905092915050565b60006020828403121561266657600080fd5b81356001600160e01b031981168114611d0f57600080fd5b60008083601f84011261269057600080fd5b50813567ffffffffffffffff8111156126a857600080fd5b60208301915083602060a0830285010111156126c357600080fd5b9250929050565b600080602083850312156126dd57600080fd5b823567ffffffffffffffff8111156126f457600080fd5b6127008582860161267e565b90969095509350505050565b60006020828403121561271e57600080fd5b5035919050565b80356001600160a01b038116811461273c57600080fd5b919050565b6000806040838503121561275457600080fd5b8235915061276460208401612725565b90509250929050565b60008083601f84011261277f57600080fd5b50813567ffffffffffffffff81111561279757600080fd5b6020830191508360208260051b85010111156126c357600080fd5b6000806000604084860312156127c757600080fd5b83359250602084013567ffffffffffffffff8111156127e557600080fd5b6127f18682870161276d565b9497909650939450505050565b60008060008060008060a0878903121561281757600080fd5b61282087612725565b95506020870135945060408701359350606087013567ffffffffffffffff81111561284a57600080fd5b61285689828a0161267e565b979a9699509497949695608090950135949350505050565b6000806000806060858703121561288457600080fd5b8435935061289460208601612725565b9250604085013567ffffffffffffffff8111156128b057600080fd5b6128bc8782880161276d565b95989497509550505050565b600080600080606085870312156128de57600080fd5b6128e785612725565b935060208501359250604085013567ffffffffffffffff8111156128b057600080fd5b6000806040838503121561291d57600080fd5b61292683612725565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561295d57600080fd5b823567ffffffffffffffff8082111561297557600080fd5b818501915085601f83011261298957600080fd5b81358181111561299b5761299b612934565b8060051b604051601f19603f830116810181811085821117156129c0576129c0612934565b6040529182528482019250838101850191888311156129de57600080fd5b938501935b82851015612a03576129f485612725565b845293850193928501926129e3565b98975050505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612a505783516001600160a01b031683529284019291840191600101612a2b565b50909695505050505050565b801515811461120657600080fd5b600060208284031215612a7c57600080fd5b8135611d0f81612a5c565b600060208284031215612a9957600080fd5b611d0f82612725565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415612ae257612ae2612ab8565b5060010190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252601190820152701dd85b1b195d0819dc995e5b1a5cdd1959607a1b604082015260600190565b60008219821115612b5e57612b5e612ab8565b500190565b600082821015612b7557612b75612ab8565b500390565b600082612b9757634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615612bb657612bb6612ab8565b500290565b600060208284031215612bcd57600080fd5b5051919050565b600060208284031215612be657600080fd5b8151611d0f81612a5c565b60005b83811015612c0c578181015183820152602001612bf4565b838111156107cb5750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612c55816017850160208801612bf1565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612c86816028840160208801612bf1565b01602801949350505050565b6020815260008251806020840152612cb1816040850160208701612bf1565b601f01601f19169190910160400192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600081612d1f57612d1f612ab8565b506000190190565b634e487b7160e01b600052603160045260246000fdfeaf9a8bb3cbd6b84fbccefa71ff73e26e798553c6914585a84886212a46a90279a2646970667358221220f8f6e33ff28afb6ef44a84fa075f26ca39abff8ef979baaff2116320e4a4291364736f6c63430008090033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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