OP Sepolia Testnet

Contract

0x26c6f7FA1Fe03193D1Fb759Aac5Bda8e4b5fB4F8

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount
Migrate119290742024-05-14 4:24:48546 days ago1715660688IN
0x26c6f7FA...e4b5fB4F8
0 ETH0.0003062519663.46794976

Parent Transaction Hash Block From To Amount
View All Internal Transactions
Loading...
Loading

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

Contract Name:
MestSharesFactoryV1

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IMestShare } from "../interface/IMestShare.sol";
import { IYieldAggregator } from "contracts/interface/IYieldAggregator.sol";
import { BondingCurveLib } from "../lib/BondingCurveLib.sol";

contract MestSharesFactoryV1 is Ownable {
    using SafeERC20 for IERC20;

    struct CurveFixedParam {
        uint256 basePrice;
        uint256 linearPriceSlope;
        uint256 inflectionPoint;
        uint256 inflectionPrice;
    }

    address public immutable MEST_ERC1155;

    uint256 public shareIndex;
    uint256 public depositedETHAmount;
    uint256 public referralFeePercent = 5 * 1e16;
    uint256 public creatorFeePercent = 5 * 1e16;

    CurveFixedParam public generalCurveFixedParam;
    IYieldAggregator public yieldAggregator;

    mapping(uint256 => address) public sharesMap;

    event ClaimYield(uint256 amount, address indexed to);
    event MigrateYield(address indexed yieldAggregator);
    event Create(uint256 indexed shareId, address indexed creator);
    event Trade(
        address indexed trader,
        uint256 indexed shareId,
        bool isBuy,
        uint256 quantity,
        uint256 totalPrice,
        uint256 referralFee,
        uint256 creatorFee,
        uint256 newSupply
    );

    constructor(
        address _mestERC1155,
        uint256 _basePrice,
        uint256 _inflectionPoint,
        uint256 _inflectionPrice,
        uint256 _linearPriceSlope
    ) {
        MEST_ERC1155 = _mestERC1155;

        generalCurveFixedParam.basePrice = _basePrice; // 5000000000000000;
        generalCurveFixedParam.inflectionPoint = _inflectionPoint; // 1500;
        generalCurveFixedParam.inflectionPrice = _inflectionPrice; // 102500000000000000;
        generalCurveFixedParam.linearPriceSlope = _linearPriceSlope; // 0;
    }

    fallback() external payable { }

    receive() external payable { }

    function setReferralFeePercent(uint256 _feePercent) external onlyOwner {
        referralFeePercent = _feePercent;
    }

    function setCreatorFeePercent(uint256 _feePercent) external onlyOwner {
        creatorFeePercent = _feePercent;
    }

    /**
     * @notice Migrates the yieldAggregator.
     * There are three cases:
     * Case 1: address(0) -> yieldAggregator, which initializes yield farming.
     * Case 2: yieldAggregator -> blank yieldAggregator, which cancels yield farming.
     * Case 3: yieldAggregator -> new yieldAggregator, which migrates to a new yield farming.
     * @param _yieldAggregator The address of the yield aggregator.
     */
    function migrate(address _yieldAggregator) external onlyOwner {
        require(_yieldAggregator != address(0), "Invalid yieldAggregator");

        // Case 1 if yieldAggregator is empty, else Case 2 or 3.
        if (address(yieldAggregator) == address(0)) {
            _setYieldAggregator(_yieldAggregator);
        } else {
            // Step 1: Withdraw all yieldToken into ETH.
            _withdrawAllYieldTokenToETH();

            // Step 2: Revoke the approval of the old yieldAggregator.
            address yieldToken = yieldAggregator.yieldToken();
            IERC20(yieldToken).safeApprove(address(yieldAggregator), 0);

            // Step 3: Set the new yieldAggregator.
            _setYieldAggregator(_yieldAggregator);

            // Step 4: Deposit all ETH into the new yieldAggregator as yieldToken.
            _depositAllETHToYieldToken();
        }

        emit MigrateYield(_yieldAggregator);
    }

    /**
     * @notice Only for owner to claim a specific yield amount.
     * @param amount The yield amount the owner claims.
     * @param to The address receiving the yield.
     */
    function claimYield(uint256 amount, address to) public onlyOwner {
        uint256 maxAmount = yieldAggregator.yieldMaxClaimable(depositedETHAmount);
        require(amount <= maxAmount, "Insufficient yield");

        yieldAggregator.yieldWithdraw(amount);
        _safeTransferETH(to, amount);

        emit ClaimYield(amount, to);
    }

    /**
     * @notice Creates a share with an auto-incremented ID.
     * @param creator The address of the creator, which will be used as creator fee recipient.
     * @dev The share ID is identical to the ERC1155 ID.
     */
    function createShare(address creator) public {
        sharesMap[shareIndex] = creator;

        emit Create(shareIndex, creator);

        shareIndex++;
    }

    /**
     * @param shareId The ID of the share.
     * @param quantity The quantity of shares.
     * @param referral The address of the referral fee recipient.
     */
    function buyShare(uint256 shareId, uint256 quantity, address referral) public payable {
        require(address(yieldAggregator) != address(0), "Invalid yieldAggregator");
        require(shareId < shareIndex, "Invalid shareId");

        address creator = sharesMap[shareId];
        uint256 fromSupply = IMestShare(MEST_ERC1155).shareFromSupply(shareId);
        (uint256 buyPriceAfterFee, uint256 buyPrice, uint256 referralFee, uint256 creatorFee) =
            getBuyPriceAfterFee(shareId, quantity, referral);

        require(fromSupply > 0 || msg.sender == creator, "First buyer must be creator");
        require(msg.value >= buyPriceAfterFee, "Insufficient payment");

        // Mint shares to the buyer
        IMestShare(MEST_ERC1155).shareMint(msg.sender, shareId, quantity);
        emit Trade(
            msg.sender, shareId, true, quantity, buyPriceAfterFee, referralFee, creatorFee, fromSupply + quantity
        );

        // Deposit the buy price (in ETH) to the yield aggregator (e.g., Aave)
        _safeTransferETH(address(yieldAggregator), buyPrice);
        yieldAggregator.yieldDeposit();
        depositedETHAmount += buyPrice;

        // Transfer referral and creator fees
        _safeTransferETH(referral, referralFee);
        _safeTransferETH(creator, creatorFee);

        // If buyer paid more than necessary, refund the excess
        uint256 refundAmount = msg.value - buyPriceAfterFee;
        if (refundAmount > 0) {
            _safeTransferETH(msg.sender, refundAmount);
        }
    }

    /**
     * @param shareId The ID of the share.
     * @param quantity The quantity of shares.
     * @param minETHAmount The minimum amount of ETH will be used for slippage protection.
     * @param referral The address of the referral fee recipient.
     */
    function sellShare(uint256 shareId, uint256 quantity, uint256 minETHAmount, address referral) public {
        require(shareId < shareIndex, "Invalid shareId");
        require(IMestShare(MEST_ERC1155).shareBalanceOf(msg.sender, shareId) >= quantity, "Insufficient shares");

        address creator = sharesMap[shareId];
        (uint256 sellPriceAfterFee, uint256 sellPrice, uint256 referralFee, uint256 creatorFee) =
            getSellPriceAfterFee(shareId, quantity, referral);
        require(sellPriceAfterFee >= minETHAmount, "Insufficient minReceive");

        // Burn shares from the seller
        IMestShare(MEST_ERC1155).shareBurn(msg.sender, shareId, quantity);
        uint256 fromSupply = IMestShare(MEST_ERC1155).shareFromSupply(shareId);
        emit Trade(msg.sender, shareId, false, quantity, sellPriceAfterFee, referralFee, creatorFee, fromSupply);

        // Withdraw the sell price (in ETH) from the yield aggregator (e.g., Aave)
        yieldAggregator.yieldWithdraw(sellPrice);
        depositedETHAmount -= sellPrice;

        // Transfer ETH to the seller
        _safeTransferETH(msg.sender, sellPriceAfterFee);

        // Transfer referral and creator fees
        _safeTransferETH(referral, referralFee);
        _safeTransferETH(creator, creatorFee);
    }

    /**
     * @notice Calculates buy price and fees.
     * @return buyPriceAfterFee The amount user pay after fees.
     * @return buyPrice The initial price of the shares.
     * @return referralFee Fee by the referral. If = address(0), there is no referral fee.
     * @return creatorFee Fee by the share's creator.
     */
    function getBuyPriceAfterFee(
        uint256 shareId,
        uint256 quantity,
        address referral
    ) public view returns (uint256 buyPriceAfterFee, uint256 buyPrice, uint256 referralFee, uint256 creatorFee) {
        uint256 fromSupply = IMestShare(MEST_ERC1155).shareFromSupply(shareId);
        uint256 actualReferralFeePercent = referral != address(0) ? referralFeePercent : 0;

        buyPrice = _subTotal(fromSupply, quantity);
        referralFee = (buyPrice * actualReferralFeePercent) / 1 ether;
        creatorFee = (buyPrice * creatorFeePercent) / 1 ether;
        buyPriceAfterFee = buyPrice + referralFee + creatorFee;
    }

    /**
     * @notice Calculates sell price and fees.
     * @return sellPriceAfterFee The amount user receives after fees.
     * @return sellPrice The initial price of the shares.
     * @return referralFee Fee by the referral. If = address(0), there is no referral fee.
     * @return creatorFee Fee by the share's creator.
     */
    function getSellPriceAfterFee(
        uint256 shareId,
        uint256 quantity,
        address referral
    ) public view returns (uint256 sellPriceAfterFee, uint256 sellPrice, uint256 referralFee, uint256 creatorFee) {
        uint256 fromSupply = IMestShare(MEST_ERC1155).shareFromSupply(shareId);
        uint256 actualReferralFeePercent = referral != address(0) ? referralFeePercent : 0;
        require(fromSupply >= quantity, "Exceeds supply");

        sellPrice = _subTotal(fromSupply - quantity, quantity);
        referralFee = (sellPrice * actualReferralFeePercent) / 1 ether;
        creatorFee = (sellPrice * creatorFeePercent) / 1 ether;
        sellPriceAfterFee = sellPrice - referralFee - creatorFee;
    }

    /**
     * @notice Sets the yieldAggregator and approves it to spend the yieldToken.
     * @param _yieldAggregator The address of the yieldAggregator.
     */
    function _setYieldAggregator(address _yieldAggregator) internal {
        yieldAggregator = IYieldAggregator(_yieldAggregator);

        address yieldToken = yieldAggregator.yieldToken();
        IERC20(yieldToken).safeApprove(_yieldAggregator, type(uint256).max);
    }

    /**
     * @notice Withdraws all yieldToken into the MestSharesFactory as ETH.
     */
    function _withdrawAllYieldTokenToETH() internal {
        uint256 withdrawableETHAmount = yieldAggregator.yieldBalanceOf(address(this));
        yieldAggregator.yieldWithdraw(withdrawableETHAmount);
    }

    /**
     * @notice Deposits all ETH into the yieldAggregator as yieldToken.
     */
    function _depositAllETHToYieldToken() internal {
        uint256 ethAmount = address(this).balance;
        _safeTransferETH(address(yieldAggregator), ethAmount);
        yieldAggregator.yieldDeposit();
    }

    /**
     * @dev Returns the area under the bonding curve, which is the price before any fees.
     * @param fromSupply The starting share supply.
     * @param quantity The number of shares to be minted.
     * @return subTotal The area under the bonding curve.
     */
    function _subTotal(uint256 fromSupply, uint256 quantity) internal view returns (uint256 subTotal) {
        unchecked {
            subTotal = generalCurveFixedParam.basePrice * quantity;
            subTotal += BondingCurveLib.linearSum(generalCurveFixedParam.linearPriceSlope, fromSupply, quantity);
            subTotal += BondingCurveLib.sigmoid2Sum(
                generalCurveFixedParam.inflectionPoint, generalCurveFixedParam.inflectionPrice, fromSupply, quantity
            );
        }
    }

    /**
     * @notice Transfers ETH to the recipient address
     * @param to The destination of the transfer
     * @param value The value to be transferred
     * @dev Fails with `ETH transfer failed`
     */
    function _safeTransferETH(address to, uint256 value) internal {
        if (value > 0) {
            (bool success,) = to.call{ value: value }(new bytes(0));
            require(success, "ETH transfer failed");
        }
    }
}

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

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev 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 {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

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

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

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

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

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

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

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

interface IMestShare {
    function shareMint(address to, uint256 id, uint256 amount) external;

    function shareBurn(address from, uint256 id, uint256 amount) external;

    function shareFromSupply(uint256 id) external view returns (uint256);

    function shareBalanceOf(address user, uint256 id) external view returns (uint256);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

interface IYieldAggregator {
    function yieldDeposit() external;

    function yieldWithdraw(uint256 amount) external;

    function yieldBalanceOf(address owner) external view returns (uint256 withdrawableETHAmount);

    function yieldToken() external view returns (address);

    function yieldMaxClaimable(uint256 depositedETHAmount) external view returns (uint256 maxClaimableETH);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

import { FixedPointMathLib } from "solady/utils/FixedPointMathLib.sol";

library BondingCurveLib {
    function sigmoid2Sum(
        uint256 inflectionPoint,
        uint256 inflectionPrice,
        uint256 fromSupply,
        uint256 quantity
    ) internal pure returns (uint256 sum) {
        // We don't need checked arithmetic for the sum.
        // The max possible sum for the quadratic region is capped at:
        // `n * (n + 1) * (2*n + 1) * h < 2**32 * 2**33 * 2**34 * 2**128 = 2**227`.
        // The max possible sum for the sqrt region is capped at:
        // `end * (2*h * sqrt(end)) < 2**32 * 2**129 * 2**16 = 2**177`.
        // The overall sum is capped by:
        // `2**161 + 2**227 <= 2**228 < 2 **256`.
        // The result will be small enough for unchecked multiplication with a 16-bit BPS.
        unchecked {
            uint256 g = inflectionPoint;
            uint256 h = inflectionPrice;

            // Early return to save gas if either `g` or `h` is zero.
            if (g * h == 0) return 0;

            uint256 s = uint256(fromSupply) + 1;
            uint256 end = s + uint256(quantity);
            uint256 quadraticEnd = FixedPointMathLib.min(g, end);

            if (s < quadraticEnd) {
                uint256 k = uint256(fromSupply); // `s - 1`.
                uint256 n = quadraticEnd - 1;
                // In practice, `h` (units: wei) will be set to be much greater than `g * g`.
                uint256 a = FixedPointMathLib.rawDiv(h, g * g);
                // Use the closed form to compute the sum.
                // sum(i ^2)/ g^2 considered as infinitesimal and use taylor series
                sum = ((n * (n + 1) * ((n << 1) + 1) - k * (k + 1) * ((k << 1) + 1)) / 6) * a;
                s = quadraticEnd;
            }

            if (s < end) {
                uint256 c = (3 * g) >> 2;
                uint256 h2 = h << 1;
                do {
                    uint256 r = FixedPointMathLib.sqrt((s - c) * g);
                    sum += FixedPointMathLib.rawDiv(h2 * r, g);
                } while (++s != end);
            }
        }
    }

    function linearSum(
        uint256 linearPriceSlope,
        uint256 fromSupply,
        uint256 quantity
    ) internal pure returns (uint256 sum) {
        // We don't need checked arithmetic for the sum because the max possible
        // intermediate value is capped at:
        // `k * m < 2**32 * 2**128 = 2**160 < 2**256`.
        // As `quantity` is 32 bits, max possible value for `sum`
        // is capped at:
        // `2**32 * 2**160 = 2**192 < 2**256`.
        // The result will be small enough for unchecked multiplication with a 16-bit BPS.
        unchecked {
            uint256 m = linearPriceSlope;
            uint256 k = uint256(fromSupply);
            uint256 n = k + uint256(quantity);
            // Use the closed form to compute the sum.
            return m * ((n * (n + 1) - k * (k + 1)) >> 1);
        }
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

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

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 11 of 11 : FixedPointMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error ExpOverflow();

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error FactorialOverflow();

    /// @dev The operation failed, due to an overflow.
    error RPowOverflow();

    /// @dev The mantissa is too big to fit.
    error MantissaOverflow();

    /// @dev The operation failed, due to an multiplication overflow.
    error MulWadFailed();

    /// @dev The operation failed, due to an multiplication overflow.
    error SMulWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error DivWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error SDivWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error MulDivFailed();

    /// @dev The division failed, as the denominator is zero.
    error DivFailed();

    /// @dev The full precision multiply-divide operation failed, either due
    /// to the result being larger than 256 bits, or a division by a zero.
    error FullMulDivFailed();

    /// @dev The output is undefined, as the input is less-than-or-equal to zero.
    error LnWadUndefined();

    /// @dev The input outside the acceptable domain.
    error OutOfDomain();

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

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant WAD = 1e18;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              SIMPLIFIED FIXED POINT OPERATIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
            if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
                mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := sdiv(z, WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
    function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
    function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up.
    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
    function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, WAD)
            // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
            if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) {
                mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := sdiv(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
    function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
    function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up.
    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
    function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }

    /// @dev Equivalent to `x` to the power of `y`.
    /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Using `ln(x)` means `x` must be greater than 0.
        return expWad((lnWad(x) * y) / int256(WAD));
    }

    /// @dev Returns `exp(x)`, denominated in `WAD`.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is less than 0.5 we return zero.
            // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
            if (x <= -41446531673892822313) return r;

            /// @solidity memory-safe-assembly
            assembly {
                // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
                // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
                if iszero(slt(x, 135305999368893231589)) {
                    mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
                    revert(0x1c, 0x04)
                }
            }

            // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5 ** 18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // `k` is in the range `[-61, 195]`.

            // Evaluate using a (6, 7)-term rational approximation.
            // `p` is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            /// @solidity memory-safe-assembly
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already `2**96` too large.
                r := sdiv(p, q)
            }

            // r should be in the range `(0.09, 0.25) * 2**96`.

            // We now need to multiply r by:
            // - The scale factor `s ≈ 6.031367120`.
            // - The `2**k` factor from the range reduction.
            // - The `1e18 / 2**96` factor for base conversion.
            // We do this all at once, with an intermediate result in `2**213`
            // basis, so the final right shift is always by a positive amount.
            r = int256(
                (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
            );
        }
    }

    /// @dev Returns `ln(x)`, denominated in `WAD`.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
    function lnWad(int256 x) internal pure returns (int256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
            // We do this by multiplying by `2**96 / 10**18`. But since
            // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
            // and add `ln(2**96 / 10**18)` at the end.

            // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // We place the check here for more optimal stack operations.
            if iszero(sgt(x, 0)) {
                mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
                revert(0x1c, 0x04)
            }
            // forgefmt: disable-next-item
            r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            x := shr(159, shl(r, x))

            // Evaluate using a (8, 8)-term rational approximation.
            // `p` is made monic, we will multiply by a scale factor later.
            // forgefmt: disable-next-item
            let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
                sar(96, mul(add(43456485725739037958740375743393,
                sar(96, mul(add(24828157081833163892658089445524,
                sar(96, mul(add(3273285459638523848632254066296,
                    x), x))), x))), x)), 11111509109440967052023855526967)
            p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
            p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
            p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.

            // `q` is monic by convention.
            let q := add(5573035233440673466300451813936, x)
            q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
            q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
            q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
            q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
            q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
            q := add(909429971244387300277376558375, sar(96, mul(x, q)))

            // `p / q` is in the range `(0, 0.125) * 2**96`.

            // Finalization, we need to:
            // - Multiply by the scale factor `s = 5.549…`.
            // - Add `ln(2**96 / 10**18)`.
            // - Add `k * ln(2)`.
            // - Multiply by `10**18 / 2**96 = 5**18 >> 78`.

            // The q polynomial is known not to have zeros in the domain.
            // No scaling required because p is already `2**96` too large.
            p := sdiv(p, q)
            // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
            p := mul(1677202110996718588342820967067443963516166, p)
            // Add `ln(2) * k * 5**18 * 2**192`.
            // forgefmt: disable-next-item
            p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
            // Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
            p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
            // Base conversion: mul `2**18 / 2**192`.
            r := sar(174, p)
        }
    }

    /// @dev Returns `W_0(x)`, denominated in `WAD`.
    /// See: https://en.wikipedia.org/wiki/Lambert_W_function
    /// a.k.a. Product log function. This is an approximation of the principal branch.
    function lambertW0Wad(int256 x) internal pure returns (int256 w) {
        // forgefmt: disable-next-item
        unchecked {
            if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
            int256 wad = int256(WAD);
            int256 p = x;
            uint256 c; // Whether we need to avoid catastrophic cancellation.
            uint256 i = 4; // Number of iterations.
            if (w <= 0x1ffffffffffff) {
                if (-0x4000000000000 <= w) {
                    i = 1; // Inputs near zero only take one step to converge.
                } else if (w <= -0x3ffffffffffffff) {
                    i = 32; // Inputs near `-1/e` take very long to converge.
                }
            } else if (w >> 63 == 0) {
                /// @solidity memory-safe-assembly
                assembly {
                    // Inline log2 for more performance, since the range is small.
                    let v := shr(49, w)
                    let l := shl(3, lt(0xff, v))
                    l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
                        0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
                    w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
                    c := gt(l, 60)
                    i := add(2, add(gt(l, 53), c))
                }
            } else {
                int256 ll = lnWad(w = lnWad(w));
                /// @solidity memory-safe-assembly
                assembly {
                    // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
                    w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
                    i := add(3, iszero(shr(68, x)))
                    c := iszero(shr(143, x))
                }
                if (c == 0) {
                    do { // If `x` is big, use Newton's so that intermediate values won't overflow.
                        int256 e = expWad(w);
                        /// @solidity memory-safe-assembly
                        assembly {
                            let t := mul(w, div(e, wad))
                            w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
                        }
                        if (p <= w) break;
                        p = w;
                    } while (--i != 0);
                    /// @solidity memory-safe-assembly
                    assembly {
                        w := sub(w, sgt(w, 2))
                    }
                    return w;
                }
            }
            do { // Otherwise, use Halley's for faster convergence.
                int256 e = expWad(w);
                /// @solidity memory-safe-assembly
                assembly {
                    let t := add(w, wad)
                    let s := sub(mul(w, e), mul(x, wad))
                    w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
                }
                if (p <= w) break;
                p = w;
            } while (--i != c);
            /// @solidity memory-safe-assembly
            assembly {
                w := sub(w, sgt(w, 2))
            }
            // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
            // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
            if (c != 0) {
                int256 t = w | 1;
                /// @solidity memory-safe-assembly
                assembly {
                    x := sdiv(mul(x, wad), t)
                }
                x = (t * (wad + lnWad(x)));
                /// @solidity memory-safe-assembly
                assembly {
                    w := sdiv(x, add(wad, t))
                }
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  GENERAL NUMBER UTILITIES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
    function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                // 512-bit multiply `[p1 p0] = x * y`.
                // Compute the product mod `2**256` and mod `2**256 - 1`
                // then use the Chinese Remainder Theorem to reconstruct
                // the 512 bit result. The result is stored in two 256
                // variables such that `product = p1 * 2**256 + p0`.

                // Least significant 256 bits of the product.
                result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
                let mm := mulmod(x, y, not(0))
                // Most significant 256 bits of the product.
                let p1 := sub(mm, add(result, lt(mm, result)))

                // Handle non-overflow cases, 256 by 256 division.
                if iszero(p1) {
                    if iszero(d) {
                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                        revert(0x1c, 0x04)
                    }
                    result := div(result, d)
                    break
                }

                // Make sure the result is less than `2**256`. Also prevents `d == 0`.
                if iszero(gt(d, p1)) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }

                /*------------------- 512 by 256 division --------------------*/

                // Make division exact by subtracting the remainder from `[p1 p0]`.
                // Compute remainder using mulmod.
                let r := mulmod(x, y, d)
                // `t` is the least significant bit of `d`.
                // Always greater or equal to 1.
                let t := and(d, sub(0, d))
                // Divide `d` by `t`, which is a power of two.
                d := div(d, t)
                // Invert `d mod 2**256`
                // Now that `d` is an odd number, it has an inverse
                // modulo `2**256` such that `d * inv = 1 mod 2**256`.
                // Compute the inverse by starting with a seed that is correct
                // correct for four bits. That is, `d * inv = 1 mod 2**4`.
                let inv := xor(2, mul(3, d))
                // Now use Newton-Raphson iteration to improve the precision.
                // Thanks to Hensel's lifting lemma, this also works in modular
                // arithmetic, doubling the correct bits in each step.
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
                result :=
                    mul(
                        // Divide [p1 p0] by the factors of two.
                        // Shift in bits from `p1` into `p0`. For this we need
                        // to flip `t` such that it is `2**256 / t`.
                        or(
                            mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
                            div(sub(result, r), t)
                        ),
                        // inverse mod 2**256
                        mul(inv, sub(2, mul(d, inv)))
                    )
                break
            }
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Uniswap-v3-core under MIT license:
    /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
    function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        result = fullMulDiv(x, y, d);
        /// @solidity memory-safe-assembly
        assembly {
            if mulmod(x, y, d) {
                result := add(result, 1)
                if iszero(result) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Returns `floor(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), d)
        }
    }

    /// @dev Returns `ceil(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
        }
    }

    /// @dev Returns `ceil(x / d)`.
    /// Reverts if `d` is zero.
    function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(d) {
                mstore(0x00, 0x65244e4e) // `DivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(x, d))), div(x, d))
        }
    }

    /// @dev Returns `max(0, x - y)`.
    function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
    /// Reverts if the computation overflows.
    function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
            if x {
                z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
                let half := shr(1, b) // Divide `b` by 2.
                // Divide `y` by 2 every iteration.
                for { y := shr(1, y) } y { y := shr(1, y) } {
                    let xx := mul(x, x) // Store x squared.
                    let xxRound := add(xx, half) // Round to the nearest number.
                    // Revert if `xx + half` overflowed, or if `x ** 2` overflows.
                    if or(lt(xxRound, xx), shr(128, x)) {
                        mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                        revert(0x1c, 0x04)
                    }
                    x := div(xxRound, b) // Set `x` to scaled `xxRound`.
                    // If `y` is odd:
                    if and(y, 1) {
                        let zx := mul(z, x) // Compute `z * x`.
                        let zxRound := add(zx, half) // Round to the nearest number.
                        // If `z * x` overflowed or `zx + half` overflowed:
                        if or(xor(div(zx, x), z), lt(zxRound, zx)) {
                            // Revert if `x` is non-zero.
                            if iszero(iszero(x)) {
                                mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                                revert(0x1c, 0x04)
                            }
                        }
                        z := div(zxRound, b) // Return properly scaled `zxRound`.
                    }
                }
            }
        }
    }

    /// @dev Returns the square root of `x`.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
            // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffffff, shr(r, x))))
            z := shl(shr(1, r), z)

            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could
            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
            // That's not possible if `x < 256` but we can just verify those cases exhaustively.

            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.

            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
            // with largest error when `s = 1` and when `s = 256` or `1/256`.

            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
            // Then we can estimate `sqrt(y)` using
            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.

            // There is no overflow risk here since `y < 2**136` after the first branch above.
            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If `x+1` is a perfect square, the Babylonian method cycles between
            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            z := sub(z, lt(div(x, z), z))
        }
    }

    /// @dev Returns the cube root of `x`.
    /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
    /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
    function cbrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))

            z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))

            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)

            z := sub(z, lt(div(x, mul(z, z)), z))
        }
    }

    /// @dev Returns the square root of `x`, denominated in `WAD`.
    function sqrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            z = 10 ** 9;
            if (x <= type(uint256).max / 10 ** 36 - 1) {
                x *= 10 ** 18;
                z = 1;
            }
            z *= sqrt(x);
        }
    }

    /// @dev Returns the cube root of `x`, denominated in `WAD`.
    function cbrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            z = 10 ** 12;
            if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) {
                if (x >= type(uint256).max / 10 ** 36) {
                    x *= 10 ** 18;
                    z = 10 ** 6;
                } else {
                    x *= 10 ** 36;
                    z = 1;
                }
            }
            z *= cbrt(x);
        }
    }

    /// @dev Returns the factorial of `x`.
    function factorial(uint256 x) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(x, 58)) {
                mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
                revert(0x1c, 0x04)
            }
            for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) }
        }
    }

    /// @dev Returns the log2 of `x`.
    /// Equivalent to computing the index of the most significant bit (MSB) of `x`.
    /// Returns 0 if `x` is zero.
    function log2(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0x0706060506020504060203020504030106050205030304010505030400000000))
        }
    }

    /// @dev Returns the log2 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log2Up(uint256 x) internal pure returns (uint256 r) {
        r = log2(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(r, 1), x))
        }
    }

    /// @dev Returns the log10 of `x`.
    /// Returns 0 if `x` is zero.
    function log10(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(x, 100000000000000000000000000000000000000)) {
                x := div(x, 100000000000000000000000000000000000000)
                r := 38
            }
            if iszero(lt(x, 100000000000000000000)) {
                x := div(x, 100000000000000000000)
                r := add(r, 20)
            }
            if iszero(lt(x, 10000000000)) {
                x := div(x, 10000000000)
                r := add(r, 10)
            }
            if iszero(lt(x, 100000)) {
                x := div(x, 100000)
                r := add(r, 5)
            }
            r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
        }
    }

    /// @dev Returns the log10 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log10Up(uint256 x) internal pure returns (uint256 r) {
        r = log10(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(exp(10, r), x))
        }
    }

    /// @dev Returns the log256 of `x`.
    /// Returns 0 if `x` is zero.
    function log256(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(shr(3, r), lt(0xff, shr(r, x)))
        }
    }

    /// @dev Returns the log256 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log256Up(uint256 x) internal pure returns (uint256 r) {
        r = log256(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(shl(3, r), 1), x))
        }
    }

    /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
    /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
    function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
        /// @solidity memory-safe-assembly
        assembly {
            mantissa := x
            if mantissa {
                if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
                    mantissa := div(mantissa, 1000000000000000000000000000000000)
                    exponent := 33
                }
                if iszero(mod(mantissa, 10000000000000000000)) {
                    mantissa := div(mantissa, 10000000000000000000)
                    exponent := add(exponent, 19)
                }
                if iszero(mod(mantissa, 1000000000000)) {
                    mantissa := div(mantissa, 1000000000000)
                    exponent := add(exponent, 12)
                }
                if iszero(mod(mantissa, 1000000)) {
                    mantissa := div(mantissa, 1000000)
                    exponent := add(exponent, 6)
                }
                if iszero(mod(mantissa, 10000)) {
                    mantissa := div(mantissa, 10000)
                    exponent := add(exponent, 4)
                }
                if iszero(mod(mantissa, 100)) {
                    mantissa := div(mantissa, 100)
                    exponent := add(exponent, 2)
                }
                if iszero(mod(mantissa, 10)) {
                    mantissa := div(mantissa, 10)
                    exponent := add(exponent, 1)
                }
            }
        }
    }

    /// @dev Convenience function for packing `x` into a smaller number using `sci`.
    /// The `mantissa` will be in bits [7..255] (the upper 249 bits).
    /// The `exponent` will be in bits [0..6] (the lower 7 bits).
    /// Use `SafeCastLib` to safely ensure that the `packed` number is small
    /// enough to fit in the desired unsigned integer type:
    /// ```
    ///     uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
    /// ```
    function packSci(uint256 x) internal pure returns (uint256 packed) {
        (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
        /// @solidity memory-safe-assembly
        assembly {
            if shr(249, x) {
                mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
                revert(0x1c, 0x04)
            }
            packed := or(shl(7, x), packed)
        }
    }

    /// @dev Convenience function for unpacking a packed number from `packSci`.
    function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
        unchecked {
            unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
        }
    }

    /// @dev Returns the average of `x` and `y`.
    function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = (x & y) + ((x ^ y) >> 1);
        }
    }

    /// @dev Returns the average of `x` and `y`.
    function avg(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = (x >> 1) + (y >> 1) + (x & y & 1);
        }
    }

    /// @dev Returns the absolute value of `x`.
    function abs(int256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(sar(255, x), add(sar(255, x), x))
        }
    }

    /// @dev Returns the absolute distance between `x` and `y`.
    function dist(int256 x, int256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), slt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), gt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), sgt(y, x)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(uint256 x, uint256 minValue, uint256 maxValue)
        internal
        pure
        returns (uint256 z)
    {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
        }
    }

    /// @dev Returns greatest common divisor of `x` and `y`.
    function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            for { z := x } y {} {
                let t := y
                y := mod(z, y)
                z := t
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   RAW NUMBER OPERATIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(x, y)
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mod(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := smod(x, y)
        }
    }

    /// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
    function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := addmod(x, y, d)
        }
    }

    /// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
    function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mulmod(x, y, d)
        }
    }
}

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

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_mestERC1155","type":"address"},{"internalType":"uint256","name":"_basePrice","type":"uint256"},{"internalType":"uint256","name":"_inflectionPoint","type":"uint256"},{"internalType":"uint256","name":"_inflectionPrice","type":"uint256"},{"internalType":"uint256","name":"_linearPriceSlope","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ClaimYield","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"shareId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"}],"name":"Create","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"yieldAggregator","type":"address"}],"name":"MigrateYield","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":"trader","type":"address"},{"indexed":true,"internalType":"uint256","name":"shareId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referralFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creatorFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupply","type":"uint256"}],"name":"Trade","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"MEST_ERC1155","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"address","name":"referral","type":"address"}],"name":"buyShare","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"claimYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creator","type":"address"}],"name":"createShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creatorFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositedETHAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"generalCurveFixedParam","outputs":[{"internalType":"uint256","name":"basePrice","type":"uint256"},{"internalType":"uint256","name":"linearPriceSlope","type":"uint256"},{"internalType":"uint256","name":"inflectionPoint","type":"uint256"},{"internalType":"uint256","name":"inflectionPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"address","name":"referral","type":"address"}],"name":"getBuyPriceAfterFee","outputs":[{"internalType":"uint256","name":"buyPriceAfterFee","type":"uint256"},{"internalType":"uint256","name":"buyPrice","type":"uint256"},{"internalType":"uint256","name":"referralFee","type":"uint256"},{"internalType":"uint256","name":"creatorFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"address","name":"referral","type":"address"}],"name":"getSellPriceAfterFee","outputs":[{"internalType":"uint256","name":"sellPriceAfterFee","type":"uint256"},{"internalType":"uint256","name":"sellPrice","type":"uint256"},{"internalType":"uint256","name":"referralFee","type":"uint256"},{"internalType":"uint256","name":"creatorFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_yieldAggregator","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"minETHAmount","type":"uint256"},{"internalType":"address","name":"referral","type":"address"}],"name":"sellShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feePercent","type":"uint256"}],"name":"setCreatorFeePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feePercent","type":"uint256"}],"name":"setReferralFeePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shareIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sharesMap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yieldAggregator","outputs":[{"internalType":"contract IYieldAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

0x60a060405266b1a2bc2ec5000060035566b1a2bc2ec5000060045534801561002657600080fd5b50604051611d5f380380611d5f833981016040819052610045916100c0565b61004e33610070565b6001600160a01b03909416608052600592909255600755600855600655610115565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600080600060a086880312156100d857600080fd5b85516001600160a01b03811681146100ef57600080fd5b602087015160408801516060890151608090990151929a91995097965090945092505050565b608051611bfe6101616000396000818161033e015281816104a2015281816105f50152818161079f01528181610b1e01528181610de201528181610f3b0152610fb70152611bfe6000f3fe6080604052600436106101175760003560e01c80636ff6c4b81161009a578063b6bbe07311610061578063b6bbe0731461032c578063c56ad1ad14610360578063ce5494bb14610376578063d2cd5d7314610396578063f2fde38b146103b657005b80636ff6c4b814610283578063715018a6146102a35780637c88ab84146102b85780638da5cb5b146102d8578063a57d4fd2146102f657005b80632a194b6d116100de5780632a194b6d146101d55780634cd14dc61461020d57806353613dd31461022d578063614524e21461024357806361fa18d51461026357005b80630e8b4d611461012057806313c9440b1461016857806314cea1581461018c5780631f43b7ce1461019f5780631fdb5f53146101bf57005b3661011e57005b005b34801561012c57600080fd5b506005546006546007546008546101439392919084565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561017457600080fd5b5061017e60035481565b60405190815260200161015f565b61011e61019a366004611982565b6103d6565b3480156101ab57600080fd5b506101436101ba366004611982565b610795565b3480156101cb57600080fd5b5061017e60025481565b3480156101e157600080fd5b506009546101f5906001600160a01b031681565b6040516001600160a01b03909116815260200161015f565b34801561021957600080fd5b5061011e6102283660046119bb565b610905565b34801561023957600080fd5b5061017e60045481565b34801561024f57600080fd5b5061011e61025e3660046119eb565b610a76565b34801561026f57600080fd5b5061011e61027e366004611a04565b610a83565b34801561028f57600080fd5b5061011e61029e3660046119eb565b610af3565b3480156102af57600080fd5b5061011e610b00565b3480156102c457600080fd5b506101436102d3366004611982565b610b14565b3480156102e457600080fd5b506000546001600160a01b03166101f5565b34801561030257600080fd5b506101f56103113660046119eb565b600a602052600090815260409020546001600160a01b031681565b34801561033857600080fd5b506101f57f000000000000000000000000000000000000000000000000000000000000000081565b34801561036c57600080fd5b5061017e60015481565b34801561038257600080fd5b5061011e610391366004611a04565b610c2d565b3480156103a257600080fd5b5061011e6103b1366004611a28565b610d81565b3480156103c257600080fd5b5061011e6103d1366004611a04565b61111d565b6009546001600160a01b031661042d5760405162461bcd60e51b815260206004820152601760248201527624b73b30b634b2103cb4b2b63220b3b3b932b3b0ba37b960491b60448201526064015b60405180910390fd5b60015483106104705760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a59081cda185c995259608a1b6044820152606401610424565b6000838152600a602052604080822054905163d2cf911560e01b8152600481018690526001600160a01b0391821692917f0000000000000000000000000000000000000000000000000000000000000000169063d2cf911590602401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190611a69565b9050600080600080610520898989610b14565b9350935093509350600085118061053f5750336001600160a01b038716145b61058b5760405162461bcd60e51b815260206004820152601b60248201527f4669727374206275796572206d7573742062652063726561746f7200000000006044820152606401610424565b833410156105d25760405162461bcd60e51b8152602060048201526014602482015273125b9cdd59999a58da595b9d081c185e5b595b9d60621b6044820152606401610424565b60405163106fcedf60e21b8152336004820152602481018a9052604481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906341bf3b7c90606401600060405180830381600087803b15801561064157600080fd5b505af1158015610655573d6000803e3d6000fd5b508b92503391507f29db2a6062b25ead33a5fc8d1163c4d7f54397202547c27c1c99a20344647734905060018b88878761068f848e611a98565b6040805196151587526020870195909552938501929092526060840152608083015260a082015260c00160405180910390a36009546106d7906001600160a01b031684611196565b600960009054906101000a90046001600160a01b03166001600160a01b031663bb282e5c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072757600080fd5b505af115801561073b573d6000803e3d6000fd5b5050505082600260008282546107519190611a98565b9091555061076190508783611196565b61076b8682611196565b60006107778534611ab1565b90508015610789576107893382611196565b50505050505050505050565b60008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d2cf9115896040518263ffffffff1660e01b81526004016107eb91815260200190565b602060405180830381865afa158015610808573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082c9190611a69565b905060006001600160a01b038716610845576000610849565b6003545b90508782101561088c5760405162461bcd60e51b815260206004820152600e60248201526d4578636565647320737570706c7960901b6044820152606401610424565b61089f6108998984611ab1565b89611255565b9450670de0b6b3a76400006108b48287611ac4565b6108be9190611adb565b9350670de0b6b3a7640000600454866108d79190611ac4565b6108e19190611adb565b9250826108ee8587611ab1565b6108f89190611ab1565b9550505093509350935093565b61090d61128e565b6009546002546040516328e762dd60e01b815260048101919091526000916001600160a01b0316906328e762dd90602401602060405180830381865afa15801561095b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097f9190611a69565b9050808311156109c65760405162461bcd60e51b8152602060048201526012602482015271125b9cdd59999a58da595b9d081e5a595b1960721b6044820152606401610424565b6009546040516316d7ac4560e31b8152600481018590526001600160a01b039091169063b6bd622890602401600060405180830381600087803b158015610a0c57600080fd5b505af1158015610a20573d6000803e3d6000fd5b50505050610a2e8284611196565b816001600160a01b03167fc82fd9ebea57700479e05121ad619652619f27f7d29858cdae6682fda41fe55284604051610a6991815260200190565b60405180910390a2505050565b610a7e61128e565b600355565b600180546000908152600a602052604080822080546001600160a01b0319166001600160a01b0386169081179091559254905190917f748fd6a01f0f0df2e8354235caf8fdf83654b5a47b2358be7e7bffb16b726ceb91a360018054906000610aeb83611afd565b919050555050565b610afb61128e565b600455565b610b0861128e565b610b1260006112e8565b565b60008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d2cf9115896040518263ffffffff1660e01b8152600401610b6a91815260200190565b602060405180830381865afa158015610b87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bab9190611a69565b905060006001600160a01b038716610bc4576000610bc8565b6003545b9050610bd48289611255565b9450670de0b6b3a7640000610be98287611ac4565b610bf39190611adb565b9350670de0b6b3a764000060045486610c0c9190611ac4565b610c169190611adb565b925082610c238587611a98565b6108f89190611a98565b610c3561128e565b6001600160a01b038116610c855760405162461bcd60e51b815260206004820152601760248201527624b73b30b634b2103cb4b2b63220b3b3b932b3b0ba37b960491b6044820152606401610424565b6009546001600160a01b0316610ca357610c9e81611338565b610d4a565b610cab6113d0565b600954604080516376d5de8560e01b815290516000926001600160a01b0316916376d5de859160048083019260209291908290030181865afa158015610cf5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d199190611b16565b600954909150610d37906001600160a01b038084169116600061149f565b610d4082611338565b610d486115d6565b505b6040516001600160a01b038216907f3f2269c1f47e2dbf65345d265a81b09075809b1d86fb70a8dcc517a705658eae90600090a250565b6001548410610dc45760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a59081cda185c995259608a1b6044820152606401610424565b6040516327e662e160e21b81523360048201526024810185905283907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639f998b8490604401602060405180830381865afa158015610e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e559190611a69565b1015610e995760405162461bcd60e51b8152602060048201526013602482015272496e73756666696369656e742073686172657360681b6044820152606401610424565b6000848152600a60205260408120546001600160a01b031690808080610ec0898988610795565b935093509350935086841015610f185760405162461bcd60e51b815260206004820152601760248201527f496e73756666696369656e74206d696e526563656976650000000000000000006044820152606401610424565b6040516317a99ced60e31b8152336004820152602481018a9052604481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063bd4ce76890606401600060405180830381600087803b158015610f8757600080fd5b505af1158015610f9b573d6000803e3d6000fd5b505060405163d2cf911560e01b8152600481018c9052600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316915063d2cf911590602401602060405180830381865afa158015611007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102b9190611a69565b6040805160008152602081018c9052908101879052606081018590526080810184905260a081018290529091508a9033907f29db2a6062b25ead33a5fc8d1163c4d7f54397202547c27c1c99a203446477349060c00160405180910390a36009546040516316d7ac4560e31b8152600481018690526001600160a01b039091169063b6bd622890602401600060405180830381600087803b1580156110cf57600080fd5b505af11580156110e3573d6000803e3d6000fd5b5050505083600260008282546110f99190611ab1565b9091555061110990503386611196565b6111138784611196565b6107898683611196565b61112561128e565b6001600160a01b03811661118a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610424565b611193816112e8565b50565b801561125157604080516000808252602082019092526001600160a01b0384169083906040516111c69190611b57565b60006040518083038185875af1925050503d8060008114611203576040519150601f19603f3d011682016040523d82523d6000602084013e611208565b606091505b505090508061124f5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610424565b505b5050565b60055460065490820290600180850185028585018083010203901c02600754600854919092019161128791858561163e565b0192915050565b6000546001600160a01b03163314610b125760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610424565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600980546001600160a01b0319166001600160a01b038316908117909155604080516376d5de8560e01b81529051600092916376d5de859160048083019260209291908290030181865afa158015611394573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b89190611b16565b90506112516001600160a01b0382168360001961149f565b600954604051638812ebc960e01b81523060048201526000916001600160a01b031690638812ebc990602401602060405180830381865afa158015611419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143d9190611a69565b6009546040516316d7ac4560e31b8152600481018390529192506001600160a01b03169063b6bd622890602401600060405180830381600087803b15801561148457600080fd5b505af1158015611498573d6000803e3d6000fd5b5050505050565b8015806115195750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156114f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115179190611a69565b155b6115845760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610424565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261124f908490611775565b60095447906115ee906001600160a01b031682611196565b600960009054906101000a90046001600160a01b03166001600160a01b031663bb282e5c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561148457600080fd5b6000848480820283036116565760009250505061176d565b60018581019085870101838118818511028418808310156116a05760066001808a018a028a821b820102600019840180850290831b90920191909102030485800285040295509150815b81831015611767576003850260021c600185901b5b600061174b888488030270ffffffffffffffffffffffffffffffffff811160071b81811c68ffffffffffffffffff1060061b1781811c64ffffffffff1060051b1781811c62ffffff1060041b1781811c620100000160b5600192831c1b0260121c80830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b8202889004989098019750600180860195859003016116b55750505b50505050505b949350505050565b60006117ca826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661184a9092919063ffffffff16565b90508051600014806117eb5750808060200190518101906117eb9190611b73565b61124f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610424565b606061176d848460008585600080866001600160a01b031685876040516118719190611b57565b60006040518083038185875af1925050503d80600081146118ae576040519150601f19603f3d011682016040523d82523d6000602084013e6118b3565b606091505b50915091506118c4878383876118cf565b979650505050505050565b6060831561193e578251600003611937576001600160a01b0385163b6119375760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610424565b508161176d565b61176d83838151156119535781518083602001fd5b8060405162461bcd60e51b81526004016104249190611b95565b6001600160a01b038116811461119357600080fd5b60008060006060848603121561199757600080fd5b833592506020840135915060408401356119b08161196d565b809150509250925092565b600080604083850312156119ce57600080fd5b8235915060208301356119e08161196d565b809150509250929050565b6000602082840312156119fd57600080fd5b5035919050565b600060208284031215611a1657600080fd5b8135611a218161196d565b9392505050565b60008060008060808587031215611a3e57600080fd5b8435935060208501359250604085013591506060850135611a5e8161196d565b939692955090935050565b600060208284031215611a7b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611aab57611aab611a82565b92915050565b81810381811115611aab57611aab611a82565b8082028115828204841417611aab57611aab611a82565b600082611af857634e487b7160e01b600052601260045260246000fd5b500490565b600060018201611b0f57611b0f611a82565b5060010190565b600060208284031215611b2857600080fd5b8151611a218161196d565b60005b83811015611b4e578181015183820152602001611b36565b50506000910152565b60008251611b69818460208701611b33565b9190910192915050565b600060208284031215611b8557600080fd5b81518015158114611a2157600080fd5b6020815260008251806020840152611bb4816040850160208701611b33565b601f01601f1916919091016040019291505056fea2646970667358221220dc0bf4e046a612379e353d372bada2e3d596ca06004bf72b10d7826bb6391bac64736f6c6343000819003300000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d050000000000000000000000000000000000000000000000000011c37937e0800000000000000000000000000000000000000000000000000000000000000005dc000000000000000000000000000000000000000000000000016c2734f97a40000000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106101175760003560e01c80636ff6c4b81161009a578063b6bbe07311610061578063b6bbe0731461032c578063c56ad1ad14610360578063ce5494bb14610376578063d2cd5d7314610396578063f2fde38b146103b657005b80636ff6c4b814610283578063715018a6146102a35780637c88ab84146102b85780638da5cb5b146102d8578063a57d4fd2146102f657005b80632a194b6d116100de5780632a194b6d146101d55780634cd14dc61461020d57806353613dd31461022d578063614524e21461024357806361fa18d51461026357005b80630e8b4d611461012057806313c9440b1461016857806314cea1581461018c5780631f43b7ce1461019f5780631fdb5f53146101bf57005b3661011e57005b005b34801561012c57600080fd5b506005546006546007546008546101439392919084565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561017457600080fd5b5061017e60035481565b60405190815260200161015f565b61011e61019a366004611982565b6103d6565b3480156101ab57600080fd5b506101436101ba366004611982565b610795565b3480156101cb57600080fd5b5061017e60025481565b3480156101e157600080fd5b506009546101f5906001600160a01b031681565b6040516001600160a01b03909116815260200161015f565b34801561021957600080fd5b5061011e6102283660046119bb565b610905565b34801561023957600080fd5b5061017e60045481565b34801561024f57600080fd5b5061011e61025e3660046119eb565b610a76565b34801561026f57600080fd5b5061011e61027e366004611a04565b610a83565b34801561028f57600080fd5b5061011e61029e3660046119eb565b610af3565b3480156102af57600080fd5b5061011e610b00565b3480156102c457600080fd5b506101436102d3366004611982565b610b14565b3480156102e457600080fd5b506000546001600160a01b03166101f5565b34801561030257600080fd5b506101f56103113660046119eb565b600a602052600090815260409020546001600160a01b031681565b34801561033857600080fd5b506101f57f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d0581565b34801561036c57600080fd5b5061017e60015481565b34801561038257600080fd5b5061011e610391366004611a04565b610c2d565b3480156103a257600080fd5b5061011e6103b1366004611a28565b610d81565b3480156103c257600080fd5b5061011e6103d1366004611a04565b61111d565b6009546001600160a01b031661042d5760405162461bcd60e51b815260206004820152601760248201527624b73b30b634b2103cb4b2b63220b3b3b932b3b0ba37b960491b60448201526064015b60405180910390fd5b60015483106104705760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a59081cda185c995259608a1b6044820152606401610424565b6000838152600a602052604080822054905163d2cf911560e01b8152600481018690526001600160a01b0391821692917f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d05169063d2cf911590602401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190611a69565b9050600080600080610520898989610b14565b9350935093509350600085118061053f5750336001600160a01b038716145b61058b5760405162461bcd60e51b815260206004820152601b60248201527f4669727374206275796572206d7573742062652063726561746f7200000000006044820152606401610424565b833410156105d25760405162461bcd60e51b8152602060048201526014602482015273125b9cdd59999a58da595b9d081c185e5b595b9d60621b6044820152606401610424565b60405163106fcedf60e21b8152336004820152602481018a9052604481018990527f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d056001600160a01b0316906341bf3b7c90606401600060405180830381600087803b15801561064157600080fd5b505af1158015610655573d6000803e3d6000fd5b508b92503391507f29db2a6062b25ead33a5fc8d1163c4d7f54397202547c27c1c99a20344647734905060018b88878761068f848e611a98565b6040805196151587526020870195909552938501929092526060840152608083015260a082015260c00160405180910390a36009546106d7906001600160a01b031684611196565b600960009054906101000a90046001600160a01b03166001600160a01b031663bb282e5c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072757600080fd5b505af115801561073b573d6000803e3d6000fd5b5050505082600260008282546107519190611a98565b9091555061076190508783611196565b61076b8682611196565b60006107778534611ab1565b90508015610789576107893382611196565b50505050505050505050565b60008060008060007f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d056001600160a01b031663d2cf9115896040518263ffffffff1660e01b81526004016107eb91815260200190565b602060405180830381865afa158015610808573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082c9190611a69565b905060006001600160a01b038716610845576000610849565b6003545b90508782101561088c5760405162461bcd60e51b815260206004820152600e60248201526d4578636565647320737570706c7960901b6044820152606401610424565b61089f6108998984611ab1565b89611255565b9450670de0b6b3a76400006108b48287611ac4565b6108be9190611adb565b9350670de0b6b3a7640000600454866108d79190611ac4565b6108e19190611adb565b9250826108ee8587611ab1565b6108f89190611ab1565b9550505093509350935093565b61090d61128e565b6009546002546040516328e762dd60e01b815260048101919091526000916001600160a01b0316906328e762dd90602401602060405180830381865afa15801561095b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097f9190611a69565b9050808311156109c65760405162461bcd60e51b8152602060048201526012602482015271125b9cdd59999a58da595b9d081e5a595b1960721b6044820152606401610424565b6009546040516316d7ac4560e31b8152600481018590526001600160a01b039091169063b6bd622890602401600060405180830381600087803b158015610a0c57600080fd5b505af1158015610a20573d6000803e3d6000fd5b50505050610a2e8284611196565b816001600160a01b03167fc82fd9ebea57700479e05121ad619652619f27f7d29858cdae6682fda41fe55284604051610a6991815260200190565b60405180910390a2505050565b610a7e61128e565b600355565b600180546000908152600a602052604080822080546001600160a01b0319166001600160a01b0386169081179091559254905190917f748fd6a01f0f0df2e8354235caf8fdf83654b5a47b2358be7e7bffb16b726ceb91a360018054906000610aeb83611afd565b919050555050565b610afb61128e565b600455565b610b0861128e565b610b1260006112e8565b565b60008060008060007f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d056001600160a01b031663d2cf9115896040518263ffffffff1660e01b8152600401610b6a91815260200190565b602060405180830381865afa158015610b87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bab9190611a69565b905060006001600160a01b038716610bc4576000610bc8565b6003545b9050610bd48289611255565b9450670de0b6b3a7640000610be98287611ac4565b610bf39190611adb565b9350670de0b6b3a764000060045486610c0c9190611ac4565b610c169190611adb565b925082610c238587611a98565b6108f89190611a98565b610c3561128e565b6001600160a01b038116610c855760405162461bcd60e51b815260206004820152601760248201527624b73b30b634b2103cb4b2b63220b3b3b932b3b0ba37b960491b6044820152606401610424565b6009546001600160a01b0316610ca357610c9e81611338565b610d4a565b610cab6113d0565b600954604080516376d5de8560e01b815290516000926001600160a01b0316916376d5de859160048083019260209291908290030181865afa158015610cf5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d199190611b16565b600954909150610d37906001600160a01b038084169116600061149f565b610d4082611338565b610d486115d6565b505b6040516001600160a01b038216907f3f2269c1f47e2dbf65345d265a81b09075809b1d86fb70a8dcc517a705658eae90600090a250565b6001548410610dc45760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a59081cda185c995259608a1b6044820152606401610424565b6040516327e662e160e21b81523360048201526024810185905283907f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d056001600160a01b031690639f998b8490604401602060405180830381865afa158015610e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e559190611a69565b1015610e995760405162461bcd60e51b8152602060048201526013602482015272496e73756666696369656e742073686172657360681b6044820152606401610424565b6000848152600a60205260408120546001600160a01b031690808080610ec0898988610795565b935093509350935086841015610f185760405162461bcd60e51b815260206004820152601760248201527f496e73756666696369656e74206d696e526563656976650000000000000000006044820152606401610424565b6040516317a99ced60e31b8152336004820152602481018a9052604481018990527f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d056001600160a01b03169063bd4ce76890606401600060405180830381600087803b158015610f8757600080fd5b505af1158015610f9b573d6000803e3d6000fd5b505060405163d2cf911560e01b8152600481018c9052600092507f00000000000000000000000027db12865d94288f97f6d8c9a4865e8207a23d056001600160a01b0316915063d2cf911590602401602060405180830381865afa158015611007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102b9190611a69565b6040805160008152602081018c9052908101879052606081018590526080810184905260a081018290529091508a9033907f29db2a6062b25ead33a5fc8d1163c4d7f54397202547c27c1c99a203446477349060c00160405180910390a36009546040516316d7ac4560e31b8152600481018690526001600160a01b039091169063b6bd622890602401600060405180830381600087803b1580156110cf57600080fd5b505af11580156110e3573d6000803e3d6000fd5b5050505083600260008282546110f99190611ab1565b9091555061110990503386611196565b6111138784611196565b6107898683611196565b61112561128e565b6001600160a01b03811661118a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610424565b611193816112e8565b50565b801561125157604080516000808252602082019092526001600160a01b0384169083906040516111c69190611b57565b60006040518083038185875af1925050503d8060008114611203576040519150601f19603f3d011682016040523d82523d6000602084013e611208565b606091505b505090508061124f5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610424565b505b5050565b60055460065490820290600180850185028585018083010203901c02600754600854919092019161128791858561163e565b0192915050565b6000546001600160a01b03163314610b125760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610424565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600980546001600160a01b0319166001600160a01b038316908117909155604080516376d5de8560e01b81529051600092916376d5de859160048083019260209291908290030181865afa158015611394573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b89190611b16565b90506112516001600160a01b0382168360001961149f565b600954604051638812ebc960e01b81523060048201526000916001600160a01b031690638812ebc990602401602060405180830381865afa158015611419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143d9190611a69565b6009546040516316d7ac4560e31b8152600481018390529192506001600160a01b03169063b6bd622890602401600060405180830381600087803b15801561148457600080fd5b505af1158015611498573d6000803e3d6000fd5b5050505050565b8015806115195750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156114f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115179190611a69565b155b6115845760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610424565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261124f908490611775565b60095447906115ee906001600160a01b031682611196565b600960009054906101000a90046001600160a01b03166001600160a01b031663bb282e5c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561148457600080fd5b6000848480820283036116565760009250505061176d565b60018581019085870101838118818511028418808310156116a05760066001808a018a028a821b820102600019840180850290831b90920191909102030485800285040295509150815b81831015611767576003850260021c600185901b5b600061174b888488030270ffffffffffffffffffffffffffffffffff811160071b81811c68ffffffffffffffffff1060061b1781811c64ffffffffff1060051b1781811c62ffffff1060041b1781811c620100000160b5600192831c1b0260121c80830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b8202889004989098019750600180860195859003016116b55750505b50505050505b949350505050565b60006117ca826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661184a9092919063ffffffff16565b90508051600014806117eb5750808060200190518101906117eb9190611b73565b61124f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610424565b606061176d848460008585600080866001600160a01b031685876040516118719190611b57565b60006040518083038185875af1925050503d80600081146118ae576040519150601f19603f3d011682016040523d82523d6000602084013e6118b3565b606091505b50915091506118c4878383876118cf565b979650505050505050565b6060831561193e578251600003611937576001600160a01b0385163b6119375760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610424565b508161176d565b61176d83838151156119535781518083602001fd5b8060405162461bcd60e51b81526004016104249190611b95565b6001600160a01b038116811461119357600080fd5b60008060006060848603121561199757600080fd5b833592506020840135915060408401356119b08161196d565b809150509250925092565b600080604083850312156119ce57600080fd5b8235915060208301356119e08161196d565b809150509250929050565b6000602082840312156119fd57600080fd5b5035919050565b600060208284031215611a1657600080fd5b8135611a218161196d565b9392505050565b60008060008060808587031215611a3e57600080fd5b8435935060208501359250604085013591506060850135611a5e8161196d565b939692955090935050565b600060208284031215611a7b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611aab57611aab611a82565b92915050565b81810381811115611aab57611aab611a82565b8082028115828204841417611aab57611aab611a82565b600082611af857634e487b7160e01b600052601260045260246000fd5b500490565b600060018201611b0f57611b0f611a82565b5060010190565b600060208284031215611b2857600080fd5b8151611a218161196d565b60005b83811015611b4e578181015183820152602001611b36565b50506000910152565b60008251611b69818460208701611b33565b9190910192915050565b600060208284031215611b8557600080fd5b81518015158114611a2157600080fd5b6020815260008251806020840152611bb4816040850160208701611b33565b601f01601f1916919091016040019291505056fea2646970667358221220dc0bf4e046a612379e353d372bada2e3d596ca06004bf72b10d7826bb6391bac64736f6c63430008190033

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
0x26c6f7FA1Fe03193D1Fb759Aac5Bda8e4b5fB4F8
Loading...
Loading
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.