ETH Price: $3,387.44 (-1.50%)
Gas: 16 Gwei

Contract

0x422d17ccC1442501D039595ffcaAa71b4686Bf4E
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer200185862024-06-04 12:54:1144 days ago1717505651IN
0x422d17cc...b4686Bf4E
0 ETH0.000416268.03779672
Approve167223402023-02-27 21:54:59506 days ago1677534899IN
0x422d17cc...b4686Bf4E
0 ETH0.0012641127.38022182
Transfer And Cal...167152112023-02-26 21:54:59507 days ago1677448499IN
0x422d17cc...b4686Bf4E
0 ETH0.0056186532.10203739
Suggest Minter167150232023-02-26 21:16:35507 days ago1677446195IN
0x422d17cc...b4686Bf4E
0 ETH0.0014337425.03301936
Suggest Minter167149712023-02-26 21:06:11507 days ago1677445571IN
0x422d17cc...b4686Bf4E
0 ETH0.001500626.20042132
0x60e06040167146822023-02-26 20:07:59507 days ago1677442079IN
 Create: Frankencoin
0 ETH0.0790232724.89428404

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
167146822023-02-26 20:07:59507 days ago1677442079
0x422d17cc...b4686Bf4E
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Frankencoin

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 9 : Frankencoin.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./ERC20PermitLight.sol";
import "./Equity.sol";
import "./IReserve.sol";
import "./IFrankencoin.sol";

contract Frankencoin is ERC20PermitLight, IFrankencoin {

   uint256 public constant MIN_FEE = 1000 * (10**18);
   uint256 public immutable MIN_APPLICATION_PERIOD; // for example 10 days

   IReserve override public immutable reserve;
   uint256 private minterReserveE6;

   mapping (address => uint256) public minters;
   mapping (address => address) public positions;

   event MinterApplied(address indexed minter, uint256 applicationPeriod, uint256 applicationFee, string message);
   event MinterDenied(address indexed minter, string message);

   /**
    * Initiates the Frankencoin with the provided minimum application period for new plugins
    * in seconds, for example 10 days, i.e. 3600*24*10 = 864000
    */
   constructor(uint256 _minApplicationPeriod) ERC20(18){
      MIN_APPLICATION_PERIOD = _minApplicationPeriod;
      reserve = new Equity(this);
   }

   function name() override external pure returns (string memory){
      return "Frankencoin V1";
   }

   function symbol() override external pure returns (string memory){
      return "ZCHF";
   }

   /**
    * @notice Minting is suggested either by (1) person applying for a new original position,
    * or (2) by the minting hub when cloning a position. The minting hub has the priviledge
    * to call with zero application fee and period.
    * @param _minter             address of the position want to add to the minters
    * @param _applicationPeriod  application period in seconds
    * @param _applicationFee     application fee in parts per million
    * @param _message            message string
    */
   function suggestMinter(address _minter, uint256 _applicationPeriod, 
      uint256 _applicationFee, string calldata _message) override external 
   {
      require(_applicationPeriod >= MIN_APPLICATION_PERIOD || totalSupply() == 0, "period too short");
      require(_applicationFee >= MIN_FEE || totalSupply() == 0, "fee too low");
      require(minters[_minter] == 0, "already registered");
      _transfer(msg.sender, address(reserve), _applicationFee);
      minters[_minter] = block.timestamp + _applicationPeriod;
      emit MinterApplied(_minter, _applicationPeriod, _applicationFee, _message);
   }

   function minterReserve() public view returns (uint256) {
      return minterReserveE6 / 1000000;
   }

   function registerPosition(address _position) override external {
      require(isMinter(msg.sender), "not minter");
      positions[_position] = msg.sender;
   }

   /**
    * @notice Get reserve balance (amount of ZCHF)
    * @return ZCHF in dec18 format
    */
   function equity() public view returns (uint256) {
      uint256 balance = balanceOf(address(reserve));
      uint256 minReserve = minterReserve();
      if (balance <= minReserve){
        return 0;
      } else {
        return balance - minReserve;
      }
    }

   function denyMinter(address _minter, address[] calldata _helpers, string calldata _message) override external {
      require(block.timestamp <= minters[_minter], "too late");
      require(reserve.isQualified(msg.sender, _helpers), "not qualified");
      delete minters[_minter];
      emit MinterDenied(_minter, _message);
   }

   /**
 * @notice Mint amount of ZCHF for address _target
 * @param _target       address that receives ZCHF if it's a minter
 * @param _amount       amount ZCHF before fees and pool contribution requested
 *                      number in dec18 format
 * @param _reservePPM   reserve requirement in parts per million
 * @param _feesPPM      fees in parts per million
 */
   function mint(address _target, uint256 _amount, uint32 _reservePPM, uint32 _feesPPM) override external minterOnly {
      uint256 _minterReserveE6 = _amount * _reservePPM;
      uint256 reserveMint = (_minterReserveE6 + 999_999) / 1000_000; // make sure rounded up
      uint256 fees = (_amount * _feesPPM + 999_999) / 1000_000; // make sure rounded up
      _mint(_target, _amount - reserveMint - fees);
      _mint(address(reserve), reserveMint + fees);
      minterReserveE6 += reserveMint * 1000_000;
   }

   /**
    * @notice Mint amount of ZCHF for address _target
    * @param _target   address that receives ZCHF if it's a minter
    * @param _amount   amount in dec18 format
    */
   function mint(address _target, uint256 _amount) override external minterOnly {
      _mint(_target, _amount);
   }

   function burn(uint256 _amount) external {
      _burn(msg.sender, _amount);
   }

   /**
    * Burn that amount without reclaiming the reserve.
    * The caller is only allowed to use this method for tokens also minted through the caller with the same _reservePPM amount.
    * For example, if someone minted 50 ZCHF earlier with a 20% reserve requirement (200000 ppm), they got 40 ZCHF and paid
    * 10 ZCHF into the reserve. Now they want to repay the debt by burning 50 ZCHF. When doing so using this method, the 10 ZCHF
    * that went into the reserve are not returned. Instead, they are donated to the reserve pool, making the pool share holders
    * richer. This can make sense in combination with 'notifyLoss', i.e. when it is the pool share holders that bear the risk
    * and depending on the outcome they make a profit or a loss.
    */
   function burn(uint256 amount, uint32 reservePPM) external override minterOnly {
      _burn(msg.sender, amount);
      minterReserveE6 -= amount * reservePPM;
   }

   function calculateAssignedReserve(uint256 mintedAmount, uint32 _reservePPM) public view returns (uint256) {
      uint256 theoreticalReserve = _reservePPM * mintedAmount / 1000000;
      uint256 currentReserve = balanceOf(address(reserve));
      if (currentReserve < minterReserve()){
         // not enough reserves, owner has to take a loss
         return theoreticalReserve * currentReserve / minterReserve();
      } else {
         return theoreticalReserve;
      }
   }

   /**
    * Burns the target amount taking the tokens to be burned from the payer and the payer's reserve.
    * The caller is only allowed to use this method for tokens also minted through the caller with the same _reservePPM amount.
    * Example: the calling contract has previously minted 100 ZCHF with a reserve ratio of 20% (i.e. 200000 ppm). To burn half
    * of that again, the minter calls burnFrom with a target amount of 50 ZCHF. Assuming that reserves are only 90% covered,
    * this call will deduct 41 ZCHF from the payer's balance and 9 from the reserve, while reducing the minter reserve by 10.
    */
   function burnFrom(address payer, uint256 targetTotalBurnAmount, uint32 _reservePPM) external override minterOnly returns (uint256) {
      uint256 assigned = calculateAssignedReserve(targetTotalBurnAmount, _reservePPM);
      _transfer(address(reserve), payer, assigned); 
      _burn(payer, targetTotalBurnAmount); // and burn everything
      minterReserveE6 -= targetTotalBurnAmount * _reservePPM; // reduce reserve requirements by original ratio
      return assigned;
   }

   /**
    * Burns the provided number of tokens plus whatever reserves are associated with that amount given the reserve requirement.
    * The caller is only allowed to use this method for tokens also minted through the caller with the same _reservePPM amount.
    * Example: the calling contract has previously minted 100 ZCHF with a reserve ratio of 20% (i.e. 200000 ppm). Now they have
    * 41 ZCHF that they do not need so they decide to repay that amount. Assuming the reserves are only 90% covered,
    * the call to burnWithReserve will burn the 41 plus 9 from the reserve, reducing the outstanding 'debt' of the caller by
    * 50 ZCHF in total. This total is returned by the method so the caller knows how much less they owe.
    */
   function burnWithReserve(uint256 _amountExcludingReserve /* 41 */, uint32 _reservePPM /* 20% */) 
      external override minterOnly returns (uint256) {
      uint256 currentReserve = balanceOf(address(reserve)); // 18, 10% below what we should have
      uint256 minterReserve_ = minterReserve(); // 20
      uint256 adjustedReservePPM = currentReserve < minterReserve_ ? _reservePPM * currentReserve / minterReserve_ : _reservePPM; // 18%
      uint256 freedAmount = 1000000 * _amountExcludingReserve / (1000000 - adjustedReservePPM); // 0.18 * 41 /0.82 = 50
      minterReserveE6 -= freedAmount * _reservePPM; // reduce reserve requirements by original ratio, here 10
      _transfer(address(reserve), msg.sender, freedAmount - _amountExcludingReserve); // collect 9 assigned reserve, maybe less than original reserve
      _burn(msg.sender, freedAmount); // 41
      return freedAmount;
   }

   function burn(address _owner, uint256 _amount) override external minterOnly {
      _burn(_owner, _amount);
   }

   modifier minterOnly() {
      require(isMinter(msg.sender) || isMinter(positions[msg.sender]), "not approved minter");
      _;
   }

   function notifyLoss(uint256 _amount) override external minterOnly {
      uint256 reserveLeft = balanceOf(address(reserve));
      if (reserveLeft >= _amount){
         _transfer(address(reserve), msg.sender, _amount);
      } else {
         _transfer(address(reserve), msg.sender, reserveLeft);
         _mint(msg.sender, _amount - reserveLeft);
      }
   }
   function isMinter(address _minter) override public view returns (bool){
      return minters[_minter] != 0 && block.timestamp >= minters[_minter];
   }

   function isPosition(address _position) override public view returns (address){
      return positions[_position];
   }

}

