ETH Price: $2,089.09 (+0.15%)

Contract

0xEE89b02Fc0F4e401F12227A2639dff3a035F3C6F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Schedule Custom ...212831412024-11-28 2:04:11471 days ago1732759451IN
0xEE89b02F...a035F3C6F
0 ETH0.0003907210.74967593
Create Vesting T...203050832024-07-14 13:36:47608 days ago1720964207IN
0xEE89b02F...a035F3C6F
0 ETH0.000869942.68190515
Create Vesting T...202702332024-07-09 16:49:11613 days ago1720543751IN
0xEE89b02F...a035F3C6F
0 ETH0.005121778.17867907
Create Vesting T...202702202024-07-09 16:46:35613 days ago1720543595IN
0xEE89b02F...a035F3C6F
0 ETH0.005429578.67002651
Create Vesting T...202701852024-07-09 16:39:35613 days ago1720543175IN
0xEE89b02F...a035F3C6F
0 ETH0.00580949.27654546
Create Vesting T...202701582024-07-09 16:34:11613 days ago1720542851IN
0xEE89b02F...a035F3C6F
0 ETH0.008602019.34116563
Create Vesting T...201939752024-06-29 1:10:47623 days ago1719623447IN
0xEE89b02F...a035F3C6F
0 ETH0.000445211.3730451
Create Vesting T...201861622024-06-27 22:59:11625 days ago1719529151IN
0xEE89b02F...a035F3C6F
0 ETH0.001416574.02919583
Create Vesting T...201861352024-06-27 22:53:47625 days ago1719528827IN
0xEE89b02F...a035F3C6F
0 ETH0.001458514.14847175
Create Vesting T...201860912024-06-27 22:44:59625 days ago1719528299IN
0xEE89b02F...a035F3C6F
0 ETH0.001658464.71721475
Create Vesting T...201860852024-06-27 22:43:47625 days ago1719528227IN
0xEE89b02F...a035F3C6F
0 ETH0.001745194.96390046
Create Vesting T...201584112024-06-24 1:57:23628 days ago1719194243IN
0xEE89b02F...a035F3C6F
0 ETH0.000567091.74894154
Create Vesting T...201584062024-06-24 1:56:23628 days ago1719194183IN
0xEE89b02F...a035F3C6F
0 ETH0.000539091.66259875
Create Vesting T...201584062024-06-24 1:56:23628 days ago1719194183IN
0xEE89b02F...a035F3C6F
0 ETH0.000539091.66259875
Create Vesting T...201581752024-06-24 1:10:11628 days ago1719191411IN
0xEE89b02F...a035F3C6F
0 ETH0.000582171.79571133
Create Vesting T...201580422024-06-24 0:43:23628 days ago1719189803IN
0xEE89b02F...a035F3C6F
0 ETH0.000617931.81045397
Create Vesting T...201464142024-06-22 9:40:47630 days ago1719049247IN
0xEE89b02F...a035F3C6F
0 ETH0.000897862.75114637
Create Vesting T...201459972024-06-22 8:17:11630 days ago1719044231IN
0xEE89b02F...a035F3C6F
0 ETH0.001152543.5317605
Create Vesting T...201458732024-06-22 7:52:23630 days ago1719042743IN
0xEE89b02F...a035F3C6F
0 ETH0.000935572.86701015
Create Vesting T...201458672024-06-22 7:51:11630 days ago1719042671IN
0xEE89b02F...a035F3C6F
0 ETH0.000851882.6105513
Create Vesting T...201458212024-06-22 7:41:59630 days ago1719042119IN
0xEE89b02F...a035F3C6F
0 ETH0.00077222.36638965
Create Vesting T...201457802024-06-22 7:33:35630 days ago1719041615IN
0xEE89b02F...a035F3C6F
0 ETH0.000895422.54695606
Create Vesting T...201457422024-06-22 7:25:59630 days ago1719041159IN
0xEE89b02F...a035F3C6F
0 ETH0.000763312.22264816
Create Vesting T...201125522024-06-17 15:58:35635 days ago1718639915IN
0xEE89b02F...a035F3C6F
0 ETH0.0046361214.29084311
Create Vesting T...201125262024-06-17 15:53:23635 days ago1718639603IN
0xEE89b02F...a035F3C6F
0 ETH0.0038229811.78828268
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x3d602d80203050832024-07-14 13:36:47608 days ago1720964207
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80202702332024-07-09 16:49:11613 days ago1720543751
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80202702202024-07-09 16:46:35613 days ago1720543595
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80202701852024-07-09 16:39:35613 days ago1720543175
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80202701582024-07-09 16:34:11613 days ago1720542851
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201939752024-06-29 1:10:47623 days ago1719623447
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201861622024-06-27 22:59:11625 days ago1719529151
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201861352024-06-27 22:53:47625 days ago1719528827
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201860912024-06-27 22:44:59625 days ago1719528299
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201860852024-06-27 22:43:47625 days ago1719528227
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201584112024-06-24 1:57:23628 days ago1719194243
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201584062024-06-24 1:56:23628 days ago1719194183
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201584062024-06-24 1:56:23628 days ago1719194183
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201581752024-06-24 1:10:11628 days ago1719191411
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201580422024-06-24 0:43:23628 days ago1719189803
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201464142024-06-22 9:40:47630 days ago1719049247
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201459972024-06-22 8:17:11630 days ago1719044231
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201458732024-06-22 7:52:23630 days ago1719042743
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201458672024-06-22 7:51:11630 days ago1719042671
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201458212024-06-22 7:41:59630 days ago1719042119
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201457802024-06-22 7:33:35630 days ago1719041615
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201457422024-06-22 7:25:59630 days ago1719041159
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201125522024-06-17 15:58:35635 days ago1718639915
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201125262024-06-17 15:53:23635 days ago1718639603
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
0x3d602d80201058582024-06-16 17:31:11636 days ago1718559071
0xEE89b02F...a035F3C6F
 Contract Creation0 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
VestingTokenFactory

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 10000 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: None
// Unvest Contracts (last updated v3.0.0) (VestingTokenFactory.sol)
pragma solidity ^0.8.24;

import { Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol";

import { FactoryFeeManager } from "./abstracts/FactoryFeeManager.sol";

import { Errors } from "./libraries/Errors.sol";
import { IFeeManager } from "./interfaces/IFeeManager.sol";
import { IVestingToken } from "./interfaces/IVestingToken.sol";

/*

 _   _  _   _ __     __ _____  ____  _____ 
| | | || \ | |\ \   / /| ____|/ ___||_   _|
| | | ||  \| | \ \ / / |  _|  \___ \  | |  
| |_| || |\  |  \ V /  | |___  ___) | | |  
 \___/ |_| \_|   \_/   |_____||____/  |_|  
                                           
 */

/// @title VestingTokenFactory
/// @dev The VestingTokenFactory contract can be used to create vesting contracts for any ERC20 token.
/// @author JA (@ubinatus) v3
/// @author Klaus Hott (@Janther) v2
contract VestingTokenFactory is FactoryFeeManager {
    /// @param underlyingToken Address of the ERC20 that will be vest into `vestingToken`.
    /// @param vestingToken    Address of the newly deployed `VestingToken`.
    event VestingTokenCreated(address indexed underlyingToken, address vestingToken);

    /// @notice The address that will be used as a delegate call target for `VestingToken`s.
    address public immutable implementation;

    /// @dev It will be used as the salt for create2
    bytes32 internal _salt;

    /// @dev Maps `underlyingToken`s to an array of `VestingToken`s.
    mapping(address => address[]) internal _vestingTokensByUnderlyingToken;

    /// @dev Creates a vesting token factory contract.
    ///
    /// Requirements:
    ///
    /// - `implementationAddress` has to be a contract.
    /// - `feeCollectorAddress` can't be address 0x0.
    /// - `transferFeePercentage` must be within minTransferFee and maxTransferFee.
    ///
    /// @param implementationAddress    Address of `VestingToken` contract implementation.
    /// @param feeCollectorAddress      Address of `feeCollector`.
    /// @param creationFeeValue         Value for `creationFee` that will be charged when deploying `VestingToken`'s.
    /// @param transferFeePercentage    Value for `transferFeePercentage` that will be charged on `VestingToken`'s
    /// transfers.
    /// @param claimFeeValue            Value for `claimFee` that will be charged on `VestingToken`'s claims.
    constructor(
        address implementationAddress,
        address feeCollectorAddress,
        uint64 creationFeeValue,
        uint64 transferFeePercentage,
        uint64 claimFeeValue
    )
        Ownable(msg.sender)
    {
        if (implementationAddress == address(0)) revert Errors.AddressCanNotBeZero();

        bytes32 seed;
        assembly ("memory-safe") {
            seed := chainid()
        }
        _salt = seed;

        implementation = implementationAddress;
        setFeeCollector(feeCollectorAddress);
        scheduleGlobalCreationFee(creationFeeValue);
        scheduleGlobalTransferFee(transferFeePercentage);
        scheduleGlobalClaimFee(claimFeeValue);
        _feeData.creationFee = creationFeeValue;
        _feeData.transferFeePercentage = transferFeePercentage;
        _feeData.claimFee = claimFeeValue;
    }

    /// @notice Increments the salt one step.
    /// @dev In the rare case that create2 fails, this function can be used to skip that particular salt.
    function nextSalt() public {
        assembly {
            // Allocate memory for the _salt value to hash
            let ptr := mload(0x40)
            // Store current _salt value in memory allocated
            mstore(ptr, sload(_salt.slot))
            // Perform keccak256 hash of the _salt value stored in memory
            let hash := keccak256(ptr, 32)
            // Update _salt with the new hash value
            sstore(_salt.slot, hash)
        }
    }

    /// @notice Creates new VestingToken contracts.
    ///
    /// Requirements:
    ///
    /// - `underlyingTokenAddress` cannot be the zero address.
    /// - `timestamps` must be given in ascending order.
    /// - `percentages` must be given in ascending order and the last one must always be 1 eth, where 1 eth equals to
    /// 100%.
    ///
    /// @param name                   The token collection name.
    /// @param symbol                 The token collection symbol.
    /// @param underlyingTokenAddress The ERC20 token that will be held by this contract.
    /// @param milestonesArray        Array of all Milestones for this Contract's lifetime.
    function createVestingToken(
        string calldata name,
        string calldata symbol,
        address underlyingTokenAddress,
        IVestingToken.Milestone[] calldata milestonesArray
    )
        external
        payable
        returns (address vestingToken)
    {
        address impl = implementation;
        bytes32 salt = _salt;

        // Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, impl)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, impl), 0x5af43d82803e903d91602b57fd5bf3))
            vestingToken := create2(0, 0x09, 0x37, salt)
        }

        if (vestingToken == address(0)) revert Errors.FailedToDeploy();
        nextSalt();

        _processCreationFee(underlyingTokenAddress);

        IVestingToken(vestingToken).initialize(name, symbol, underlyingTokenAddress, milestonesArray);

        _vestingTokensByUnderlyingToken[underlyingTokenAddress].push(vestingToken);
        emit VestingTokenCreated(underlyingTokenAddress, vestingToken);
    }

    /// @notice Exposes the whole array that `_vestingTokensByUnderlyingToken` maps.
    function vestingTokens(address underlyingToken) external view returns (address[] memory) {
        return _vestingTokensByUnderlyingToken[underlyingToken];
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling 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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

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

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

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: None
// Unvest Contracts (last updated v3.0.0) (FactoryFeeManager.sol)
pragma solidity ^0.8.24;

import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol";

import { Errors } from "../libraries/Errors.sol";
import { IFeeManager } from "../interfaces/IFeeManager.sol";
import { IFactoryFeeManager } from "../interfaces/IFactoryFeeManager.sol";

/// @title FactoryFeeManager
/// @notice See the documentation in {IFactoryFeeManager}.
/// @author JA (@ubinatus)
abstract contract FactoryFeeManager is Ownable2Step, IFactoryFeeManager {
    /**
     *
     * CONSTANTS
     *
     */

    /// @dev Transfer fee is calculated using 18 decimals where 0.05 ether is 5%.
    uint64 internal constant MAX_TRANSFER_FEE = 0.05 ether;

    /**
     *
     * STATE
     *
     */

    /// @dev Stores fee related information for collection purposes.
    FeeData internal _feeData;

    /// @dev Stores the info necessary for an upcoming change of the global creation fee.
    UpcomingFeeData internal _upcomingCreationFee;

    /// @dev Stores the info necessary for an upcoming change of the global transfer fee.
    UpcomingFeeData internal _upcomingTransferFee;

    /// @dev Stores the info necessary for an upcoming change of the global claim fee.
    UpcomingFeeData internal _upcomingClaimFee;

    /// @dev Maps `underlyingToken`s to a custom creation fee struct.
    mapping(address => CustomFeeData) internal _creationFeeByUnderlyingToken;

    /// @dev Maps `underlyingToken`s to a custom transfer fee struct.
    mapping(address => CustomFeeData) internal _transferFeeByUnderlyingToken;

    /// @dev Maps `underlyingToken`s to a custom claim fee struct.
    mapping(address => CustomFeeData) internal _claimFeeByUnderlyingToken;

    /**
     *
     * FUNCTIONS
     *
     */

    /// @inheritdoc IFactoryFeeManager
    function setFeeCollector(address newFeeCollector) public override onlyOwner {
        if (newFeeCollector == address(0)) revert Errors.AddressCanNotBeZero();

        _feeData.feeCollector = newFeeCollector;
        emit FeeCollectorChange(newFeeCollector);
    }

    /// @inheritdoc IFactoryFeeManager
    function scheduleGlobalCreationFee(uint64 newFeeValue) public override onlyOwner {
        if (_upcomingCreationFee.valueChangeAt <= block.timestamp) {
            _feeData.creationFee = _upcomingCreationFee.nextValue;
        }

        _upcomingCreationFee.nextValue = newFeeValue;
        _upcomingCreationFee.valueChangeAt = uint64(block.timestamp + 1 hours);

        emit GlobalCreationFeeChange(newFeeValue);
    }

    /// @inheritdoc IFactoryFeeManager
    function scheduleGlobalTransferFee(uint64 newFeePercentage) public override onlyOwner {
        if (newFeePercentage > MAX_TRANSFER_FEE) revert Errors.FeeOutOfRange();

        _upcomingTransferFee.nextValue = newFeePercentage;
        _upcomingTransferFee.valueChangeAt = uint64(block.timestamp + 1 hours);

        emit GlobalTransferFeeChange(newFeePercentage);
    }

    /// @inheritdoc IFactoryFeeManager
    function scheduleGlobalClaimFee(uint64 newFeeValue) public override onlyOwner {
        if (_upcomingClaimFee.valueChangeAt <= block.timestamp) {
            _feeData.claimFee = _upcomingClaimFee.nextValue;
        }

        _upcomingClaimFee.nextValue = newFeeValue;
        _upcomingClaimFee.valueChangeAt = uint64(block.timestamp + 1 hours);

        emit GlobalClaimFeeChange(newFeeValue);
    }

    /// @inheritdoc IFactoryFeeManager
    function scheduleCustomCreationFee(address underlyingToken, uint64 newFeeValue) external override onlyOwner {
        CustomFeeData storage customFee = _creationFeeByUnderlyingToken[underlyingToken];

        if (customFee.valueChangeAt <= block.timestamp) {
            customFee.value = customFee.nextValue;
        }

        uint64 ts = uint64(block.timestamp + 1 hours);

        customFee.nextEnableState = true;
        customFee.statusChangeAt = ts;
        customFee.nextValue = newFeeValue;
        customFee.valueChangeAt = ts;

        emit CustomCreationFeeChange(underlyingToken, newFeeValue);
    }

    /// @inheritdoc IFactoryFeeManager
    function scheduleCustomTransferFee(address underlyingToken, uint64 newFeePercentage) external override onlyOwner {
        if (newFeePercentage > MAX_TRANSFER_FEE) revert Errors.FeeOutOfRange();

        CustomFeeData storage customFee = _transferFeeByUnderlyingToken[underlyingToken];

        if (customFee.valueChangeAt <= block.timestamp) {
            customFee.value = customFee.nextValue;
        }

        uint64 ts = uint64(block.timestamp + 1 hours);

        customFee.nextEnableState = true;
        customFee.statusChangeAt = ts;
        customFee.nextValue = newFeePercentage;
        customFee.valueChangeAt = ts;

        emit CustomTransferFeeChange(underlyingToken, newFeePercentage);
    }

    /// @inheritdoc IFactoryFeeManager
    function scheduleCustomClaimFee(address underlyingToken, uint64 newFeeValue) external override onlyOwner {
        CustomFeeData storage customFee = _claimFeeByUnderlyingToken[underlyingToken];

        if (customFee.valueChangeAt <= block.timestamp) {
            customFee.value = customFee.nextValue;
        }

        uint64 ts = uint64(block.timestamp + 1 hours);

        customFee.nextEnableState = true;
        customFee.statusChangeAt = ts;
        customFee.nextValue = newFeeValue;
        customFee.valueChangeAt = ts;

        emit CustomClaimFeeChange(underlyingToken, newFeeValue);
    }

    /// @inheritdoc IFactoryFeeManager
    function toggleCustomCreationFee(address underlyingToken, bool enable) external override onlyOwner {
        CustomFeeData storage customFee = _creationFeeByUnderlyingToken[underlyingToken];

        if (customFee.statusChangeAt <= block.timestamp) {
            customFee.isEnabled = customFee.nextEnableState;
        }

        customFee.nextEnableState = enable;
        customFee.statusChangeAt = uint64(block.timestamp + 1 hours);

        emit CustomCreationFeeToggle(underlyingToken, enable);
    }

    /// @inheritdoc IFactoryFeeManager
    function toggleCustomTransferFee(address underlyingToken, bool enable) external override onlyOwner {
        CustomFeeData storage customFee = _transferFeeByUnderlyingToken[underlyingToken];

        if (customFee.statusChangeAt <= block.timestamp) {
            customFee.isEnabled = customFee.nextEnableState;
        }

        customFee.nextEnableState = enable;
        customFee.statusChangeAt = uint64(block.timestamp + 1 hours);

        emit CustomTransferFeeToggle(underlyingToken, enable);
    }

    /// @inheritdoc IFactoryFeeManager
    function toggleCustomClaimFee(address underlyingToken, bool enable) external override onlyOwner {
        CustomFeeData storage customFee = _claimFeeByUnderlyingToken[underlyingToken];

        if (customFee.statusChangeAt <= block.timestamp) {
            customFee.isEnabled = customFee.nextEnableState;
        }

        customFee.nextEnableState = enable;
        customFee.statusChangeAt = uint64(block.timestamp + 1 hours);

        emit CustomClaimFeeToggle(underlyingToken, enable);
    }

    /// @inheritdoc IFactoryFeeManager
    function minTransferFee() external pure override returns (uint64) {
        return 0;
    }

    /// @inheritdoc IFactoryFeeManager
    function maxTransferFee() external pure override returns (uint64) {
        return MAX_TRANSFER_FEE;
    }

    /// @inheritdoc IFactoryFeeManager
    function feeCollector() external view override returns (address) {
        return _feeData.feeCollector;
    }

    /// @inheritdoc IFactoryFeeManager
    function globalCreationFee() external view override returns (uint64) {
        return block.timestamp >= _upcomingCreationFee.valueChangeAt
            ? _upcomingCreationFee.nextValue
            : _feeData.creationFee;
    }

    /// @inheritdoc IFactoryFeeManager
    function globalTransferFee() external view override returns (uint64) {
        return block.timestamp >= _upcomingTransferFee.valueChangeAt
            ? _upcomingTransferFee.nextValue
            : _feeData.transferFeePercentage;
    }

    /// @inheritdoc IFactoryFeeManager
    function globalClaimFee() external view override returns (uint64) {
        return block.timestamp >= _upcomingClaimFee.valueChangeAt ? _upcomingClaimFee.nextValue : _feeData.claimFee;
    }

    /// @inheritdoc IFeeManager
    function creationFeeData(address underlyingToken)
        external
        view
        returns (address feeCollectorAddress, uint64 creationFeeValue)
    {
        feeCollectorAddress = _feeData.feeCollector;
        creationFeeValue =
            _getCurrentFee(_feeData.creationFee, _upcomingCreationFee, _creationFeeByUnderlyingToken[underlyingToken]);
    }

    /// @notice Returns the current transfer fee for a specific underlying token, considering any pending updates.
    /// @param underlyingToken Address of the `underlyingToken`.
    function transferFeeData(address underlyingToken)
        external
        view
        returns (address feeCollectorAddress, uint64 transferFeePercentage)
    {
        feeCollectorAddress = _feeData.feeCollector;
        transferFeePercentage = _getCurrentFee(
            _feeData.transferFeePercentage, _upcomingTransferFee, _transferFeeByUnderlyingToken[underlyingToken]
        );
    }

    /// @notice Returns the current claim fee for a specific underlying token, considering any pending updates.
    /// @param underlyingToken Address of the `underlyingToken`.
    function claimFeeData(address underlyingToken)
        external
        view
        returns (address feeCollectorAddress, uint64 claimFeeValue)
    {
        feeCollectorAddress = _feeData.feeCollector;
        claimFeeValue =
            _getCurrentFee(_feeData.claimFee, _upcomingClaimFee, _claimFeeByUnderlyingToken[underlyingToken]);
    }

    /// @notice Calculates the current fee based on global, custom, and upcoming fee data.
    /// @dev This function considers the current timestamp and determines the appropriate fee
    /// based on whether a custom or upcoming fee should be applied.
    /// @param globalValue The default global fee value used when no custom fees are applicable.
    /// @param upcomingGlobalFee A struct containing data about an upcoming fee change, including the timestamp
    /// for the change and the new value to be applied.
    /// @param customFee A struct containing data about the custom fee, including its enablement status,
    /// timestamps for changes, and its values (current and new).
    /// @return currentValue The calculated current fee value, taking into account the global value,
    /// custom fee, and upcoming fee data based on the current timestamp.
    function _getCurrentFee(
        uint64 globalValue,
        UpcomingFeeData memory upcomingGlobalFee,
        CustomFeeData memory customFee
    )
        internal
        view
        returns (uint64 currentValue)
    {
        if (block.timestamp >= customFee.statusChangeAt) {
            // If isCustomFee is true based on status, directly return the value based on the customFee conditions.
            if (customFee.nextEnableState) {
                return block.timestamp >= customFee.valueChangeAt ? customFee.nextValue : customFee.value;
            }
        } else if (customFee.isEnabled) {
            // This block handles the case where current timestamp is not past statusChangeAt, but custom is enabled.
            return block.timestamp >= customFee.valueChangeAt ? customFee.nextValue : customFee.value;
        }

        // If none of the custom fee conditions apply, return the global or upcoming fee value.
        return block.timestamp >= upcomingGlobalFee.valueChangeAt ? upcomingGlobalFee.nextValue : globalValue;
    }

    /// @notice Processes the creation fee for a transaction.
    /// @dev This function retrieves the creation fee data from the manager contract and, if the creation fee is greater
    /// than zero, sends the `msg.value` to the fee collector address. Reverts if the transferred value is less than the
    /// required creation fee or if the transfer fails.
    function _processCreationFee(address underlyingToken) internal {
        uint64 creationFeeValue =
            _getCurrentFee(_feeData.creationFee, _upcomingCreationFee, _creationFeeByUnderlyingToken[underlyingToken]);

        if (creationFeeValue != 0) {
            if (msg.value < creationFeeValue) revert Errors.InsufficientCreationFee();

            bytes4 unsuccessfulClaimFeeTransfer = Errors.UnsuccessfulCreationFeeTransfer.selector;
            address feeCollectorAddress = _feeData.feeCollector;

            assembly {
                let ptr := mload(0x40)
                let sendSuccess := call(gas(), feeCollectorAddress, callvalue(), 0x00, 0x00, 0x00, 0x00)
                if iszero(sendSuccess) {
                    mstore(ptr, unsuccessfulClaimFeeTransfer)
                    revert(ptr, 0x04)
                }
            }
        }
    }
}

// SPDX-License-Identifier: None
// Unvest Contracts (last updated v3.0.0) (interfaces/IFactoryFeeManager.sol)
pragma solidity ^0.8.24;

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

/// @title IFactoryFeeManager
/// @dev Interface that describes the struct and accessor function for the data related to the collection of fees.
interface IFactoryFeeManager is IFeeManager {
    /**
     *
     * EVENTS
     *
     */

    /// @param feeCollector Address of the new fee collector.
    event FeeCollectorChange(address indexed feeCollector);

    /// @param creationFeeValue Value for the new creation fee.
    event GlobalCreationFeeChange(uint64 creationFeeValue);

    /// @param transferFeePercentage Value for the new transfer fee.
    event GlobalTransferFeeChange(uint64 transferFeePercentage);

    /// @param claimFeeValue Value for the new claim fee.
    event GlobalClaimFeeChange(uint64 claimFeeValue);

    /// @param underlyingToken Address of the underlying token.
    /// @param creationFeeValue Value for the new creation fee.
    event CustomCreationFeeChange(address indexed underlyingToken, uint64 creationFeeValue);

    /// @param underlyingToken Address of the underlying token.
    /// @param enable Indicates the enabled state of the fee.
    event CustomCreationFeeToggle(address indexed underlyingToken, bool enable);

    /// @param underlyingToken Address of the underlying token.
    /// @param transferFeePercentage Value for the new transfer fee.
    event CustomTransferFeeChange(address indexed underlyingToken, uint64 transferFeePercentage);

    /// @param underlyingToken Address of the underlying token.
    /// @param enable Indicates the enabled state of the fee.
    event CustomTransferFeeToggle(address indexed underlyingToken, bool enable);

    /// @param underlyingToken Address of the underlying token.
    /// @param claimFeeValue Value for the new claim fee.
    event CustomClaimFeeChange(address indexed underlyingToken, uint64 claimFeeValue);

    /// @param underlyingToken Address of the underlying token.
    /// @param enable Indicates the enabled state of the fee.
    event CustomClaimFeeToggle(address indexed underlyingToken, bool enable);

    /**
     *
     * FUNCTIONS
     *
     */

    /// @dev Set address of fee collector.
    ///
    /// Requirements:
    ///
    /// - `msg.sender` has to be the owner of the contract.
    /// - `newFeeCollector` can't be address 0x0.
    ///
    /// @param newFeeCollector Address of `feeCollector`.
    ///
    function setFeeCollector(address newFeeCollector) external;

    /// @notice Sets a new global creation fee value, to take effect after 1 hour.
    /// @param newFeeValue Value for `creationFee` that will be charged on `VestingToken`'s deployments.
    function scheduleGlobalCreationFee(uint64 newFeeValue) external;

    /// @notice Sets a new global transfer fee percentage, to take effect after 1 hour.
    ///
    /// @dev Percentages and fees are calculated using 18 decimals where 1 ether is 100%.
    ///
    /// Requirements:
    ///
    /// - `newFeePercentage` must be within minTransferFee and maxTransferFee.
    ///
    /// @param newFeePercentage Value for `transferFeePercentage` that will be charged on `VestingToken`'s transfers.
    function scheduleGlobalTransferFee(uint64 newFeePercentage) external;

    /// @notice Sets a new global claim fee value, to take effect after 1 hour.
    /// @param newFeeValue Value for `claimFee` that will be charged on `VestingToken`'s claims.
    function scheduleGlobalClaimFee(uint64 newFeeValue) external;

    /// @notice Sets a new custom creation fee value for a specific underlying token, to be enabled and take effect
    /// after 1 hour from the time of this transaction.
    ///
    /// @dev Allows the contract owner to modify the creation fee associated with a specific underlying token.
    /// The new fee becomes effective after a delay of 1 hour, aiming to provide a buffer for users to be aware of the
    /// upcoming fee change.
    /// This function updates the fee and schedules its activation, ensuring transparency and predictability in fee
    /// adjustments.
    /// The fee is specified in wei, allowing for granular control over the fee structure. Emits a
    /// `CustomCreationFeeChange` event upon successful fee update.
    ///
    /// Requirements:
    /// - The caller must have owner privileges to execute this function.
    ///
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @param newFeeValue The new creation fee amount to be set, in wei, to replace the current fee after the specified
    /// delay.
    function scheduleCustomCreationFee(address underlyingToken, uint64 newFeeValue) external;

    /// @notice Sets a new custom transfer fee percentage for a specific underlying token, to be enabled and take effect
    /// after 1 hour from the time of this transaction.
    ///
    /// @dev This function allows the contract owner to adjust the transfer fee for an underlying token.
    /// The fee adjustment is delayed by 1 hour to provide transparency and predictability. Fees are calculated with
    /// precision to 18 decimal places, where 1 ether equals 100% fee.
    /// The function enforces fee limits; `newFeePercentage` must be within the predefined 0-`MAX_TRANSFER_FEE` bounds.
    /// If the custom fee was previously disabled or set to a different value, this operation schedules the new fee to
    /// take effect after the delay, enabling it if necessary.
    /// Emits a `CustomTransferFeeChange` event upon successful execution.
    ///
    /// Requirements:
    /// - Caller must be the contract owner.
    /// - `newFeePercentage` must be within the range limited by `MAX_TRANSFER_FEE`.
    ///
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @param newFeePercentage The new transfer fee percentage to be applied, expressed in ether terms (18 decimal
    /// places) where 1 ether represents 100%.
    function scheduleCustomTransferFee(address underlyingToken, uint64 newFeePercentage) external;

    /// @notice Sets a new custom claim fee value for a specific underlying token, to be enabled and take effect
    /// after 1 hour from the time of this transaction.
    ///
    /// @dev Allows the contract owner to modify the claim fee associated with a specific underlying token.
    /// The new fee becomes effective after a delay of 1 hour, aiming to provide a buffer for users to be aware of the
    /// upcoming fee change.
    /// This function updates the fee and schedules its activation, ensuring transparency and predictability in fee
    /// adjustments.
    /// The fee is specified in wei, allowing for granular control over the fee structure. Emits a
    /// `CustomClaimFeeChange` event upon successful fee update.
    ///
    /// Requirements:
    /// - The caller must have owner privileges to execute this function.
    ///
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @param newFeeValue The new claim fee amount to be set, in wei, to replace the current fee after the specified
    /// delay.
    function scheduleCustomClaimFee(address underlyingToken, uint64 newFeeValue) external;
    /// @notice Enables or disables the custom creation fee for a given underlying token, with the change taking effect
    /// after 1 hour.
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @param enable True to enable the fee, false to disable it.
    function toggleCustomCreationFee(address underlyingToken, bool enable) external;

    /// @notice Enables or disables the custom transfer fee for a given underlying token, to take effect after 1 hour.
    ///
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @param enable True to enable the fee, false to disable it.
    function toggleCustomTransferFee(address underlyingToken, bool enable) external;

    /// @notice Enables or disables the custom claim fee for a given underlying token, with the change taking effect
    /// after 1 hour.
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @param enable True to enable the fee, false to disable it.
    function toggleCustomClaimFee(address underlyingToken, bool enable) external;

    /// @dev Exposes the minimum transfer fee.
    function minTransferFee() external pure returns (uint64);

    /// @dev Exposes the maximum transfer fee.
    function maxTransferFee() external pure returns (uint64);

    /// @notice Exposes the `FeeData.feeCollector` to users.
    function feeCollector() external view returns (address);

    /// @notice Retrieves the current global creation fee to users.
    function globalCreationFee() external view returns (uint64);

    /// @notice Retrieves the current global transfer fee percentage to users.
    function globalTransferFee() external view returns (uint64);

    /// @notice Retrieves the current global claim fee to users.
    function globalClaimFee() external view returns (uint64);

    /// @notice Returns the current creation fee for a specific underlying token, considering any pending updates.
    /// @param underlyingToken Address of the `underlyingToken`.
    function creationFeeData(address underlyingToken)
        external
        view
        override
        returns (address feeCollectorAddress, uint64 creationFeeValue);

    /// @notice Returns the current transfer fee for a specific underlying token, considering any pending updates.
    /// @param underlyingToken Address of the `underlyingToken`.
    function transferFeeData(address underlyingToken)
        external
        view
        override
        returns (address feeCollectorAddress, uint64 transferFeePercentage);

    /// @notice Returns the current claim fee for a specific underlying token, considering any pending updates.
    /// @param underlyingToken Address of the `underlyingToken`.
    function claimFeeData(address underlyingToken)
        external
        view
        override
        returns (address feeCollectorAddress, uint64 claimFeeValue);
}

// SPDX-License-Identifier: None
// Unvest Contracts (last updated v3.0.0) (interfaces/IFeeManager.sol)
pragma solidity ^0.8.24;

/// @title IFeeManager
/// @dev Interface that describes the struct and accessor function for the data related to the collection of fees.
interface IFeeManager {
    /// @dev The `FeeData` struct is used to store fee configurations such as the collection address and fee amounts for
    /// various transaction types in the contract.
    struct FeeData {
        /// @notice The address designated to collect fees.
        /// @dev This address is responsible for receiving fees generated from various sources.
        address feeCollector;
        /// @notice The fixed fee amount required to be sent as value with each `createVestingToken` operation.
        /// @dev `creationFee` is denominated in the smallest unit of the token. It must be sent as the transaction
        /// value during the execution of the payable `createVestingToken` function.
        uint64 creationFee;
        /// @notice The transfer fee expressed in ether, where 0.01 ether corresponds to a 1% fee.
        /// @dev `transferFeePercentage` is not in basis points but in ether units, with each ether unit representing a
        /// percentage of the transaction value to be collected as a fee. This structure allows for flexible and easily
        /// understandable fee calculations for `transfer` and `transferFrom` operations.
        uint64 transferFeePercentage;
        /// @notice The fixed fee amount required to be sent as value with each `claim` operation.
        /// @dev `claimFee` is denominated in the smallest unit of the token. It must be sent as the transaction value
        /// during the execution of the payable `claim` function.
        uint64 claimFee;
    }

    /// @dev Stores global fee data upcoming change and timestamp for that change.
    struct UpcomingFeeData {
        /// @notice The new fee value in wei to be applied at `valueChangeAt`.
        uint64 nextValue;
        /// @notice Timestamp at which a new fee value becomes effective.
        uint64 valueChangeAt;
    }

    /// @dev Stores custom fee data, including its current state, upcoming changes, and the timestamps for those
    /// changes.
    struct CustomFeeData {
        /// @notice Indicates if the custom fee is currently enabled.
        bool isEnabled;
        /// @notice The current fee value in wei.
        uint64 value;
        /// @notice The new fee value in wei to be applied at `valueChangeAt`.
        uint64 nextValue;
        /// @notice Timestamp at which a new fee value becomes effective.
        uint64 valueChangeAt;
        /// @notice Indicates the future state of `isEnabled` after `statusChangeAt`.
        bool nextEnableState;
        /// @notice Timestamp at which the change to `isEnabled` becomes effective.
        uint64 statusChangeAt;
    }

    /// @notice Exposes the creation fee for new `VestingToken`s deployments.
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @dev Enabled custom fees overrides the global creation fee.
    function creationFeeData(address underlyingToken)
        external
        view
        returns (address feeCollector, uint64 creationFeeValue);

    /// @notice Exposes the transfer fee for `VestingToken`s to consume.
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @dev Enabled custom fees overrides the global transfer fee.
    function transferFeeData(address underlyingToken)
        external
        view
        returns (address feeCollector, uint64 transferFeePercentage);

    /// @notice Exposes the claim fee for `VestingToken`s to consume.
    /// @param underlyingToken Address of the `underlyingToken`.
    /// @dev Enabled custom fees overrides the global claim fee.
    function claimFeeData(address underlyingToken) external view returns (address feeCollector, uint64 claimFeeValue);
}

File 8 of 9 : IVestingToken.sol
// SPDX-License-Identifier: None
// Unvest Contracts (last updated v3.0.0) (interfaces/IVestingToken.sol)
pragma solidity ^0.8.24;

/// @title IVestingToken
/// @dev Interface that describes the Milestone struct and initialize function so the `VestingTokenFactory` knows how to
/// initialize the `VestingToken`.
interface IVestingToken {
    /// @dev Ramps describes how the periods between release tokens.
    ///     - Cliff releases nothing until the end of the period.
    ///     - Linear releases tokens every second according to a linear slope.
    ///
    /// (0) Cliff             (1) Linear
    ///  |                     |
    ///  |        _____        |        _____
    ///  |       |             |       /
    ///  |       |             |      /
    ///  |_______|_____        |_____/_______
    ///      T0   T1               T0   T1
    ///
    enum Ramp {
        Cliff,
        Linear
    }

    /// @dev `timestamp` represents a moment in time when this Milestone is considered expired.
    /// @dev `ramp` defines the behaviour of the release of tokens in period between the previous Milestone and the
    /// current one.
    /// @dev `percentage` is the percentage of tokens that should be released once this Milestone has expired.
    struct Milestone {
        uint64 timestamp;
        Ramp ramp;
        uint64 percentage;
    }

    /// @notice Initializes the contract by setting up the ERC20 variables, the `underlyingToken`, and the
    /// `milestonesArray` information.
    ///
    /// @param name                   The token collection name.
    /// @param symbol                 The token collection symbol.
    /// @param underlyingTokenAddress The ERC20 token that will be held by this contract.
    /// @param milestonesArray        Array of all Milestones for this Contract's lifetime.
    function initialize(
        string memory name,
        string memory symbol,
        address underlyingTokenAddress,
        Milestone[] calldata milestonesArray
    )
        external;
}

File 9 of 9 : Errors.sol
// SPDX-License-Identifier: None
// Unvest Contracts (last updated v3.0.0) (libraries/Errors.sol)
pragma solidity ^0.8.24;

/// @title Errors Library
/// @notice Provides custom errors for VestingTokenFactory and VestingToken contracts.
library Errors {
    /*//////////////////////////////////////////////////////
                      VestingTokenFactory
    //////////////////////////////////////////////////////*/

    /// @notice Error to indicate that an address cannot be the zero address.
    error AddressCanNotBeZero();

    /// @notice Error to indicate that deployment of a contract failed.
    error FailedToDeploy();

    /// @notice Error to indicate that a fee is out of the accepted range.
    error FeeOutOfRange();

    /// @notice Error to indicate that the creation fee is insufficient.
    error InsufficientCreationFee();

    /// @notice Error to indicate an unsuccessful transfer of the creation fee.
    error UnsuccessfulCreationFeeTransfer();

    /*//////////////////////////////////////////////////////
                      VestingToken
    //////////////////////////////////////////////////////*/

    /// @notice Error to indicate that the minimum number of milestones has not been reached.
    error MinMilestonesNotReached();

    /// @notice Error to indicate that the maximum number of milestones has been exceeded.
    error MaxAllowedMilestonesHit();

    /// @notice Error to indicate that the claimable amount of an import is greater than expected.
    error ClaimableAmountOfImportIsGreaterThanExpected();

    /// @notice Error to indicate that equal percentages are only allowed before setting up linear milestones.
    error EqualPercentagesOnlyAllowedBeforeLinear();

    /// @notice Error to indicate that the sum of all individual amounts is not equal to the `totalAmount`.
    error InvalidTotalAmount();

    /// @notice Error to indicate that input arrays must have the same length.
    error InputArraysMustHaveSameLength();

    /// @notice Error to indicate that the last percentage in a milestone must be 100.
    error LastPercentageMustBe100();

    /// @notice Error to indicate that milestone percentages are not sorted in ascending order.
    error MilestonePercentagesNotSorted();

    /// @notice Error to indicate that milestone timestamps are not sorted in ascending chronological order.
    error MilestoneTimestampsNotSorted();

    /// @notice Error to indicate that there are more than two equal percentages, which is not allowed.
    error MoreThanTwoEqualPercentages();

    /// @notice Error to indicate that only the last percentage in a series can be 100.
    error OnlyLastPercentageCanBe100();

    /// @notice Error to indicate that the amount unlocked is greater than expected.
    error UnlockedIsGreaterThanExpected();

    /// @notice Error to indicate an unsuccessful fetch of token balance.
    error UnsuccessfulFetchOfTokenBalance();

    /// @notice Error to indicate that the claim fee provided does not match the expected claim fee.
    error IncorrectClaimFee();

    /// @notice Error to indicate an unsuccessful transfer of the claim fee.
    error UnsuccessfulClaimFeeTransfer();

    /// @notice Error to indicate that there is no balance available to claim.
    error NoClaimableAmount();
}

Settings
{
  "viaIR": false,
  "optimizer": {
    "runs": 10000,
    "enabled": true
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {},
  "remappings": [
    "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
    "@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
    "@prb/test/=node_modules/@prb/test/",
    "forge-std/=node_modules/forge-std/",
    "@sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "hardhat/=node_modules/hardhat/",
    "solmate/=node_modules/solmate/"
  ]
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"implementationAddress","type":"address"},{"internalType":"address","name":"feeCollectorAddress","type":"address"},{"internalType":"uint64","name":"creationFeeValue","type":"uint64"},{"internalType":"uint64","name":"transferFeePercentage","type":"uint64"},{"internalType":"uint64","name":"claimFeeValue","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressCanNotBeZero","type":"error"},{"inputs":[],"name":"FailedToDeploy","type":"error"},{"inputs":[],"name":"FeeOutOfRange","type":"error"},{"inputs":[],"name":"InsufficientCreationFee","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"uint64","name":"claimFeeValue","type":"uint64"}],"name":"CustomClaimFeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"bool","name":"enable","type":"bool"}],"name":"CustomClaimFeeToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"uint64","name":"creationFeeValue","type":"uint64"}],"name":"CustomCreationFeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"bool","name":"enable","type":"bool"}],"name":"CustomCreationFeeToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"uint64","name":"transferFeePercentage","type":"uint64"}],"name":"CustomTransferFeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"bool","name":"enable","type":"bool"}],"name":"CustomTransferFeeToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeCollector","type":"address"}],"name":"FeeCollectorChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"claimFeeValue","type":"uint64"}],"name":"GlobalClaimFeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"creationFeeValue","type":"uint64"}],"name":"GlobalCreationFeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"transferFeePercentage","type":"uint64"}],"name":"GlobalTransferFeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","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":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"address","name":"vestingToken","type":"address"}],"name":"VestingTokenCreated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"}],"name":"claimFeeData","outputs":[{"internalType":"address","name":"feeCollectorAddress","type":"address"},{"internalType":"uint64","name":"claimFeeValue","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"underlyingTokenAddress","type":"address"},{"components":[{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"enum IVestingToken.Ramp","name":"ramp","type":"uint8"},{"internalType":"uint64","name":"percentage","type":"uint64"}],"internalType":"struct IVestingToken.Milestone[]","name":"milestonesArray","type":"tuple[]"}],"name":"createVestingToken","outputs":[{"internalType":"address","name":"vestingToken","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"}],"name":"creationFeeData","outputs":[{"internalType":"address","name":"feeCollectorAddress","type":"address"},{"internalType":"uint64","name":"creationFeeValue","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalClaimFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalCreationFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalTransferFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTransferFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"minTransferFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextSalt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint64","name":"newFeeValue","type":"uint64"}],"name":"scheduleCustomClaimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint64","name":"newFeeValue","type":"uint64"}],"name":"scheduleCustomCreationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"uint64","name":"newFeePercentage","type":"uint64"}],"name":"scheduleCustomTransferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newFeeValue","type":"uint64"}],"name":"scheduleGlobalClaimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newFeeValue","type":"uint64"}],"name":"scheduleGlobalCreationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newFeePercentage","type":"uint64"}],"name":"scheduleGlobalTransferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"toggleCustomClaimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"toggleCustomCreationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"toggleCustomTransferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"}],"name":"transferFeeData","outputs":[{"internalType":"address","name":"feeCollectorAddress","type":"address"},{"internalType":"uint64","name":"transferFeePercentage","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingToken","type":"address"}],"name":"vestingTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b5060405162002778380380620027788339810160408190526200003491620004fe565b33806200005c57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b620000678162000129565b506001600160a01b0385166200009057604051630191b71b60e61b815260040160405180910390fd5b46600a8190556001600160a01b038616608052620000ae8562000147565b620000b984620001c3565b620000c483620002a5565b620000cf8262000367565b50600280546001600160401b03948516600160a01b02600160a01b600160e01b03199091161790556003805491841668010000000000000000026001600160801b0319909216929093169190911717905550620005969050565b600180546001600160a01b0319169055620001448162000448565b50565b6200015162000498565b6001600160a01b0381166200017957604051630191b71b60e61b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517f3908cc4801f68d354a4e28f598ec87870f4b8a4b9a945c81b641d1b677575d5290600090a250565b620001cd62000498565b60045442680100000000000000009091046001600160401b031611620002195760045460028054600160a01b600160e01b0319166001600160401b03909216600160a01b029190911790555b600480546001600160401b0319166001600160401b0383161790556200024242610e106200056e565b60048054600160401b600160801b031916680100000000000000006001600160401b039384160217905560405190821681527fdc663ce9869376cda68a5429f71cfda2f85e38946169c7c5dd9a934bd65b9be2906020015b60405180910390a150565b620002af62000498565b66b1a2bc2ec500006001600160401b0382161115620002e157604051630c8249ad60e01b815260040160405180910390fd5b600580546001600160401b0319166001600160401b0383161790556200030a42610e106200056e565b60058054600160401b600160801b031916680100000000000000006001600160401b039384160217905560405190821681527f7cbfd2355a19b093f09fca925a0ac09d89cc7ade0571552291ad3b29c4711846906020016200029a565b6200037162000498565b60065442680100000000000000009091046001600160401b031611620003c25760065460038054600160401b600160801b0319166001600160401b0390921668010000000000000000029190911790555b600680546001600160401b0319166001600160401b038316179055620003eb42610e106200056e565b60068054600160401b600160801b031916680100000000000000006001600160401b039384160217905560405190821681527f077e520e1de8a2228d35654310735e95867cc81ce703fa6af848266001cc974e906020016200029a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b03163314620004c75760405163118cdaa760e01b815233600482015260240162000053565b565b80516001600160a01b0381168114620004e157600080fd5b919050565b80516001600160401b0381168114620004e157600080fd5b600080600080600060a086880312156200051757600080fd5b6200052286620004c9565b94506200053260208701620004c9565b93506200054260408701620004e6565b92506200055260608701620004e6565b91506200056260808701620004e6565b90509295509295909350565b808201808211156200059057634e487b7160e01b600052601160045260246000fd5b92915050565b6080516121bf620005b96000396000818161033201526112e901526121bf6000f3fe6080604052600436106101b75760003560e01c8063848b170b116100ec578063b17675df1161008a578063de38279811610064578063de38279814610524578063e30c397814610544578063f2fde38b1461056f578063f6362c241461058f57600080fd5b8063b17675df146104c4578063b9e45a77146104e4578063c415b95c146104f957600080fd5b80638da5cb5b116100c65780638da5cb5b14610452578063a364fc281461047d578063a42dce8014610490578063ad7dd0e9146104b057600080fd5b8063848b170b146103f057806385a442fb1461041057806387d533481461043057600080fd5b80634b2675ef1161015957806367f5a0fe1161013357806367f5a0fe14610379578063715018a614610399578063763b6d9e146103ae57806379ba5097146103db57600080fd5b80634b2675ef146102e057806352a21938146103005780635c60da1b1461032057600080fd5b806323a59f721161019557806323a59f7214610266578063243cfc5214610286578063297ab84d146102a05780633cd43ad6146102c057600080fd5b806305b84d0e146101bc578063092a409e146101de5780630f3db9da14610211575b600080fd5b3480156101c857600080fd5b506101dc6101d7366004611e37565b6105a4565b005b3480156101ea57600080fd5b506101f3610757565b60405167ffffffffffffffff90911681526020015b60405180910390f35b34801561021d57600080fd5b5061023161022c366004611e6a565b6107b4565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835267ffffffffffffffff909116602083015201610208565b34801561027257600080fd5b506101dc610281366004611e85565b6108b4565b34801561029257600080fd5b5066b1a2bc2ec500006101f3565b3480156102ac57600080fd5b506102316102bb366004611e6a565b610a0d565b3480156102cc57600080fd5b506101dc6102db366004611e85565b610b19565b3480156102ec57600080fd5b506102316102fb366004611e6a565b610c69565b34801561030c57600080fd5b506101dc61031b366004611ec1565b610d5f565b34801561032c57600080fd5b506103547f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610208565b34801561038557600080fd5b506101dc610394366004611e85565b610e54565b3480156103a557600080fd5b506101dc610fa4565b3480156103ba57600080fd5b506103ce6103c9366004611e6a565b610fb8565b6040516102089190611edc565b3480156103e757600080fd5b506101dc611048565b3480156103fc57600080fd5b506101dc61040b366004611ec1565b6110c4565b34801561041c57600080fd5b506101dc61042b366004611ec1565b6111ce565b34801561043c57600080fd5b506101dc604051600a8054825260209091209055565b34801561045e57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610354565b61035461048b366004611f7f565b6112e4565b34801561049c57600080fd5b506101dc6104ab366004611e6a565b6114f7565b3480156104bc57600080fd5b5060006101f3565b3480156104d057600080fd5b506101dc6104df366004611e37565b6115bb565b3480156104f057600080fd5b506101f3611764565b34801561050557600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff16610354565b34801561053057600080fd5b506101dc61053f366004611e37565b6117b5565b34801561055057600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610354565b34801561057b57600080fd5b506101dc61058a366004611e6a565b6119a9565b34801561059b57600080fd5b506101f3611a59565b6105ac611a9e565b73ffffffffffffffffffffffffffffffffffffffff821660009081526009602052604090208054427101000000000000000000000000000000000090910467ffffffffffffffff161161063e57805467ffffffffffffffff6901000000000000000000820416610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9091161781555b600061064c42610e1061205d565b825460018401805467ffffffffffffffff84811667ffffffffffffffff19909216821790925571010000000000000000000000000000000000027fffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffff918716690100000000000000000081027fffffffffffff00ffffffffffffffff0000000000000000ffffffffffffffffff90941693909317790100000000000000000000000000000000000000000000000000179190911617845560405190815290915073ffffffffffffffffffffffffffffffffffffffff8516907f10e7851dccd0aa958c0427eab0f87de98322a4c75e412170128b5da28ff431f9906020015b60405180910390a250505050565b60045460009068010000000000000000900467ffffffffffffffff164210156107a3575060025474010000000000000000000000000000000000000000900467ffffffffffffffff1690565b5060045467ffffffffffffffff1690565b60025460035460408051808201825260065467ffffffffffffffff80821683526801000000000000000091829004811660208085019190915273ffffffffffffffffffffffffffffffffffffffff888116600090815260098352868120875160c081018952815460ff808216151583526101008204881696830196909652690100000000000000000081048716998201999099527101000000000000000000000000000000000089048616606082015279010000000000000000000000000000000000000000000000000090980490931615156080880152600190920154831660a087015290961695946108ad94929004169190611af1565b9050915091565b6108bc611a9e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260096020526040902060018101544267ffffffffffffffff9091161161094457805460ff79010000000000000000000000000000000000000000000000000082041615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161781555b80547fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff167901000000000000000000000000000000000000000000000000008315150217815561099642610e1061205d565b60018201805467ffffffffffffffff191667ffffffffffffffff92909216919091179055604051821515815273ffffffffffffffffffffffffffffffffffffffff8416907f817e4baa0fe0b5a470cf9d688c01f6e1b916093a935332d3887f7c126c62f2a3906020015b60405180910390a2505050565b60025460408051808201825260045467ffffffffffffffff808216835268010000000000000000909104811660208084019190915273ffffffffffffffffffffffffffffffffffffffff868116600090815260078352858120865160c081018852815460ff808216151583526101008204881696830196909652690100000000000000000081048716988201989098527101000000000000000000000000000000000088048616606082015279010000000000000000000000000000000000000000000000000090970490931615156080870152600190920154831660a086015285169490936108ad937401000000000000000000000000000000000000000090920490921691611af1565b610b21611a9e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260076020526040902060018101544267ffffffffffffffff90911611610ba957805460ff79010000000000000000000000000000000000000000000000000082041615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161781555b80547fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff1679010000000000000000000000000000000000000000000000000083151502178155610bfb42610e1061205d565b60018201805467ffffffffffffffff191667ffffffffffffffff92909216919091179055604051821515815273ffffffffffffffffffffffffffffffffffffffff8416907f3214db9d0368c605ee7912e17d6ce3e2b8f763f75eef779b37447f185b7fdd5c90602001610a00565b60025460035460408051808201825260055467ffffffffffffffff808216835268010000000000000000909104811660208084019190915273ffffffffffffffffffffffffffffffffffffffff878116600090815260088352858120865160c081018852815460ff808216151583526101008204881696830196909652690100000000000000000081048716988201989098527101000000000000000000000000000000000088048616606082015279010000000000000000000000000000000000000000000000000090970490931615156080870152600190920154831660a086015290951694936108ad9391169190611af1565b610d67611a9e565b66b1a2bc2ec5000067ffffffffffffffff82161115610db2576040517f0c8249ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff191667ffffffffffffffff8316179055610ddb42610e1061205d565b600580547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560405190821681527f7cbfd2355a19b093f09fca925a0ac09d89cc7ade0571552291ad3b29c4711846906020015b60405180910390a150565b610e5c611a9e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040902060018101544267ffffffffffffffff90911611610ee457805460ff79010000000000000000000000000000000000000000000000000082041615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161781555b80547fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff1679010000000000000000000000000000000000000000000000000083151502178155610f3642610e1061205d565b60018201805467ffffffffffffffff191667ffffffffffffffff92909216919091179055604051821515815273ffffffffffffffffffffffffffffffffffffffff8416907f1c5b73930be04bbb372581b795b09eb3ff401d7a7833985e5d58e8929275d1b590602001610a00565b610fac611a9e565b610fb66000611b94565b565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600b602090815260409182902080548351818402810184019094528084526060939283018282801561103c57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611011575b50505050509050919050565b600154339073ffffffffffffffffffffffffffffffffffffffff1681146110b8576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b6110c181611b94565b50565b6110cc611a9e565b600654426801000000000000000090910467ffffffffffffffff161161113357600654600380547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1667ffffffffffffffff90921668010000000000000000029190911790555b6006805467ffffffffffffffff191667ffffffffffffffff831617905561115c42610e1061205d565b600680547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560405190821681527f077e520e1de8a2228d35654310735e95867cc81ce703fa6af848266001cc974e90602001610e49565b6111d6611a9e565b600454426801000000000000000090910467ffffffffffffffff161161124957600454600280547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff1667ffffffffffffffff90921674010000000000000000000000000000000000000000029190911790555b6004805467ffffffffffffffff191667ffffffffffffffff831617905561127242610e1061205d565b600480547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560405190821681527fdc663ce9869376cda68a5429f71cfda2f85e38946169c7c5dd9a934bd65b9be290602001610e49565b6000807f000000000000000000000000000000000000000000000000000000000000000090506000600a549050763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b1760205280603760096000f5925073ffffffffffffffffffffffffffffffffffffffff83166113a3576040517f2628e9f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113b8604051600a8054825260209091209055565b6113c186611bc5565b6040517f3e2a347300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690633e2a34739061141f908d908d908d908d908d908d908d906004016120e6565b600060405180830381600087803b15801561143957600080fd5b505af115801561144d573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff8681166000818152600b6020908152604080832080546001810182559084529282902090920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169488169485179055905192835290917f9020e4abe651b6323f3420a1335588cd97e6c1407ba23ab0b00ca8c5db73bb65910160405180910390a25050979650505050505050565b6114ff611a9e565b73ffffffffffffffffffffffffffffffffffffffff811661154c576040517f646dc6c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f3908cc4801f68d354a4e28f598ec87870f4b8a4b9a945c81b641d1b677575d5290600090a250565b6115c3611a9e565b73ffffffffffffffffffffffffffffffffffffffff821660009081526007602052604090208054427101000000000000000000000000000000000090910467ffffffffffffffff161161165557805467ffffffffffffffff6901000000000000000000820416610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9091161781555b600061166342610e1061205d565b825460018401805467ffffffffffffffff84811667ffffffffffffffff19909216821790925571010000000000000000000000000000000000027fffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffff918716690100000000000000000081027fffffffffffff00ffffffffffffffff0000000000000000ffffffffffffffffff90941693909317790100000000000000000000000000000000000000000000000000179190911617845560405190815290915073ffffffffffffffffffffffffffffffffffffffff8516907f1887aaab88dd2c41fc815de278c75e221e1f988e95b42872fddba4cbddd87e2c90602001610749565b60065460009068010000000000000000900467ffffffffffffffff164210156117a4575060035468010000000000000000900467ffffffffffffffff1690565b5060065467ffffffffffffffff1690565b6117bd611a9e565b66b1a2bc2ec5000067ffffffffffffffff82161115611808576040517f0c8249ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090208054427101000000000000000000000000000000000090910467ffffffffffffffff161161189a57805467ffffffffffffffff6901000000000000000000820416610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9091161781555b60006118a842610e1061205d565b825460018401805467ffffffffffffffff84811667ffffffffffffffff19909216821790925571010000000000000000000000000000000000027fffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffff918716690100000000000000000081027fffffffffffff00ffffffffffffffff0000000000000000ffffffffffffffffff90941693909317790100000000000000000000000000000000000000000000000000179190911617845560405190815290915073ffffffffffffffffffffffffffffffffffffffff8516907f8046c16fd658a847402dd2fd9fe79b7fa1ba0bff750def79f149830b9840d71090602001610749565b6119b1611a9e565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155611a1460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60055460009068010000000000000000900467ffffffffffffffff16421015611a8d575060035467ffffffffffffffff1690565b5060055467ffffffffffffffff1690565b60005473ffffffffffffffffffffffffffffffffffffffff163314610fb6576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016110af565b60008160a0015167ffffffffffffffff164210611b4457816080015115611b3f57816060015167ffffffffffffffff16421015611b32578160200151611b38565b81604001515b9050611b8d565b611b6b565b815115611b6b57816060015167ffffffffffffffff16421015611b32578160200151611b38565b826020015167ffffffffffffffff16421015611b875783611b8a565b82515b90505b9392505050565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556110c181611d81565b60025460408051808201825260045467ffffffffffffffff808216835268010000000000000000909104811660208084019190915273ffffffffffffffffffffffffffffffffffffffff8616600090815260078252848120855160c081018752815460ff808216151583526101008204871695830195909552690100000000000000000081048616978201979097527101000000000000000000000000000000000087048516606082015279010000000000000000000000000000000000000000000000000090960490921615156080860152600190910154821660a085015293611ccd93740100000000000000000000000000000000000000009091049091169190611af1565b905067ffffffffffffffff811615611d7d578067ffffffffffffffff16341015611d23576040517f535b747000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517ff16835af000000000000000000000000000000000000000000000000000000009173ffffffffffffffffffffffffffffffffffffffff1690600080808034865af180611d7857838252600482fd5b505050505b5050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611e1a57600080fd5b919050565b803567ffffffffffffffff81168114611e1a57600080fd5b60008060408385031215611e4a57600080fd5b611e5383611df6565b9150611e6160208401611e1f565b90509250929050565b600060208284031215611e7c57600080fd5b611b8d82611df6565b60008060408385031215611e9857600080fd5b611ea183611df6565b915060208301358015158114611eb657600080fd5b809150509250929050565b600060208284031215611ed357600080fd5b611b8d82611e1f565b6020808252825182820181905260009190848201906040850190845b81811015611f2a57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611ef8565b50909695505050505050565b60008083601f840112611f4857600080fd5b50813567ffffffffffffffff811115611f6057600080fd5b602083019150836020828501011115611f7857600080fd5b9250929050565b60008060008060008060006080888a031215611f9a57600080fd5b873567ffffffffffffffff80821115611fb257600080fd5b611fbe8b838c01611f36565b909950975060208a0135915080821115611fd757600080fd5b611fe38b838c01611f36565b9097509550859150611ff760408b01611df6565b945060608a013591508082111561200d57600080fd5b818a0191508a601f83011261202157600080fd5b81358181111561203057600080fd5b8b602060608302850101111561204557600080fd5b60208301945080935050505092959891949750929550565b80820180821115612097577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6080815260006120fa60808301898b61209d565b6020838203602085015261210f82898b61209d565b9150604073ffffffffffffffffffffffffffffffffffffffff8816604086015260608584036060870152838785526020850190508894506000805b8981101561219e5767ffffffffffffffff8061216589611e1f565b1684528688013560028110612178578384fd5b8488015280612188898801611e1f565b168487015250958301959183019160010161214a565b50909e9d505050505050505050505050505056fea164736f6c6343000818000a0000000000000000000000005d6eda5f757b382cc2050ad5a4608151040fc95b0000000000000000000000009bf8cf33916403f2b66d3390e50d1931e18ae89400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058d15e176280000000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106101b75760003560e01c8063848b170b116100ec578063b17675df1161008a578063de38279811610064578063de38279814610524578063e30c397814610544578063f2fde38b1461056f578063f6362c241461058f57600080fd5b8063b17675df146104c4578063b9e45a77146104e4578063c415b95c146104f957600080fd5b80638da5cb5b116100c65780638da5cb5b14610452578063a364fc281461047d578063a42dce8014610490578063ad7dd0e9146104b057600080fd5b8063848b170b146103f057806385a442fb1461041057806387d533481461043057600080fd5b80634b2675ef1161015957806367f5a0fe1161013357806367f5a0fe14610379578063715018a614610399578063763b6d9e146103ae57806379ba5097146103db57600080fd5b80634b2675ef146102e057806352a21938146103005780635c60da1b1461032057600080fd5b806323a59f721161019557806323a59f7214610266578063243cfc5214610286578063297ab84d146102a05780633cd43ad6146102c057600080fd5b806305b84d0e146101bc578063092a409e146101de5780630f3db9da14610211575b600080fd5b3480156101c857600080fd5b506101dc6101d7366004611e37565b6105a4565b005b3480156101ea57600080fd5b506101f3610757565b60405167ffffffffffffffff90911681526020015b60405180910390f35b34801561021d57600080fd5b5061023161022c366004611e6a565b6107b4565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835267ffffffffffffffff909116602083015201610208565b34801561027257600080fd5b506101dc610281366004611e85565b6108b4565b34801561029257600080fd5b5066b1a2bc2ec500006101f3565b3480156102ac57600080fd5b506102316102bb366004611e6a565b610a0d565b3480156102cc57600080fd5b506101dc6102db366004611e85565b610b19565b3480156102ec57600080fd5b506102316102fb366004611e6a565b610c69565b34801561030c57600080fd5b506101dc61031b366004611ec1565b610d5f565b34801561032c57600080fd5b506103547f0000000000000000000000005d6eda5f757b382cc2050ad5a4608151040fc95b81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610208565b34801561038557600080fd5b506101dc610394366004611e85565b610e54565b3480156103a557600080fd5b506101dc610fa4565b3480156103ba57600080fd5b506103ce6103c9366004611e6a565b610fb8565b6040516102089190611edc565b3480156103e757600080fd5b506101dc611048565b3480156103fc57600080fd5b506101dc61040b366004611ec1565b6110c4565b34801561041c57600080fd5b506101dc61042b366004611ec1565b6111ce565b34801561043c57600080fd5b506101dc604051600a8054825260209091209055565b34801561045e57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610354565b61035461048b366004611f7f565b6112e4565b34801561049c57600080fd5b506101dc6104ab366004611e6a565b6114f7565b3480156104bc57600080fd5b5060006101f3565b3480156104d057600080fd5b506101dc6104df366004611e37565b6115bb565b3480156104f057600080fd5b506101f3611764565b34801561050557600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff16610354565b34801561053057600080fd5b506101dc61053f366004611e37565b6117b5565b34801561055057600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610354565b34801561057b57600080fd5b506101dc61058a366004611e6a565b6119a9565b34801561059b57600080fd5b506101f3611a59565b6105ac611a9e565b73ffffffffffffffffffffffffffffffffffffffff821660009081526009602052604090208054427101000000000000000000000000000000000090910467ffffffffffffffff161161063e57805467ffffffffffffffff6901000000000000000000820416610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9091161781555b600061064c42610e1061205d565b825460018401805467ffffffffffffffff84811667ffffffffffffffff19909216821790925571010000000000000000000000000000000000027fffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffff918716690100000000000000000081027fffffffffffff00ffffffffffffffff0000000000000000ffffffffffffffffff90941693909317790100000000000000000000000000000000000000000000000000179190911617845560405190815290915073ffffffffffffffffffffffffffffffffffffffff8516907f10e7851dccd0aa958c0427eab0f87de98322a4c75e412170128b5da28ff431f9906020015b60405180910390a250505050565b60045460009068010000000000000000900467ffffffffffffffff164210156107a3575060025474010000000000000000000000000000000000000000900467ffffffffffffffff1690565b5060045467ffffffffffffffff1690565b60025460035460408051808201825260065467ffffffffffffffff80821683526801000000000000000091829004811660208085019190915273ffffffffffffffffffffffffffffffffffffffff888116600090815260098352868120875160c081018952815460ff808216151583526101008204881696830196909652690100000000000000000081048716998201999099527101000000000000000000000000000000000089048616606082015279010000000000000000000000000000000000000000000000000090980490931615156080880152600190920154831660a087015290961695946108ad94929004169190611af1565b9050915091565b6108bc611a9e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260096020526040902060018101544267ffffffffffffffff9091161161094457805460ff79010000000000000000000000000000000000000000000000000082041615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161781555b80547fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff167901000000000000000000000000000000000000000000000000008315150217815561099642610e1061205d565b60018201805467ffffffffffffffff191667ffffffffffffffff92909216919091179055604051821515815273ffffffffffffffffffffffffffffffffffffffff8416907f817e4baa0fe0b5a470cf9d688c01f6e1b916093a935332d3887f7c126c62f2a3906020015b60405180910390a2505050565b60025460408051808201825260045467ffffffffffffffff808216835268010000000000000000909104811660208084019190915273ffffffffffffffffffffffffffffffffffffffff868116600090815260078352858120865160c081018852815460ff808216151583526101008204881696830196909652690100000000000000000081048716988201989098527101000000000000000000000000000000000088048616606082015279010000000000000000000000000000000000000000000000000090970490931615156080870152600190920154831660a086015285169490936108ad937401000000000000000000000000000000000000000090920490921691611af1565b610b21611a9e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260076020526040902060018101544267ffffffffffffffff90911611610ba957805460ff79010000000000000000000000000000000000000000000000000082041615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161781555b80547fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff1679010000000000000000000000000000000000000000000000000083151502178155610bfb42610e1061205d565b60018201805467ffffffffffffffff191667ffffffffffffffff92909216919091179055604051821515815273ffffffffffffffffffffffffffffffffffffffff8416907f3214db9d0368c605ee7912e17d6ce3e2b8f763f75eef779b37447f185b7fdd5c90602001610a00565b60025460035460408051808201825260055467ffffffffffffffff808216835268010000000000000000909104811660208084019190915273ffffffffffffffffffffffffffffffffffffffff878116600090815260088352858120865160c081018852815460ff808216151583526101008204881696830196909652690100000000000000000081048716988201989098527101000000000000000000000000000000000088048616606082015279010000000000000000000000000000000000000000000000000090970490931615156080870152600190920154831660a086015290951694936108ad9391169190611af1565b610d67611a9e565b66b1a2bc2ec5000067ffffffffffffffff82161115610db2576040517f0c8249ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff191667ffffffffffffffff8316179055610ddb42610e1061205d565b600580547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560405190821681527f7cbfd2355a19b093f09fca925a0ac09d89cc7ade0571552291ad3b29c4711846906020015b60405180910390a150565b610e5c611a9e565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040902060018101544267ffffffffffffffff90911611610ee457805460ff79010000000000000000000000000000000000000000000000000082041615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161781555b80547fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff1679010000000000000000000000000000000000000000000000000083151502178155610f3642610e1061205d565b60018201805467ffffffffffffffff191667ffffffffffffffff92909216919091179055604051821515815273ffffffffffffffffffffffffffffffffffffffff8416907f1c5b73930be04bbb372581b795b09eb3ff401d7a7833985e5d58e8929275d1b590602001610a00565b610fac611a9e565b610fb66000611b94565b565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600b602090815260409182902080548351818402810184019094528084526060939283018282801561103c57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611011575b50505050509050919050565b600154339073ffffffffffffffffffffffffffffffffffffffff1681146110b8576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b6110c181611b94565b50565b6110cc611a9e565b600654426801000000000000000090910467ffffffffffffffff161161113357600654600380547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1667ffffffffffffffff90921668010000000000000000029190911790555b6006805467ffffffffffffffff191667ffffffffffffffff831617905561115c42610e1061205d565b600680547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560405190821681527f077e520e1de8a2228d35654310735e95867cc81ce703fa6af848266001cc974e90602001610e49565b6111d6611a9e565b600454426801000000000000000090910467ffffffffffffffff161161124957600454600280547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff1667ffffffffffffffff90921674010000000000000000000000000000000000000000029190911790555b6004805467ffffffffffffffff191667ffffffffffffffff831617905561127242610e1061205d565b600480547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560405190821681527fdc663ce9869376cda68a5429f71cfda2f85e38946169c7c5dd9a934bd65b9be290602001610e49565b6000807f0000000000000000000000005d6eda5f757b382cc2050ad5a4608151040fc95b90506000600a549050763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b1760205280603760096000f5925073ffffffffffffffffffffffffffffffffffffffff83166113a3576040517f2628e9f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113b8604051600a8054825260209091209055565b6113c186611bc5565b6040517f3e2a347300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690633e2a34739061141f908d908d908d908d908d908d908d906004016120e6565b600060405180830381600087803b15801561143957600080fd5b505af115801561144d573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff8681166000818152600b6020908152604080832080546001810182559084529282902090920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169488169485179055905192835290917f9020e4abe651b6323f3420a1335588cd97e6c1407ba23ab0b00ca8c5db73bb65910160405180910390a25050979650505050505050565b6114ff611a9e565b73ffffffffffffffffffffffffffffffffffffffff811661154c576040517f646dc6c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f3908cc4801f68d354a4e28f598ec87870f4b8a4b9a945c81b641d1b677575d5290600090a250565b6115c3611a9e565b73ffffffffffffffffffffffffffffffffffffffff821660009081526007602052604090208054427101000000000000000000000000000000000090910467ffffffffffffffff161161165557805467ffffffffffffffff6901000000000000000000820416610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9091161781555b600061166342610e1061205d565b825460018401805467ffffffffffffffff84811667ffffffffffffffff19909216821790925571010000000000000000000000000000000000027fffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffff918716690100000000000000000081027fffffffffffff00ffffffffffffffff0000000000000000ffffffffffffffffff90941693909317790100000000000000000000000000000000000000000000000000179190911617845560405190815290915073ffffffffffffffffffffffffffffffffffffffff8516907f1887aaab88dd2c41fc815de278c75e221e1f988e95b42872fddba4cbddd87e2c90602001610749565b60065460009068010000000000000000900467ffffffffffffffff164210156117a4575060035468010000000000000000900467ffffffffffffffff1690565b5060065467ffffffffffffffff1690565b6117bd611a9e565b66b1a2bc2ec5000067ffffffffffffffff82161115611808576040517f0c8249ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090208054427101000000000000000000000000000000000090910467ffffffffffffffff161161189a57805467ffffffffffffffff6901000000000000000000820416610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff9091161781555b60006118a842610e1061205d565b825460018401805467ffffffffffffffff84811667ffffffffffffffff19909216821790925571010000000000000000000000000000000000027fffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffff918716690100000000000000000081027fffffffffffff00ffffffffffffffff0000000000000000ffffffffffffffffff90941693909317790100000000000000000000000000000000000000000000000000179190911617845560405190815290915073ffffffffffffffffffffffffffffffffffffffff8516907f8046c16fd658a847402dd2fd9fe79b7fa1ba0bff750def79f149830b9840d71090602001610749565b6119b1611a9e565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155611a1460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60055460009068010000000000000000900467ffffffffffffffff16421015611a8d575060035467ffffffffffffffff1690565b5060055467ffffffffffffffff1690565b60005473ffffffffffffffffffffffffffffffffffffffff163314610fb6576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016110af565b60008160a0015167ffffffffffffffff164210611b4457816080015115611b3f57816060015167ffffffffffffffff16421015611b32578160200151611b38565b81604001515b9050611b8d565b611b6b565b815115611b6b57816060015167ffffffffffffffff16421015611b32578160200151611b38565b826020015167ffffffffffffffff16421015611b875783611b8a565b82515b90505b9392505050565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556110c181611d81565b60025460408051808201825260045467ffffffffffffffff808216835268010000000000000000909104811660208084019190915273ffffffffffffffffffffffffffffffffffffffff8616600090815260078252848120855160c081018752815460ff808216151583526101008204871695830195909552690100000000000000000081048616978201979097527101000000000000000000000000000000000087048516606082015279010000000000000000000000000000000000000000000000000090960490921615156080860152600190910154821660a085015293611ccd93740100000000000000000000000000000000000000009091049091169190611af1565b905067ffffffffffffffff811615611d7d578067ffffffffffffffff16341015611d23576040517f535b747000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517ff16835af000000000000000000000000000000000000000000000000000000009173ffffffffffffffffffffffffffffffffffffffff1690600080808034865af180611d7857838252600482fd5b505050505b5050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611e1a57600080fd5b919050565b803567ffffffffffffffff81168114611e1a57600080fd5b60008060408385031215611e4a57600080fd5b611e5383611df6565b9150611e6160208401611e1f565b90509250929050565b600060208284031215611e7c57600080fd5b611b8d82611df6565b60008060408385031215611e9857600080fd5b611ea183611df6565b915060208301358015158114611eb657600080fd5b809150509250929050565b600060208284031215611ed357600080fd5b611b8d82611e1f565b6020808252825182820181905260009190848201906040850190845b81811015611f2a57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611ef8565b50909695505050505050565b60008083601f840112611f4857600080fd5b50813567ffffffffffffffff811115611f6057600080fd5b602083019150836020828501011115611f7857600080fd5b9250929050565b60008060008060008060006080888a031215611f9a57600080fd5b873567ffffffffffffffff80821115611fb257600080fd5b611fbe8b838c01611f36565b909950975060208a0135915080821115611fd757600080fd5b611fe38b838c01611f36565b9097509550859150611ff760408b01611df6565b945060608a013591508082111561200d57600080fd5b818a0191508a601f83011261202157600080fd5b81358181111561203057600080fd5b8b602060608302850101111561204557600080fd5b60208301945080935050505092959891949750929550565b80820180821115612097577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6080815260006120fa60808301898b61209d565b6020838203602085015261210f82898b61209d565b9150604073ffffffffffffffffffffffffffffffffffffffff8816604086015260608584036060870152838785526020850190508894506000805b8981101561219e5767ffffffffffffffff8061216589611e1f565b1684528688013560028110612178578384fd5b8488015280612188898801611e1f565b168487015250958301959183019160010161214a565b50909e9d505050505050505050505050505056fea164736f6c6343000818000a

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

0000000000000000000000005d6eda5f757b382cc2050ad5a4608151040fc95b0000000000000000000000009bf8cf33916403f2b66d3390e50d1931e18ae89400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058d15e176280000000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : implementationAddress (address): 0x5D6EDa5f757b382cC2050AD5a4608151040FC95b
Arg [1] : feeCollectorAddress (address): 0x9Bf8cF33916403F2B66d3390E50d1931e18ae894
Arg [2] : creationFeeValue (uint64): 0
Arg [3] : transferFeePercentage (uint64): 25000000000000000
Arg [4] : claimFeeValue (uint64): 0

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000005d6eda5f757b382cc2050ad5a4608151040fc95b
Arg [1] : 0000000000000000000000009bf8cf33916403f2b66d3390e50d1931e18ae894
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 0000000000000000000000000000000000000000000000000058d15e17628000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000


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

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