ETH Price: $2,764.98 (+5.39%)

Contract

0xfF8697d8d2998d6AA2e09B405795C6F4BEeB0C81
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Redeem205911992024-08-23 12:07:5911 hrs ago1724414879IN
0xfF8697d8...4BEeB0C81
0 ETH0.000192823.71418108
Redeem205625012024-08-19 11:53:234 days ago1724068403IN
0xfF8697d8...4BEeB0C81
0 ETH0.000379426.46154407
Redeem205344352024-08-15 13:49:478 days ago1723729787IN
0xfF8697d8...4BEeB0C81
0 ETH0.000404236.88392698
Redeem205320522024-08-15 5:50:238 days ago1723701023IN
0xfF8697d8...4BEeB0C81
0 ETH0.000170394.09392917
Redeem205245722024-08-14 4:46:479 days ago1723610807IN
0xfF8697d8...4BEeB0C81
0 ETH0.000148223.56122454
Redeem205191902024-08-13 10:45:2310 days ago1723545923IN
0xfF8697d8...4BEeB0C81
0 ETH0.000233473.97599497
Redeem205061342024-08-11 15:02:1112 days ago1723388531IN
0xfF8697d8...4BEeB0C81
0 ETH0.000268714.57605954
Redeem204889402024-08-09 5:26:1114 days ago1723181171IN
0xfF8697d8...4BEeB0C81
0 ETH0.000085281.45241028
Redeem204676342024-08-06 6:07:3517 days ago1722924455IN
0xfF8697d8...4BEeB0C81
0 ETH0.000358665.70629731
Redeem204634582024-08-05 16:07:5918 days ago1722874079IN
0xfF8697d8...4BEeB0C81
0 ETH0.0011239127.00363711
Redeem204162372024-07-30 1:55:1124 days ago1722304511IN
0xfF8697d8...4BEeB0C81
0 ETH0.000197344.74143383
Redeem203255772024-07-17 10:13:2337 days ago1721211203IN
0xfF8697d8...4BEeB0C81
0 ETH0.0005170712.42349237
Redeem202818402024-07-11 7:42:4743 days ago1720683767IN
0xfF8697d8...4BEeB0C81
0 ETH0.000371036.31861735
Redeem202802562024-07-11 2:23:4743 days ago1720664627IN
0xfF8697d8...4BEeB0C81
0 ETH0.00023295.59574522
Redeem202776622024-07-10 17:42:3544 days ago1720633355IN
0xfF8697d8...4BEeB0C81
0 ETH0.000664815.97279956
Redeem202682512024-07-09 10:10:1145 days ago1720519811IN
0xfF8697d8...4BEeB0C81
0 ETH0.00037216.3368713
Redeem202672952024-07-09 6:57:3545 days ago1720508255IN
0xfF8697d8...4BEeB0C81
0 ETH0.000194914.68311518
Redeem202306622024-07-04 4:08:2350 days ago1720066103IN
0xfF8697d8...4BEeB0C81
0 ETH0.000197624.74810159
Redeem202127852024-07-01 16:12:5953 days ago1719850379IN
0xfF8697d8...4BEeB0C81
0 ETH0.0006923611.79070358
Redeem202127512024-07-01 16:06:1153 days ago1719849971IN
0xfF8697d8...4BEeB0C81
0 ETH0.0006699711.40947288
Redeem202127252024-07-01 16:00:5953 days ago1719849659IN
0xfF8697d8...4BEeB0C81
0 ETH0.0006912711.77221593
Redeem201831602024-06-27 12:55:2357 days ago1719492923IN
0xfF8697d8...4BEeB0C81
0 ETH0.000434925.68271711
Redeem201828482024-06-27 11:52:4757 days ago1719489167IN
0xfF8697d8...4BEeB0C81
0 ETH0.000432096.58726149
Redeem201654022024-06-25 1:25:2359 days ago1719278723IN
0xfF8697d8...4BEeB0C81
0 ETH0.000322495.49305549
Redeem199570002024-05-26 22:21:3589 days ago1716762095IN
0xfF8697d8...4BEeB0C81
0 ETH0.000234884
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Depository

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 4000 runs

Other Settings:
default evmVersion
File 1 of 6 : Depository.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IErrorsTokenomics} from "./interfaces/IErrorsTokenomics.sol";
import {IGenericBondCalculator} from "./interfaces/IGenericBondCalculator.sol";
import {IToken} from "./interfaces/IToken.sol";
import {ITokenomics} from "./interfaces/ITokenomics.sol";
import {ITreasury} from "./interfaces/ITreasury.sol";

/*
* In this contract we consider OLAS tokens. The initial numbers will be as follows:
*  - For the first 10 years there will be the cap of 1 billion (1e27) tokens;
*  - After 10 years, the inflation rate is capped at 2% per year.
* Starting from a year 11, the maximum number of tokens that can be reached per the year x is 1e27 * (1.02)^x.
* To make sure that a unit(n) does not overflow the total supply during the year x, we have to check that
* 2^n - 1 >= 1e27 * (1.02)^x. We limit n by 96, thus it would take 220+ years to reach that total supply.
*
* We then limit each time variable to last until the value of 2^32 - 1 in seconds.
* 2^32 - 1 gives 136+ years counted in seconds starting from the year 1970.
* Thus, this counter is safe until the year 2106.
*
* The number of blocks cannot be practically bigger than the number of seconds, since there is more than one second
* in a block. Thus, it is safe to assume that uint32 for the number of blocks is also sufficient.
*
* In conclusion, this contract is only safe to use until 2106.
*/

// The size of the struct is 160 + 96 + 32 * 2 = 256 + 64 (2 slots)
struct Bond {
    // Account address
    address account;
    // OLAS remaining to be paid out
    // After 10 years, the OLAS inflation rate is 2% per year. It would take 220+ years to reach 2^96 - 1
    uint96 payout;
    // Bond maturity time
    // 2^32 - 1 is enough to count 136 years starting from the year of 1970. This counter is safe until the year of 2106
    uint32 maturity;
    // Product Id of a bond
    // We assume that the number of products will not be bigger than the number of seconds
    uint32 productId;
}

// The size of the struct is 160 + 32 + 160 + 96 = 256 + 192 (2 slots)
struct Product {
    // priceLP (reserve0 / totalSupply or reserve1 / totalSupply) with 18 additional decimals
    // priceLP = 2 * r0/L * 10^18 = 2*r0*10^18/sqrt(r0*r1) ~= 61 + 96 - sqrt(96 * 112) ~= 53 bits (if LP is balanced)
    // or 2* r0/sqrt(r0) * 10^18 => 87 bits + 60 bits = 147 bits (if LP is unbalanced)
    uint160 priceLP;
    // Bond vesting time
    // 2^32 - 1 is enough to count 136 years starting from the year of 1970. This counter is safe until the year of 2106
    uint32 vesting;
    // Token to accept as a payment
    address token;
    // Supply of remaining OLAS tokens
    // After 10 years, the OLAS inflation rate is 2% per year. It would take 220+ years to reach 2^96 - 1
    uint96 supply;
}