File 2 of 9 : IFrankencoin.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./IReserve.sol";

interface IFrankencoin is IERC20 {

    function suggestMinter(address _minter, uint256 _applicationPeriod, 
      uint256 _applicationFee, string calldata _message) external;

    function registerPosition(address position) external;

    function denyMinter(address minter, address[] calldata helpers, string calldata message) external;

    function reserve() external view returns (IReserve);

    function isMinter(address minter) external view returns (bool);

    function isPosition(address position) external view returns (address);
    
    function mint(address target, uint256 amount) external;

    function mint(address target, uint256 amount, uint32 reservePPM, uint32 feePPM) external;

    function burn(uint256 amountIncludingReserve, uint32 reservePPM) external;

    function burnFrom(address payer, uint256 targetTotalBurnAmount, uint32 _reservePPM) external returns (uint256);

    function burnWithReserve(uint256 amountExcludingReserve, uint32 reservePPM) external returns (uint256);

    function burn(address target, uint256 amount) external;

    function notifyLoss(uint256 amount) external;

}

File 3 of 9 : IReserve.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IReserve {
   function isQualified(address sender, address[] calldata helpers) external view returns (bool);
}

File 4 of 9 : Equity.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

import "./Frankencoin.sol";
import "./IERC677Receiver.sol";
import "./ERC20PermitLight.sol";
import "./MathUtil.sol";
import "./IReserve.sol";

/** 
 * @title Reserve pool for the Frankencoin
 */
contract Equity is ERC20PermitLight, MathUtil, IReserve {

    uint32 public constant VALUATION_FACTOR = 3;
    uint32 private constant QUORUM = 300;

    uint8 private constant BLOCK_TIME_RESOLUTION_BITS = 24;
    uint256 public constant MIN_HOLDING_DURATION = 90*7200 << BLOCK_TIME_RESOLUTION_BITS; // in blocks, about 90 days, set to 5 blocks for testing

    Frankencoin immutable public zchf;

    // should hopefully be grouped into one storage slot
    uint64 private totalVotesAnchorTime; // 40 Bit for the block number, 24 Bit sub-block time resolution
    uint192 private totalVotesAtAnchor;

    mapping (address => address) public delegates;
    mapping (address => uint64) private voteAnchor; // 40 Bit for the block number, 24 Bit sub-block time resolution

    event Delegation(address indexed from, address indexed to);
    event Trade(address who, int amount, uint totPrice, uint newprice); // amount pos or neg for mint or redemption

    constructor(Frankencoin zchf_) ERC20(18) {
        zchf = zchf_;
    }

    function name() override external pure returns (string memory) {
        return "Frankencoin Pool Share";
    }

    function symbol() override external pure returns (string memory) {
        return "FPS";
    }

    function price() public view returns (uint256){
        return VALUATION_FACTOR * zchf.equity() * ONE_DEC18 / totalSupply();
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) override internal {
        super._beforeTokenTransfer(from, to, amount);
        if (amount > 0){
            uint256 roundingLoss = adjustRecipientVoteAnchor(to, amount);
            adjustTotalVotes(from, amount, roundingLoss);
        }
    }

    function canRedeem() external view returns (bool){
        return canRedeem(msg.sender);
    }

    function canRedeem(address owner) public view returns (bool) {
        return anchorTime() - voteAnchor[owner] >= MIN_HOLDING_DURATION;
    }

     /**
     * @notice Decrease the total votes anchor when tokens lose their voting power due to being moved
     * @param from      sender
     * @param amount    amount to be sent
     */
    function adjustTotalVotes(address from, uint256 amount, uint256 roundingLoss) internal {
        uint256 lostVotes = from == address(0x0) ? 0 : (anchorTime() - voteAnchor[from]) * amount;
        totalVotesAtAnchor = uint192(totalVotes() - roundingLoss - lostVotes);
        totalVotesAnchorTime = anchorTime();
    }

    /**
     * @notice the vote anchor of the recipient is moved forward such that the number of calculated
     * votes does not change despite the higher balance.
     * @param to        receiver address
     * @param amount    amount to be received
     * @return the number of votes lost due to rounding errors
     */
    function adjustRecipientVoteAnchor(address to, uint256 amount) internal returns (uint256){
        if (to != address(0x0)) {
            uint256 recipientVotes = votes(to); // for example 21 if 7 shares were held for 3 blocks
            uint256 newbalance = balanceOf(to) + amount; // for example 11 if 4 shares are added
            voteAnchor[to] = uint64(anchorTime() - recipientVotes / newbalance); // new example anchor is only 21 / 11 = 1 block in the past
            return recipientVotes % newbalance; // we have lost 21 % 11 = 10 votes
        } else {
            // optimization for burn, vote anchor of null address does not matter
            return 0;
        }
    }

    function anchorTime() internal view returns (uint64){
        return uint64(block.number << BLOCK_TIME_RESOLUTION_BITS);
    }

    function votes(address holder) public view returns (uint256) {
        return balanceOf(holder) * (anchorTime() - voteAnchor[holder]);
    }

    function totalVotes() public view returns (uint256) {
        return totalVotesAtAnchor + totalSupply() * (anchorTime() - totalVotesAnchorTime);
    }

    function isQualified(address sender, address[] calldata helpers) external override view returns (bool) {
        uint256 _votes = votes(sender);
        for (uint i=0; i<helpers.length; i++){
            address current = helpers[i];
            require(current != sender);
            require(canVoteFor(sender, current));
            for (uint j=i+1; j<helpers.length; j++){
                require(current != helpers[j]); // ensure helper unique
            }
            _votes += votes(current);
        }
        return _votes * 10000 >= QUORUM * totalVotes();
    }

    function delegateVoteTo(address delegate) external {
        delegates[msg.sender] = delegate;
        emit Delegation(msg.sender, delegate);
    }

    function canVoteFor(address delegate, address owner) public view returns (bool) {
        if (owner == delegate){
            return true;
        } else if (owner == address(0x0)){
            return false;
        } else {
            return canVoteFor(delegate, delegates[owner]);
        }
    }

    function onTokenTransfer(address from, uint256 amount, bytes calldata) external returns (bool) {
        require(msg.sender == address(zchf), "caller must be zchf");
        if (totalSupply() == 0){
            require(amount >= ONE_DEC18, "initial deposit must >= 1");
            // initialize with 1000 shares for 1 ZCHF
            uint256 initialAmount = 1000 * ONE_DEC18;
            _mint(from, initialAmount);
            amount -= ONE_DEC18;
            emit Trade(msg.sender, int(initialAmount), ONE_DEC18, price());
        }
        uint256 shares = calculateSharesInternal(zchf.equity() - amount, amount);
        _mint(from, shares);
        require(totalSupply() < 2**90, "total supply exceeded"); // to guard against overflows with price and vote calculations
        emit Trade(msg.sender, int(shares), amount, price());
        return true;
    }

    /**
     * @notice Calculate shares received when depositing ZCHF
     * @dev this function is called after the transfer of ZCHF happens
     * @param investment ZCHF invested, in dec18 format
     * @return amount of shares received for the ZCHF invested
     */
    function calculateShares(uint256 investment) public view returns (uint256) {
        return calculateSharesInternal(zchf.equity(), investment);
    }

    function calculateSharesInternal(uint256 capitalBefore, uint256 investment) internal view returns (uint256) {
        uint256 totalShares = totalSupply();
        uint256 newTotalShares = _mulD18(totalShares, _cubicRoot(_divD18(capitalBefore + investment, capitalBefore)));
        return newTotalShares - totalShares;
    }

    function redeem(address target, uint256 shares) public returns (uint256) {
        require(canRedeem(msg.sender));
        uint256 proceeds = calculateProceeds(shares);
        _burn(msg.sender, shares);
        zchf.transfer(target, proceeds);
        emit Trade(msg.sender, -int(shares), proceeds, price());
        return proceeds;
    }

    /**
     * @notice Calculate ZCHF received when depositing shares
     * @dev this function is called before any transfer happens
     * @param shares number of shares we want to exchange for ZCHF,
     *               in dec18 format
     * @return amount of ZCHF received for the shares
     */
    function calculateProceeds(uint256 shares) public view returns (uint256) {
        uint256 totalShares = totalSupply();
        uint256 capital = zchf.equity();
        require(shares + ONE_DEC18 < totalShares, "too many shares"); // make sure there is always at least one share
        uint256 newTotalShares = totalShares - shares;
        uint256 newCapital = _mulD18(capital, _power3(_divD18(newTotalShares, totalShares)));
        return capital - newCapital;
    }

}