/// @title Bond Depository - Smart contract for OLAS Bond Depository
/// @author AL
/// @author Aleksandr Kuperman - <[email protected]>
contract Depository is IErrorsTokenomics {
    event OwnerUpdated(address indexed owner);
    event TokenomicsUpdated(address indexed tokenomics);
    event TreasuryUpdated(address indexed treasury);
    event BondCalculatorUpdated(address indexed bondCalculator);
    event CreateBond(address indexed token, uint256 indexed productId, address indexed owner, uint256 bondId,
        uint256 amountOLAS, uint256 tokenAmount, uint256 maturity);
    event RedeemBond(uint256 indexed productId, address indexed owner, uint256 bondId);
    event CreateProduct(address indexed token, uint256 indexed productId, uint256 supply, uint256 priceLP,
        uint256 vesting);
    event CloseProduct(address indexed token, uint256 indexed productId, uint256 supply);

    // Minimum bond vesting value
    uint256 public constant MIN_VESTING = 1 days;
    // Depository version number
    string public constant VERSION = "1.0.1";
    
    // Owner address
    address public owner;
    // Individual bond counter
    // We assume that the number of bonds will not be bigger than the number of seconds
    uint32 public bondCounter;
    // Bond product counter
    // We assume that the number of products will not be bigger than the number of seconds
    uint32 public productCounter;

    // OLAS token address
    address public immutable olas;
    // Tkenomics contract address
    address public tokenomics;
    // Treasury contract address
    address public treasury;
    // Bond Calculator contract address
    address public bondCalculator;

    // Mapping of bond Id => account bond instance
    mapping(uint256 => Bond) public mapUserBonds;
    // Mapping of product Id => bond product instance
    mapping(uint256 => Product) public mapBondProducts;

    /// @dev Depository constructor.
    /// @param _olas OLAS token address.
    /// @param _treasury Treasury address.
    /// @param _tokenomics Tokenomics address.
    constructor(address _olas, address _tokenomics, address _treasury, address _bondCalculator)
    {
        owner = msg.sender;

        // Check for at least one zero contract address
        if (_olas == address(0) || _tokenomics == address(0) || _treasury == address(0) || _bondCalculator == address(0)) {
            revert ZeroAddress();
        }
        olas = _olas;
        tokenomics = _tokenomics;
        treasury = _treasury;
        bondCalculator = _bondCalculator;
    }

    /// @dev Changes the owner address.
    /// @param newOwner Address of a new owner.
    /// #if_succeeds {:msg "Changing owner"} old(owner) == msg.sender ==> owner == newOwner;
    function changeOwner(address newOwner) external {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        // Check for the zero address
        if (newOwner == address(0)) {
            revert ZeroAddress();
        }

        owner = newOwner;
        emit OwnerUpdated(newOwner);
    }

    /// @dev Changes various managing contract addresses.
    /// @param _tokenomics Tokenomics address.
    /// @param _treasury Treasury address.
    /// #if_succeeds {:msg "tokenomics changed"} _tokenomics != address(0) ==> tokenomics == _tokenomics;
    /// #if_succeeds {:msg "treasury changed"} _treasury != address(0) ==> treasury == _treasury;
    function changeManagers(address _tokenomics, address _treasury) external {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        // Change Tokenomics contract address
        if (_tokenomics != address(0)) {
            tokenomics = _tokenomics;
            emit TokenomicsUpdated(_tokenomics);
        }
        // Change Treasury contract address
        if (_treasury != address(0)) {
            treasury = _treasury;
            emit TreasuryUpdated(_treasury);
        }
    }

    /// @dev Changes Bond Calculator contract address
    /// #if_succeeds {:msg "bondCalculator changed"} _bondCalculator != address(0) ==> bondCalculator == _bondCalculator;
    function changeBondCalculator(address _bondCalculator) external {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        if (_bondCalculator != address(0)) {
            bondCalculator = _bondCalculator;
            emit BondCalculatorUpdated(_bondCalculator);
        }
    }

    /// @dev Creates a new bond product.
    /// @param token LP token to be deposited for pairs like OLAS-DAI, OLAS-ETH, etc.
    /// @param priceLP LP token price with 18 additional decimals.
    /// @param supply Supply in OLAS tokens.
    /// @param vesting Vesting period (in seconds).
    /// @return productId New bond product Id.
    /// #if_succeeds {:msg "productCounter increases"} productCounter == old(productCounter) + 1;
    /// #if_succeeds {:msg "isActive"} mapBondProducts[productId].supply > 0 && mapBondProducts[productId].vesting == vesting;
    function create(address token, uint256 priceLP, uint256 supply, uint256 vesting) external returns (uint256 productId) {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        // Check for the pool liquidity as the LP price being greater than zero
        if (priceLP == 0) {
            revert ZeroValue();
        }

        // Check the priceLP limit value
        if (priceLP > type(uint160).max) {
            revert Overflow(priceLP, type(uint160).max);
        }

        // Check that the supply is greater than zero
        if (supply == 0) {
            revert ZeroValue();
        }

        // Check the supply limit value
        if (supply > type(uint96).max) {
            revert Overflow(supply, type(uint96).max);
        }

        // Check the vesting minimum limit value
        if (vesting < MIN_VESTING) {
            revert LowerThan(vesting, MIN_VESTING);
        }

        // Check for the maturity time overflow for the current timestamp
        uint256 maturity = block.timestamp + vesting;
        if (maturity > type(uint32).max) {
            revert Overflow(maturity, type(uint32).max);
        }

        // Check if the LP token is enabled
        if (!ITreasury(treasury).isEnabled(token)) {
            revert UnauthorizedToken(token);
        }

        // Check if the bond amount is beyond the limits
        if (!ITokenomics(tokenomics).reserveAmountForBondProgram(supply)) {
            revert LowerThan(ITokenomics(tokenomics).effectiveBond(), supply);
        }

        // Push newly created bond product into the list of products
        productId = productCounter;
        mapBondProducts[productId] = Product(uint160(priceLP), uint32(vesting), token, uint96(supply));
        // Even if we create a bond product every second, 2^32 - 1 is enough for the next 136 years
        productCounter = uint32(productId + 1);
        emit CreateProduct(token, productId, supply, priceLP, vesting);
    }

    /// @dev Closes bonding products.
    /// @notice This will terminate programs regardless of their vesting time.
    /// @param productIds Set of product Ids.
    /// @return closedProductIds Set of closed product Ids.
    /// #if_succeeds {:msg "productCounter not touched"} productCounter == old(productCounter);
    /// #if_succeeds {:msg "success closed"} forall (uint k in productIds) mapBondProducts[productIds[k]].vesting == 0 && mapBondProducts[productIds[k]].supply == 0;
    function close(uint256[] memory productIds) external returns (uint256[] memory closedProductIds) {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        // Calculate the number of closed products
        uint256 numProducts = productIds.length;
        uint256[] memory ids = new uint256[](numProducts);
        uint256 numClosedProducts;
        // Traverse to close all possible products
        for (uint256 i = 0; i < numProducts; ++i) {
            uint256 productId = productIds[i];
            // Check if the product is still open by getting its supply amount
            uint256 supply = mapBondProducts[productId].supply;
            // The supply is greater than zero only if the product is active, otherwise it is already closed
            if (supply > 0) {
                // Refund unused OLAS supply from the product if it was not used by the product completely
                ITokenomics(tokenomics).refundFromBondProgram(supply);
                address token = mapBondProducts[productId].token;
                delete mapBondProducts[productId];

                ids[numClosedProducts] = productIds[i];
                ++numClosedProducts;
                emit CloseProduct(token, productId, supply);
            }
        }

        // Get the correct array size of closed product Ids
        closedProductIds = new uint256[](numClosedProducts);
        for (uint256 i = 0; i < numClosedProducts; ++i) {
            closedProductIds[i] = ids[i];
        }
    }

    /// @dev Deposits tokens in exchange for a bond from a specified product.
    /// @param productId Product Id.
    /// @param tokenAmount Token amount to deposit for the bond.
    /// @return payout The amount of OLAS tokens due.
    /// @return maturity Timestamp for payout redemption.
    /// @return bondId Id of a newly created bond.
    /// #if_succeeds {:msg "token is valid"} mapBondProducts[productId].token != address(0);
    /// #if_succeeds {:msg "input supply is non-zero"} old(mapBondProducts[productId].supply) > 0 && mapBondProducts[productId].supply <= type(uint96).max;
    /// #if_succeeds {:msg "vesting is non-zero"} mapBondProducts[productId].vesting > 0 && mapBondProducts[productId].vesting + block.timestamp <= type(uint32).max;
    /// #if_succeeds {:msg "bond Id"} bondCounter == old(bondCounter) + 1 && bondCounter <= type(uint32).max;
    /// #if_succeeds {:msg "payout"} old(mapBondProducts[productId].supply) == mapBondProducts[productId].supply + payout;
    /// #if_succeeds {:msg "OLAS balances"} IToken(mapBondProducts[productId].token).balanceOf(treasury) == old(IToken(mapBondProducts[productId].token).balanceOf(treasury)) + tokenAmount;
    function deposit(uint256 productId, uint256 tokenAmount) external
        returns (uint256 payout, uint256 maturity, uint256 bondId)
    {
        // Check the token amount
        if (tokenAmount == 0) {
            revert ZeroValue();
        }

        // Get the bonding product
        Product storage product = mapBondProducts[productId];

        // Check for the product supply, which is zero if the product was closed or never existed
        uint256 supply = product.supply;
        if (supply == 0) {
            revert ProductClosed(productId);
        }

        // Calculate the bond maturity based on its vesting time
        maturity = block.timestamp + product.vesting;
        // Check for the time limits
        if (maturity > type(uint32).max) {
            revert Overflow(maturity, type(uint32).max);
        }

        // Get the LP token address
        address token = product.token;

        // Calculate the payout in OLAS tokens based on the LP pair with the discount factor (DF) calculation
        // Note that payout cannot be zero since the price LP is non-zero, otherwise the product would not be created
        payout = IGenericBondCalculator(bondCalculator).calculatePayoutOLAS(tokenAmount, product.priceLP);

        // Check for the sufficient supply
        if (payout > supply) {
            revert ProductSupplyLow(token, productId, payout, supply);
        }

        // Decrease the supply for the amount of payout
        supply -= payout;
        product.supply = uint96(supply);

        // Create and add a new bond, update the bond counter
        bondId = bondCounter;
        mapUserBonds[bondId] = Bond(msg.sender, uint96(payout), uint32(maturity), uint32(productId));
        bondCounter = uint32(bondId + 1);

        // Deposit that token amount to mint OLAS tokens in exchange
        ITreasury(treasury).depositTokenForOLAS(msg.sender, tokenAmount, token, payout);

        // Close the product if the supply becomes zero
        if (supply == 0) {
            delete mapBondProducts[productId];
            emit CloseProduct(token, productId, supply);
        }

        emit CreateBond(token, productId, msg.sender, bondId, payout, tokenAmount, maturity);
    }

    /// @dev Redeems account bonds.
    /// @param bondIds Bond Ids to redeem.
    /// @return payout Total payout sent in OLAS tokens.
    /// #if_succeeds {:msg "payout > 0"} payout > 0;
    /// #if_succeeds {:msg "msg.sender is the only owner"} old(forall (uint k in bondIds) mapUserBonds[bondIds[k]].account == msg.sender);
    /// #if_succeeds {:msg "accounts deleted"} forall (uint k in bondIds) mapUserBonds[bondIds[k]].account == address(0);
    /// #if_succeeds {:msg "payouts are zeroed"} forall (uint k in bondIds) mapUserBonds[bondIds[k]].payout == 0;
    /// #if_succeeds {:msg "maturities are zeroed"} forall (uint k in bondIds) mapUserBonds[bondIds[k]].maturity == 0;
    function redeem(uint256[] memory bondIds) external returns (uint256 payout) {
        for (uint256 i = 0; i < bondIds.length; ++i) {
            // Get the amount to pay and the maturity status
            uint256 pay = mapUserBonds[bondIds[i]].payout;
            bool matured = block.timestamp >= mapUserBonds[bondIds[i]].maturity;

            // Revert if the bond does not exist or is not matured yet
            if (pay == 0 || !matured) {
                revert BondNotRedeemable(bondIds[i]);
            }

            // Check that the msg.sender is the owner of the bond
            if (mapUserBonds[bondIds[i]].account != msg.sender) {
                revert OwnerOnly(msg.sender, mapUserBonds[bondIds[i]].account);
            }

            // Increase the payout
            payout += pay;

            // Get the productId
            uint256 productId = mapUserBonds[bondIds[i]].productId;

            // Delete the Bond struct and release the gas
            delete mapUserBonds[bondIds[i]];
            emit RedeemBond(productId, msg.sender, bondIds[i]);
        }

        // Check for the non-zero payout
        if (payout == 0) {
            revert ZeroValue();
        }

        // No reentrancy risk here since it's the last operation, and originated from the OLAS token
        // No need to check for the return value, since it either reverts or returns true, see the ERC20 implementation
        IToken(olas).transfer(msg.sender, payout);
    }

    /// @dev Gets an array of active or inactive product Ids.
    /// @param active Flag to select active or inactive products.
    /// @return productIds Product Ids.
    function getProducts(bool active) external view returns (uint256[] memory productIds) {
        // Calculate the number of existing products
        uint256 numProducts = productCounter;
        bool[] memory positions = new bool[](numProducts);
        uint256 numSelectedProducts;
        // Traverse to find requested products
        for (uint256 i = 0; i < numProducts; ++i) {
            // Product is always active if its supply is not zero, and inactive otherwise
            if ((active && mapBondProducts[i].supply > 0) || (!active && mapBondProducts[i].supply == 0)) {
                positions[i] = true;
                ++numSelectedProducts;
            }
        }

        // Form active or inactive products index array
        productIds = new uint256[](numSelectedProducts);
        uint256 numPos;
        for (uint256 i = 0; i < numProducts; ++i) {
            if (positions[i]) {
                productIds[numPos] = i;
                ++numPos;
            }
        }
    }

    /// @dev Gets activity information about a given product.
    /// @param productId Product Id.
    /// @return status True if the product is active.
    function isActiveProduct(uint256 productId) external view returns (bool status) {
        status = (mapBondProducts[productId].supply > 0);
    }

    /// @dev Gets bond Ids for the account address.
    /// @param account Account address to query bonds for.
    /// @param matured Flag to get matured bonds only or all of them.
    /// @return bondIds Bond Ids.
    /// @return payout Cumulative expected OLAS payout.
    /// #if_succeeds {:msg "matured bonds"} matured == true ==> forall (uint k in bondIds)
    /// mapUserBonds[bondIds[k]].account == account && block.timestamp >= mapUserBonds[bondIds[k]].maturity;
    function getBonds(address account, bool matured) external view
        returns (uint256[] memory bondIds, uint256 payout)
    {
        // Check the address
        if (account == address(0)) {
            revert ZeroAddress();
        }

        uint256 numAccountBonds;
        // Calculate the number of pending bonds
        uint256 numBonds = bondCounter;
        bool[] memory positions = new bool[](numBonds);
        // Record the bond number if it belongs to the account address and was not yet redeemed
        for (uint256 i = 0; i < numBonds; ++i) {
            // Check if the bond belongs to the account
            // If not and the address is zero, the bond was redeemed or never existed
            if (mapUserBonds[i].account == account) {
                // Check if requested bond is not matured but owned by the account address
                if (!matured ||
                    // Or if the requested bond is matured, i.e., the bond maturity timestamp passed
                    block.timestamp >= mapUserBonds[i].maturity)
                {
                    positions[i] = true;
                    ++numAccountBonds;
                    // The payout is always bigger than zero if the bond exists
                    payout += mapUserBonds[i].payout;
                }
            }
        }

        // Form pending bonds index array
        bondIds = new uint256[](numAccountBonds);
        uint256 numPos;
        for (uint256 i = 0; i < numBonds; ++i) {
            if (positions[i]) {
                bondIds[numPos] = i;
                ++numPos;
            }
        }
    }

    /// @dev Calculates the maturity and payout to claim for a single bond.
    /// @param bondId The account bond Id.
    /// @return payout The payout amount in OLAS.
    /// @return matured True if the payout can be redeemed.
    function getBondStatus(uint256 bondId) external view returns (uint256 payout, bool matured) {
        payout = mapUserBonds[bondId].payout;
        // If payout is zero, the bond has been redeemed or never existed
        if (payout > 0) {
            matured = block.timestamp >= mapUserBonds[bondId].maturity;
        }
    }

    /// @dev Gets current reserves of OLAS / totalSupply of LP tokens.
    /// @param token Token address.
    /// @return priceLP Resulting reserveX / totalSupply ratio with 18 decimals.
    function getCurrentPriceLP(address token) external view returns (uint256 priceLP) {
        return IGenericBondCalculator(bondCalculator).getCurrentPriceLP(token);
    }
}

File 2 of 6 : IErrorsTokenomics.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

/// @dev Errors.
interface IErrorsTokenomics {
    /// @dev Only `manager` has a privilege, but the `sender` was provided.
    /// @param sender Sender address.
    /// @param manager Required sender address as a manager.
    error ManagerOnly(address sender, address manager);

    /// @dev Only `owner` has a privilege, but the `sender` was provided.
    /// @param sender Sender address.
    /// @param owner Required sender address as an owner.
    error OwnerOnly(address sender, address owner);

    /// @dev Provided zero address.
    error ZeroAddress();

    /// @dev Wrong length of two arrays.
    /// @param numValues1 Number of values in a first array.
    /// @param numValues2 Number of values in a second array.
    error WrongArrayLength(uint256 numValues1, uint256 numValues2);

    /// @dev Service Id does not exist in registry records.
    /// @param serviceId Service Id.
    error ServiceDoesNotExist(uint256 serviceId);

    /// @dev Zero value when it has to be different from zero.
    error ZeroValue();

    /// @dev Non-zero value when it has to be zero.
    error NonZeroValue();

    /// @dev Value overflow.
    /// @param provided Overflow value.
    /// @param max Maximum possible value.
    error Overflow(uint256 provided, uint256 max);

    /// @dev Service was never deployed.
    /// @param serviceId Service Id.
    error ServiceNeverDeployed(uint256 serviceId);

    /// @dev Token is disabled or not whitelisted.
    /// @param tokenAddress Address of a token.
    error UnauthorizedToken(address tokenAddress);

    /// @dev Provided token address is incorrect.
    /// @param provided Provided token address.
    /// @param expected Expected token address.
    error WrongTokenAddress(address provided, address expected);

    /// @dev Bond is not redeemable (does not exist or not matured).
    /// @param bondId Bond Id.
    error BondNotRedeemable(uint256 bondId);