File 5 of 9 : ERC20PermitLight.sol
// SPDX-License-Identifier: MIT
// Copied from https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol
// and modified it.

pragma solidity ^0.8.0;

import "./ERC20.sol";

abstract contract ERC20PermitLight is ERC20 {
   
   /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(address => uint256) public nonces;

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

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

        unchecked { // unchecked to save a little gas with the nonce increment...
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"),
                                bytes32(0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
            _approve(recoveredAddress, spender, value);
        }
    }

    function DOMAIN_SEPARATOR() public view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    //keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
                    bytes32(0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218),
                    block.chainid,
                    address(this)
                )
            );
    }

}

File 6 of 9 : IERC20.sol
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2016-2019 zOS Global Limited
*
*/
pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */

interface IERC20 {

    // Optional functions
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);

    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    function transferAndCall(address recipient, uint256 amount, bytes calldata data) 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.
     *
     * > 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

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

}

File 7 of 9 : MathUtil.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;

/** 
 * @title Functions for share valuation
 */
contract MathUtil {

    uint256 internal constant ONE_DEC18 = 10**18;
    uint256 internal constant THRESH_DEC18 =  10000000000000000;//0.01
    /**
     * @notice Cubic root with Halley approximation
     *         Number 1e18 decimal
     * @param _v     number for which we calculate x**(1/3)
     * @return returns _v**(1/3)
     */
    function _cubicRoot(uint256 _v) internal pure returns (uint256) {
        uint256 x = ONE_DEC18;
        uint256 xOld;
        bool cond;
        do {
            xOld = x;
            uint256 powX3 = _mulD18(_mulD18(x, x), x);
            x = _mulD18(x, _divD18( (powX3 + 2 * _v) , (2 * powX3 + _v)));
            cond = xOld > x ? xOld - x > THRESH_DEC18 : x - xOld > THRESH_DEC18;
        } while ( cond );
        return x;
    }

    function _mulD18(uint256 _a, uint256 _b) internal pure returns(uint256) {
        return _a * _b / ONE_DEC18;
    }

    function _divD18(uint256 _a, uint256 _b) internal pure returns(uint256) {
        return (_a * ONE_DEC18) / _b ;
    }

    function _power3(uint256 _x) internal pure returns(uint256) {
        return _mulD18(_mulD18(_x, _x), _x);
    }

}

File 8 of 9 : IERC677Receiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC677Receiver {
    
    function onTokenTransfer(address from, uint256 amount, bytes calldata data) external returns (bool);

}

File 9 of 9 : ERC20.sol
// SPDX-License-Identifier: MIT
// Copied and adjusted from OpenZeppelin
// Adjustments:
// - modifications to support ERC-677
// - removed require messages to save space
// - removed unnecessary require statements
// - removed GSN Context
// - upgraded to 0.8 to drop SafeMath
// - let name() and symbol() be implemented by subclass
// - infinite allowance support, with 2^255 and above considered infinite

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./IERC677Receiver.sol";

/**
 * @dev Implementation of the `IERC20` interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using `_mint`.
 * For a generic mechanism see `ERC20Mintable`.
 *
 * *For a detailed writeup see our guide [How to implement supply
 * mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an `Approval` event is emitted on calls to `transferFrom`.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard `decreaseAllowance` and `increaseAllowance`
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See `IERC20.approve`.
 */