    /// @dev The product is expired.
    /// @param tokenAddress Address of a token.
    /// @param productId Product Id.
    /// @param deadline The program expiry time.
    /// @param curTime Current timestamp.
    error ProductExpired(address tokenAddress, uint256 productId, uint256 deadline, uint256 curTime);

    /// @dev The product is already closed.
    /// @param productId Product Id.
    error ProductClosed(uint256 productId);

    /// @dev The product supply is low for the requested payout.
    /// @param tokenAddress Address of a token.
    /// @param productId Product Id.
    /// @param requested Requested payout.
    /// @param actual Actual supply left.
    error ProductSupplyLow(address tokenAddress, uint256 productId, uint256 requested, uint256 actual);

    /// @dev Received lower value than the expected one.
    /// @param provided Provided value is lower.
    /// @param expected Expected value.
    error LowerThan(uint256 provided, uint256 expected);

    /// @dev Wrong amount received / provided.
    /// @param provided Provided amount.
    /// @param expected Expected amount.
    error WrongAmount(uint256 provided, uint256 expected);

    /// @dev Insufficient token allowance.
    /// @param provided Provided amount.
    /// @param expected Minimum expected amount.
    error InsufficientAllowance(uint256 provided, uint256 expected);

    /// @dev Failure of a transfer.
    /// @param token Address of a token.
    /// @param from Address `from`.
    /// @param to Address `to`.
    /// @param amount Token amount.
    error TransferFailed(address token, address from, address to, uint256 amount);

    /// @dev Incentives claim has failed.
    /// @param account Account address.
    /// @param reward Reward amount.
    /// @param topUp Top-up amount.
    error ClaimIncentivesFailed(address account, uint256 reward, uint256 topUp);

    /// @dev Caught reentrancy violation.
    error ReentrancyGuard();

    /// @dev Failure of treasury re-balance during the reward allocation.
    /// @param epochNumber Epoch number.
    error TreasuryRebalanceFailed(uint256 epochNumber);

    /// @dev Operation with a wrong component / agent Id.
    /// @param unitId Component / agent Id.
    /// @param unitType Type of the unit (component / agent).
    error WrongUnitId(uint256 unitId, uint256 unitType);

    /// @dev The donator address is blacklisted.
    /// @param account Donator account address.
    error DonatorBlacklisted(address account);

    /// @dev The contract is already initialized.
    error AlreadyInitialized();

    /// @dev The contract has to be delegate-called via proxy.
    error DelegatecallOnly();

    /// @dev The contract is paused.
    error Paused();

    /// @dev Caught an operation that is not supposed to happen in the same block.
    error SameBlockNumberViolation();
}

File 3 of 6 : IGenericBondCalculator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

/// @dev Interface for generic bond calculator.
interface IGenericBondCalculator {
    /// @dev Calculates the amount of OLAS tokens based on the bonding calculator mechanism.
    /// @param tokenAmount LP token amount.
    /// @param priceLP LP token price.
    /// @return amountOLAS Resulting amount of OLAS tokens.
    function calculatePayoutOLAS(uint256 tokenAmount, uint256 priceLP) external view
        returns (uint256 amountOLAS);

    /// @dev Get reserveX/reserveY at the time of product creation.
    /// @param token Token address.
    /// @return priceLP Resulting reserve ratio.
    function getCurrentPriceLP(address token) external view returns (uint256 priceLP);
}

File 4 of 6 : IToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

/// @dev Generic token interface for IERC20 and IERC721 tokens.
interface IToken {
    /// @dev Gets the amount of tokens owned by a specified account.
    /// @param account Account address.
    /// @return Amount of tokens owned.
    function balanceOf(address account) external view returns (uint256);

    /// @dev Gets the owner of the token Id.
    /// @param tokenId Token Id.
    /// @return Token Id owner address.
    function ownerOf(uint256 tokenId) external view returns (address);

    /// @dev Gets the total amount of tokens stored by the contract.
    /// @return Amount of tokens.
    function totalSupply() external view returns (uint256);

    /// @dev Transfers the token amount.
    /// @param to Address to transfer to.
    /// @param amount The amount to transfer.
    /// @return True if the function execution is successful.
    function transfer(address to, uint256 amount) external returns (bool);

    /// @dev Gets remaining number of tokens that the `spender` can transfer on behalf of `owner`.
    /// @param owner Token owner.
    /// @param spender Account address that is able to transfer tokens on behalf of the owner.
    /// @return Token amount allowed to be transferred.
    function allowance(address owner, address spender) external view returns (uint256);

    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    /// @param spender Account address that will be able to transfer tokens on behalf of the caller.
    /// @param amount Token amount.
    /// @return True if the function execution is successful.
    function approve(address spender, uint256 amount) external returns (bool);

    /// @dev Transfers the token amount that was previously approved up until the maximum allowance.
    /// @param from Account address to transfer from.
    /// @param to Account address to transfer to.
    /// @param amount Amount to transfer to.
    /// @return True if the function execution is successful.
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 5 of 6 : ITokenomics.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

/// @dev Interface for tokenomics management.
interface ITokenomics {
    /// @dev Gets effective bond (bond left).
    /// @return Effective bond.
    function effectiveBond() external pure returns (uint256);

    /// @dev Record global data to the checkpoint
    function checkpoint() external returns (bool);

    /// @dev Tracks the deposited ETH service donations during the current epoch.
    /// @notice This function is only called by the treasury where the validity of arrays and values has been performed.
    /// @param donator Donator account address.
    /// @param serviceIds Set of service Ids.
    /// @param amounts Correspondent set of ETH amounts provided by services.
    /// @param donationETH Overall service donation amount in ETH.
    function trackServiceDonations(
        address donator,
        uint256[] memory serviceIds,
        uint256[] memory amounts,
        uint256 donationETH
    ) external;

    /// @dev Reserves OLAS amount from the effective bond to be minted during a bond program.
    /// @notice Programs exceeding the limit in the epoch are not allowed.
    /// @param amount Requested amount for the bond program.
    /// @return True if effective bond threshold is not reached.
    function reserveAmountForBondProgram(uint256 amount) external returns(bool);

    /// @dev Refunds unused bond program amount.
    /// @param amount Amount to be refunded from the bond program.
    function refundFromBondProgram(uint256 amount) external;

    /// @dev Gets component / agent owner incentives and clears the balances.
    /// @param account Account address.
    /// @param unitTypes Set of unit types (component / agent).
    /// @param unitIds Set of corresponding unit Ids where account is the owner.
    /// @return reward Reward amount.
    /// @return topUp Top-up amount.
    function accountOwnerIncentives(address account, uint256[] memory unitTypes, uint256[] memory unitIds) external
        returns (uint256 reward, uint256 topUp);

    /// @dev Gets inverse discount factor with the multiple of 1e18 of the last epoch.
    /// @return idf Discount factor with the multiple of 1e18.
    function getLastIDF() external view returns (uint256 idf);

    /// @dev Gets the service registry contract address
    /// @return Service registry contract address;
    function serviceRegistry() external view returns (address);
}

File 6 of 6 : ITreasury.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

/// @dev Interface for treasury management.
interface ITreasury {
    /// @dev Allows approved address to deposit an asset for OLAS.
    /// @param account Account address making a deposit of LP tokens for OLAS.
    /// @param tokenAmount Token amount to get OLAS for.
    /// @param token Token address.
    /// @param olaMintAmount Amount of OLAS token issued.
    function depositTokenForOLAS(address account, uint256 tokenAmount, address token, uint256 olaMintAmount) external;

    /// @dev Deposits service donations in ETH.
    /// @param serviceIds Set of service Ids.
    /// @param amounts Set of corresponding amounts deposited on behalf of each service Id.
    function depositServiceDonationsETH(uint256[] memory serviceIds, uint256[] memory amounts) external payable;

    /// @dev Gets information about token being enabled.
    /// @param token Token address.
    /// @return enabled True is token is enabled.
    function isEnabled(address token) external view returns (bool enabled);

    /// @dev Withdraws ETH and / or OLAS amounts to the requested account address.
    /// @notice Only dispenser contract can call this function.
    /// @notice Reentrancy guard is on a dispenser side.
    /// @notice Zero account address is not possible, since the dispenser contract interacts with msg.sender.
    /// @param account Account address.
    /// @param accountRewards Amount of account rewards.
    /// @param accountTopUps Amount of account top-ups.
    /// @return success True if the function execution is successful.
    function withdrawToAccount(address account, uint256 accountRewards, uint256 accountTopUps) external returns (bool success);

    /// @dev Re-balances treasury funds to account for the treasury reward for a specific epoch.
    /// @param treasuryRewards Treasury rewards.
    /// @return success True, if the function execution is successful.
    function rebalanceTreasury(uint256 treasuryRewards) external returns (bool success);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_olas","type":"address"},{"internalType":"address","name":"_tokenomics","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_bondCalculator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"uint256","name":"bondId","type":"uint256"}],"name":"BondNotRedeemable","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"topUp","type":"uint256"}],"name":"ClaimIncentivesFailed","type":"error"},{"inputs":[],"name":"DelegatecallOnly","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"DonatorBlacklisted","type":"error"},{"inputs":[{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"LowerThan","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"manager","type":"address"}],"name":"ManagerOnly","type":"error"},{"inputs":[],"name":"NonZeroValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"Overflow","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"OwnerOnly","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[{"internalType":"uint256","name":"productId","type":"uint256"}],"name":"ProductClosed","type":"error"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"productId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"curTime","type":"uint256"}],"name":"ProductExpired","type":"error"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"productId","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"ProductSupplyLow","type":"error"},{"inputs":[],"name":"ReentrancyGuard","type":"error"},{"inputs":[],"name":"SameBlockNumberViolation","type":"error"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"ServiceDoesNotExist","type":"error"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"ServiceNeverDeployed","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"epochNumber","type":"uint256"}],"name":"TreasuryRebalanceFailed","type":"error"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"UnauthorizedToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"WrongAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"numValues1","type":"uint256"},{"internalType":"uint256","name":"numValues2","type":"uint256"}],"name":"WrongArrayLength","type":"error"},{"inputs":[{"internalType":"address","name":"provided","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"WrongTokenAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"unitId","type":"uint256"},{"internalType":"uint256","name":"unitType","type":"uint256"}],"name":"WrongUnitId","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bondCalculator","type":"address"}],"name":"BondCalculatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"}],"name":"CloseProduct","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"bondId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOLAS","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maturity","type":"uint256"}],"name":"CreateBond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceLP","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vesting","type":"uint256"}],"name":"CreateProduct","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"productId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"bondId","type":"uint256"}],"name":"RedeemBond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenomics","type":"address"}],"name":"TokenomicsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"inputs":[],"name":"MIN_VESTING","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondCalculator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondCounter","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bondCalculator","type":"address"}],"name":"changeBondCalculator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenomics","type":"address"},{"internalType":"address","name":"_treasury","type":"address"}],"name":"changeManagers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"productIds","type":"uint256[]"}],"name":"close","outputs":[{"internalType":"uint256[]","name":"closedProductIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"priceLP","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"vesting","type":"uint256"}],"name":"create","outputs":[{"internalType":"uint256","name":"productId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"productId","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"bondId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bondId","type":"uint256"}],"name":"getBondStatus","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"bool","name":"matured","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"matured","type":"bool"}],"name":"getBonds","outputs":[{"internalType":"uint256[]","name":"bondIds","type":"uint256[]"},{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getCurrentPriceLP","outputs":[{"internalType":"uint256","name":"priceLP","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"active","type":"bool"}],"name":"getProducts","outputs":[{"internalType":"uint256[]","name":"productIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"productId","type":"uint256"}],"name":"isActiveProduct","outputs":[{"internalType":"bool","name":"status","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mapBondProducts","outputs":[{"internalType":"uint160","name":"priceLP","type":"uint160"},{"internalType":"uint32","name":"vesting","type":"uint32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint96","name":"supply","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mapUserBonds","outputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint96","name":"payout","type":"uint96"},{"internalType":"uint32","name":"maturity","type":"uint32"},{"internalType":"uint32","name":"productId","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"olas","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"productCounter","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"bondIds","type":"uint256[]"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenomics","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a060405234801562000010575f80fd5b50604051620023a4380380620023a483398101604081905262000033916200010b565b5f80546001600160a01b031916331790556001600160a01b03841615806200006257506001600160a01b038316155b806200007557506001600160a01b038216155b806200008857506001600160a01b038116155b15620000a75760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03938416608052600180549385166001600160a01b031994851617905560028054928516928416929092179091556003805491909316911617905562000165565b80516001600160a01b038116811462000106575f80fd5b919050565b5f805f80608085870312156200011f575f80fd5b6200012a85620000ef565b93506200013a60208601620000ef565b92506200014a60408601620000ef565b91506200015a60608601620000ef565b905092959194509250565b60805161221f620001855f395f818161018c0152611d79015261221f5ff3fe608060405234801561000f575f80fd5b5060043610610183575f3560e01c80638c71ec16116100dd578063e42f991911610088578063f9afb26a11610063578063f9afb26a14610471578063fc63e42d14610484578063ffa1ad7414610520575f80fd5b8063e42f991914610367578063e91b0a4114610400578063f731960c14610428575f80fd5b8063c5332b7c116100b8578063c5332b7c14610313578063ce2d683f14610326578063e2bbb15814610339575f80fd5b80638c71ec16146102db5780638da5cb5b146102ee578063a6f9dae114610300575f80fd5b80634ac7251d1161013d5780635b400e4f116101185780635b400e4f1461029d57806361d027b3146102be57806363e63e3b146102d1575f80fd5b80634ac7251d146102545780635831d8851461026757806358d3ec6a1461027d575f80fd5b8063158555371161016d57806315855537146101e05780631f16653b146101f357806324415cf614610233575f80fd5b806231d115146101875780630c062810146101cb575b5f80fd5b6101ae7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101de6101d9366004611e0c565b610569565b005b6101de6101ee366004611e3d565b61068c565b5f5461021e907801000000000000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101c2565b610246610241366004611e3d565b61073b565b6040519081526020016101c2565b6001546101ae906001600160a01b031681565b5f5461021e90600160a01b900463ffffffff1681565b61029061028b366004611e8a565b6107c6565b6040516101c29190611f9a565b6102b06102ab366004611fb9565b610aa2565b6040516101c2929190611fee565b6002546101ae906001600160a01b031681565b6102466201518081565b6102466102e936600461200f565b610cb3565b5f546101ae906001600160a01b031681565b6101de61030e366004611e3d565b611236565b6003546101ae906001600160a01b031681565b610290610334366004612045565b611313565b61034c610347366004612060565b6114ee565b604080519384526020840192909252908201526060016101c2565b6103bc610375366004612080565b60056020525f9081526040902080546001909101546001600160a01b0380831692600160a01b9081900463ffffffff169291821691046bffffffffffffffffffffffff1684565b604080516001600160a01b03958616815263ffffffff94909416602085015291909316908201526bffffffffffffffffffffffff90911660608201526080016101c2565b61041361040e366004612080565b611a00565b604080519283529015156020830152016101c2565b610461610436366004612080565b5f90815260056020526040902060010154600160a01b90046bffffffffffffffffffffffff16151590565b60405190151581526020016101c2565b61024661047f366004611e8a565b611a4b565b6104dd610492366004612080565b60046020525f9081526040902080546001909101546001600160a01b03821691600160a01b90046bffffffffffffffffffffffff169063ffffffff8082169164010000000090041684565b604080516001600160a01b0390951685526bffffffffffffffffffffffff909316602085015263ffffffff918216928401929092521660608201526080016101c2565b61055c6040518060400160405280600581526020017f312e302e3100000000000000000000000000000000000000000000000000000081525081565b6040516101c29190612097565b5f546001600160a01b031633146105ac575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6001600160a01b0382161561061a57600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040517f4672fe7e13cfb163442d0b729b5733fb3efafc66cbe3677eac9940eb41c284c2905f90a25b6001600160a01b0381161561068857600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1905f90a25b5050565b5f546001600160a01b031633146106ca575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b6001600160a01b0381161561073857600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f179276fedd32be7c465135f8e074aefcd470c855d2550f83a36a45bfbaa61ea5905f90a25b50565b6003546040517f24415cf60000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301525f9216906324415cf690602401602060405180830381865afa15801561079c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107c09190612100565b92915050565b5f546060906001600160a01b03163314610807575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b81515f8167ffffffffffffffff81111561082357610823611e5d565b60405190808252806020026020018201604052801561084c578160200160208202803683370190505b5090505f805b83811015610a02575f86828151811061086d5761086d612117565b6020908102919091018101515f8181526005909252604090912060010154909150600160a01b90046bffffffffffffffffffffffff1680156109ef576001546040517f7048960c000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0390911690637048960c906024015f604051808303815f87803b158015610905575f80fd5b505af1158015610917573d5f803e3d5ffd5b5050505f83815260056020526040812060018101805482547fffffffffffffffff000000000000000000000000000000000000000000000000169092559190915589516001600160a01b03909116915089908590811061097957610979612117565b602002602001015186868151811061099357610993612117565b60209081029190910101526109a785612171565b945082816001600160a01b03167f677b70dc7e4a19e6af55f981ac3706886716a25e9c0b978ec0c427f51ce68b18846040516109e591815260200190565b60405180910390a3505b5050806109fb90612171565b9050610852565b508067ffffffffffffffff811115610a1c57610a1c611e5d565b604051908082528060200260200182016040528015610a45578160200160208202803683370190505b5093505f5b81811015610a9957828181518110610a6457610a64612117565b6020026020010151858281518110610a7e57610a7e612117565b6020908102919091010152610a9281612171565b9050610a4a565b50505050919050565b60605f6001600160a01b038416610ae5576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8054600160a01b900463ffffffff16818167ffffffffffffffff811115610b0f57610b0f611e5d565b604051908082528060200260200182016040528015610b38578160200160208202803683370190505b5090505f5b82811015610bfd575f818152600460205260409020546001600160a01b03808a16911603610bed57861580610b8857505f8181526004602052604090206001015463ffffffff164210155b15610bed576001828281518110610ba157610ba1612117565b91151560209283029190910190910152610bba84612171565b5f82815260046020526040902054909450610bea90600160a01b90046bffffffffffffffffffffffff16866121a8565b94505b610bf681612171565b9050610b3d565b508267ffffffffffffffff811115610c1757610c17611e5d565b604051908082528060200260200182016040528015610c40578160200160208202803683370190505b5094505f805b83811015610ca757828181518110610c6057610c60612117565b602002602001015115610c975780878381518110610c8057610c80612117565b6020908102919091010152610c9482612171565b91505b610ca081612171565b9050610c46565b50505050509250929050565b5f80546001600160a01b03163314610cf2575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b835f03610d2b576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841115610d7c576040517f7ae59685000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0360248201526044016105a3565b825f03610db5576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6bffffffffffffffffffffffff831115610e10576040517f7ae59685000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff60248201526044016105a3565b62015180821015610e59576040517f491a2bb1000000000000000000000000000000000000000000000000000000008152600481018390526201518060248201526044016105a3565b5f610e6483426121a8565b905063ffffffff811115610eb1576040517f7ae596850000000000000000000000000000000000000000000000000000000081526004810182905263ffffffff60248201526044016105a3565b6002546040517f9015d3710000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015290911690639015d37190602401602060405180830381865afa158015610f12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3691906121bb565b610f77576040517fe3d87c620000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024016105a3565b6001546040517f426e77df000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b039091169063426e77df906024016020604051808303815f875af1158015610fd8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ffc91906121bb565b6110b15760015f9054906101000a90046001600160a01b03166001600160a01b0316638fc2b24d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611050573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110749190612100565b6040517f491a2bb10000000000000000000000000000000000000000000000000000000081526004810191909152602481018590526044016105a3565b5f8054604080516080810182526001600160a01b03808a16825263ffffffff88811660208085019182528d84168587019081526bffffffffffffffffffffffff808e166060880190815278010000000000000000000000000000000000000000000000009099048516808b52600590935296909820945185549251909316600160a01b9081027fffffffffffffffff0000000000000000000000000000000000000000000000009093169385169390931791909117845595519451909316909202929091169190911760019182015590925061118e9083906121a8565b5f805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055604080518581526020810187905290810184905282906001600160a01b038816907f5fd24ab6321cb12fa0b131d7749ca303e20d69422e8191bc5d2ae4959bae08db9060600160405180910390a350949350505050565b5f546001600160a01b03163314611274575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b6001600160a01b0381166112b4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b5f8054606091780100000000000000000000000000000000000000000000000090910463ffffffff16908167ffffffffffffffff81111561135657611356611e5d565b60405190808252806020026020018201604052801561137f578160200160208202803683370190505b5090505f805b8381101561143a578580156113be57505f81815260056020526040902060010154600160a01b90046bffffffffffffffffffffffff1615155b806113f55750851580156113f557505f81815260056020526040902060010154600160a01b90046bffffffffffffffffffffffff16155b1561142a57600183828151811061140e5761140e612117565b9115156020928302919091019091015261142782612171565b91505b61143381612171565b9050611385565b508067ffffffffffffffff81111561145457611454611e5d565b60405190808252806020026020018201604052801561147d578160200160208202803683370190505b5093505f805b848110156114e45783818151811061149d5761149d612117565b6020026020010151156114d457808683815181106114bd576114bd612117565b60209081029190910101526114d182612171565b91505b6114dd81612171565b9050611483565b5050505050919050565b5f805f835f0361152a576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f85815260056020526040812060018101549091600160a01b9091046bffffffffffffffffffffffff1690819003611591576040517f4decba84000000000000000000000000000000000000000000000000000000008152600481018890526024016105a3565b81546115aa90600160a01b900463ffffffff16426121a8565b935063ffffffff8411156115f7576040517f7ae596850000000000000000000000000000000000000000000000000000000081526004810185905263ffffffff60248201526044016105a3565b600182015460035483546040517f7e5b0998000000000000000000000000000000000000000000000000000000008152600481018a90526001600160a01b03918216602482015292811692911690637e5b099890604401602060405180830381865afa158015611669573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061168d9190612100565b9550818611156116e9576040517f545a90850000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810189905260448101879052606481018390526084016105a3565b6116f386836121d6565b9150818360010160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505f60149054906101000a900463ffffffff1663ffffffff1693506040518060800160405280336001600160a01b03168152602001876bffffffffffffffffffffffff1681526020018663ffffffff1681526020018963ffffffff1681525060045f8681526020019081526020015f205f820151815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151815f0160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506040820151816001015f6101000a81548163ffffffff021916908363ffffffff16021790555060608201518160010160046101000a81548163ffffffff021916908363ffffffff16021790555090505083600161185491906121a8565b5f805463ffffffff92909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790556002546040517f1ac17db9000000000000000000000000000000000000000000000000000000008152336004820152602481018990526001600160a01b0383811660448301526064820189905290911690631ac17db9906084015f604051808303815f87803b158015611901575f80fd5b505af1158015611913573d5f803e3d5ffd5b50505050815f0361199f575f8881526005602052604080822080547fffffffffffffffff000000000000000000000000000000000000000000000000168155600101919091555188906001600160a01b038316907f677b70dc7e4a19e6af55f981ac3706886716a25e9c0b978ec0c427f51ce68b18906119969086815260200190565b60405180910390a35b604080518581526020810188905290810188905260608101869052339089906001600160a01b038416907ffa892a5592accfded99f9df9ad2d678230f37aeeb8fde5dd3b73769b5069bc0e9060800160405180910390a45050509250925092565b5f81815260046020526040812054600160a01b90046bffffffffffffffffffffffff16908115611a4657505f8281526004602052604090206001015463ffffffff164210155b915091565b5f805b8251811015611d0a575f60045f858481518110611a6d57611a6d612117565b602002602001015181526020019081526020015f205f0160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff1690505f60045f868581518110611ac357611ac3612117565b60209081029190910181015182528101919091526040015f206001015463ffffffff164210159050811580611af6575080155b15611b4a57848381518110611b0d57611b0d612117565b60200260200101516040517f26c4eabd0000000000000000000000000000000000000000000000000000000081526004016105a391815260200190565b336001600160a01b031660045f878681518110611b6957611b69612117565b60209081029190910181015182528101919091526040015f20546001600160a01b031614611bee573360045f878681518110611ba757611ba7612117565b602090810291909101810151825281019190915260409081015f2054905163521eb56d60e11b81526001600160a01b039283166004820152911660248201526044016105a3565b611bf882856121a8565b93505f60045f878681518110611c1057611c10612117565b602002602001015181526020019081526020015f2060010160049054906101000a900463ffffffff1663ffffffff16905060045f878681518110611c5657611c56612117565b60209081029190910181015182528101919091526040015f90812090815560010180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558551339082907f97f4572ff501a5533a09cf8d7d39be87e303470dd8bc7cff4fe91212be76bc7390899088908110611cd757611cd7612117565b6020026020010151604051611cee91815260200190565b60405180910390a350505080611d0390612171565b9050611a4e565b50805f03611d44576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303815f875af1158015611dc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611deb91906121bb565b50919050565b80356001600160a01b0381168114611e07575f80fd5b919050565b5f8060408385031215611e1d575f80fd5b611e2683611df1565b9150611e3460208401611df1565b90509250929050565b5f60208284031215611e4d575f80fd5b611e5682611df1565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f6020808385031215611e9b575f80fd5b823567ffffffffffffffff80821115611eb2575f80fd5b818501915085601f830112611ec5575f80fd5b813581811115611ed757611ed7611e5d565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715611f1a57611f1a611e5d565b604052918252848201925083810185019188831115611f37575f80fd5b938501935b82851015611f5557843584529385019392850192611f3c565b98975050505050505050565b5f8151808452602080850194508084015f5b83811015611f8f57815187529582019590820190600101611f73565b509495945050505050565b602081525f611e566020830184611f61565b8015158114610738575f80fd5b5f8060408385031215611fca575f80fd5b611fd383611df1565b91506020830135611fe381611fac565b809150509250929050565b604081525f6120006040830185611f61565b90508260208301529392505050565b5f805f8060808587031215612022575f80fd5b61202b85611df1565b966020860135965060408601359560600135945092505050565b5f60208284031215612055575f80fd5b8135611e5681611fac565b5f8060408385031215612071575f80fd5b50508035926020909101359150565b5f60208284031215612090575f80fd5b5035919050565b5f6020808352835180828501525f5b818110156120c2578581018301518582016040015282016120a6565b505f6040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b5f60208284031215612110575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036121a1576121a1612144565b5060010190565b808201808211156107c0576107c0612144565b5f602082840312156121cb575f80fd5b8151611e5681611fac565b818103818111156107c0576107c061214456fea2646970667358221220fadf1cd51bf146cccb0dfd9b2828941b27248fba457289120615e40ee3896b0364736f6c634300081400330000000000000000000000000001a500a6b18995b03f44bb040a5ffc28e45cb0000000000000000000000000c096362fa6f4a4b1a9ea68b1043416f3381ce300000000000000000000000000a0da53447c0f6c4987964d8463da7e6628b30f820000000000000000000000001521918961bdbc9ed4c67a7103d5999e4130e6cb

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610183575f3560e01c80638c71ec16116100dd578063e42f991911610088578063f9afb26a11610063578063f9afb26a14610471578063fc63e42d14610484578063ffa1ad7414610520575f80fd5b8063e42f991914610367578063e91b0a4114610400578063f731960c14610428575f80fd5b8063c5332b7c116100b8578063c5332b7c14610313578063ce2d683f14610326578063e2bbb15814610339575f80fd5b80638c71ec16146102db5780638da5cb5b146102ee578063a6f9dae114610300575f80fd5b80634ac7251d1161013d5780635b400e4f116101185780635b400e4f1461029d57806361d027b3146102be57806363e63e3b146102d1575f80fd5b80634ac7251d146102545780635831d8851461026757806358d3ec6a1461027d575f80fd5b8063158555371161016d57806315855537146101e05780631f16653b146101f357806324415cf614610233575f80fd5b806231d115146101875780630c062810146101cb575b5f80fd5b6101ae7f0000000000000000000000000001a500a6b18995b03f44bb040a5ffc28e45cb081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101de6101d9366004611e0c565b610569565b005b6101de6101ee366004611e3d565b61068c565b5f5461021e907801000000000000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101c2565b610246610241366004611e3d565b61073b565b6040519081526020016101c2565b6001546101ae906001600160a01b031681565b5f5461021e90600160a01b900463ffffffff1681565b61029061028b366004611e8a565b6107c6565b6040516101c29190611f9a565b6102b06102ab366004611fb9565b610aa2565b6040516101c2929190611fee565b6002546101ae906001600160a01b031681565b6102466201518081565b6102466102e936600461200f565b610cb3565b5f546101ae906001600160a01b031681565b6101de61030e366004611e3d565b611236565b6003546101ae906001600160a01b031681565b610290610334366004612045565b611313565b61034c610347366004612060565b6114ee565b604080519384526020840192909252908201526060016101c2565b6103bc610375366004612080565b60056020525f9081526040902080546001909101546001600160a01b0380831692600160a01b9081900463ffffffff169291821691046bffffffffffffffffffffffff1684565b604080516001600160a01b03958616815263ffffffff94909416602085015291909316908201526bffffffffffffffffffffffff90911660608201526080016101c2565b61041361040e366004612080565b611a00565b604080519283529015156020830152016101c2565b610461610436366004612080565b5f90815260056020526040902060010154600160a01b90046bffffffffffffffffffffffff16151590565b60405190151581526020016101c2565b61024661047f366004611e8a565b611a4b565b6104dd610492366004612080565b60046020525f9081526040902080546001909101546001600160a01b03821691600160a01b90046bffffffffffffffffffffffff169063ffffffff8082169164010000000090041684565b604080516001600160a01b0390951685526bffffffffffffffffffffffff909316602085015263ffffffff918216928401929092521660608201526080016101c2565b61055c6040518060400160405280600581526020017f312e302e3100000000000000000000000000000000000000000000000000000081525081565b6040516101c29190612097565b5f546001600160a01b031633146105ac575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6001600160a01b0382161561061a57600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040517f4672fe7e13cfb163442d0b729b5733fb3efafc66cbe3677eac9940eb41c284c2905f90a25b6001600160a01b0381161561068857600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d1905f90a25b5050565b5f546001600160a01b031633146106ca575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b6001600160a01b0381161561073857600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f179276fedd32be7c465135f8e074aefcd470c855d2550f83a36a45bfbaa61ea5905f90a25b50565b6003546040517f24415cf60000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301525f9216906324415cf690602401602060405180830381865afa15801561079c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107c09190612100565b92915050565b5f546060906001600160a01b03163314610807575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b81515f8167ffffffffffffffff81111561082357610823611e5d565b60405190808252806020026020018201604052801561084c578160200160208202803683370190505b5090505f805b83811015610a02575f86828151811061086d5761086d612117565b6020908102919091018101515f8181526005909252604090912060010154909150600160a01b90046bffffffffffffffffffffffff1680156109ef576001546040517f7048960c000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0390911690637048960c906024015f604051808303815f87803b158015610905575f80fd5b505af1158015610917573d5f803e3d5ffd5b5050505f83815260056020526040812060018101805482547fffffffffffffffff000000000000000000000000000000000000000000000000169092559190915589516001600160a01b03909116915089908590811061097957610979612117565b602002602001015186868151811061099357610993612117565b60209081029190910101526109a785612171565b945082816001600160a01b03167f677b70dc7e4a19e6af55f981ac3706886716a25e9c0b978ec0c427f51ce68b18846040516109e591815260200190565b60405180910390a3505b5050806109fb90612171565b9050610852565b508067ffffffffffffffff811115610a1c57610a1c611e5d565b604051908082528060200260200182016040528015610a45578160200160208202803683370190505b5093505f5b81811015610a9957828181518110610a6457610a64612117565b6020026020010151858281518110610a7e57610a7e612117565b6020908102919091010152610a9281612171565b9050610a4a565b50505050919050565b60605f6001600160a01b038416610ae5576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8054600160a01b900463ffffffff16818167ffffffffffffffff811115610b0f57610b0f611e5d565b604051908082528060200260200182016040528015610b38578160200160208202803683370190505b5090505f5b82811015610bfd575f818152600460205260409020546001600160a01b03808a16911603610bed57861580610b8857505f8181526004602052604090206001015463ffffffff164210155b15610bed576001828281518110610ba157610ba1612117565b91151560209283029190910190910152610bba84612171565b5f82815260046020526040902054909450610bea90600160a01b90046bffffffffffffffffffffffff16866121a8565b94505b610bf681612171565b9050610b3d565b508267ffffffffffffffff811115610c1757610c17611e5d565b604051908082528060200260200182016040528015610c40578160200160208202803683370190505b5094505f805b83811015610ca757828181518110610c6057610c60612117565b602002602001015115610c975780878381518110610c8057610c80612117565b6020908102919091010152610c9482612171565b91505b610ca081612171565b9050610c46565b50505050509250929050565b5f80546001600160a01b03163314610cf2575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b835f03610d2b576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841115610d7c576040517f7ae59685000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0360248201526044016105a3565b825f03610db5576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6bffffffffffffffffffffffff831115610e10576040517f7ae59685000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff60248201526044016105a3565b62015180821015610e59576040517f491a2bb1000000000000000000000000000000000000000000000000000000008152600481018390526201518060248201526044016105a3565b5f610e6483426121a8565b905063ffffffff811115610eb1576040517f7ae596850000000000000000000000000000000000000000000000000000000081526004810182905263ffffffff60248201526044016105a3565b6002546040517f9015d3710000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015290911690639015d37190602401602060405180830381865afa158015610f12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3691906121bb565b610f77576040517fe3d87c620000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024016105a3565b6001546040517f426e77df000000000000000000000000000000000000000000000000000000008152600481018690526001600160a01b039091169063426e77df906024016020604051808303815f875af1158015610fd8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ffc91906121bb565b6110b15760015f9054906101000a90046001600160a01b03166001600160a01b0316638fc2b24d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611050573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110749190612100565b6040517f491a2bb10000000000000000000000000000000000000000000000000000000081526004810191909152602481018590526044016105a3565b5f8054604080516080810182526001600160a01b03808a16825263ffffffff88811660208085019182528d84168587019081526bffffffffffffffffffffffff808e166060880190815278010000000000000000000000000000000000000000000000009099048516808b52600590935296909820945185549251909316600160a01b9081027fffffffffffffffff0000000000000000000000000000000000000000000000009093169385169390931791909117845595519451909316909202929091169190911760019182015590925061118e9083906121a8565b5f805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055604080518581526020810187905290810184905282906001600160a01b038816907f5fd24ab6321cb12fa0b131d7749ca303e20d69422e8191bc5d2ae4959bae08db9060600160405180910390a350949350505050565b5f546001600160a01b03163314611274575f5460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044016105a3565b6001600160a01b0381166112b4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b5f8054606091780100000000000000000000000000000000000000000000000090910463ffffffff16908167ffffffffffffffff81111561135657611356611e5d565b60405190808252806020026020018201604052801561137f578160200160208202803683370190505b5090505f805b8381101561143a578580156113be57505f81815260056020526040902060010154600160a01b90046bffffffffffffffffffffffff1615155b806113f55750851580156113f557505f81815260056020526040902060010154600160a01b90046bffffffffffffffffffffffff16155b1561142a57600183828151811061140e5761140e612117565b9115156020928302919091019091015261142782612171565b91505b61143381612171565b9050611385565b508067ffffffffffffffff81111561145457611454611e5d565b60405190808252806020026020018201604052801561147d578160200160208202803683370190505b5093505f805b848110156114e45783818151811061149d5761149d612117565b6020026020010151156114d457808683815181106114bd576114bd612117565b60209081029190910101526114d182612171565b91505b6114dd81612171565b9050611483565b5050505050919050565b5f805f835f0361152a576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f85815260056020526040812060018101549091600160a01b9091046bffffffffffffffffffffffff1690819003611591576040517f4decba84000000000000000000000000000000000000000000000000000000008152600481018890526024016105a3565b81546115aa90600160a01b900463ffffffff16426121a8565b935063ffffffff8411156115f7576040517f7ae596850000000000000000000000000000000000000000000000000000000081526004810185905263ffffffff60248201526044016105a3565b600182015460035483546040517f7e5b0998000000000000000000000000000000000000000000000000000000008152600481018a90526001600160a01b03918216602482015292811692911690637e5b099890604401602060405180830381865afa158015611669573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061168d9190612100565b9550818611156116e9576040517f545a90850000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810189905260448101879052606481018390526084016105a3565b6116f386836121d6565b9150818360010160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505f60149054906101000a900463ffffffff1663ffffffff1693506040518060800160405280336001600160a01b03168152602001876bffffffffffffffffffffffff1681526020018663ffffffff1681526020018963ffffffff1681525060045f8681526020019081526020015f205f820151815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151815f0160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506040820151816001015f6101000a81548163ffffffff021916908363ffffffff16021790555060608201518160010160046101000a81548163ffffffff021916908363ffffffff16021790555090505083600161185491906121a8565b5f805463ffffffff92909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790556002546040517f1ac17db9000000000000000000000000000000000000000000000000000000008152336004820152602481018990526001600160a01b0383811660448301526064820189905290911690631ac17db9906084015f604051808303815f87803b158015611901575f80fd5b505af1158015611913573d5f803e3d5ffd5b50505050815f0361199f575f8881526005602052604080822080547fffffffffffffffff000000000000000000000000000000000000000000000000168155600101919091555188906001600160a01b038316907f677b70dc7e4a19e6af55f981ac3706886716a25e9c0b978ec0c427f51ce68b18906119969086815260200190565b60405180910390a35b604080518581526020810188905290810188905260608101869052339089906001600160a01b038416907ffa892a5592accfded99f9df9ad2d678230f37aeeb8fde5dd3b73769b5069bc0e9060800160405180910390a45050509250925092565b5f81815260046020526040812054600160a01b90046bffffffffffffffffffffffff16908115611a4657505f8281526004602052604090206001015463ffffffff164210155b915091565b5f805b8251811015611d0a575f60045f858481518110611a6d57611a6d612117565b602002602001015181526020019081526020015f205f0160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff1690505f60045f868581518110611ac357611ac3612117565b60209081029190910181015182528101919091526040015f206001015463ffffffff164210159050811580611af6575080155b15611b4a57848381518110611b0d57611b0d612117565b60200260200101516040517f26c4eabd0000000000000000000000000000000000000000000000000000000081526004016105a391815260200190565b336001600160a01b031660045f878681518110611b6957611b69612117565b60209081029190910181015182528101919091526040015f20546001600160a01b031614611bee573360045f878681518110611ba757611ba7612117565b602090810291909101810151825281019190915260409081015f2054905163521eb56d60e11b81526001600160a01b039283166004820152911660248201526044016105a3565b611bf882856121a8565b93505f60045f878681518110611c1057611c10612117565b602002602001015181526020019081526020015f2060010160049054906101000a900463ffffffff1663ffffffff16905060045f878681518110611c5657611c56612117565b60209081029190910181015182528101919091526040015f90812090815560010180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558551339082907f97f4572ff501a5533a09cf8d7d39be87e303470dd8bc7cff4fe91212be76bc7390899088908110611cd757611cd7612117565b6020026020010151604051611cee91815260200190565b60405180910390a350505080611d0390612171565b9050611a4e565b50805f03611d44576040517f7c946ed700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f0000000000000000000000000001a500a6b18995b03f44bb040a5ffc28e45cb06001600160a01b03169063a9059cbb906044016020604051808303815f875af1158015611dc7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611deb91906121bb565b50919050565b80356001600160a01b0381168114611e07575f80fd5b919050565b5f8060408385031215611e1d575f80fd5b611e2683611df1565b9150611e3460208401611df1565b90509250929050565b5f60208284031215611e4d575f80fd5b611e5682611df1565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f6020808385031215611e9b575f80fd5b823567ffffffffffffffff80821115611eb2575f80fd5b818501915085601f830112611ec5575f80fd5b813581811115611ed757611ed7611e5d565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715611f1a57611f1a611e5d565b604052918252848201925083810185019188831115611f37575f80fd5b938501935b82851015611f5557843584529385019392850192611f3c565b98975050505050505050565b5f8151808452602080850194508084015f5b83811015611f8f57815187529582019590820190600101611f73565b509495945050505050565b602081525f611e566020830184611f61565b8015158114610738575f80fd5b5f8060408385031215611fca575f80fd5b611fd383611df1565b91506020830135611fe381611fac565b809150509250929050565b604081525f6120006040830185611f61565b90508260208301529392505050565b5f805f8060808587031215612022575f80fd5b61202b85611df1565b966020860135965060408601359560600135945092505050565b5f60208284031215612055575f80fd5b8135611e5681611fac565b5f8060408385031215612071575f80fd5b50508035926020909101359150565b5f60208284031215612090575f80fd5b5035919050565b5f6020808352835180828501525f5b818110156120c2578581018301518582016040015282016120a6565b505f6040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b5f60208284031215612110575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036121a1576121a1612144565b5060010190565b808201808211156107c0576107c0612144565b5f602082840312156121cb575f80fd5b8151611e5681611fac565b818103818111156107c0576107c061214456fea2646970667358221220fadf1cd51bf146cccb0dfd9b2828941b27248fba457289120615e40ee3896b0364736f6c63430008140033

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

0000000000000000000000000001a500a6b18995b03f44bb040a5ffc28e45cb0000000000000000000000000c096362fa6f4a4b1a9ea68b1043416f3381ce300000000000000000000000000a0da53447c0f6c4987964d8463da7e6628b30f820000000000000000000000001521918961bdbc9ed4c67a7103d5999e4130e6cb

-----Decoded View---------------
Arg [0] : _olas (address): 0x0001A500A6B18995B03f44bb040A5fFc28E45CB0
Arg [1] : _tokenomics (address): 0xc096362fa6f4A4B1a9ea68b1043416f3381ce300
Arg [2] : _treasury (address): 0xa0DA53447C0f6C4987964d8463da7e6628B30f82
Arg [3] : _bondCalculator (address): 0x1521918961bDBC9Ed4C67a7103D5999e4130E6CB

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000000001a500a6b18995b03f44bb040a5ffc28e45cb0
Arg [1] : 000000000000000000000000c096362fa6f4a4b1a9ea68b1043416f3381ce300
Arg [2] : 000000000000000000000000a0da53447c0f6c4987964d8463da7e6628b30f82
Arg [3] : 0000000000000000000000001521918961bdbc9ed4c67a7103d5999e4130e6cb


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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.