abstract contract ERC20 is IERC20 {

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    uint8 public immutable override decimals;

    constructor(uint8 _decimals) {
        decimals = _decimals;
    }

    /**
     * @dev See `IERC20.totalSupply`.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See `IERC20.balanceOf`.
     */
    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See `IERC20.transfer`.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev See `IERC20.allowance`.
     */
    function allowance(address owner, address spender) external view override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See `IERC20.approve`.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) external override returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev See `IERC20.transferFrom`.
     *
     * Emits an `Approval` event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of `ERC20`;
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `value`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
        _transfer(sender, recipient, amount);
        uint256 currentAllowance = _allowances[sender][msg.sender];
        if (currentAllowance < (1 << 255)){
            // Only decrease the allowance if it was not set to 'infinite'
            // Documented in /doc/infiniteallowance.md
            require(currentAllowance >= amount, "approval not enough");
            _approve(sender, msg.sender, currentAllowance - amount);
        }
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to `transfer`, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(recipient != address(0));
        
        _beforeTokenTransfer(sender, recipient, amount);
        require(_balances[sender]>=amount, "balance not enough");
        _balances[sender] -= amount;
        _balances[recipient] += amount;
        emit Transfer(sender, recipient, amount);
    }

    // ERC-677 functionality, can be useful for swapping and wrapping tokens
    function transferAndCall(address recipient, uint256 amount, bytes calldata data) external override returns (bool) {
        bool success = transfer(recipient, amount);
        if (success){
            success = IERC677Receiver(recipient).onTokenTransfer(msg.sender, amount, data);
        }
        return success;
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a `Transfer` event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address recipient, uint256 amount) internal virtual {
        require(recipient != address(0));

        _beforeTokenTransfer(address(0), recipient, amount);

        _totalSupply += amount;
        _balances[recipient] += amount;
        emit Transfer(address(0), recipient, amount);
    }

     /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a `Transfer` event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        _beforeTokenTransfer(account, address(0), amount);

        _totalSupply -= amount;
        _balances[account] -= amount;
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an `Approval` event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) virtual internal {
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_minApplicationPeriod","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"applicationPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"applicationFee","type":"uint256"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"MinterApplied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"MinterDenied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_APPLICATION_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"reservePPM","type":"uint32"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"payer","type":"address"},{"internalType":"uint256","name":"targetTotalBurnAmount","type":"uint256"},{"internalType":"uint32","name":"_reservePPM","type":"uint32"}],"name":"burnFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountExcludingReserve","type":"uint256"},{"internalType":"uint32","name":"_reservePPM","type":"uint32"}],"name":"burnWithReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintedAmount","type":"uint256"},{"internalType":"uint32","name":"_reservePPM","type":"uint32"}],"name":"calculateAssignedReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"},{"internalType":"address[]","name":"_helpers","type":"address[]"},{"internalType":"string","name":"_message","type":"string"}],"name":"denyMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"equity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_position","type":"address"}],"name":"isPosition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_reservePPM","type":"uint32"},{"internalType":"uint32","name":"_feesPPM","type":"uint32"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minterReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"notifyLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"positions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_position","type":"address"}],"name":"registerPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserve","outputs":[{"internalType":"contract IReserve","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"},{"internalType":"uint256","name":"_applicationPeriod","type":"uint256"},{"internalType":"uint256","name":"_applicationFee","type":"uint256"},{"internalType":"string","name":"_message","type":"string"}],"name":"suggestMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transferAndCall","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b50604051620039e2380380620039e283398101604081905262000034916200009d565b601260805260a081905260405130906200004e906200008f565b6001600160a01b039091168152602001604051809103906000f0801580156200007b573d6000803e3d6000fd5b506001600160a01b031660c05250620000b7565b611c6a8062001d7883390190565b600060208284031215620000b057600080fd5b5051919050565b60805160a05160c051611c3d6200013b600039600081816104e7015281816105e4015281816108a9015281816108ec015281816109170152818161095a01528181610a2001528181610c5b01528181610d2301528181610eec01528181611062015261134e0152600081816102980152610f43015260006103160152611c3d6000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c806391a0ac6a1161011a578063b52c696d116100ad578063d38bb0091161007c578063d38bb0091461051c578063d505accf14610524578063dd62ed3e14610537578063ea889b8a14610570578063f46eccc41461058357600080fd5b8063b52c696d146104bc578063cbca628e146104cf578063cd3293de146104e2578063d1a15ff11461050957600080fd5b80639dc29fac116100e95780639dc29fac14610470578063a47d75ad14610483578063a9059cbb14610496578063aa271e1a146104a957600080fd5b806391a0ac6a1461042257806395d89b411461042a5780639b404da61461044a5780639cc063581461045d57600080fd5b80633644e5151161019d57806355f575101161016c57806355f575101461038d57806361f3d110146103b657806370a08231146103c957806376c7a3c7146103f25780637ecebe001461040257600080fd5b80633644e5151461034a5780634000aea01461035257806340c10f191461036557806342966c681461037a57600080fd5b80631a46c7e9116101d95780631a46c7e91461029357806323b872dd146102ba5780632748913b146102cd578063313ce5671461031157600080fd5b806306fdde031461020b578063095ea7b31461024757806316e0e5381461026a57806318160ddd1461028b575b600080fd5b60408051808201909152600e81526d4672616e6b656e636f696e20563160901b60208201525b60405161023e919061163f565b60405180910390f35b61025a6102553660046116a9565b6105a3565b604051901515815260200161023e565b61027d6102783660046116e7565b6105ba565b60405190815260200161023e565b60025461027d565b61027d7f000000000000000000000000000000000000000000000000000000000000000081565b61025a6102c8366004611713565b61065c565b6102f96102db36600461174f565b6001600160a01b039081166000908152600660205260409020541690565b6040516001600160a01b03909116815260200161023e565b6103387f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff909116815260200161023e565b61027d610703565b61025a6103603660046117ba565b61075c565b6103786103733660046116a9565b6107f2565b005b610378610388366004611814565b61084d565b6102f961039b36600461174f565b6006602052600090815260409020546001600160a01b031681565b6103786103c4366004611814565b61085a565b61027d6103d736600461174f565b6001600160a01b031660009081526020819052604090205490565b61027d683635c9adc5dea0000081565b61027d61041036600461174f565b60036020526000908152604090205481565b61027d610950565b6040805180820190915260048152632d21a42360e11b6020820152610231565b61037861045836600461182d565b6109b6565b61037861046b3660046116e7565b610b32565b61037861047e3660046116a9565b610bb3565b61027d6104913660046116e7565b610c0a565b61025a6104a43660046116a9565b610d66565b61025a6104b736600461174f565b610d73565b6103786104ca36600461174f565b610db4565b6103786104dd3660046118df565b610e1f565b6102f97f000000000000000000000000000000000000000000000000000000000000000081565b61037861051736600461192c565b610f41565b61027d6110e4565b610378610532366004611983565b6110fc565b61027d6105453660046119f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61027d61057e366004611a20565b6112ec565b61027d61059136600461174f565b60056020526000908152604090205481565b60006105b03384846113ad565b5060015b92915050565b600080620f42406105d18563ffffffff8616611a72565b6105db9190611a89565b9050600061061e7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660009081526020819052604090205490565b90506106286110e4565b811015610654576106376110e4565b6106418284611a72565b61064b9190611a89565b925050506105b4565b5090506105b4565b600061066984848461140f565b6001600160a01b0384166000908152600160209081526040808320338452909152902054600160ff1b8110156106f857828110156106e45760405162461bcd60e51b81526020600482015260136024820152720c2e0e0e4deecc2d840dcdee840cadcdeeaced606b1b60448201526064015b60405180910390fd5b6106f885336106f38685611aab565b6113ad565b506001949350505050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6000806107698686610d66565b905080156107e957604051635260769b60e11b81526001600160a01b0387169063a4c0ed36906107a3903390899089908990600401611ae7565b6020604051808303816000875af11580156107c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e69190611b0f565b90505b95945050505050565b6107fb33610d73565b80610823575033600090815260066020526040902054610823906001600160a01b0316610d73565b61083f5760405162461bcd60e51b81526004016106db90611b31565b6108498282611520565b5050565b61085733826115bd565b50565b61086333610d73565b8061088b57503360009081526006602052604090205461088b906001600160a01b0316610d73565b6108a75760405162461bcd60e51b81526004016106db90611b31565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316600090815260208190526040902054818110610912576108497f0000000000000000000000000000000000000000000000000000000000000000338461140f565b61093d7f0000000000000000000000000000000000000000000000000000000000000000338361140f565b6108493361094b8385611aab565b611520565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660009081526020819052604081205460006109936110e4565b90508082116109a55760009250505090565b6109af8183611aab565b9250505090565b6001600160a01b038516600090815260056020526040902054421115610a095760405162461bcd60e51b8152602060048201526008602482015267746f6f206c61746560c01b60448201526064016106db565b604051635e1121cf60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635e1121cf90610a5990339088908890600401611b5e565b602060405180830381865afa158015610a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9a9190611b0f565b610ad65760405162461bcd60e51b815260206004820152600d60248201526c1b9bdd081c5d585b1a599a5959609a1b60448201526064016106db565b6001600160a01b03851660008181526005602052604080822091909155517fd60c86e83346fdbe3124cb7d1cba32973a9f62d05c4ec801bfe6c09d1038038190610b239085908590611bb8565b60405180910390a25050505050565b610b3b33610d73565b80610b63575033600090815260066020526040902054610b63906001600160a01b0316610d73565b610b7f5760405162461bcd60e51b81526004016106db90611b31565b610b8933836115bd565b610b9963ffffffff821683611a72565b60046000828254610baa9190611aab565b90915550505050565b610bbc33610d73565b80610be4575033600090815260066020526040902054610be4906001600160a01b0316610d73565b610c005760405162461bcd60e51b81526004016106db90611b31565b61084982826115bd565b6000610c1533610d73565b80610c3d575033600090815260066020526040902054610c3d906001600160a01b0316610d73565b610c595760405162461bcd60e51b81526004016106db90611b31565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660009081526020819052604081205490610c9b6110e4565b90506000818310610cb2578463ffffffff16610ccd565b81610cc38463ffffffff8816611a72565b610ccd9190611a89565b90506000610cde82620f4240611aab565b610ceb88620f4240611a72565b610cf59190611a89565b9050610d0763ffffffff871682611a72565b60046000828254610d189190611aab565b90915550610d5290507f000000000000000000000000000000000000000000000000000000000000000033610d4d8a85611aab565b61140f565b610d5c33826115bd565b9695505050505050565b60006105b033848461140f565b6001600160a01b038116600090815260056020526040812054158015906105b45750506001600160a01b031660009081526005602052604090205442101590565b610dbd33610d73565b610df65760405162461bcd60e51b815260206004820152600a6024820152693737ba1036b4b73a32b960b11b60448201526064016106db565b6001600160a01b0316600090815260066020526040902080546001600160a01b03191633179055565b610e2833610d73565b80610e50575033600090815260066020526040902054610e50906001600160a01b0316610d73565b610e6c5760405162461bcd60e51b81526004016106db90611b31565b6000610e7e63ffffffff841685611a72565b90506000620f4240610e9383620f423f611bd4565b610e9d9190611a89565b90506000620f4240610eb563ffffffff861688611a72565b610ec290620f423f611bd4565b610ecc9190611a89565b9050610ee78782610edd858a611aab565b61094b9190611aab565b610f157f000000000000000000000000000000000000000000000000000000000000000061094b8385611bd4565b610f2282620f4240611a72565b60046000828254610f339190611bd4565b909155505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000084101580610f705750600254155b610faf5760405162461bcd60e51b815260206004820152601060248201526f1c195c9a5bd9081d1bdbc81cda1bdc9d60821b60448201526064016106db565b683635c9adc5dea0000083101580610fc75750600254155b6110015760405162461bcd60e51b815260206004820152600b60248201526a66656520746f6f206c6f7760a81b60448201526064016106db565b6001600160a01b0385166000908152600560205260409020541561105c5760405162461bcd60e51b8152602060048201526012602482015271185b1c9958591e481c9959da5cdd195c995960721b60448201526064016106db565b611087337f00000000000000000000000000000000000000000000000000000000000000008561140f565b6110918442611bd4565b6001600160a01b038616600081815260056020526040908190209290925590517f97326258efdae63280617ca33884e507791c2abeed7b82acd77f1853394ef94b90610b23908790879087908790611be7565b6000620f42406004546110f79190611a89565b905090565b4284101561114c5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064016106db565b60006001611158610703565b6001600160a01b038a811660008181526003602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611264573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061129a5750876001600160a01b0316816001600160a01b0316145b6112d75760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b60448201526064016106db565b6112e28188886113ad565b5050505050505050565b60006112f733610d73565b8061131f57503360009081526006602052604090205461131f906001600160a01b0316610d73565b61133b5760405162461bcd60e51b81526004016106db90611b31565b600061134784846105ba565b90506113747f0000000000000000000000000000000000000000000000000000000000000000868361140f565b61137e85856115bd565b61138e63ffffffff841685611a72565b6004600082825461139f9190611aab565b909155509095945050505050565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03821661142257600080fd5b6001600160a01b03831660009081526020819052604090205481111561147f5760405162461bcd60e51b81526020600482015260126024820152710c4c2d8c2dcc6ca40dcdee840cadcdeeaced60731b60448201526064016106db565b6001600160a01b038316600090815260208190526040812080548392906114a7908490611aab565b90915550506001600160a01b038216600090815260208190526040812080548392906114d4908490611bd4565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161140291815260200190565b6001600160a01b03821661153357600080fd5b80600260008282546115459190611bd4565b90915550506001600160a01b03821660009081526020819052604081208054839290611572908490611bd4565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b80600260008282546115cf9190611aab565b90915550506001600160a01b038216600090815260208190526040812080548392906115fc908490611aab565b90915550506040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016115b1565b600060208083528351808285015260005b8181101561166c57858101830151858201604001528201611650565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146116a457600080fd5b919050565b600080604083850312156116bc57600080fd5b6116c58361168d565b946020939093013593505050565b803563ffffffff811681146116a457600080fd5b600080604083850312156116fa57600080fd5b8235915061170a602084016116d3565b90509250929050565b60008060006060848603121561172857600080fd5b6117318461168d565b925061173f6020850161168d565b9150604084013590509250925092565b60006020828403121561176157600080fd5b61176a8261168d565b9392505050565b60008083601f84011261178357600080fd5b50813567ffffffffffffffff81111561179b57600080fd5b6020830191508360208285010111156117b357600080fd5b9250929050565b600080600080606085870312156117d057600080fd5b6117d98561168d565b935060208501359250604085013567ffffffffffffffff8111156117fc57600080fd5b61180887828801611771565b95989497509550505050565b60006020828403121561182657600080fd5b5035919050565b60008060008060006060868803121561184557600080fd5b61184e8661168d565b9450602086013567ffffffffffffffff8082111561186b57600080fd5b818801915088601f83011261187f57600080fd5b81358181111561188e57600080fd5b8960208260051b85010111156118a357600080fd5b6020830196508095505060408801359150808211156118c157600080fd5b506118ce88828901611771565b969995985093965092949392505050565b600080600080608085870312156118f557600080fd5b6118fe8561168d565b935060208501359250611913604086016116d3565b9150611921606086016116d3565b905092959194509250565b60008060008060006080868803121561194457600080fd5b61194d8661168d565b94506020860135935060408601359250606086013567ffffffffffffffff81111561197757600080fd5b6118ce88828901611771565b600080600080600080600060e0888a03121561199e57600080fd5b6119a78861168d565b96506119b56020890161168d565b95506040880135945060608801359350608088013560ff811681146119d957600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611a0957600080fd5b611a128361168d565b915061170a6020840161168d565b600080600060608486031215611a3557600080fd5b611a3e8461168d565b925060208401359150611a53604085016116d3565b90509250925092565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105b4576105b4611a5c565b600082611aa657634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156105b4576105b4611a5c565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000610d5c606083018486611abe565b600060208284031215611b2157600080fd5b8151801515811461176a57600080fd5b6020808252601390820152723737ba1030b8383937bb32b21036b4b73a32b960691b604082015260600190565b6001600160a01b03848116825260406020808401829052908301849052600091859160608501845b87811015611bab5783611b988661168d565b1682529382019390820190600101611b86565b5098975050505050505050565b602081526000611bcc602083018486611abe565b949350505050565b808201808211156105b4576105b4611a5c565b848152836020820152606060408201526000610d5c606083018486611abe56fea264697066735822122090bd4cb1972b845149b84313bfaae0f7898ce3828b197d22d0c0fa22b0359f5764736f6c6343000813003360c060405234801561001057600080fd5b50604051611c6a380380611c6a83398101604081905261002f91610045565b60126080526001600160a01b031660a052610075565b60006020828403121561005757600080fd5b81516001600160a01b038116811461006e57600080fd5b9392505050565b60805160a051611ba66100c46000396000818161044d015281816105e00152818161080e01528181610ad001528181610b7c01528181610ccd0152610e2b015260006102b40152611ba66000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c80635e1121cf11610104578063a9059cbb116100a2578063d505accf11610071578063d505accf1461046f578063d8bff5a514610482578063dd62ed3e14610495578063f97ed509146104ce57600080fd5b8063a9059cbb14610415578063ad08ce5b14610428578063b0c2bf061461043b578063c4d4803a1461044857600080fd5b806395d89b41116100de57806395d89b41146103c65780639823004f146103e5578063a035b1fe146103fa578063a4c0ed361461040257600080fd5b80635e1121cf1461036a57806370a082311461037d5780637ecebe00146103a657600080fd5b8063250f25f4116101715780633c835ab01161014b5780633c835ab0146102f05780633ec16194146103035780634000aea014610316578063587cde1e1461032957600080fd5b8063250f25f414610292578063313ce567146102af5780633644e515146102e857600080fd5b8063151535b9116101ad578063151535b91461025157806318160ddd146102645780631e9a69501461026c57806323b872dd1461027f57600080fd5b806306fdde03146101d4578063095ea7b3146102185780630d15fd771461023b575b600080fd5b6040805180820190915260168152754672616e6b656e636f696e20506f6f6c20536861726560501b60208201525b60405161020f919061170f565b60405180910390f35b61022b610226366004611779565b6104d6565b604051901515815260200161020f565b6102436104ed565b60405190815260200161020f565b61022b61025f3660046117a3565b610547565b600254610243565b61024361027a366004611779565b61058f565b61022b61028d3660046117be565b6106a1565b61029a600381565b60405163ffffffff909116815260200161020f565b6102d67f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff909116815260200161020f565b610243610748565b61022b6102fe3660046117fa565b6107a1565b61024361031136600461182d565b610807565b61022b610324366004611846565b610894565b6103526103373660046117a3565b6005602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161020f565b61022b6103783660046118cc565b61092a565b61024361038b3660046117a3565b6001600160a01b031660009081526020819052604090205490565b6102436103b43660046117a3565b60036020526000908152604090205481565b60408051808201909152600381526246505360e81b6020820152610202565b6103f86103f33660046117a3565b610a63565b005b610243610aba565b61022b610410366004611846565b610b6f565b61022b610423366004611779565b610e0c565b61024361043636600461182d565b610e19565b6102436509e34000000081565b6103527f000000000000000000000000000000000000000000000000000000000000000081565b6103f861047d366004611951565b610f40565b6102436104903660046117a3565b611130565b6102436104a33660046117fa565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61022b611191565b60006104e333848461119c565b5060015b92915050565b600454600090610509906001600160401b03164360181b6119da565b6001600160401b031661051b60025490565b6105259190611a01565b6004546105429190600160401b90046001600160c01b0316611a18565b905090565b6001600160a01b0381166000908152600660205260408120546509e3400000009061057e906001600160401b03164360181b6119da565b6001600160401b0316101592915050565b600061059a33610547565b6105a357600080fd5b60006105ae83610e19565b90506105ba33846111fe565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015610629573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064d9190611a2b565b507fd98fb7c2b7c7b545387da80b92c08bc5d2a4b922fb74851c3d27ee07ca897bdf3361067985611a4d565b83610682610aba565b6040516106929493929190611a69565b60405180910390a19392505050565b60006106ae848484611294565b6001600160a01b0384166000908152600160209081526040808320338452909152902054600160ff1b81101561073d57828110156107295760405162461bcd60e51b81526020600482015260136024820152720c2e0e0e4deecc2d840dcdee840cadcdeeaced606b1b60448201526064015b60405180910390fd5b61073d85336107388685611a8f565b61119c565b506001949350505050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6000826001600160a01b0316826001600160a01b0316036107c4575060016104e7565b6001600160a01b0382166107da575060006104e7565b6001600160a01b03808316600090815260056020526040902054610800918591166107a1565b90506104e7565b60006104e77f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391a0ac6a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561086a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088e9190611aa2565b836113b0565b6000806108a18686610e0c565b9050801561092157604051635260769b60e11b81526001600160a01b0387169063a4c0ed36906108db903390899089908990600401611abb565b6020604051808303816000875af11580156108fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091e9190611a2b565b90505b95945050505050565b60008061093685611130565b905060005b83811015610a3757600085858381811061095757610957611b03565b905060200201602081019061096c91906117a3565b9050866001600160a01b0316816001600160a01b03160361098c57600080fd5b61099687826107a1565b61099f57600080fd5b60006109ac836001611a18565b90505b85811015610a0d578686828181106109c9576109c9611b03565b90506020020160208101906109de91906117a3565b6001600160a01b0316826001600160a01b0316036109fb57600080fd5b80610a0581611b19565b9150506109af565b50610a1781611130565b610a219084611a18565b9250508080610a2f90611b19565b91505061093b565b50610a406104ed565b610a4c9061012c611a01565b610a5882612710611a01565b101595945050505050565b3360008181526005602052604080822080546001600160a01b0319166001600160a01b03861690811790915590519092917fd000f39f92c3ed77f890f16b6ced1555e0ab2cdf470522d2210de67d8c83d45b91a350565b6000610ac560025490565b670de0b6b3a76400007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391a0ac6a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b509190611aa2565b610b5b906003611a01565b610b659190611a01565b6105429190611b48565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610bdf5760405162461bcd60e51b815260206004820152601360248201527231b0b63632b91036bab9ba103132903d31b43360691b6044820152606401610720565b600254600003610cc557670de0b6b3a7640000841015610c415760405162461bcd60e51b815260206004820152601960248201527f696e697469616c206465706f736974206d757374203e3d2031000000000000006044820152606401610720565b6000610c57670de0b6b3a76400006103e8611a01565b9050610c6386826113eb565b610c75670de0b6b3a764000086611a8f565b94507fd98fb7c2b7c7b545387da80b92c08bc5d2a4b922fb74851c3d27ee07ca897bdf3382670de0b6b3a7640000610cab610aba565b604051610cbb9493929190611a69565b60405180910390a1505b6000610d5d857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391a0ac6a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4d9190611aa2565b610d579190611a8f565b866113b0565b9050610d6986826113eb565b6001605a1b610d7760025490565b10610dbc5760405162461bcd60e51b81526020600482015260156024820152741d1bdd185b081cdd5c1c1b1e48195e18d959591959605a1b6044820152606401610720565b7fd98fb7c2b7c7b545387da80b92c08bc5d2a4b922fb74851c3d27ee07ca897bdf338287610de8610aba565b604051610df89493929190611a69565b60405180910390a150600195945050505050565b60006104e3338484611294565b600080610e2560025490565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391a0ac6a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eab9190611aa2565b905081610ec0670de0b6b3a764000086611a18565b10610eff5760405162461bcd60e51b815260206004820152600f60248201526e746f6f206d616e792073686172657360881b6044820152606401610720565b6000610f0b8584611a8f565b90506000610f2a83610f25610f20858861148c565b6114b2565b6114c3565b9050610f368184611a8f565b9695505050505050565b42841015610f905760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610720565b60006001610f9c610748565b6001600160a01b038a811660008181526003602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156110a8573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906110de5750876001600160a01b0316816001600160a01b0316145b61111b5760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610720565b61112681888861119c565b5050505050505050565b6001600160a01b03811660009081526006602052604081205461115f906001600160401b03164360181b6119da565b6001600160401b0316611187836001600160a01b031660009081526020819052604090205490565b6104e79190611a01565b600061054233610547565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b61120a826000836114d8565b806002600082825461121c9190611a8f565b90915550506001600160a01b03821660009081526020819052604081208054839290611249908490611a8f565b90915550506040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b6001600160a01b0382166112a757600080fd5b6112b28383836114d8565b6001600160a01b03831660009081526020819052604090205481111561130f5760405162461bcd60e51b81526020600482015260126024820152710c4c2d8c2dcc6ca40dcdee840cadcdeeaced60731b6044820152606401610720565b6001600160a01b03831660009081526020819052604081208054839290611337908490611a8f565b90915550506001600160a01b03821660009081526020819052604081208054839290611364908490611a18565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516111f191815260200190565b6000806113bc60025490565b905060006113df82610f256113da6113d4888a611a18565b8961148c565b6114fe565b90506109218282611a8f565b6001600160a01b0382166113fe57600080fd5b61140a600083836114d8565b806002600082825461141c9190611a18565b90915550506001600160a01b03821660009081526020819052604081208054839290611449908490611a18565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001611288565b6000816114a1670de0b6b3a764000085611a01565b6114ab9190611b48565b9392505050565b60006104e76114c183846114c3565b835b6000670de0b6b3a76400006114a18385611a01565b80156114f95760006114ea83836115a3565b90506114f7848383611661565b505b505050565b6000670de0b6b3a764000081805b829150600061152461151e85866114c3565b856114c3565b905061155d84610f25611538896002611a01565b6115429085611a18565b8961154e866002611a01565b6115589190611a18565b61148c565b935083831161157e57662386f26fc100006115788486611a8f565b11611592565b662386f26fc100006115908585611a8f565b115b9150508061150c5750909392505050565b60006001600160a01b038316156116595760006115bf84611130565b90506000836115e3866001600160a01b031660009081526020819052604090205490565b6115ed9190611a18565b90506115f98183611b48565b61160f906001600160401b034360181b16611a8f565b6001600160a01b0386166000908152600660205260409020805467ffffffffffffffff19166001600160401b03929092169190911790556116508183611b5c565b925050506104e7565b5060006104e7565b60006001600160a01b038416156116bb576001600160a01b03841660009081526006602052604090205483906116a3906001600160401b03164360181b6119da565b6001600160401b03166116b69190611a01565b6116be565b60005b905080826116ca6104ed565b6116d49190611a8f565b6116de9190611a8f565b6001600160c01b0316600160401b0267ffffffffffffffff19166001600160401b034360181b161760045550505050565b600060208083528351808285015260005b8181101561173c57858101830151858201604001528201611720565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461177457600080fd5b919050565b6000806040838503121561178c57600080fd5b6117958361175d565b946020939093013593505050565b6000602082840312156117b557600080fd5b6114ab8261175d565b6000806000606084860312156117d357600080fd5b6117dc8461175d565b92506117ea6020850161175d565b9150604084013590509250925092565b6000806040838503121561180d57600080fd5b6118168361175d565b91506118246020840161175d565b90509250929050565b60006020828403121561183f57600080fd5b5035919050565b6000806000806060858703121561185c57600080fd5b6118658561175d565b93506020850135925060408501356001600160401b038082111561188857600080fd5b818701915087601f83011261189c57600080fd5b8135818111156118ab57600080fd5b8860208285010111156118bd57600080fd5b95989497505060200194505050565b6000806000604084860312156118e157600080fd5b6118ea8461175d565b925060208401356001600160401b038082111561190657600080fd5b818601915086601f83011261191a57600080fd5b81358181111561192957600080fd5b8760208260051b850101111561193e57600080fd5b6020830194508093505050509250925092565b600080600080600080600060e0888a03121561196c57600080fd5b6119758861175d565b96506119836020890161175d565b95506040880135945060608801359350608088013560ff811681146119a757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b634e487b7160e01b600052601160045260246000fd5b6001600160401b038281168282160390808211156119fa576119fa6119c4565b5092915050565b80820281158282048414176104e7576104e76119c4565b808201808211156104e7576104e76119c4565b600060208284031215611a3d57600080fd5b815180151581146114ab57600080fd5b6000600160ff1b8201611a6257611a626119c4565b5060000390565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b818103818111156104e7576104e76119c4565b600060208284031215611ab457600080fd5b5051919050565b6001600160a01b0385168152602081018490526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b600052603260045260246000fd5b600060018201611b2b57611b2b6119c4565b5060010190565b634e487b7160e01b600052601260045260246000fd5b600082611b5757611b57611b32565b500490565b600082611b6b57611b6b611b32565b50069056fea2646970667358221220ac01cdbbe9aeaf35c054f9e1df101fbe5af5df88be31ffa4a1560cd3a2361e7864736f6c6343000813003300000000000000000000000000000000000000000000000000000000000d2f00

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102065760003560e01c806391a0ac6a1161011a578063b52c696d116100ad578063d38bb0091161007c578063d38bb0091461051c578063d505accf14610524578063dd62ed3e14610537578063ea889b8a14610570578063f46eccc41461058357600080fd5b8063b52c696d146104bc578063cbca628e146104cf578063cd3293de146104e2578063d1a15ff11461050957600080fd5b80639dc29fac116100e95780639dc29fac14610470578063a47d75ad14610483578063a9059cbb14610496578063aa271e1a146104a957600080fd5b806391a0ac6a1461042257806395d89b411461042a5780639b404da61461044a5780639cc063581461045d57600080fd5b80633644e5151161019d57806355f575101161016c57806355f575101461038d57806361f3d110146103b657806370a08231146103c957806376c7a3c7146103f25780637ecebe001461040257600080fd5b80633644e5151461034a5780634000aea01461035257806340c10f191461036557806342966c681461037a57600080fd5b80631a46c7e9116101d95780631a46c7e91461029357806323b872dd146102ba5780632748913b146102cd578063313ce5671461031157600080fd5b806306fdde031461020b578063095ea7b31461024757806316e0e5381461026a57806318160ddd1461028b575b600080fd5b60408051808201909152600e81526d4672616e6b656e636f696e20563160901b60208201525b60405161023e919061163f565b60405180910390f35b61025a6102553660046116a9565b6105a3565b604051901515815260200161023e565b61027d6102783660046116e7565b6105ba565b60405190815260200161023e565b60025461027d565b61027d7f00000000000000000000000000000000000000000000000000000000000d2f0081565b61025a6102c8366004611713565b61065c565b6102f96102db36600461174f565b6001600160a01b039081166000908152600660205260409020541690565b6040516001600160a01b03909116815260200161023e565b6103387f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff909116815260200161023e565b61027d610703565b61025a6103603660046117ba565b61075c565b6103786103733660046116a9565b6107f2565b005b610378610388366004611814565b61084d565b6102f961039b36600461174f565b6006602052600090815260409020546001600160a01b031681565b6103786103c4366004611814565b61085a565b61027d6103d736600461174f565b6001600160a01b031660009081526020819052604090205490565b61027d683635c9adc5dea0000081565b61027d61041036600461174f565b60036020526000908152604090205481565b61027d610950565b6040805180820190915260048152632d21a42360e11b6020820152610231565b61037861045836600461182d565b6109b6565b61037861046b3660046116e7565b610b32565b61037861047e3660046116a9565b610bb3565b61027d6104913660046116e7565b610c0a565b61025a6104a43660046116a9565b610d66565b61025a6104b736600461174f565b610d73565b6103786104ca36600461174f565b610db4565b6103786104dd3660046118df565b610e1f565b6102f97f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e81565b61037861051736600461192c565b610f41565b61027d6110e4565b610378610532366004611983565b6110fc565b61027d6105453660046119f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61027d61057e366004611a20565b6112ec565b61027d61059136600461174f565b60056020526000908152604090205481565b60006105b03384846113ad565b5060015b92915050565b600080620f42406105d18563ffffffff8616611a72565b6105db9190611a89565b9050600061061e7f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e6001600160a01b031660009081526020819052604090205490565b90506106286110e4565b811015610654576106376110e4565b6106418284611a72565b61064b9190611a89565b925050506105b4565b5090506105b4565b600061066984848461140f565b6001600160a01b0384166000908152600160209081526040808320338452909152902054600160ff1b8110156106f857828110156106e45760405162461bcd60e51b81526020600482015260136024820152720c2e0e0e4deecc2d840dcdee840cadcdeeaced606b1b60448201526064015b60405180910390fd5b6106f885336106f38685611aab565b6113ad565b506001949350505050565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6000806107698686610d66565b905080156107e957604051635260769b60e11b81526001600160a01b0387169063a4c0ed36906107a3903390899089908990600401611ae7565b6020604051808303816000875af11580156107c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e69190611b0f565b90505b95945050505050565b6107fb33610d73565b80610823575033600090815260066020526040902054610823906001600160a01b0316610d73565b61083f5760405162461bcd60e51b81526004016106db90611b31565b6108498282611520565b5050565b61085733826115bd565b50565b61086333610d73565b8061088b57503360009081526006602052604090205461088b906001600160a01b0316610d73565b6108a75760405162461bcd60e51b81526004016106db90611b31565b7f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e6001600160a01b0316600090815260208190526040902054818110610912576108497f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e338461140f565b61093d7f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e338361140f565b6108493361094b8385611aab565b611520565b6001600160a01b037f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e1660009081526020819052604081205460006109936110e4565b90508082116109a55760009250505090565b6109af8183611aab565b9250505090565b6001600160a01b038516600090815260056020526040902054421115610a095760405162461bcd60e51b8152602060048201526008602482015267746f6f206c61746560c01b60448201526064016106db565b604051635e1121cf60e01b81526001600160a01b037f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e1690635e1121cf90610a5990339088908890600401611b5e565b602060405180830381865afa158015610a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9a9190611b0f565b610ad65760405162461bcd60e51b815260206004820152600d60248201526c1b9bdd081c5d585b1a599a5959609a1b60448201526064016106db565b6001600160a01b03851660008181526005602052604080822091909155517fd60c86e83346fdbe3124cb7d1cba32973a9f62d05c4ec801bfe6c09d1038038190610b239085908590611bb8565b60405180910390a25050505050565b610b3b33610d73565b80610b63575033600090815260066020526040902054610b63906001600160a01b0316610d73565b610b7f5760405162461bcd60e51b81526004016106db90611b31565b610b8933836115bd565b610b9963ffffffff821683611a72565b60046000828254610baa9190611aab565b90915550505050565b610bbc33610d73565b80610be4575033600090815260066020526040902054610be4906001600160a01b0316610d73565b610c005760405162461bcd60e51b81526004016106db90611b31565b61084982826115bd565b6000610c1533610d73565b80610c3d575033600090815260066020526040902054610c3d906001600160a01b0316610d73565b610c595760405162461bcd60e51b81526004016106db90611b31565b7f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e6001600160a01b031660009081526020819052604081205490610c9b6110e4565b90506000818310610cb2578463ffffffff16610ccd565b81610cc38463ffffffff8816611a72565b610ccd9190611a89565b90506000610cde82620f4240611aab565b610ceb88620f4240611a72565b610cf59190611a89565b9050610d0763ffffffff871682611a72565b60046000828254610d189190611aab565b90915550610d5290507f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e33610d4d8a85611aab565b61140f565b610d5c33826115bd565b9695505050505050565b60006105b033848461140f565b6001600160a01b038116600090815260056020526040812054158015906105b45750506001600160a01b031660009081526005602052604090205442101590565b610dbd33610d73565b610df65760405162461bcd60e51b815260206004820152600a6024820152693737ba1036b4b73a32b960b11b60448201526064016106db565b6001600160a01b0316600090815260066020526040902080546001600160a01b03191633179055565b610e2833610d73565b80610e50575033600090815260066020526040902054610e50906001600160a01b0316610d73565b610e6c5760405162461bcd60e51b81526004016106db90611b31565b6000610e7e63ffffffff841685611a72565b90506000620f4240610e9383620f423f611bd4565b610e9d9190611a89565b90506000620f4240610eb563ffffffff861688611a72565b610ec290620f423f611bd4565b610ecc9190611a89565b9050610ee78782610edd858a611aab565b61094b9190611aab565b610f157f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e61094b8385611bd4565b610f2282620f4240611a72565b60046000828254610f339190611bd4565b909155505050505050505050565b7f00000000000000000000000000000000000000000000000000000000000d2f0084101580610f705750600254155b610faf5760405162461bcd60e51b815260206004820152601060248201526f1c195c9a5bd9081d1bdbc81cda1bdc9d60821b60448201526064016106db565b683635c9adc5dea0000083101580610fc75750600254155b6110015760405162461bcd60e51b815260206004820152600b60248201526a66656520746f6f206c6f7760a81b60448201526064016106db565b6001600160a01b0385166000908152600560205260409020541561105c5760405162461bcd60e51b8152602060048201526012602482015271185b1c9958591e481c9959da5cdd195c995960721b60448201526064016106db565b611087337f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e8561140f565b6110918442611bd4565b6001600160a01b038616600081815260056020526040908190209290925590517f97326258efdae63280617ca33884e507791c2abeed7b82acd77f1853394ef94b90610b23908790879087908790611be7565b6000620f42406004546110f79190611a89565b905090565b4284101561114c5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064016106db565b60006001611158610703565b6001600160a01b038a811660008181526003602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611264573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061129a5750876001600160a01b0316816001600160a01b0316145b6112d75760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b60448201526064016106db565b6112e28188886113ad565b5050505050505050565b60006112f733610d73565b8061131f57503360009081526006602052604090205461131f906001600160a01b0316610d73565b61133b5760405162461bcd60e51b81526004016106db90611b31565b600061134784846105ba565b90506113747f000000000000000000000000cc4b224b4647f090d323a0b6f78a1a31963ddf5e868361140f565b61137e85856115bd565b61138e63ffffffff841685611a72565b6004600082825461139f9190611aab565b909155509095945050505050565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03821661142257600080fd5b6001600160a01b03831660009081526020819052604090205481111561147f5760405162461bcd60e51b81526020600482015260126024820152710c4c2d8c2dcc6ca40dcdee840cadcdeeaced60731b60448201526064016106db565b6001600160a01b038316600090815260208190526040812080548392906114a7908490611aab565b90915550506001600160a01b038216600090815260208190526040812080548392906114d4908490611bd4565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161140291815260200190565b6001600160a01b03821661153357600080fd5b80600260008282546115459190611bd4565b90915550506001600160a01b03821660009081526020819052604081208054839290611572908490611bd4565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b80600260008282546115cf9190611aab565b90915550506001600160a01b038216600090815260208190526040812080548392906115fc908490611aab565b90915550506040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016115b1565b600060208083528351808285015260005b8181101561166c57858101830151858201604001528201611650565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146116a457600080fd5b919050565b600080604083850312156116bc57600080fd5b6116c58361168d565b946020939093013593505050565b803563ffffffff811681146116a457600080fd5b600080604083850312156116fa57600080fd5b8235915061170a602084016116d3565b90509250929050565b60008060006060848603121561172857600080fd5b6117318461168d565b925061173f6020850161168d565b9150604084013590509250925092565b60006020828403121561176157600080fd5b61176a8261168d565b9392505050565b60008083601f84011261178357600080fd5b50813567ffffffffffffffff81111561179b57600080fd5b6020830191508360208285010111156117b357600080fd5b9250929050565b600080600080606085870312156117d057600080fd5b6117d98561168d565b935060208501359250604085013567ffffffffffffffff8111156117fc57600080fd5b61180887828801611771565b95989497509550505050565b60006020828403121561182657600080fd5b5035919050565b60008060008060006060868803121561184557600080fd5b61184e8661168d565b9450602086013567ffffffffffffffff8082111561186b57600080fd5b818801915088601f83011261187f57600080fd5b81358181111561188e57600080fd5b8960208260051b85010111156118a357600080fd5b6020830196508095505060408801359150808211156118c157600080fd5b506118ce88828901611771565b969995985093965092949392505050565b600080600080608085870312156118f557600080fd5b6118fe8561168d565b935060208501359250611913604086016116d3565b9150611921606086016116d3565b905092959194509250565b60008060008060006080868803121561194457600080fd5b61194d8661168d565b94506020860135935060408601359250606086013567ffffffffffffffff81111561197757600080fd5b6118ce88828901611771565b600080600080600080600060e0888a03121561199e57600080fd5b6119a78861168d565b96506119b56020890161168d565b95506040880135945060608801359350608088013560ff811681146119d957600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611a0957600080fd5b611a128361168d565b915061170a6020840161168d565b600080600060608486031215611a3557600080fd5b611a3e8461168d565b925060208401359150611a53604085016116d3565b90509250925092565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105b4576105b4611a5c565b600082611aa657634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156105b4576105b4611a5c565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201526000610d5c606083018486611abe565b600060208284031215611b2157600080fd5b8151801515811461176a57600080fd5b6020808252601390820152723737ba1030b8383937bb32b21036b4b73a32b960691b604082015260600190565b6001600160a01b03848116825260406020808401829052908301849052600091859160608501845b87811015611bab5783611b988661168d565b1682529382019390820190600101611b86565b5098975050505050505050565b602081526000611bcc602083018486611abe565b949350505050565b808201808211156105b4576105b4611a5c565b848152836020820152606060408201526000610d5c606083018486611abe56fea264697066735822122090bd4cb1972b845149b84313bfaae0f7898ce3828b197d22d0c0fa22b0359f5764736f6c63430008130033

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

00000000000000000000000000000000000000000000000000000000000d2f00

-----Decoded View---------------
Arg [0] : _minApplicationPeriod (uint256): 864000

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000d2f00


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.