Contract 0xb4bebD34f6DaaFd808f73De0d10235a92Fbb6c3D 5

Token Contract 
 
 
Txn Hash
Method
Block
From
To
Value
0x824c713f40d119adc94e6731ba87d30350e9dcf58f64a80d6559c34ffcd5844fApprove160387362022-11-24 8:46:357 days 7 hrs ago0xcb70c73907ac286cf2d4ff39b3212d5d9e803ed4 IN  PowerIndex: YETI Token0 Ether0.00028989 11.9972767
0x5651bc0faa3f1fce136aa9de124a548a3baf1ef48f5c2589bcb8641ff0004945Approve160187462022-11-21 13:40:3510 days 2 hrs agoENS Name mazumba.eth IN  PowerIndex: YETI Token0 Ether0.00055331 11.91277554
0x9e7db72f9ec87d734ba1be7cd67d11214191dee33119f923977e106056afe911Exitswap Pool Am...159191352022-11-07 15:46:5924 days 52 mins ago0x891bad61014e35395474a260b58bb6df4fd8991b IN  PowerIndex: YETI Token0 Ether0.00678845 30.0782771
0x34f94e5198698fadd5d47c2575db8dcd8029c7184044569a96c214259f872c41Approve159191322022-11-07 15:46:2324 days 53 mins ago0x891bad61014e35395474a260b58bb6df4fd8991b IN  PowerIndex: YETI Token0 Ether0.00088387 30.39157196
0xdbb769fa68cc11f31a77183df0bf6d86898377a0a2248e4b00761608945b966aApprove159191232022-11-07 15:44:3524 days 54 mins ago0x891bad61014e35395474a260b58bb6df4fd8991b IN  PowerIndex: YETI Token0 Ether0.00138549 30
0x33db0de58009e3ce0415001f61c5b77c2d772ba351a218bb88a728a3d35de350Approve158251022022-10-25 12:28:3537 days 4 hrs ago0x450cf20323733ea1ba31357cc129bd7da188cc68 IN  PowerIndex: YETI Token0 Ether0.00041802 9
0x8f5c1f682ab8abfb09afd6ab719164cf926d8c9f17a4332fc388f7e5c3f58f6eApprove158065702022-10-22 22:16:2339 days 18 hrs ago0x65e2e5b72beb0685aed44f06664a18850422344b IN  PowerIndex: YETI Token0 Ether0.00040499 15.25593942
0x45223f5b3687b8e45d2680bd502cd756c87716ebea1874b6bc21cb81dec0d594Approve158065682022-10-22 22:15:5939 days 18 hrs ago0x65e2e5b72beb0685aed44f06664a18850422344b IN  PowerIndex: YETI Token0 Ether0.0006539 14.07858975
0xc0c89267c1db75a352ed2012fb5423f656be178b6ecd088767a8dc185ff52d9eApprove157783242022-10-18 23:37:3543 days 17 hrs ago0x2856ce7e218326fb8e098e8747d23331ac01a7b0 IN  PowerIndex: YETI Token0 Ether0.00083676 18.01552824
0x510e654f939ab6ca15d9ae40b9581f627afd5598a3425177d927557e543bbeffApprove157752352022-10-18 13:17:3544 days 3 hrs ago0x20c7593bcf04bdcf0376b49cc6f99c67b71f9d27 IN  PowerIndex: YETI Token0 Ether0.00036685 15.18242101
0x4289d1ee0c650dcb352a6d147390885659f99c9ea62f7f663f23e6ad27778736Transfer157420332022-10-13 22:00:4748 days 18 hrs ago0x42138f6de48cb12e03edc632434b462f2aea7241 IN  PowerIndex: YETI Token0 Ether0.00064751 20.79618618
0x199f1f566b96d1dc14f0de52cf4b483ff9c1e74a9abaff789122d179f97ff499Approve157395242022-10-13 13:34:1149 days 3 hrs ago0xd3026810dc30a641a19e1a7af27bfb5d59f184df IN  PowerIndex: YETI Token0 Ether0.00090176 19.41485862
0xdfa87eac35a9f79d8ee48e898918dd4dc88bb1f4156947ce1af6fa7b17544d33Approve157243722022-10-11 10:48:2351 days 5 hrs ago0x882e11f884e9d221706db9a36ba4856292b26d87 IN  PowerIndex: YETI Token0 Ether0.00098965 21.30714727
0x99f799b665c26dc133ff59e139d09421d61f5319be9d4c7d5ad2983e61d397ffApprove157015652022-10-08 6:25:4754 days 10 hrs ago0x329b0f4597b15cd81d6f62dcf2ad6b3fe1d74d87 IN  PowerIndex: YETI Token0 Ether0.00038839 8.36215155
0x3ee7450fc8248b05128d7bbb80ec1df84b42e39977b6bd62f2d3e516d2ae0763Transfer156869072022-10-06 5:14:2356 days 11 hrs ago0xc80445c3e4b05518a504e821f9ff930e74f988b4 IN  PowerIndex: YETI Token0 Ether0.000093333
0x7f41e996e8aaf133d62374b2faa6dfd029a58f071b414333f3ff57eef8accc96Approve156719522022-10-04 2:59:1158 days 13 hrs ago0x1081d3833eaf0e68a2cd0d18ff69d8d1da72b50a IN  PowerIndex: YETI Token0 Ether0.00051565 11.10201785
0xc9ae78df8c199c85d2c2547db25a37609a109155e595ff36eca6457e3f8859ebApprove156575372022-10-02 2:41:3560 days 13 hrs ago0xd2aa9428257667576d42fd6641d4a492b79009c0 IN  PowerIndex: YETI Token0 Ether0.00015301 6.332789
0x5cac9f92ae78dd2ccaadff19d64695af53d84793dcfb87c7ca8bd7509074c418Approve156434972022-09-30 3:34:3562 days 13 hrs ago0xef8a47c8da817fb5a9be047e2d2e30e964af4341 IN  PowerIndex: YETI Token0 Ether0.00106653 22.96244581
0x9ae00453fab8f34ab4e0b2af5a34fea9bf3a3e5811b9a69db1173fd813663306Approve156120142022-09-25 17:54:5966 days 22 hrs agoENS Name mintapes.eth IN  PowerIndex: YETI Token0 Ether0.00041535 8.94246711
0x6c5a541a031cc1509fb1dc9d80695883da6ebed744fade9315d47c1a455c99bdApprove155579172022-09-18 4:00:4774 days 12 hrs ago0x2019eee50316018c3d4bc555c2a89ed89b45d8ce IN  PowerIndex: YETI Token0 Ether0.00034006 7.32147429
0xbeed7e626ba8495c815604a1ebfd25f7075fd0714578af4f37695c3b52d6668eTransfer155397032022-09-15 14:30:5977 days 2 hrs ago0x284ef411b9bd8cc3043b436e0601b67661cfe4ea IN  PowerIndex: YETI Token0 Ether0.0009977 20.69924519
0x32842de33ea6c02c67b6c190713fd4de1949052091426f1a22dc94af0af08898Approve155386332022-09-15 10:54:1177 days 5 hrs agoENS Name bcshed.eth IN  PowerIndex: YETI Token0 Ether0.0002367 9.79631451
0x23787b5e1dc29c1d9b65d5c0d651f7bd00d767077bb2b2425645a442d895b2bcTransfer155094072022-09-10 14:59:2582 days 1 hr ago0xe98fdd45e18ab387d074342f4113b81eab2be599 IN  PowerIndex: YETI Token0 Ether0.00055393 11.48664215
0xfe4285fc946086567aa07fd9d7ad27fafc0ff7b3489a07764fdc1fbfad008fb9Approve154622992022-09-03 0:32:3889 days 16 hrs ago0x8d1f11398bc7e19d94cc5efebb5447b138745aa0 IN  PowerIndex: YETI Token0 Ether0.00020752 8.58849221
0xa8794d8947e99794f89fbe074733df78d6aa1d3166916adf050822ac9bc052c4Approve154330692022-08-29 8:26:5394 days 8 hrs ago0x6177523dc30ebd43566d0a791ef8a2e611e6f29e IN  PowerIndex: YETI Token0 Ether0.00027477 5.9158456
[ Download CSV Export 

OVERVIEW

YETI index is an index on the market focused on tokens with majority of projects presented in the index were recently merged with Yearn Finance, namely: YFI, SUSHI, CREAM, AKRO, COVER, K3PR, CVP, PICKLE.

Latest 1 internal transaction
Parent Txn Hash Block From To Value
0x25e101b30462cfa57a65538607835fd73d1f5bfbe117fd6820176ba1d149310b114199832020-12-09 17:16:25721 days 23 hrs ago PowerIndex: Deployer  Contract Creation0 Ether
[ Download CSV Export 
Loading

Similar Match Source Code
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0x26607aC599266b21d13c7aCF7942c7701a8b699c

Contract Name:
PowerIndexPool

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 2 runs

Other Settings:
default evmVersion
File 1 of 11 : BConst.sol
// SPDX-License-Identifier: GPL-3.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.6.12;

contract BConst {
    uint public constant BONE              = 10**18;

    uint public constant MIN_BOUND_TOKENS  = 2;
    uint public constant MAX_BOUND_TOKENS  = 9;

    uint public constant MIN_FEE           = BONE / 10**6;
    uint public constant MAX_FEE           = BONE / 10;

    uint public constant MIN_WEIGHT        = 1000000000;
    uint public constant MAX_WEIGHT        = BONE * 50;
    uint public constant MAX_TOTAL_WEIGHT  = BONE * 50;
    uint public constant MIN_BALANCE       = BONE / 10**12;

    uint public constant INIT_POOL_SUPPLY  = BONE * 100;

    uint public constant MIN_BPOW_BASE     = 1 wei;
    uint public constant MAX_BPOW_BASE     = (2 * BONE) - 1 wei;
    uint public constant BPOW_PRECISION    = BONE / 10**10;

    uint public constant MAX_IN_RATIO      = BONE / 2;
    uint public constant MAX_OUT_RATIO     = (BONE / 3) + 1 wei;
}

File 2 of 11 : BNum.sol
// SPDX-License-Identifier: GPL-3.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.6.12;

import "./BConst.sol";

contract BNum is BConst {

    function btoi(uint a)
        internal pure
        returns (uint)
    {
        return a / BONE;
    }

    function bfloor(uint a)
        internal pure
        returns (uint)
    {
        return btoi(a) * BONE;
    }

    function badd(uint a, uint b)
        internal pure
        returns (uint)
    {
        uint c = a + b;
        require(c >= a, "ERR_ADD_OVERFLOW");
        return c;
    }

    function bsub(uint a, uint b)
        internal pure
        returns (uint)
    {
        (uint c, bool flag) = bsubSign(a, b);
        require(!flag, "ERR_SUB_UNDERFLOW");
        return c;
    }

    function bsubSign(uint a, uint b)
        internal pure
        returns (uint, bool)
    {
        if (a >= b) {
            return (a - b, false);
        } else {
            return (b - a, true);
        }
    }

    function bmul(uint a, uint b)
        internal pure
        returns (uint)
    {
        uint c0 = a * b;
        require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW");
        uint c1 = c0 + (BONE / 2);
        require(c1 >= c0, "ERR_MUL_OVERFLOW");
        uint c2 = c1 / BONE;
        return c2;
    }

    function bdiv(uint a, uint b)
        internal pure
        returns (uint)
    {
        require(b != 0, "ERR_DIV_ZERO");
        uint c0 = a * BONE;
        require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow
        uint c1 = c0 + (b / 2);
        require(c1 >= c0, "ERR_DIV_INTERNAL"); //  badd require
        uint c2 = c1 / b;
        return c2;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
      require(b > 0, "ERR_DIV_ZERO");
      return a / b;
    }

    // DSMath.wpow
    function bpowi(uint a, uint n)
        internal pure
        returns (uint)
    {
        uint z = n % 2 != 0 ? a : BONE;

        for (n /= 2; n != 0; n /= 2) {
            a = bmul(a, a);

            if (n % 2 != 0) {
                z = bmul(z, a);
            }
        }
        return z;
    }

    // Compute b^(e.w) by splitting it into (b^e)*(b^0.w).
    // Use `bpowi` for `b^e` and `bpowK` for k iterations
    // of approximation of b^0.w
    function bpow(uint base, uint exp)
        internal pure
        returns (uint)
    {
        require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW");
        require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH");

        uint whole  = bfloor(exp);
        uint remain = bsub(exp, whole);

        uint wholePow = bpowi(base, btoi(whole));

        if (remain == 0) {
            return wholePow;
        }

        uint partialResult = bpowApprox(base, remain, BPOW_PRECISION);
        return bmul(wholePow, partialResult);
    }

    function bpowApprox(uint base, uint exp, uint precision)
        internal pure
        returns (uint)
    {
        // term 0:
        uint a     = exp;
        (uint x, bool xneg)  = bsubSign(base, BONE);
        uint term = BONE;
        uint sum   = term;
        bool negative = false;


        // term(k) = numer / denom
        //         = (product(a - i - 1, i=1-->k) * x^k) / (k!)
        // each iteration, multiply previous term by (a-(k-1)) * x / k
        // continue until term is less than precision
        for (uint i = 1; term >= precision; i++) {
            uint bigK = i * BONE;
            (uint c, bool cneg) = bsubSign(a, bsub(bigK, BONE));
            term = bmul(term, bmul(c, x));
            term = bdiv(term, bigK);
            if (term == 0) break;

            if (xneg) negative = !negative;
            if (cneg) negative = !negative;
            if (negative) {
                sum = bsub(sum, term);
            } else {
                sum = badd(sum, term);
            }
        }

        return sum;
    }

}

File 3 of 11 : BToken.sol
// SPDX-License-Identifier: GPL-3.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.6.12;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./BNum.sol";

contract BTokenBase is BNum {

    mapping(address => uint)                   internal _balance;
    mapping(address => mapping(address=>uint)) internal _allowance;
    uint internal _totalSupply;

    event Approval(address indexed src, address indexed dst, uint amt);
    event Transfer(address indexed src, address indexed dst, uint amt);

    function _mint(uint amt) internal {
        _balance[address(this)] = badd(_balance[address(this)], amt);
        _totalSupply = badd(_totalSupply, amt);
        emit Transfer(address(0), address(this), amt);
    }

    function _burn(uint amt) internal {
        require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL");
        _balance[address(this)] = bsub(_balance[address(this)], amt);
        _totalSupply = bsub(_totalSupply, amt);
        emit Transfer(address(this), address(0), amt);
    }

    function _move(address src, address dst, uint amt) internal {
        require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL");
        _validateAddress(src);
        _validateAddress(dst);
        _balance[src] = bsub(_balance[src], amt);
        _balance[dst] = badd(_balance[dst], amt);
        emit Transfer(src, dst, amt);
    }

    function _push(address to, uint amt) internal {
        _move(address(this), to, amt);
    }

    function _pull(address from, uint amt) internal {
        _move(from, address(this), amt);
    }

    function _validateAddress(address addr) internal {
        require(addr != address(0), "ERR_NULL_ADDRESS");
    }
}

contract BToken is BTokenBase, IERC20 {

    string  internal _name;
    string  internal _symbol;
    uint8   private _decimals = 18;

    function name() public view returns (string memory) {
        return _name;
    }

    function symbol() public view returns (string memory) {
        return _symbol;
    }

    function decimals() public view returns(uint8) {
        return _decimals;
    }

    function allowance(address src, address dst) external override view returns (uint) {
        return _allowance[src][dst];
    }

    function balanceOf(address whom) external override view returns (uint) {
        return _balance[whom];
    }

    function totalSupply() public override view returns (uint) {
        return _totalSupply;
    }

    function approve(address dst, uint amt) external override returns (bool) {
        _validateAddress(dst);
        _allowance[msg.sender][dst] = amt;
        emit Approval(msg.sender, dst, amt);
        return true;
    }

    function increaseApproval(address dst, uint amt) external returns (bool) {
        _validateAddress(dst);
        _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt);
        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
        return true;
    }

    function decreaseApproval(address dst, uint amt) external returns (bool) {
        _validateAddress(dst);
        uint oldValue = _allowance[msg.sender][dst];
        if (amt > oldValue) {
            _allowance[msg.sender][dst] = 0;
        } else {
            _allowance[msg.sender][dst] = bsub(oldValue, amt);
        }
        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
        return true;
    }

    function transfer(address dst, uint amt) external override returns (bool) {
        _move(msg.sender, dst, amt);
        return true;
    }

    function transferFrom(address src, address dst, uint amt) external override returns (bool) {
        require(msg.sender == src || amt <= _allowance[src][msg.sender], "ERR_BTOKEN_BAD_CALLER");
        _move(src, dst, amt);
        if (msg.sender != src && _allowance[src][msg.sender] != uint256(-1)) {
            _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt);
            emit Approval(src, msg.sender, _allowance[src][msg.sender]);
        }
        return true;
    }
}

File 4 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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 `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 5 of 11 : BPoolInterface.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./BMathInterface.sol";

interface BPoolInterface is IERC20, BMathInterface {
  function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn) external;

  function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) external;

  function swapExactAmountIn(
    address,
    uint256,
    address,
    uint256,
    uint256
  ) external returns (uint256, uint256);

  function swapExactAmountOut(
    address,
    uint256,
    address,
    uint256,
    uint256
  ) external returns (uint256, uint256);

  function joinswapExternAmountIn(
    address,
    uint256,
    uint256
  ) external returns (uint256);

  function joinswapPoolAmountOut(
    address,
    uint256,
    uint256
  ) external returns (uint256);

  function exitswapPoolAmountIn(
    address,
    uint256,
    uint256
  ) external returns (uint256);

  function exitswapExternAmountOut(
    address,
    uint256,
    uint256
  ) external returns (uint256);

  function getDenormalizedWeight(address) external view returns (uint256);

  function getBalance(address) external view returns (uint256);

  function getSwapFee() external view returns (uint256);

  function getTotalDenormalizedWeight() external view returns (uint256);

  function getCommunityFee()
    external
    view
    returns (
      uint256,
      uint256,
      uint256,
      address
    );

  function calcAmountWithCommunityFee(
    uint256,
    uint256,
    address
  ) external view returns (uint256, uint256);

  function getRestrictions() external view returns (address);

  function isPublicSwap() external view returns (bool);

  function isFinalized() external view returns (bool);

  function isBound(address t) external view returns (bool);

  function getCurrentTokens() external view returns (address[] memory tokens);

  function getFinalTokens() external view returns (address[] memory tokens);

  function setSwapFee(uint256) external;

  function setCommunityFeeAndReceiver(
    uint256,
    uint256,
    uint256,
    address
  ) external;

  function setController(address) external;

  function setPublicSwap(bool) external;

  function finalize() external;

  function bind(
    address,
    uint256,
    uint256
  ) external;

  function rebind(
    address,
    uint256,
    uint256
  ) external;

  function unbind(address) external;

  function callVoting(
    address voting,
    bytes4 signature,
    bytes calldata args,
    uint256 value
  ) external;

  function getMinWeight() external view returns (uint256);

  function getMaxBoundTokens() external view returns (uint256);
}

File 6 of 11 : BMathInterface.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

interface BMathInterface {
  function calcInGivenOut(
    uint256 tokenBalanceIn,
    uint256 tokenWeightIn,
    uint256 tokenBalanceOut,
    uint256 tokenWeightOut,
    uint256 tokenAmountOut,
    uint256 swapFee
  ) external pure returns (uint256 tokenAmountIn);
}

File 7 of 11 : PowerIndexPoolInterface.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

import "./BPoolInterface.sol";

interface PowerIndexPoolInterface is BPoolInterface {
  function bind(
    address,
    uint256,
    uint256,
    uint256,
    uint256
  ) external;

  function setDynamicWeight(
    address token,
    uint256 targetDenorm,
    uint256 fromTimestamp,
    uint256 targetTimestamp
  ) external;

  function getDynamicWeightSettings(address token)
    external
    view
    returns (
      uint256 fromTimestamp,
      uint256 targetTimestamp,
      uint256 fromDenorm,
      uint256 targetDenorm
    );

  function getMinWeight() external view override returns (uint256);
}

File 8 of 11 : PowerIndexPool.sol
/*
https://powerpool.finance/

          wrrrw r wrr
         ppwr rrr wppr0       prwwwrp                                 prwwwrp                   wr0
        rr 0rrrwrrprpwp0      pp   pr  prrrr0 pp   0r  prrrr0  0rwrrr pp   pr  prrrr0  prrrr0    r0
        rrp pr   wr00rrp      prwww0  pp   wr pp w00r prwwwpr  0rw    prwww0  pp   wr pp   wr    r0
        r0rprprwrrrp pr0      pp      wr   pr pp rwwr wr       0r     pp      wr   pr wr   pr    r0
         prwr wrr0wpwr        00        www0   0w0ww    www0   0w     00        www0    www0   0www0
          wrr ww0rrrr

*/

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.6.12;

import "./balancer-core/BPool.sol";
import "./interfaces/PowerIndexPoolInterface.sol";

contract PowerIndexPool is BPool {
  /// @notice The event emitted when a dynamic weight set to token
  event SetDynamicWeight(
    address indexed token,
    uint256 fromDenorm,
    uint256 targetDenorm,
    uint256 fromTimestamp,
    uint256 targetTimestamp
  );

  /// @notice The event emitted when weight per second bounds set
  event SetWeightPerSecondBounds(uint256 minWeightPerSecond, uint256 maxWeightPerSecond);

  struct DynamicWeight {
    uint256 fromTimestamp;
    uint256 targetTimestamp;
    uint256 targetDenorm;
  }

  /// @dev Mapping for storing dynamic weights settings. fromDenorm stored in _records mapping as denorm variable
  mapping(address => DynamicWeight) private _dynamicWeights;

  /// @dev Min weight per second limit
  uint256 private _minWeightPerSecond;
  /// @dev Max weight per second limit
  uint256 private _maxWeightPerSecond;

  constructor(
    string memory name,
    string memory symbol,
    uint256 minWeightPerSecond,
    uint256 maxWeightPerSecond
  ) public BPool(name, symbol) {
    _minWeightPerSecond = minWeightPerSecond;
    _maxWeightPerSecond = maxWeightPerSecond;
  }

  /*** Controller Interface ***/

  /**
   * @notice Set weight per second bounds by controller
   * @param minWeightPerSecond Min weight per second
   * @param maxWeightPerSecond Max weight per second
   */
  function setWeightPerSecondBounds(uint256 minWeightPerSecond, uint256 maxWeightPerSecond) public _logs_ _lock_ {
    _onlyController();
    _minWeightPerSecond = minWeightPerSecond;
    _maxWeightPerSecond = maxWeightPerSecond;

    emit SetWeightPerSecondBounds(minWeightPerSecond, maxWeightPerSecond);
  }

  /**
   * @notice Set dynamic weight for token by controller
   * @param token Token for change settings
   * @param targetDenorm Target weight. fromDenorm will be fetch by current value of _getDenormWeight
   * @param fromTimestamp From timestamp of dynamic weight
   * @param targetTimestamp Target timestamp of dynamic weight
   */
  function setDynamicWeight(
    address token,
    uint256 targetDenorm,
    uint256 fromTimestamp,
    uint256 targetTimestamp
  ) public _logs_ _lock_ {
    _onlyController();
    _requireTokenIsBound(token);

    require(fromTimestamp > block.timestamp, "CANT_SET_PAST_TIMESTAMP");
    require(targetTimestamp > fromTimestamp, "TIMESTAMP_INCORRECT_DELTA");
    require(targetDenorm >= MIN_WEIGHT && targetDenorm <= MAX_WEIGHT, "TARGET_WEIGHT_BOUNDS");

    uint256 fromDenorm = _getDenormWeight(token);
    uint256 weightPerSecond = _getWeightPerSecond(fromDenorm, targetDenorm, fromTimestamp, targetTimestamp);
    require(weightPerSecond <= _maxWeightPerSecond, "MAX_WEIGHT_PER_SECOND");
    require(weightPerSecond >= _minWeightPerSecond, "MIN_WEIGHT_PER_SECOND");

    _records[token].denorm = fromDenorm;

    _dynamicWeights[token] = DynamicWeight({
      fromTimestamp: fromTimestamp,
      targetTimestamp: targetTimestamp,
      targetDenorm: targetDenorm
    });

    uint256 denormSum = 0;
    uint256 len = _tokens.length;
    for (uint256 i = 0; i < len; i++) {
      denormSum = badd(denormSum, _dynamicWeights[_tokens[i]].targetDenorm);
    }

    require(denormSum <= MAX_TOTAL_WEIGHT, "MAX_TARGET_TOTAL_WEIGHT");

    emit SetDynamicWeight(token, fromDenorm, targetDenorm, fromTimestamp, targetTimestamp);
  }

  /**
   * @notice Bind and setDynamicWeight at the same time
   * @param token Token for bind
   * @param balance Initial balance
   * @param targetDenorm Target weight
   * @param fromTimestamp From timestamp of dynamic weight
   * @param targetTimestamp Target timestamp of dynamic weight
   */
  function bind(
    address token,
    uint256 balance,
    uint256 targetDenorm,
    uint256 fromTimestamp,
    uint256 targetTimestamp
  )
    external
    _logs_ // _lock_  Bind does not lock because it jumps to `rebind` and `setDynamicWeight`, which does
  {
    super.bind(token, balance, MIN_WEIGHT);

    setDynamicWeight(token, targetDenorm, fromTimestamp, targetTimestamp);
  }

  /**
   * @notice Override parent unbind function
   * @param token Token for unbind
   */
  function unbind(address token) public override {
    super.unbind(token);

    _dynamicWeights[token] = DynamicWeight(0, 0, 0);
  }

  /**
   * @notice Override parent bind function and disable.
   */
  function bind(
    address,
    uint256,
    uint256
  ) public override {
    revert("DISABLED"); // Only new bind function is allowed
  }

  /**
   * @notice Override parent rebind function. Allowed only for calling from bind function
   * @param token Token for rebind
   * @param balance Balance for rebind
   * @param denorm Weight for rebind
   */
  function rebind(
    address token,
    uint256 balance,
    uint256 denorm
  ) public override {
    require(denorm == MIN_WEIGHT && _dynamicWeights[token].fromTimestamp == 0, "ONLY_NEW_TOKENS_ALLOWED");
    super.rebind(token, balance, denorm);
  }

  /*** View Functions ***/

  function getDynamicWeightSettings(address token)
    external
    view
    returns (
      uint256 fromTimestamp,
      uint256 targetTimestamp,
      uint256 fromDenorm,
      uint256 targetDenorm
    )
  {
    DynamicWeight storage dw = _dynamicWeights[token];
    return (dw.fromTimestamp, dw.targetTimestamp, _records[token].denorm, dw.targetDenorm);
  }

  function getWeightPerSecondBounds() external view returns (uint256 minWeightPerSecond, uint256 maxWeightPerSecond) {
    return (_minWeightPerSecond, _maxWeightPerSecond);
  }

  /*** Internal Functions ***/

  function _getDenormWeight(address token) internal view override returns (uint256) {
    DynamicWeight memory dw = _dynamicWeights[token];
    uint256 fromDenorm = _records[token].denorm;

    if (dw.fromTimestamp == 0 || dw.targetDenorm == fromDenorm || block.timestamp <= dw.fromTimestamp) {
      return fromDenorm;
    }
    if (block.timestamp >= dw.targetTimestamp) {
      return dw.targetDenorm;
    }

    uint256 weightPerSecond = _getWeightPerSecond(fromDenorm, dw.targetDenorm, dw.fromTimestamp, dw.targetTimestamp);
    uint256 deltaCurrentTime = bsub(block.timestamp, dw.fromTimestamp);
    if (dw.targetDenorm > fromDenorm) {
      return badd(fromDenorm, deltaCurrentTime * weightPerSecond);
    } else {
      return bsub(fromDenorm, deltaCurrentTime * weightPerSecond);
    }
  }

  function _getWeightPerSecond(
    uint256 fromDenorm,
    uint256 targetDenorm,
    uint256 fromTimestamp,
    uint256 targetTimestamp
  ) internal pure returns (uint256) {
    uint256 delta = targetDenorm > fromDenorm ? bsub(targetDenorm, fromDenorm) : bsub(fromDenorm, targetDenorm);
    return div(delta, bsub(targetTimestamp, fromTimestamp));
  }

  function _getTotalWeight() internal view override returns (uint256) {
    uint256 sum = 0;
    uint256 len = _tokens.length;
    for (uint256 i = 0; i < len; i++) {
      sum = badd(sum, _getDenormWeight(_tokens[i]));
    }
    return sum;
  }

  function _addTotalWeight(uint256 _amount) internal virtual override {
    // storage total weight don't change, it's calculated only by _getTotalWeight()
  }

  function _subTotalWeight(uint256 _amount) internal virtual override {
    // storage total weight don't change, it's calculated only by _getTotalWeight()
  }
}

File 9 of 11 : BPool.sol
// SPDX-License-Identifier: GPL-3.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.6.12;

import "./BToken.sol";
import "./BMath.sol";
import "../interfaces/IPoolRestrictions.sol";
import "../interfaces/BPoolInterface.sol";

contract BPool is BToken, BMath, BPoolInterface {

    struct Record {
        bool bound;   // is token bound to pool
        uint index;   // private
        uint denorm;  // denormalized weight
        uint balance;
    }

    event LOG_SWAP(
        address indexed caller,
        address indexed tokenIn,
        address indexed tokenOut,
        uint256         tokenAmountIn,
        uint256         tokenAmountOut
    );

    event LOG_JOIN(
        address indexed caller,
        address indexed tokenIn,
        uint256         tokenAmountIn
    );

    event LOG_EXIT(
        address indexed caller,
        address indexed tokenOut,
        uint256         tokenAmountOut
    );

    event LOG_CALL(
        bytes4  indexed sig,
        address indexed caller,
        bytes           data
    ) anonymous;

    event LOG_CALL_VOTING(
        address indexed voting,
        bool    indexed success,
        bytes4  indexed inputSig,
        bytes           inputData,
        bytes           outputData
    );

    event LOG_COMMUNITY_FEE(
        address indexed caller,
        address indexed receiver,
        address indexed token,
        uint256         tokenAmount
    );

    modifier _logs_() {
        emit LOG_CALL(msg.sig, msg.sender, msg.data);
        _;
    }

    modifier _lock_() {
        _preventReentrancy();
        _mutex = true;
        _;
        _mutex = false;
    }

    modifier _viewlock_() {
        _preventReentrancy();
        _;
    }

    bool private _mutex;

    address private _controller; // has CONTROL role
    bool private _publicSwap; // true if PUBLIC can call SWAP functions

    address private _wrapper; // can join, exit and swaps when _wrapperMode is true
    bool private _wrapperMode;

    IPoolRestrictions private _restrictions;

    // `setSwapFee` and `finalize` require CONTROL
    // `finalize` sets `PUBLIC can SWAP`, `PUBLIC can JOIN`
    uint private _swapFee;
    uint private _communitySwapFee;
    uint private _communityJoinFee;
    uint private _communityExitFee;
    address private _communityFeeReceiver;
    bool private _finalized;

    address[] internal _tokens;
    mapping(address => Record) internal _records;
    uint internal _totalWeight;

    mapping(address => uint256) internal _lastSwapBlock;

    constructor(string memory name, string memory symbol) public {
        _name = name;
        _symbol = symbol;
        _controller = msg.sender;
        _swapFee = MIN_FEE;
        _communitySwapFee = 0;
        _communityJoinFee = 0;
        _communityExitFee = 0;
        _publicSwap = false;
        _finalized = false;
    }

    function isPublicSwap()
        external view override
        returns (bool)
    {
        return _publicSwap;
    }

    function isFinalized()
        external view override
        returns (bool)
    {
        return _finalized;
    }

    function isBound(address t)
        external view override
        returns (bool)
    {
        return _records[t].bound;
    }

    function getNumTokens()
        external view
        returns (uint)
    {
        return _tokens.length;
    }

    function getCurrentTokens()
        external view override
        _viewlock_
        returns (address[] memory tokens)
    {
        return _tokens;
    }

    function getFinalTokens()
        external view override
        _viewlock_
        returns (address[] memory tokens)
    {
        _requireContractIsFinalized();
        return _tokens;
    }

    function getDenormalizedWeight(address token)
        external view override
        _viewlock_
        returns (uint)
    {

        _requireTokenIsBound(token);
        return _getDenormWeight(token);
    }

    function getTotalDenormalizedWeight()
        external view override
        _viewlock_
        returns (uint)
    {
        return _getTotalWeight();
    }

    function getNormalizedWeight(address token)
        external view
        _viewlock_
        returns (uint)
    {

        _requireTokenIsBound(token);
        return bdiv(_getDenormWeight(token), _getTotalWeight());
    }

    function getBalance(address token)
        external view override
        _viewlock_
        returns (uint)
    {

        _requireTokenIsBound(token);
        return _records[token].balance;
    }

    function getSwapFee()
        external view override
        _viewlock_
        returns (uint)
    {
        return _swapFee;
    }

    function getCommunityFee()
        external view override
        _viewlock_
        returns (uint communitySwapFee, uint communityJoinFee, uint communityExitFee, address communityFeeReceiver)
    {
        return (_communitySwapFee, _communityJoinFee, _communityExitFee, _communityFeeReceiver);
    }

    function getController()
        external view
        _viewlock_
        returns (address)
    {
        return _controller;
    }

    function getWrapper()
        external view
        _viewlock_
        returns (address)
    {
        return _wrapper;
    }

    function getWrapperMode()
        external view
        _viewlock_
        returns (bool)
    {
        return _wrapperMode;
    }

    function getRestrictions()
        external view override
        _viewlock_
        returns (address)
    {
        return address(_restrictions);
    }

    function setSwapFee(uint swapFee)
        external override
        _logs_
        _lock_
    {
        _onlyController();
        _requireFeeInBounds(swapFee);
        _swapFee = swapFee;
    }

    function setCommunityFeeAndReceiver(
        uint communitySwapFee,
        uint communityJoinFee,
        uint communityExitFee,
        address communityFeeReceiver
    )
        external override
        _logs_
        _lock_
    {
        _onlyController();
        _requireFeeInBounds(communitySwapFee);
        _requireFeeInBounds(communityJoinFee);
        _requireFeeInBounds(communityExitFee);
        _communitySwapFee = communitySwapFee;
        _communityJoinFee = communityJoinFee;
        _communityExitFee = communityExitFee;
        _communityFeeReceiver = communityFeeReceiver;
    }

    function setRestrictions(IPoolRestrictions restrictions)
        external
        _logs_
        _lock_
    {
        _onlyController();
        _restrictions = restrictions;
    }

    function setController(address manager)
        external override
        _logs_
        _lock_
    {
        _onlyController();
        _controller = manager;
    }

    function setPublicSwap(bool public_)
        external override
        _logs_
        _lock_
    {
        _requireContractIsNotFinalized();
        _onlyController();
        _publicSwap = public_;
    }

    function setWrapper(address wrapper, bool wrapperMode)
        external
        _logs_
        _lock_
    {
        _onlyController();
        _wrapper = wrapper;
        _wrapperMode = wrapperMode;
    }

    function finalize()
        external override
        _logs_
        _lock_
    {
        _onlyController();
        _requireContractIsNotFinalized();
        require(_tokens.length >= MIN_BOUND_TOKENS, "MIN_TOKENS");

        _finalized = true;
        _publicSwap = true;

        _mintPoolShare(INIT_POOL_SUPPLY);
        _pushPoolShare(msg.sender, INIT_POOL_SUPPLY);
    }

    function callVoting(address voting, bytes4 signature, bytes calldata args, uint256 value)
        external override
        _logs_
        _lock_
    {
        require(_restrictions.isVotingSignatureAllowed(voting, signature), "NOT_ALLOWED_SIG");
        _onlyController();

        (bool success, bytes memory data) = voting.call{ value: value }(abi.encodePacked(signature, args));
        require(success, "NOT_SUCCESS");
        emit LOG_CALL_VOTING(voting, success, signature, args, data);
    }

    function bind(address token, uint balance, uint denorm)
        public override
        virtual
        _logs_
        // _lock_  Bind does not lock because it jumps to `rebind`, which does
    {
        _onlyController();
        require(!_records[token].bound, "IS_BOUND");

        require(_tokens.length < MAX_BOUND_TOKENS, "MAX_TOKENS");

        _records[token] = Record({
            bound: true,
            index: _tokens.length,
            denorm: 0,    // balance and denorm will be validated
            balance: 0   // and set by `rebind`
        });
        _tokens.push(token);
        rebind(token, balance, denorm);
    }

    function rebind(address token, uint balance, uint denorm)
        public override
        virtual
        _logs_
        _lock_
    {
        _onlyController();
        _requireTokenIsBound(token);

        require(denorm >= MIN_WEIGHT && denorm <= MAX_WEIGHT, "WEIGHT_BOUNDS");
        require(balance >= MIN_BALANCE, "MIN_BALANCE");

        // Adjust the denorm and totalWeight
        uint oldWeight = _records[token].denorm;
        if (denorm > oldWeight) {
            _addTotalWeight(bsub(denorm, oldWeight));
        } else if (denorm < oldWeight) {
            _subTotalWeight(bsub(oldWeight, denorm));
        }
        _records[token].denorm = denorm;

        // Adjust the balance record and actual token balance
        uint oldBalance = _records[token].balance;
        _records[token].balance = balance;
        if (balance > oldBalance) {
            _pullUnderlying(token, msg.sender, bsub(balance, oldBalance));
        } else if (balance < oldBalance) {
            uint tokenBalanceWithdrawn = bsub(oldBalance, balance);
            _pushUnderlying(token, msg.sender, tokenBalanceWithdrawn);
        }
    }

    function unbind(address token)
        public override
        virtual
        _logs_
        _lock_
    {
        _onlyController();
        _requireTokenIsBound(token);

        uint tokenBalance = _records[token].balance;

        _subTotalWeight(_records[token].denorm);

        // Swap the token-to-unbind with the last token,
        // then delete the last token
        uint index = _records[token].index;
        uint last = _tokens.length - 1;
        _tokens[index] = _tokens[last];
        _records[_tokens[index]].index = index;
        _tokens.pop();
        _records[token] = Record({
            bound: false,
            index: 0,
            denorm: 0,
            balance: 0
        });

        _pushUnderlying(token, msg.sender, tokenBalance);
    }

    // Absorb any tokens that have been sent to this contract into the pool
    function gulp(address token)
        external
        _logs_
        _lock_
    {
        _requireTokenIsBound(token);
        _records[token].balance = IERC20(token).balanceOf(address(this));
    }

    function getSpotPrice(address tokenIn, address tokenOut)
        external view
        _viewlock_
        returns (uint spotPrice)
    {
        require(_records[tokenIn].bound && _records[tokenOut].bound, "NOT_BOUND");
        Record storage inRecord = _records[tokenIn];
        Record storage outRecord = _records[tokenOut];
        return calcSpotPrice(inRecord.balance, _getDenormWeight(tokenIn), outRecord.balance, _getDenormWeight(tokenOut), _swapFee);
    }

    function getSpotPriceSansFee(address tokenIn, address tokenOut)
        external view
        _viewlock_
        returns (uint spotPrice)
    {
        _requireTokenIsBound(tokenIn);
        _requireTokenIsBound(tokenOut);
        Record storage inRecord = _records[tokenIn];
        Record storage outRecord = _records[tokenOut];
        return calcSpotPrice(inRecord.balance, _getDenormWeight(tokenIn), outRecord.balance, _getDenormWeight(tokenOut), 0);
    }

    function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn)
        external override
        _logs_
        _lock_
    {
        _preventSameTxOrigin();
        _onlyWrapperOrNotWrapperMode();
        _requireContractIsFinalized();

        uint poolTotal = totalSupply();
        uint ratio = bdiv(poolAmountOut, poolTotal);
        _requireMathApprox(ratio);

        for (uint i = 0; i < _tokens.length; i++) {
            address t = _tokens[i];
            uint bal = _records[t].balance;
            uint tokenAmountIn = bmul(ratio, bal);
            _requireMathApprox(tokenAmountIn);
            require(tokenAmountIn <= maxAmountsIn[i], "LIMIT_IN");
            _records[t].balance = badd(_records[t].balance, tokenAmountIn);
            emit LOG_JOIN(msg.sender, t, tokenAmountIn);
            _pullUnderlying(t, msg.sender, tokenAmountIn);
        }

        (uint poolAmountOutAfterFee, uint poolAmountOutFee) = calcAmountWithCommunityFee(
            poolAmountOut,
            _communityJoinFee,
            msg.sender
        );

        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOutAfterFee);
        _pushPoolShare(_communityFeeReceiver, poolAmountOutFee);

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, address(this), poolAmountOutFee);
    }

    function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut)
        external override
        _logs_
        _lock_
    {
        _preventSameTxOrigin();
        _onlyWrapperOrNotWrapperMode();
        _requireContractIsFinalized();

        (uint poolAmountInAfterFee, uint poolAmountInFee) = calcAmountWithCommunityFee(
            poolAmountIn,
            _communityExitFee,
            msg.sender
        );

        uint poolTotal = totalSupply();
        uint ratio = bdiv(poolAmountInAfterFee, poolTotal);
        _requireMathApprox(ratio);

        _pullPoolShare(msg.sender, poolAmountIn);
        _pushPoolShare(_communityFeeReceiver, poolAmountInFee);
        _burnPoolShare(poolAmountInAfterFee);

        for (uint i = 0; i < _tokens.length; i++) {
            address t = _tokens[i];
            uint bal = _records[t].balance;
            uint tokenAmountOut = bmul(ratio, bal);
            _requireMathApprox(tokenAmountOut);
            require(tokenAmountOut >= minAmountsOut[i], "LIMIT_OUT");
            _records[t].balance = bsub(_records[t].balance, tokenAmountOut);
            emit LOG_EXIT(msg.sender, t, tokenAmountOut);
            _pushUnderlying(t, msg.sender, tokenAmountOut);
        }

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, address(this), poolAmountInFee);
    }


    function swapExactAmountIn(
        address tokenIn,
        uint tokenAmountIn,
        address tokenOut,
        uint minAmountOut,
        uint maxPrice
    )
        external override
        _logs_
        _lock_
        returns (uint tokenAmountOut, uint spotPriceAfter)
    {
        _preventSameTxOrigin();
        _onlyWrapperOrNotWrapperMode();
        _requireTokenIsBound(tokenIn);
        _requireTokenIsBound(tokenOut);
        require(_publicSwap, "NOT_PUBLIC");

        Record storage inRecord = _records[address(tokenIn)];
        Record storage outRecord = _records[address(tokenOut)];

        uint spotPriceBefore = calcSpotPrice(
                                    inRecord.balance,
                                    _getDenormWeight(tokenIn),
                                    outRecord.balance,
                                    _getDenormWeight(tokenOut),
                                    _swapFee
                                );
        require(spotPriceBefore <= maxPrice, "LIMIT_PRICE");

        (uint tokenAmountInAfterFee, uint tokenAmountInFee) = calcAmountWithCommunityFee(
                                                                tokenAmountIn,
                                                                _communitySwapFee,
                                                                msg.sender
                                                            );

        require(tokenAmountInAfterFee <= bmul(inRecord.balance, MAX_IN_RATIO), "MAX_IN_RATIO");

        tokenAmountOut = calcOutGivenIn(
                            inRecord.balance,
                            _getDenormWeight(tokenIn),
                            outRecord.balance,
                            _getDenormWeight(tokenOut),
                            tokenAmountInAfterFee,
                            _swapFee
                        );
        require(tokenAmountOut >= minAmountOut, "LIMIT_OUT");

        inRecord.balance = badd(inRecord.balance, tokenAmountInAfterFee);
        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);

        spotPriceAfter = calcSpotPrice(
                                inRecord.balance,
                                _getDenormWeight(tokenIn),
                                outRecord.balance,
                                _getDenormWeight(tokenOut),
                                _swapFee
                            );
        require(
            spotPriceAfter >= spotPriceBefore &&
            spotPriceBefore <= bdiv(tokenAmountInAfterFee, tokenAmountOut),
            "MATH_APPROX"
        );
        require(spotPriceAfter <= maxPrice, "LIMIT_PRICE");

        emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountInAfterFee, tokenAmountOut);

        _pullCommunityFeeUnderlying(tokenIn, msg.sender, tokenAmountInFee);
        _pullUnderlying(tokenIn, msg.sender, tokenAmountInAfterFee);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, tokenIn, tokenAmountInFee);

        return (tokenAmountOut, spotPriceAfter);
    }

    function swapExactAmountOut(
        address tokenIn,
        uint maxAmountIn,
        address tokenOut,
        uint tokenAmountOut,
        uint maxPrice
    )
        external override
        _logs_
        _lock_
        returns (uint tokenAmountIn, uint spotPriceAfter)
    {
        _preventSameTxOrigin();
        _onlyWrapperOrNotWrapperMode();
        _requireTokenIsBound(tokenIn);
        _requireTokenIsBound(tokenOut);
        require(_publicSwap, "NOT_PUBLIC");

        Record storage inRecord = _records[address(tokenIn)];
        Record storage outRecord = _records[address(tokenOut)];

        require(tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO), "OUT_RATIO");

        uint spotPriceBefore = calcSpotPrice(
                                    inRecord.balance,
                                    _getDenormWeight(tokenIn),
                                    outRecord.balance,
                                    _getDenormWeight(tokenOut),
                                    _swapFee
                                );
        require(spotPriceBefore <= maxPrice, "LIMIT_PRICE");

        (uint tokenAmountOutAfterFee, uint tokenAmountOutFee) = calcAmountWithCommunityFee(
            tokenAmountOut,
            _communitySwapFee,
            msg.sender
        );

        tokenAmountIn = calcInGivenOut(
                            inRecord.balance,
                            _getDenormWeight(tokenIn),
                            outRecord.balance,
                            _getDenormWeight(tokenOut),
                            tokenAmountOut,
                            _swapFee
                        );
        require(tokenAmountIn <= maxAmountIn, "LIMIT_IN");

        inRecord.balance = badd(inRecord.balance, tokenAmountIn);
        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);

        spotPriceAfter = calcSpotPrice(
                                inRecord.balance,
                                _getDenormWeight(tokenIn),
                                outRecord.balance,
                                _getDenormWeight(tokenOut),
                                _swapFee
                            );
        require(
            spotPriceAfter >= spotPriceBefore &&
            spotPriceBefore <= bdiv(tokenAmountIn, tokenAmountOutAfterFee),
            "MATH_APPROX"
        );
        require(spotPriceAfter <= maxPrice, "LIMIT_PRICE");

        emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOutAfterFee);

        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOutAfterFee);
        _pushUnderlying(tokenOut, _communityFeeReceiver, tokenAmountOutFee);

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, tokenOut, tokenAmountOutFee);

        return (tokenAmountIn, spotPriceAfter);
    }


    function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut)
        external override
        _logs_
        _lock_
        returns (uint poolAmountOut)

    {
        _preventSameTxOrigin();
        _requireContractIsFinalized();
        _onlyWrapperOrNotWrapperMode();
        _requireTokenIsBound(tokenIn);
        require(tokenAmountIn <= bmul(_records[tokenIn].balance, MAX_IN_RATIO), "MAX_IN_RATIO");

        (uint tokenAmountInAfterFee, uint tokenAmountInFee) = calcAmountWithCommunityFee(
            tokenAmountIn,
            _communityJoinFee,
            msg.sender
        );

        Record storage inRecord = _records[tokenIn];

        poolAmountOut = calcPoolOutGivenSingleIn(
                            inRecord.balance,
                            _getDenormWeight(tokenIn),
                            _totalSupply,
                            _getTotalWeight(),
                            tokenAmountInAfterFee,
                            _swapFee
                        );

        require(poolAmountOut >= minPoolAmountOut, "LIMIT_OUT");

        inRecord.balance = badd(inRecord.balance, tokenAmountInAfterFee);

        emit LOG_JOIN(msg.sender, tokenIn, tokenAmountInAfterFee);

        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOut);
        _pullCommunityFeeUnderlying(tokenIn, msg.sender, tokenAmountInFee);
        _pullUnderlying(tokenIn, msg.sender, tokenAmountInAfterFee);

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, tokenIn, tokenAmountInFee);

        return poolAmountOut;
    }

    function joinswapPoolAmountOut(address tokenIn, uint poolAmountOut, uint maxAmountIn)
        external override
        _logs_
        _lock_
        returns (uint tokenAmountIn)
    {
        _preventSameTxOrigin();
        _requireContractIsFinalized();
        _onlyWrapperOrNotWrapperMode();
        _requireTokenIsBound(tokenIn);

        Record storage inRecord = _records[tokenIn];

        (uint poolAmountOutAfterFee, uint poolAmountOutFee) = calcAmountWithCommunityFee(
            poolAmountOut,
            _communityJoinFee,
            msg.sender
        );

        tokenAmountIn = calcSingleInGivenPoolOut(
                            inRecord.balance,
                            _getDenormWeight(tokenIn),
                            _totalSupply,
                            _getTotalWeight(),
                            poolAmountOut,
                            _swapFee
                        );

        _requireMathApprox(tokenAmountIn);
        require(tokenAmountIn <= maxAmountIn, "LIMIT_IN");

        require(tokenAmountIn <= bmul(_records[tokenIn].balance, MAX_IN_RATIO), "MAX_IN_RATIO");

        inRecord.balance = badd(inRecord.balance, tokenAmountIn);

        emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);

        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOutAfterFee);
        _pushPoolShare(_communityFeeReceiver, poolAmountOutFee);
        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, address(this), poolAmountOutFee);

        return tokenAmountIn;
    }

    function exitswapPoolAmountIn(address tokenOut, uint poolAmountIn, uint minAmountOut)
        external override
        _logs_
        _lock_
        returns (uint tokenAmountOut)
    {
        _preventSameTxOrigin();
        _requireContractIsFinalized();
        _onlyWrapperOrNotWrapperMode();
        _requireTokenIsBound(tokenOut);

        Record storage outRecord = _records[tokenOut];

        tokenAmountOut = calcSingleOutGivenPoolIn(
                            outRecord.balance,
                            _getDenormWeight(tokenOut),
                            _totalSupply,
                            _getTotalWeight(),
                            poolAmountIn,
                            _swapFee
                        );

        require(tokenAmountOut >= minAmountOut, "LIMIT_OUT");

        require(tokenAmountOut <= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), "OUT_RATIO");

        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);

        (uint tokenAmountOutAfterFee, uint tokenAmountOutFee) = calcAmountWithCommunityFee(
            tokenAmountOut,
            _communityExitFee,
            msg.sender
        );

        emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOutAfterFee);

        _pullPoolShare(msg.sender, poolAmountIn);
        _burnPoolShare(poolAmountIn);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOutAfterFee);
        _pushUnderlying(tokenOut, _communityFeeReceiver, tokenAmountOutFee);

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, tokenOut, tokenAmountOutFee);

        return tokenAmountOutAfterFee;
    }

    function exitswapExternAmountOut(address tokenOut, uint tokenAmountOut, uint maxPoolAmountIn)
        external override
        _logs_
        _lock_
        returns (uint poolAmountIn)
    {
        _preventSameTxOrigin();
        _requireContractIsFinalized();
        _onlyWrapperOrNotWrapperMode();
        _requireTokenIsBound(tokenOut);
        require(tokenAmountOut <= bmul(_records[tokenOut].balance, MAX_OUT_RATIO), "OUT_RATIO");

        Record storage outRecord = _records[tokenOut];

        (uint tokenAmountOutAfterFee, uint tokenAmountOutFee) = calcAmountWithCommunityFee(
            tokenAmountOut,
            _communityExitFee,
            msg.sender
        );

        poolAmountIn = calcPoolInGivenSingleOut(
                            outRecord.balance,
                            _getDenormWeight(tokenOut),
                            _totalSupply,
                            _getTotalWeight(),
                            tokenAmountOut,
                            _swapFee
                        );

        _requireMathApprox(poolAmountIn);
        require(poolAmountIn <= maxPoolAmountIn, "LIMIT_IN");

        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);

        emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOutAfterFee);

        _pullPoolShare(msg.sender, poolAmountIn);
        _burnPoolShare(poolAmountIn);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOutAfterFee);
        _pushUnderlying(tokenOut, _communityFeeReceiver, tokenAmountOutFee);

        emit LOG_COMMUNITY_FEE(msg.sender, _communityFeeReceiver, tokenOut, tokenAmountOutFee);

        return poolAmountIn;
    }


    // ==
    // 'Underlying' token-manipulation functions make external calls but are NOT locked
    // You must `_lock_` or otherwise ensure reentry-safety

    function _pullUnderlying(address erc20, address from, uint amount)
        internal
    {
        bool xfer = IERC20(erc20).transferFrom(from, address(this), amount);
        require(xfer, "ERC20_FALSE");
    }

    function _pushUnderlying(address erc20, address to, uint amount)
        internal
    {
        bool xfer = IERC20(erc20).transfer(to, amount);
        require(xfer, "ERC20_FALSE");
    }

    function _pullCommunityFeeUnderlying(address erc20, address from, uint amount)
        internal
    {
        bool xfer = IERC20(erc20).transferFrom(from, _communityFeeReceiver, amount);
        require(xfer, "ERC20_FALSE");
    }

    function _pullPoolShare(address from, uint amount)
        internal
    {
        _pull(from, amount);
    }

    function _pushPoolShare(address to, uint amount)
        internal
    {
        _push(to, amount);
    }

    function _mintPoolShare(uint amount)
        internal
    {
        if(address(_restrictions) != address(0)) {
            uint maxTotalSupply = _restrictions.getMaxTotalSupply(address(this));
            require(badd(_totalSupply, amount) <= maxTotalSupply, "MAX_SUPPLY");
        }
        _mint(amount);
    }

    function _burnPoolShare(uint amount)
        internal
    {
        _burn(amount);
    }

    function _requireTokenIsBound(address token)
        internal view
    {
        require(_records[token].bound, "NOT_BOUND");
    }

    function _onlyController()
        internal view
    {
        require(msg.sender == _controller, "NOT_CONTROLLER");
    }

    function _requireContractIsNotFinalized()
        internal view
    {
        require(!_finalized, "IS_FINALIZED");
    }

    function _requireContractIsFinalized()
        internal view
    {
        require(_finalized, "NOT_FINALIZED");
    }

    function _requireFeeInBounds(uint256 _fee)
        internal pure
    {
        require(_fee >= MIN_FEE && _fee <= MAX_FEE, "FEE_BOUNDS");
    }

    function _requireMathApprox(uint256 _value)
        internal pure
    {
        require(_value != 0, "MATH_APPROX");
    }

    function _preventReentrancy()
        internal view
    {
        require(!_mutex, "REENTRY");
    }

    function _onlyWrapperOrNotWrapperMode()
        internal view
    {
        require(!_wrapperMode || msg.sender == _wrapper, "ONLY_WRAPPER");
    }

    function _preventSameTxOrigin()
      internal
    {
      require(block.number > _lastSwapBlock[tx.origin], "SAME_TX_ORIGIN");
      _lastSwapBlock[tx.origin] = block.number;
    }

    function _getDenormWeight(address token)
        internal view virtual
        returns (uint)
    {
        return _records[token].denorm;
    }

    function _getTotalWeight()
        internal view virtual
        returns (uint)
    {
        return _totalWeight;
    }

    function _addTotalWeight(uint _amount) internal virtual {
        _totalWeight = badd(_totalWeight, _amount);
        require(_totalWeight <= MAX_TOTAL_WEIGHT, "MAX_TOTAL_WEIGHT");
    }

    function _subTotalWeight(uint _amount) internal virtual {
        _totalWeight = bsub(_totalWeight, _amount);
    }

    function calcAmountWithCommunityFee(
        uint tokenAmountIn,
        uint communityFee,
        address operator
    )
        public view override
        returns (uint tokenAmountInAfterFee, uint tokenAmountFee)
    {
        if (address(_restrictions) != address(0) && _restrictions.isWithoutFee(operator)) {
            return (tokenAmountIn, 0);
        }
        uint adjustedIn = bsub(BONE, communityFee);
        tokenAmountInAfterFee = bmul(tokenAmountIn, adjustedIn);
        tokenAmountFee = bsub(tokenAmountIn, tokenAmountInAfterFee);
        return (tokenAmountInAfterFee, tokenAmountFee);
    }

    function getMinWeight()
        external view override
        returns (uint)
    {
        return MIN_WEIGHT;
    }

    function getMaxBoundTokens()
        external view override
        returns (uint)
    {
      return MAX_BOUND_TOKENS;
    }
}

File 10 of 11 : BMath.sol
// SPDX-License-Identifier: GPL-3.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.6.12;

import "./BNum.sol";
import "../interfaces/BMathInterface.sol";

contract BMath is BConst, BNum, BMathInterface {
    /**********************************************************************************************
    // calcSpotPrice                                                                             //
    // sP = spotPrice                                                                            //
    // bI = tokenBalanceIn                ( bI / wI )         1                                  //
    // bO = tokenBalanceOut         sP =  -----------  *  ----------                             //
    // wI = tokenWeightIn                 ( bO / wO )     ( 1 - sF )                             //
    // wO = tokenWeightOut                                                                       //
    // sF = swapFee                                                                              //
    **********************************************************************************************/
    function calcSpotPrice(
        uint tokenBalanceIn,
        uint tokenWeightIn,
        uint tokenBalanceOut,
        uint tokenWeightOut,
        uint swapFee
    )
        public pure
        returns (uint spotPrice)
    {
        uint numer = bdiv(tokenBalanceIn, tokenWeightIn);
        uint denom = bdiv(tokenBalanceOut, tokenWeightOut);
        uint ratio = bdiv(numer, denom);
        uint scale = bdiv(BONE, bsub(BONE, swapFee));
        return  (spotPrice = bmul(ratio, scale));
    }

    /**********************************************************************************************
    // calcOutGivenIn                                                                            //
    // aO = tokenAmountOut                                                                       //
    // bO = tokenBalanceOut                                                                      //
    // bI = tokenBalanceIn              /      /            bI             \    (wI / wO) \      //
    // aI = tokenAmountIn    aO = bO * |  1 - | --------------------------  | ^            |     //
    // wI = tokenWeightIn               \      \ ( bI + ( aI * ( 1 - sF )) /              /      //
    // wO = tokenWeightOut                                                                       //
    // sF = swapFee                                                                              //
    **********************************************************************************************/
    function calcOutGivenIn(
        uint tokenBalanceIn,
        uint tokenWeightIn,
        uint tokenBalanceOut,
        uint tokenWeightOut,
        uint tokenAmountIn,
        uint swapFee
    )
        public pure
        returns (uint tokenAmountOut)
    {
        uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut);
        uint adjustedIn = bsub(BONE, swapFee);
        adjustedIn = bmul(tokenAmountIn, adjustedIn);
        uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn));
        uint foo = bpow(y, weightRatio);
        uint bar = bsub(BONE, foo);
        tokenAmountOut = bmul(tokenBalanceOut, bar);
        return tokenAmountOut;
    }

    /**********************************************************************************************
    // calcInGivenOut                                                                            //
    // aI = tokenAmountIn                                                                        //
    // bO = tokenBalanceOut               /  /     bO      \    (wO / wI)      \                 //
    // bI = tokenBalanceIn          bI * |  | ------------  | ^            - 1  |                //
    // aO = tokenAmountOut    aI =        \  \ ( bO - aO ) /                   /                 //
    // wI = tokenWeightIn           --------------------------------------------                 //
    // wO = tokenWeightOut                          ( 1 - sF )                                   //
    // sF = swapFee                                                                              //
    **********************************************************************************************/
    function calcInGivenOut(
        uint tokenBalanceIn,
        uint tokenWeightIn,
        uint tokenBalanceOut,
        uint tokenWeightOut,
        uint tokenAmountOut,
        uint swapFee
    )
        public pure override
        returns (uint tokenAmountIn)
    {
        uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn);
        uint diff = bsub(tokenBalanceOut, tokenAmountOut);
        uint y = bdiv(tokenBalanceOut, diff);
        uint foo = bpow(y, weightRatio);
        foo = bsub(foo, BONE);
        tokenAmountIn = bsub(BONE, swapFee);
        tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn);
        return tokenAmountIn;
    }

    /**********************************************************************************************
    // calcPoolOutGivenSingleIn                                                                  //
    // pAo = poolAmountOut         /                                              \              //
    // tAi = tokenAmountIn        ///      /     //    wI \      \\       \     wI \             //
    // wI = tokenWeightIn        //| tAi *| 1 - || 1 - --  | * sF || + tBi \    --  \            //
    // tW = totalWeight     pAo=||  \      \     \\    tW /      //         | ^ tW   | * pS - pS //
    // tBi = tokenBalanceIn      \\  ------------------------------------- /        /            //
    // pS = poolSupply            \\                    tBi               /        /             //
    // sF = swapFee                \                                              /              //
    **********************************************************************************************/
    function calcPoolOutGivenSingleIn(
        uint tokenBalanceIn,
        uint tokenWeightIn,
        uint poolSupply,
        uint totalWeight,
        uint tokenAmountIn,
        uint swapFee
    )
        public pure
        returns (uint poolAmountOut)
    {
        // Charge the trading fee for the proportion of tokenAi
        ///  which is implicitly traded to the other pool tokens.
        // That proportion is (1- weightTokenIn)
        // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee);
        uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);
        uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee);
        uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz));

        uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee);
        uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);

        // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;
        uint poolRatio = bpow(tokenInRatio, normalizedWeight);
        uint newPoolSupply = bmul(poolRatio, poolSupply);
        poolAmountOut = bsub(newPoolSupply, poolSupply);
        return poolAmountOut;
    }

    /**********************************************************************************************
    // calcSingleInGivenPoolOut                                                                  //
    // tAi = tokenAmountIn              //(pS + pAo)\     /    1    \\                           //
    // pS = poolSupply                 || ---------  | ^ | --------- || * bI - bI                //
    // pAo = poolAmountOut              \\    pS    /     \(wI / tW)//                           //
    // bI = balanceIn          tAi =  --------------------------------------------               //
    // wI = weightIn                              /      wI  \                                   //
    // tW = totalWeight                          |  1 - ----  |  * sF                            //
    // sF = swapFee                               \      tW  /                                   //
    **********************************************************************************************/
    function calcSingleInGivenPoolOut(
        uint tokenBalanceIn,
        uint tokenWeightIn,
        uint poolSupply,
        uint totalWeight,
        uint poolAmountOut,
        uint swapFee
    )
        public pure
        returns (uint tokenAmountIn)
    {
        uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);
        uint newPoolSupply = badd(poolSupply, poolAmountOut);
        uint poolRatio = bdiv(newPoolSupply, poolSupply);

        //uint newBalTi = poolRatio^(1/weightTi) * balTi;
        uint boo = bdiv(BONE, normalizedWeight);
        uint tokenInRatio = bpow(poolRatio, boo);
        uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn);
        uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn);
        // Do reverse order of fees charged in joinswap_ExternAmountIn, this way
        //     ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ```
        //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ;
        uint zar = bmul(bsub(BONE, normalizedWeight), swapFee);
        tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar));
        return tokenAmountIn;
    }

    /**********************************************************************************************
    // calcSingleOutGivenPoolIn                                                                  //
    // tAo = tokenAmountOut            /      /                                             \\   //
    // bO = tokenBalanceOut           /      //       pS - pAi        \     /    1    \      \\  //
    // pAi = poolAmountIn            | bO - || ----------------------- | ^ | --------- | * b0 || //
    // ps = poolSupply                \      \\          pS           /     \(wO / tW)/      //  //
    // wI = tokenWeightIn      tAo =   \      \                                             //   //
    // tW = totalWeight                    /     /      wO \       \                             //
    // sF = swapFee                    *  | 1 - |  1 - ---- | * sF  |                            //
    // eF = exitFee                        \     \      tW /       /                             //
    **********************************************************************************************/
    function calcSingleOutGivenPoolIn(
        uint tokenBalanceOut,
        uint tokenWeightOut,
        uint poolSupply,
        uint totalWeight,
        uint poolAmountIn,
        uint swapFee
    )
        public pure
        returns (uint tokenAmountOut)
    {
        uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);
        uint newPoolSupply = bsub(poolSupply, poolAmountIn);
        uint poolRatio = bdiv(newPoolSupply, poolSupply);

        // newBalTo = poolRatio^(1/weightTo) * balTo;
        uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight));
        uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut);

        uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut);

        // charge swap fee on the output token side
        //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee)
        uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee);
        tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz));
        return tokenAmountOut;
    }

    /**********************************************************************************************
    // calcPoolInGivenSingleOut                                                                  //
    // pAi = poolAmountIn               // /               tAo             \\     / wO \     \   //
    // bO = tokenBalanceOut            // | bO - -------------------------- |\   | ---- |     \  //
    // tAo = tokenAmountOut      pS - ||   \     1 - ((1 - (tO / tW)) * sF)/  | ^ \ tW /  * pS | //
    // ps = poolSupply                 \\ -----------------------------------/                /  //
    // wO = tokenWeightOut  pAi =       \\               bO                 /                /   //
    // tW = totalWeight                                                                          //
    // sF = swapFee                                                                              //
    **********************************************************************************************/
    function calcPoolInGivenSingleOut(
        uint tokenBalanceOut,
        uint tokenWeightOut,
        uint poolSupply,
        uint totalWeight,
        uint tokenAmountOut,
        uint swapFee
    )
        public pure
        returns (uint poolAmountIn)
    {

        // charge swap fee on the output token side
        uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);
        //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ;
        uint zoo = bsub(BONE, normalizedWeight);
        uint zar = bmul(zoo, swapFee);
        uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar));

        uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee);
        uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut);

        //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply;
        uint poolRatio = bpow(tokenOutRatio, normalizedWeight);
        uint newPoolSupply = bmul(poolRatio, poolSupply);
        uint poolAmountIn = bsub(poolSupply, newPoolSupply);
        return poolAmountIn;
    }
}

File 11 of 11 : IPoolRestrictions.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

interface IPoolRestrictions {
  function getMaxTotalSupply(address _pool) external view returns (uint256);

  function isVotingSignatureAllowed(address _votingAddress, bytes4 _signature) external view returns (bool);

  function isVotingSenderAllowed(address _votingAddress, address _sender) external view returns (bool);

  function isWithoutFee(address _addr) external view returns (bool);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"minWeightPerSecond","type":"uint256"},{"internalType":"uint256","name":"maxWeightPerSecond","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":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"LOG_CALL","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"voting","type":"address"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":true,"internalType":"bytes4","name":"inputSig","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"inputData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"outputData","type":"bytes"}],"name":"LOG_CALL_VOTING","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"LOG_COMMUNITY_FEE","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LOG_EXIT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"name":"LOG_JOIN","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LOG_SWAP","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromDenorm","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetDenorm","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetTimestamp","type":"uint256"}],"name":"SetDynamicWeight","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minWeightPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxWeightPerSecond","type":"uint256"}],"name":"SetWeightPerSecondBounds","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":"BONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BPOW_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INIT_POOL_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BOUND_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BPOW_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_IN_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_OUT_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TOTAL_WEIGHT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_WEIGHT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BALANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BOUND_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BPOW_BASE","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":[],"name":"MIN_WEIGHT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"whom","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"targetDenorm","type":"uint256"},{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"targetTimestamp","type":"uint256"}],"name":"bind","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"bind","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"communityFee","type":"uint256"},{"internalType":"address","name":"operator","type":"address"}],"name":"calcAmountWithCommunityFee","outputs":[{"internalType":"uint256","name":"tokenAmountInAfterFee","type":"uint256"},{"internalType":"uint256","name":"tokenAmountFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenWeightIn","type":"uint256"},{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"tokenWeightOut","type":"uint256"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcInGivenOut","outputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenWeightIn","type":"uint256"},{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"tokenWeightOut","type":"uint256"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcOutGivenIn","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"tokenWeightOut","type":"uint256"},{"internalType":"uint256","name":"poolSupply","type":"uint256"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcPoolInGivenSingleOut","outputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenWeightIn","type":"uint256"},{"internalType":"uint256","name":"poolSupply","type":"uint256"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcPoolOutGivenSingleIn","outputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenWeightIn","type":"uint256"},{"internalType":"uint256","name":"poolSupply","type":"uint256"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcSingleInGivenPoolOut","outputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"tokenWeightOut","type":"uint256"},{"internalType":"uint256","name":"poolSupply","type":"uint256"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcSingleOutGivenPoolIn","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenBalanceIn","type":"uint256"},{"internalType":"uint256","name":"tokenWeightIn","type":"uint256"},{"internalType":"uint256","name":"tokenBalanceOut","type":"uint256"},{"internalType":"uint256","name":"tokenWeightOut","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"calcSpotPrice","outputs":[{"internalType":"uint256","name":"spotPrice","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"voting","type":"address"},{"internalType":"bytes4","name":"signature","type":"bytes4"},{"internalType":"bytes","name":"args","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"callVoting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"decreaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxPoolAmountIn","type":"uint256"}],"name":"exitswapExternAmountOut","outputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"exitswapPoolAmountIn","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCommunityFee","outputs":[{"internalType":"uint256","name":"communitySwapFee","type":"uint256"},{"internalType":"uint256","name":"communityJoinFee","type":"uint256"},{"internalType":"uint256","name":"communityExitFee","type":"uint256"},{"internalType":"address","name":"communityFeeReceiver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getDenormalizedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getDynamicWeightSettings","outputs":[{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"targetTimestamp","type":"uint256"},{"internalType":"uint256","name":"fromDenorm","type":"uint256"},{"internalType":"uint256","name":"targetDenorm","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFinalTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxBoundTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getNormalizedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRestrictions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"name":"getSpotPrice","outputs":[{"internalType":"uint256","name":"spotPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"name":"getSpotPriceSansFee","outputs":[{"internalType":"uint256","name":"spotPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSwapFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDenormalizedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWeightPerSecondBounds","outputs":[{"internalType":"uint256","name":"minWeightPerSecond","type":"uint256"},{"internalType":"uint256","name":"maxWeightPerSecond","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrapperMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"gulp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"increaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"t","type":"address"}],"name":"isBound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFinalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPublicSwap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"minPoolAmountOut","type":"uint256"}],"name":"joinswapExternAmountIn","outputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"}],"name":"joinswapPoolAmountOut","outputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"denorm","type":"uint256"}],"name":"rebind","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"communitySwapFee","type":"uint256"},{"internalType":"uint256","name":"communityJoinFee","type":"uint256"},{"internalType":"uint256","name":"communityExitFee","type":"uint256"},{"internalType":"address","name":"communityFeeReceiver","type":"address"}],"name":"setCommunityFeeAndReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"targetDenorm","type":"uint256"},{"internalType":"uint256","name":"fromTimestamp","type":"uint256"},{"internalType":"uint256","name":"targetTimestamp","type":"uint256"}],"name":"setDynamicWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"public_","type":"bool"}],"name":"setPublicSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPoolRestrictions","name":"restrictions","type":"address"}],"name":"setRestrictions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"setSwapFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minWeightPerSecond","type":"uint256"},{"internalType":"uint256","name":"maxWeightPerSecond","type":"uint256"}],"name":"setWeightPerSecondBounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"bool","name":"wrapperMode","type":"bool"}],"name":"setWrapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"name":"swapExactAmountIn","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"spotPriceAfter","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"name":"swapExactAmountOut","outputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"spotPriceAfter","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"unbind","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040526005805460ff191660121790553480156200001e57600080fd5b5060405162005bf738038062005bf7833981810160405260808110156200004457600080fd5b81019080805160405193929190846401000000008211156200006557600080fd5b9083019060208201858111156200007b57600080fd5b82516401000000008111828201881017156200009657600080fd5b82525081516020918201929091019080838360005b83811015620000c5578181015183820152602001620000ab565b50505050905090810190601f168015620000f35780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200011757600080fd5b9083019060208201858111156200012d57600080fd5b82516401000000008111828201881017156200014857600080fd5b82525081516020918201929091019080838360005b83811015620001775781810151838201526020016200015d565b50505050905090810190601f168015620001a55780820380516001836020036101000a031916815260200191505b50604090815260208281015192909101518651929450925085918591620001d29160039185019062000242565b508051620001e890600490602084019062000242565b50506005805464e8d4a5100060085560006009819055600a819055600b5562010000600160b01b0319163362010000021760ff60b01b1916905550600c805460ff60a01b1916905560129190915560135550620002de9050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200028557805160ff1916838001178555620002b5565b82800160010185558215620002b5579182015b82811115620002b557825182559160200191906001019062000298565b50620002c3929150620002c7565b5090565b5b80821115620002c35760008155600101620002c8565b61590980620002ee6000396000f3fe608060405234801561001057600080fd5b50600436106103855760003560e01c806302c967481461038a57806306fdde03146103ce578063095ea7b31461044b57806309a3bbe41461048b5780630f7b1e3e146104935780631446a7ff146104cd57806315e84af9146104fb57806318160ddd14610529578063189d00ca14610531578063218b5382146105395780632245a08e1461054157806323b872dd1461058c5780632f37b624146105c25780633018205f146105e8578063313ce5671461060c57806334e199071461062a5780633fdddaa21461064757806341e5a5d414610679578063442e2152146106c557806346ab38f11461075257806349b59552146107845780634bb278f3146107a35780634d752ec3146107ab5780634f69c0d4146107e95780635c1bbaf71461085e5780635db342771461089957806366188463146108cb57806367cc71f0146108f75780636d06dfa0146108ff57806370a082311461093157806370eb8e7f1461095757806376c7a3c71461095f5780637c5e9ea4146109675780638201aa3f146109a757806382f652ad146109e75780638656b65314610a22578063867378c514610a5d5780638733ad7114610a655780638929801214610a885780638c28cbe814610ac35780638d4e408314610ae95780638f6b707014610af157806390ad688b14610af957806392eefe9b14610b30578063936c347714610b565780639381cd2b14610b5e578063948d8ce614610b6657806395d89b4114610b8c578063992e2a9214610b945780639a737aa214610b9c578063a221ee4914610ba4578063a9059cbb14610bd9578063b02f0b7314610c05578063b0e0d13614610c7a578063b7b800a414610c82578063ba019dab14610c8a578063ba9530a614610c92578063bc063e1a14610ccd578063bc694ea214610cd5578063be3bbd2e14610cdd578063c36596a614610d35578063c4195cb814610d3d578063c61641cd14610d45578063cc77828d14610d6b578063cd2ed8fb14610d73578063cf5e7bd314610d7b578063cfb2794514610da1578063d4cadf6814610dd9578063d73dd62314610de1578063d80817fb14610e0d578063dd62ed3e14610e15578063e0e5228d14610e43578063e4a28a521461048b578063e4e1e53814610e71578063ec09302114610ea3578063f1b8a9b714610eab578063f8b2cb4f14610ed1578063f8d6aed414610ef7578063fde924f714610f32575b600080fd5b6103bc600480360360608110156103a057600080fd5b506001600160a01b038135169060208101359060400135610f3a565b60408051918252519081900360200190f35b6103d66111aa565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104105781810151838201526020016103f8565b50505050905090810190601f16801561043d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6104776004803603604081101561046157600080fd5b506001600160a01b038135169060200135611240565b604080519115158252519081900360200190f35b6103bc6112a1565b6104cb600480360360808110156104a957600080fd5b50803590602081013590604081013590606001356001600160a01b03166112ae565b005b6103bc600480360360408110156104e357600080fd5b506001600160a01b0381358116916020013516611384565b6103bc6004803603604081101561051157600080fd5b506001600160a01b03813581169160200135166113f1565b6103bc6114c1565b6103bc6114c7565b6103bc6114db565b6105736004803603606081101561055757600080fd5b50803590602081013590604001356001600160a01b03166114e3565b6040805192835260208301919091528051918290030190f35b610477600480360360608110156105a257600080fd5b506001600160a01b038135811691602081013590911690604001356115bf565b610477600480360360208110156105d857600080fd5b50356001600160a01b0316611715565b6105f0611737565b604080516001600160a01b039092168252519081900360200190f35b610614611757565b6040805160ff9092168252519081900360200190f35b6104cb6004803603602081101561064057600080fd5b5035611760565b6104cb6004803603606081101561065d57600080fd5b506001600160a01b0381351690602081013590604001356117f9565b61069f6004803603602081101561068f57600080fd5b50356001600160a01b031661187d565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6104cb600480360360808110156106db57600080fd5b6001600160a01b03823516916001600160e01b031960208201351691810190606081016040820135600160201b81111561071457600080fd5b82018360208201111561072657600080fd5b803590602001918460018302840111600160201b8311171561074757600080fd5b9193509150356118b7565b6103bc6004803603606081101561076857600080fd5b506001600160a01b038135169060208101359060400135611c1f565b6104cb6004803603602081101561079a57600080fd5b50351515611e8d565b6104cb611f38565b6104cb600480360360a08110156107c157600080fd5b506001600160a01b03813516906020810135906040810135906060810135906080013561205d565b6104cb600480360360408110156107ff57600080fd5b81359190810190604081016020820135600160201b81111561082057600080fd5b82018360208201111561083257600080fd5b803590602001918460208302840111600160201b8311171561085357600080fd5b5090925090506120e0565b6103bc600480360360c081101561087457600080fd5b5080359060208101359060408101359060608101359060808101359060a00135612347565b6103bc600480360360608110156108af57600080fd5b506001600160a01b0381351690602081013590604001356123ff565b610477600480360360408110156108e157600080fd5b506001600160a01b03813516906020013561265a565b61047761273d565b6103bc6004803603606081101561091557600080fd5b506001600160a01b038135169060208101359060400135612758565b6103bc6004803603602081101561094757600080fd5b50356001600160a01b03166129c2565b6103bc6129dd565b6103bc6129e5565b610573600480360360a081101561097d57600080fd5b506001600160a01b03813581169160208101359160408201351690606081013590608001356129f7565b610573600480360360a08110156109bd57600080fd5b506001600160a01b0381358116916020810135916040820135169060608101359060800135612ddb565b6103bc600480360360c08110156109fd57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356131c2565b6103bc600480360360c0811015610a3857600080fd5b5080359060208101359060408101359060608101359060808101359060a00135613268565b6103bc613309565b6104cb60048036036040811015610a7b57600080fd5b508035906020013561331d565b6103bc600480360360c0811015610a9e57600080fd5b5080359060208101359060408101359060608101359060808101359060a001356133f1565b6104cb60048036036020811015610ad957600080fd5b50356001600160a01b031661348c565b6104776135a9565b6105f06135b9565b610b016135d3565b604080519485526020850193909352838301919091526001600160a01b03166060830152519081900360800190f35b6104cb60048036036020811015610b4657600080fd5b50356001600160a01b0316613604565b6103bc6136b3565b6103bc6136ca565b6103bc60048036036020811015610b7c57600080fd5b50356001600160a01b03166136d7565b6103d66136f3565b6103bc613754565b6103bc613760565b6103bc600480360360a0811015610bba57600080fd5b5080359060208101359060408101359060608101359060800135613765565b61047760048036036040811015610bef57600080fd5b506001600160a01b0381351690602001356137ca565b6104cb60048036036040811015610c1b57600080fd5b81359190810190604081016020820135600160201b811115610c3c57600080fd5b820183602082011115610c4e57600080fd5b803590602001918460208302840111600160201b83111715610c6f57600080fd5b5090925090506137e0565b6103bc613a48565b6103bc613a4d565b6103bc613a52565b6103bc600480360360c0811015610ca857600080fd5b5080359060208101359060408101359060608101359060808101359060a00135613a57565b6103bc613ad8565b6103bc613ae8565b610ce5613af4565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610d21578181015183820152602001610d09565b505050509050019250505060405180910390f35b6103bc613b65565b6105f0613b71565b6104cb60048036036020811015610d5b57600080fd5b50356001600160a01b0316613b8b565b610ce5613c38565b6103bc613c42565b6104cb60048036036020811015610d9157600080fd5b50356001600160a01b0316613c48565b6104cb60048036036080811015610db757600080fd5b506001600160a01b038135169060208101359060408101359060600135613c98565b6103bc614051565b61047760048036036040811015610df757600080fd5b506001600160a01b038135169060200135614062565b6105736140ee565b6103bc60048036036040811015610e2b57600080fd5b506001600160a01b03813581169160200135166140f8565b6104cb60048036036040811015610e5957600080fd5b506001600160a01b0381351690602001351515614123565b6104cb60048036036060811015610e8757600080fd5b506001600160a01b0381351690602081013590604001356141e4565b6103bc61421c565b6103bc60048036036020811015610ec157600080fd5b50356001600160a01b031661422c565b6103bc60048036036020811015610ee757600080fd5b50356001600160a01b0316614253565b6103bc600480360360c0811015610f0d57600080fd5b5080359060208101359060408101359060608101359060808101359060a00135614285565b610477614308565b6000336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2610fa5614318565b6005805461ff001916610100179055610fbc614361565b610fc46143c9565b610fcc614417565b610fd58461447a565b6001600160a01b0384166000908152600e6020526040902060039081015461100a91670de0b6b3a76400005b046001016144d6565b83111561104a576040805162461bcd60e51b81526020600482015260096024820152684f55545f524154494f60b81b604482015290519081900360640190fd5b6001600160a01b0384166000908152600e60205260408120600b549091908190611076908790336114e3565b9150915061109f836003015461108b8961459f565b600254611096614690565b8a6008546131c2565b93506110aa846146e7565b848411156110ea576040805162461bcd60e51b81526020600482015260086024820152672624a6a4aa2fa4a760c11b604482015290519081900360640190fd5b6110f8836003015487614727565b60038401556040805183815290516001600160a01b0389169133916000805160206158748339815191529181900360200190a36111353385614789565b61113e84614797565b6111498733846147a0565b600c546111619088906001600160a01b0316836147a0565b600c546040805183815290516001600160a01b03808b1693169133916000805160206158948339815191529181900360200190a45050506005805461ff00191690559392505050565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156112365780601f1061120b57610100808354040283529160200191611236565b820191906000526020600020905b81548152906001019060200180831161121957829003601f168201915b5050505050905090565b600061124b8361486d565b3360008181526001602090815260408083206001600160a01b03881680855290835292819020869055805186815290519293926000805160206158b4833981519152929181900390910190a35060015b92915050565b6802b5e3af16b188000081565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2611317614318565b6005805461ff00191661010017905561132e6148bb565b61133784614911565b61134083614911565b61134982614911565b600993909355600a91909155600b55600c80546001600160a01b0319166001600160a01b039092169190911790556005805461ff0019169055565b600061138e614318565b6113978361447a565b6113a08261447a565b6001600160a01b038084166000908152600e60205260408082209285168252902060038201546113e8906113d38761459f565b83600301546113e18861459f565b6000613765565b95945050505050565b60006113fb614318565b6001600160a01b0383166000908152600e602052604090205460ff16801561143b57506001600160a01b0382166000908152600e602052604090205460ff165b611478576040805162461bcd60e51b81526020600482015260096024820152681393d517d093d5539160ba1b604482015290519081900360640190fd5b6001600160a01b038084166000908152600e60205260408082209285168252902060038201546113e8906114ab8761459f565b83600301546114b98861459f565b600854613765565b60025490565b6402540be400670de0b6b3a76400005b0481565b633b9aca0081565b60075460009081906001600160a01b031615801590611577575060075460408051630a499ad360e01b81526001600160a01b03868116600483015291519190921691630a499ad3916024808301926020929190829003018186803b15801561154a57600080fd5b505afa15801561155e573d6000803e3d6000fd5b505050506040513d602081101561157457600080fd5b50515b15611587575083905060006115b7565b600061159b670de0b6b3a764000086614727565b90506115a786826144d6565b92506115b38684614727565b9150505b935093915050565b6000336001600160a01b03851614806115fb57506001600160a01b03841660009081526001602090815260408083203384529091529020548211155b611644576040805162461bcd60e51b815260206004820152601560248201527422a9292fa12a27a5a2a72fa120a22fa1a0a62622a960591b604482015290519081900360640190fd5b61164f84848461496c565b336001600160a01b0385161480159061168d57506001600160a01b038416600090815260016020908152604080832033845290915290205460001914155b1561170b576001600160a01b03841660009081526001602090815260408083203384529091529020546116c09083614727565b6001600160a01b0385166000818152600160209081526040808320338085529083529281902085905580519485525191936000805160206158b4833981519152929081900390910190a35b5060019392505050565b6001600160a01b0381166000908152600e602052604090205460ff165b919050565b6000611741614318565b506005546201000090046001600160a01b031690565b60055460ff1690565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a26117c9614318565b6005805461ff0019166101001790556117e06148bb565b6117e981614911565b6008556005805461ff0019169055565b633b9aca008114801561182257506001600160a01b038316600090815260116020526040902054155b61186d576040805162461bcd60e51b815260206004820152601760248201527613d3931657d39155d7d513d2d15394d7d0531313d5d151604a1b604482015290519081900360640190fd5b611878838383614a7c565b505050565b6001600160a01b0316600090815260116020908152604080832080546001820154600e909452919093206002908101549301549093919291565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2611920614318565b6005805461ff0019166101001790556007546040805163ea3457b760e01b81526001600160a01b0388811660048301526001600160e01b0319881660248301529151919092169163ea3457b7916044808301926020929190829003018186803b15801561198c57600080fd5b505afa1580156119a0573d6000803e3d6000fd5b505050506040513d60208110156119b657600080fd5b50516119fb576040805162461bcd60e51b815260206004820152600f60248201526e4e4f545f414c4c4f5745445f53494760881b604482015290519081900360640190fd5b611a036148bb565b60006060866001600160a01b03168387878760405160200180846001600160e01b03191681526004018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310611a7c5780518252601f199092019160209182019101611a5d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114611ade576040519150601f19603f3d011682016040523d82523d6000602084013e611ae3565b606091505b509150915081611b28576040805162461bcd60e51b815260206004820152600b60248201526a4e4f545f5355434345535360a81b604482015290519081900360640190fd5b856001600160e01b031916821515886001600160a01b03167f32258dd51d74a04508615e0840c1fc905dff28c96b7335e69d9a41023ecd286e88888660405180806020018060200183810383528686828181526020019250808284376000838201819052601f909101601f191690920185810384528651815286516020918201939188019250908190849084905b83811015611bce578181015183820152602001611bb6565b50505050905090810190601f168015611bfb5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a450506005805461ff00191690555050505050565b6000336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2611c8a614318565b6005805461ff001916610100179055611ca1614361565b611ca96143c9565b611cb1614417565b611cba8461447a565b6001600160a01b0384166000908152600e602052604090206003810154611cf890611ce48761459f565b600254611cef614690565b886008546133f1565b915082821015611d3b576040805162461bcd60e51b8152602060048201526009602482015268131253525517d3d55560ba1b604482015290519081900360640190fd5b6001600160a01b0385166000908152600e60205260409020600390810154611d6b91670de0b6b3a7640000611001565b821115611dab576040805162461bcd60e51b81526020600482015260096024820152684f55545f524154494f60b81b604482015290519081900360640190fd5b611db9816003015483614727565b8160030181905550600080611dd184600b54336114e3565b91509150866001600160a01b0316336001600160a01b0316600080516020615874833981519152846040518082815260200191505060405180910390a3611e183387614789565b611e2186614797565b611e2c8733846147a0565b600c54611e449088906001600160a01b0316836147a0565b600c546040805183815290516001600160a01b03808b1693169133916000805160206158948339815191529181900360200190a4506005805461ff001916905595945050505050565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2611ef6614318565b6005805461ff001916610100179055611f0d614c77565b611f156148bb565b6005805461ff0019921515600160b01b0260ff60b01b1990911617919091169055565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2611fa1614318565b6005805461ff001916610100179055611fb86148bb565b611fc0614c77565b600d5460021115612005576040805162461bcd60e51b815260206004820152600a6024820152694d494e5f544f4b454e5360b01b604482015290519081900360640190fd5b600c805460ff60a01b1916600160a01b1790556005805460ff60b01b1916600160b01b17905561203d68056bc75e2d63100000614cc5565b6120503368056bc75e2d63100000614daa565b6005805461ff0019169055565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a26120cd8585633b9aca00614db4565b6120d985848484613c98565b5050505050565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2612149614318565b6005805461ff001916610100179055612160614361565b612168614417565b6121706143c9565b600061217a6114c1565b905060006121888583614f67565b9050612193816146e7565b60005b600d548110156122c3576000600d82815481106121af57fe5b60009182526020808320909101546001600160a01b0316808352600e9091526040822060030154909250906121e485836144d6565b90506121ef816146e7565b8787858181106121fb57fe5b90506020020135811115612241576040805162461bcd60e51b81526020600482015260086024820152672624a6a4aa2fa4a760c11b604482015290519081900360640190fd5b6001600160a01b0383166000908152600e6020526040902060030154612267908261506f565b6001600160a01b0384166000818152600e60209081526040918290206003019390935580518481529051919233926000805160206158148339815191529281900390910190a36122b88333836150c3565b505050600101612196565b506000806122d487600a54336114e3565b915091506122e187614cc5565b6122eb3383614daa565b600c54612301906001600160a01b031682614daa565b600c5460408051838152905130926001600160a01b03169133916000805160206158948339815191529181900360200190a450506005805461ff00191690555050505050565b6000806123548786614f67565b90506000612362878661506f565b905060006123708289614f67565b90506000612386670de0b6b3a764000085614f67565b90506000612394838361511c565b905060006123a2828e6144d6565b905060006123b0828f614727565b905060006123cf6123c9670de0b6b3a76400008a614727565b8b6144d6565b90506123ec826123e7670de0b6b3a764000084614727565b614f67565b9f9e505050505050505050505050505050565b6000336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a261246a614318565b6005805461ff001916610100179055612481614361565b6124896143c9565b612491614417565b61249a8461447a565b6001600160a01b0384166000908152600e60205260409020600301546124cc906002670de0b6b3a76400005b046144d6565b83111561250f576040805162461bcd60e51b815260206004820152600c60248201526b4d41585f494e5f524154494f60a01b604482015290519081900360640190fd5b60008061251f85600a54336114e3565b6001600160a01b0388166000908152600e60205260409020600381015492945090925090612564906125508961459f565b60025461255b614690565b87600854613268565b9350848410156125a7576040805162461bcd60e51b8152602060048201526009602482015268131253525517d3d55560ba1b604482015290519081900360640190fd5b6125b581600301548461506f565b60038201556040805184815290516001600160a01b0389169133916000805160206158148339815191529181900360200190a36125f184614cc5565b6125fb3385614daa565b61260687338461522a565b6126118733856150c3565b600c546040805184815290516001600160a01b03808b1693169133916000805160206158948339815191529181900360200190a45050506005805461ff00191690559392505050565b60006126658361486d565b3360009081526001602090815260408083206001600160a01b0387168452909152902054808311156126ba573360009081526001602090815260408083206001600160a01b03881684529091528120556126e9565b6126c48184614727565b3360009081526001602090815260408083206001600160a01b03891684529091529020555b3360008181526001602090815260408083206001600160a01b0389168085529083529281902054815190815290519293926000805160206158b4833981519152929181900390910190a35060019392505050565b6000612747614318565b50600654600160a01b900460ff1690565b6000336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a26127c3614318565b6005805461ff0019166101001790556127da614361565b6127e26143c9565b6127ea614417565b6127f38461447a565b6001600160a01b0384166000908152600e60205260408120600a54909190819061281f908790336114e3565b9150915061284883600301546128348961459f565b60025461283f614690565b8a600854612347565b9350612853846146e7565b84841115612893576040805162461bcd60e51b81526020600482015260086024820152672624a6a4aa2fa4a760c11b604482015290519081900360640190fd5b6001600160a01b0387166000908152600e60205260409020600301546128c3906002670de0b6b3a76400006124c6565b841115612906576040805162461bcd60e51b815260206004820152600c60248201526b4d41585f494e5f524154494f60a01b604482015290519081900360640190fd5b61291483600301548561506f565b60038401556040805185815290516001600160a01b0389169133916000805160206158148339815191529181900360200190a361295086614cc5565b61295a3383614daa565b600c54612970906001600160a01b031682614daa565b61297b8733866150c3565b600c5460408051838152905130926001600160a01b03169133916000805160206158948339815191529181900360200190a45050506005805461ff00191690559392505050565b6001600160a01b031660009081526020819052604090205490565b633b9aca0090565b620f4240670de0b6b3a76400006114d7565b60408051602080825236908201819052600092839233926001600160e01b03198535169285929081908101848480828437600083820152604051601f909101601f19169092018290039550909350505050a2612a51614318565b6005805461ff001916610100179055612a68614361565b612a70614417565b612a798761447a565b612a828561447a565b600554600160b01b900460ff16612acd576040805162461bcd60e51b815260206004820152600a6024820152694e4f545f5055424c494360b01b604482015290519081900360640190fd5b6001600160a01b038088166000908152600e602052604080822092881682529020600380820154612b0691670de0b6b3a7640000611001565b861115612b46576040805162461bcd60e51b81526020600482015260096024820152684f55545f524154494f60b81b604482015290519081900360640190fd5b6000612b678360030154612b598c61459f565b84600301546114b98c61459f565b905085811115612bac576040805162461bcd60e51b815260206004820152600b60248201526a4c494d49545f505249434560a81b604482015290519081900360640190fd5b600080612bbc89600954336114e3565b91509150612be88560030154612bd18e61459f565b8660030154612bdf8e61459f565b8d600854614285565b96508a871115612c2a576040805162461bcd60e51b81526020600482015260086024820152672624a6a4aa2fa4a760c11b604482015290519081900360640190fd5b612c3885600301548861506f565b8560030181905550612c4e84600301548a614727565b8460030181905550612c758560030154612c678e61459f565b86600301546114b98e61459f565b9550828610158015612c905750612c8c8783614f67565b8311155b612ccf576040805162461bcd60e51b815260206004820152600b60248201526a09a82a890be82a0a0a49eb60ab1b604482015290519081900360640190fd5b87861115612d12576040805162461bcd60e51b815260206004820152600b60248201526a4c494d49545f505249434560a81b604482015290519081900360640190fd5b896001600160a01b03168c6001600160a01b0316336001600160a01b03166000805160206158348339815191528a86604051808381526020018281526020019250505060405180910390a4612d688c33896150c3565b612d738a33846147a0565b600c54612d8b908b906001600160a01b0316836147a0565b600c546040805183815290516001600160a01b03808e1693169133916000805160206158948339815191529181900360200190a450505050506005805461ff001916905590969095509350505050565b60408051602080825236908201819052600092839233926001600160e01b03198535169285929081908101848480828437600083820152604051601f909101601f19169092018290039550909350505050a2612e35614318565b6005805461ff001916610100179055612e4c614361565b612e54614417565b612e5d8761447a565b612e668561447a565b600554600160b01b900460ff16612eb1576040805162461bcd60e51b815260206004820152600a6024820152694e4f545f5055424c494360b01b604482015290519081900360640190fd5b6001600160a01b038088166000908152600e6020526040808220928816825281206003830154909190612ee790612b598c61459f565b905085811115612f2c576040805162461bcd60e51b815260206004820152600b60248201526a4c494d49545f505249434560a81b604482015290519081900360640190fd5b600080612f3c8b600954336114e3565b91509150612f5a85600301546002670de0b6b3a7640000816124c657fe5b821115612f9d576040805162461bcd60e51b815260206004820152600c60248201526b4d41585f494e5f524154494f60a01b604482015290519081900360640190fd5b612fc58560030154612fae8e61459f565b8660030154612fbc8e61459f565b86600854613a57565b965088871015613008576040805162461bcd60e51b8152602060048201526009602482015268131253525517d3d55560ba1b604482015290519081900360640190fd5b61301685600301548361506f565b856003018190555061302c846003015488614727565b84600301819055506130458560030154612c678e61459f565b9550828610158015613060575061305c8288614f67565b8311155b61309f576040805162461bcd60e51b815260206004820152600b60248201526a09a82a890be82a0a0a49eb60ab1b604482015290519081900360640190fd5b878611156130e2576040805162461bcd60e51b815260206004820152600b60248201526a4c494d49545f505249434560a81b604482015290519081900360640190fd5b896001600160a01b03168c6001600160a01b0316336001600160a01b0316600080516020615834833981519152858b604051808381526020018281526020019250505060405180910390a46131388c338361522a565b6131438c33846150c3565b61314e8a33896147a0565b8b6001600160a01b0316600c60009054906101000a90046001600160a01b03166001600160a01b0316336001600160a01b0316600080516020615894833981519152846040518082815260200191505060405180910390a450505050506005805461ff001916905590969095509350505050565b6000806131cf8786614f67565b905060006131e5670de0b6b3a764000083614727565b905060006131f382866144d6565b9050600061320d876123e7670de0b6b3a764000085614727565b9050600061321b8c83614727565b90506000613229828e614f67565b90506000613237828861511c565b90506000613245828e6144d6565b905060006132538e83614727565b99505050505050505050509695505050505050565b6000806132758786614f67565b9050600061329461328e670de0b6b3a764000084614727565b856144d6565b905060006132b3866132ae670de0b6b3a764000085614727565b6144d6565b905060006132c18b8361506f565b905060006132cf828d614f67565b905060006132dd828761511c565b905060006132eb828d6144d6565b90506132f7818d614727565b9e9d5050505050505050505050505050565b64e8d4a51000670de0b6b3a76400006114d7565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2613386614318565b6005805461ff00191661010017905561339d6148bb565b60128290556013819055604080518381526020810183905281517fad659e822a6c18906bbabc64f81c2a16ce19173f83c8d0bacf028b507c9ee937929181900390910190a150506005805461ff0019169055565b6000806133fe8786614f67565b9050600061340c8786614727565b9050600061341a8289614f67565b9050600061343982613434670de0b6b3a764000087614f67565b61511c565b90506000613447828d6144d6565b905060006134558d83614727565b9050600061347461346e670de0b6b3a764000089614727565b8a6144d6565b90506132f7826132ae670de0b6b3a764000084614727565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a26134f5614318565b6005805461ff00191661010017905561350d8161447a565b604080516370a0823160e01b815230600482015290516001600160a01b038316916370a08231916024808301926020929190829003018186803b15801561355357600080fd5b505afa158015613567573d6000803e3d6000fd5b505050506040513d602081101561357d57600080fd5b50516001600160a01b039091166000908152600e60205260409020600301556005805461ff0019169055565b600c54600160a01b900460ff1690565b60006135c3614318565b506006546001600160a01b031690565b6000806000806135e1614318565b5050600954600a54600b54600c54929591945092506001600160a01b0390911690565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a261366d614318565b6005805461ff0019166101001790556136846148bb565b6005805461ff00196001600160a01b03909316620100000262010000600160b01b031990911617919091169055565b60006136bd614318565b6136c5614690565b905090565b68056bc75e2d6310000081565b60006136e1614318565b6136ea8261447a565b61129b8261459f565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156112365780601f1061120b57610100808354040283529160200191611236565b6704a03ce68d21555681565b600990565b6000806137728787614f67565b905060006137808686614f67565b9050600061378e8383614f67565b905060006137b0670de0b6b3a76400006123e7670de0b6b3a764000089614727565b90506137bc82826144d6565b9a9950505050505050505050565b60006137d733848461496c565b50600192915050565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2613849614318565b6005805461ff001916610100179055613860614361565b613868614417565b6138706143c9565b60008061388085600b54336114e3565b91509150600061388e6114c1565b9050600061389c8483614f67565b90506138a7816146e7565b6138b13388614789565b600c546138c7906001600160a01b031684614daa565b6138d084614797565b60005b600d54811015613a01576000600d82815481106138ec57fe5b60009182526020808320909101546001600160a01b0316808352600e90915260408220600301549092509061392185836144d6565b905061392c816146e7565b89898581811061393857fe5b9050602002013581101561397f576040805162461bcd60e51b8152602060048201526009602482015268131253525517d3d55560ba1b604482015290519081900360640190fd5b6001600160a01b0383166000908152600e60205260409020600301546139a59082614727565b6001600160a01b0384166000818152600e60209081526040918290206003019390935580518481529051919233926000805160206158748339815191529281900390910190a36139f68333836147a0565b5050506001016138d3565b50600c5460408051858152905130926001600160a01b03169133916000805160206158948339815191529181900360200190a450506005805461ff00191690555050505050565b600981565b600281565b600181565b600080613a648786614f67565b90506000613a7a670de0b6b3a764000085614727565b9050613a8685826144d6565b90506000613a988a6123e78c8561506f565b90506000613aa6828561511c565b90506000613abc670de0b6b3a764000083614727565b9050613ac88a826144d6565b9c9b505050505050505050505050565b600a670de0b6b3a76400006114d7565b671bc16d674ec7ffff81565b6060613afe614318565b613b066143c9565b600d80548060200260200160405190810160405280929190818152602001828054801561123657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613b3e575050505050905090565b670de0b6b3a764000081565b6000613b7b614318565b506007546001600160a01b031690565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2613bf4614318565b6005805461ff001916610100179055613c0b6148bb565b600780546001600160a01b0319166001600160a01b03929092169190911790556005805461ff0019169055565b6060613b06614318565b600d5490565b613c5181615288565b60408051606081018252600080825260208083018281528385018381526001600160a01b039096168352601190915292902090518155905160018201559051600290910155565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2613d01614318565b6005805461ff001916610100179055613d186148bb565b613d218461447a565b428211613d6f576040805162461bcd60e51b8152602060048201526017602482015276043414e545f5345545f504153545f54494d455354414d5604c1b604482015290519081900360640190fd5b818111613dbf576040805162461bcd60e51b815260206004820152601960248201527854494d455354414d505f494e434f52524543545f44454c544160381b604482015290519081900360640190fd5b633b9aca008310158015613ddc57506802b5e3af16b18800008311155b613e24576040805162461bcd60e51b81526020600482015260146024820152735441524745545f5745494748545f424f554e445360601b604482015290519081900360640190fd5b6000613e2f8561459f565b90506000613e3f828686866154a0565b9050601354811115613e90576040805162461bcd60e51b815260206004820152601560248201527413505617d5d15251d21517d4115497d4d150d3d391605a1b604482015290519081900360640190fd5b601254811015613edf576040805162461bcd60e51b815260206004820152601560248201527413525397d5d15251d21517d4115497d4d150d3d391605a1b604482015290519081900360640190fd5b6001600160a01b0386166000818152600e60209081526040808320600290810187905581516060810183528981528084018981528184018c8152968652601190945291842091518255915160018201559251920191909155600d54815b81811015613f9057613f868360116000600d8581548110613f5957fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190206002015461506f565b9250600101613f3c565b506802b5e3af16b1880000821115613fe9576040805162461bcd60e51b815260206004820152601760248201527613505617d5105491d15517d513d5105317d5d15251d215604a1b604482015290519081900360640190fd5b60408051858152602081018990528082018890526060810187905290516001600160a01b038a16917f0667af890d2d91f5a21a17df455617ff8f0fcc445cc6286d717c1144a1bcd001919081900360800190a250506005805461ff0019169055505050505050565b600061405b614318565b5060085490565b600061406d8361486d565b3360009081526001602090815260408083206001600160a01b038716845290915290205461409b908361506f565b3360008181526001602090815260408083206001600160a01b0389168085529083529281902085905580519485525191936000805160206158b4833981519152929081900390910190a350600192915050565b6012546013549091565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a261418c614318565b6005805461ff0019166101001790556141a36148bb565b600680546001600160a01b0319166001600160a01b03939093169290921760ff60a01b1916600160a01b911515919091021790556005805461ff0019169055565b6040805162461bcd60e51b8152602060048201526008602482015267111254d05093115160c21b604482015290519081900360640190fd5b6002670de0b6b3a76400006114d7565b6000614236614318565b61423f8261447a565b61129b61424b8361459f565b6123e7614690565b600061425d614318565b6142668261447a565b506001600160a01b03166000908152600e602052604090206003015490565b6000806142928588614f67565b905060006142a08786614727565b905060006142ae8883614f67565b905060006142bc828561511c565b90506142d081670de0b6b3a7640000614727565b90506142e4670de0b6b3a764000087614727565b94506142f96142f38c836144d6565b86614f67565b9b9a5050505050505050505050565b600554600160b01b900460ff1690565b600554610100900460ff161561435f576040805162461bcd60e51b81526020600482015260076024820152665245454e54525960c81b604482015290519081900360640190fd5b565b3260009081526010602052604090205443116143b5576040805162461bcd60e51b815260206004820152600e60248201526d29a0a6a2afaa2c2fa7a924a3a4a760911b604482015290519081900360640190fd5b326000908152601060205260409020439055565b600c54600160a01b900460ff1661435f576040805162461bcd60e51b815260206004820152600d60248201526c1393d517d19253905312569151609a1b604482015290519081900360640190fd5b600654600160a01b900460ff16158061443a57506006546001600160a01b031633145b61435f576040805162461bcd60e51b815260206004820152600c60248201526b27a7262cafaba920a82822a960a11b604482015290519081900360640190fd5b6001600160a01b0381166000908152600e602052604090205460ff166144d3576040805162461bcd60e51b81526020600482015260096024820152681393d517d093d5539160ba1b604482015290519081900360640190fd5b50565b60008282028315806144f05750828482816144ed57fe5b04145b614534576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6706f05b59d3b20000810181811015614587576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6000670de0b6b3a7640000825b049695505050505050565b60006145a96157f2565b506001600160a01b038216600081815260116020908152604080832081516060810183528154815260018201548185015260029182015481840152948452600e9092529091200154815115806146025750808260400151145b8061460e575081514211155b1561461c5791506117329050565b816020015142106146335750604001519050611732565b600061464d828460400151856000015186602001516154a0565b9050600061465f428560000151614727565b90508284604001511115614684576146798383830261506f565b945050505050611732565b61467983838302614727565b600d546000908190815b818110156146df576146d5836146d0600d84815481106146b657fe5b6000918252602090912001546001600160a01b031661459f565b61506f565b925060010161469a565b509091505090565b806144d3576040805162461bcd60e51b815260206004820152600b60248201526a09a82a890be82a0a0a49eb60ab1b604482015290519081900360640190fd5b600080600061473685856154e2565b915091508015614781576040805162461bcd60e51b81526020600482015260116024820152704552525f5355425f554e444552464c4f5760781b604482015290519081900360640190fd5b509392505050565b6147938282615507565b5050565b6144d381615512565b6000836001600160a01b031663a9059cbb84846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156147f957600080fd5b505af115801561480d573d6000803e3d6000fd5b505050506040513d602081101561482357600080fd5b5051905080614867576040805162461bcd60e51b815260206004820152600b60248201526a45524332305f46414c534560a81b604482015290519081900360640190fd5b50505050565b6001600160a01b0381166144d3576040805162461bcd60e51b815260206004820152601060248201526f4552525f4e554c4c5f4144445245535360801b604482015290519081900360640190fd5b6005546201000090046001600160a01b0316331461435f576040805162461bcd60e51b815260206004820152600e60248201526d2727aa2fa1a7a72a2927a62622a960911b604482015290519081900360640190fd5b64e8d4a51000811080159061492e575067016345785d8a00008111155b6144d3576040805162461bcd60e51b815260206004820152600a6024820152694645455f424f554e445360b01b604482015290519081900360640190fd5b6001600160a01b0383166000908152602081905260409020548111156149d0576040805162461bcd60e51b815260206004820152601460248201527311549497d25394d551919250d251539517d0905360621b604482015290519081900360640190fd5b6149d98361486d565b6149e28261486d565b6001600160a01b038316600090815260208190526040902054614a059082614727565b6001600160a01b038085166000908152602081905260408082209390935590841681522054614a34908261506f565b6001600160a01b0380841660008181526020818152604091829020949094558051858152905191939287169260008051602061585483398151915292918290030190a3505050565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2614ae5614318565b6005805461ff001916610100179055614afc6148bb565b614b058361447a565b633b9aca008110158015614b2257506802b5e3af16b18800008111155b614b63576040805162461bcd60e51b815260206004820152600d60248201526c5745494748545f424f554e445360981b604482015290519081900360640190fd5b620f4240821015614ba9576040805162461bcd60e51b815260206004820152600b60248201526a4d494e5f42414c414e434560a81b604482015290519081900360640190fd5b6001600160a01b0383166000908152600e602052604090206002015480821115614be457614bdf614bda8383614727565b6144d3565b614bf9565b80821015614bf957614bf9614bda8284614727565b6001600160a01b0384166000908152600e602052604090206002810183905560030180549084905580841115614c4257614c3d8533614c388785614727565b6150c3565b614c65565b80841015614c65576000614c568286614727565b9050614c638633836147a0565b505b50506005805461ff0019169055505050565b600c54600160a01b900460ff161561435f576040805162461bcd60e51b815260206004820152600c60248201526b1254d7d1925390531256915160a21b604482015290519081900360640190fd5b6007546001600160a01b031615614da1576007546040805163afff324960e01b815230600482015290516000926001600160a01b03169163afff3249916024808301926020929190829003018186803b158015614d2157600080fd5b505afa158015614d35573d6000803e3d6000fd5b505050506040513d6020811015614d4b57600080fd5b50516002549091508190614d5f908461506f565b1115614d9f576040805162461bcd60e51b815260206004820152600a6024820152694d41585f535550504c5960b01b604482015290519081900360640190fd5b505b6144d3816155d0565b6147938282615633565b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2614e1d6148bb565b6001600160a01b0383166000908152600e602052604090205460ff1615614e76576040805162461bcd60e51b81526020600482015260086024820152671254d7d093d5539160c21b604482015290519081900360640190fd5b600d54600911614eba576040805162461bcd60e51b815260206004820152600a6024820152694d41585f544f4b454e5360b01b604482015290519081900360640190fd5b604080516080810182526001808252600d805460208085019182526000858701818152606087018281526001600160a01b038c16808452600e9094529782209651875460ff1916901515178755925186860155915160028601559451600390940193909355805491820181559091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b03191690911790556118788383836117f9565b600081614faa576040805162461bcd60e51b815260206004820152600c60248201526b4552525f4449565f5a45524f60a01b604482015290519081900360640190fd5b670de0b6b3a76400008302831580614fd25750670de0b6b3a7640000848281614fcf57fe5b04145b615016576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b60028304810181811015615064576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b600084828161459457fe5b6000828201838110156150bc576040805162461bcd60e51b815260206004820152601060248201526f4552525f4144445f4f564552464c4f5760801b604482015290519081900360640190fd5b9392505050565b604080516323b872dd60e01b81526001600160a01b0384811660048301523060248301526044820184905291516000928616916323b872dd91606480830192602092919082900301818787803b1580156147f957600080fd5b6000600183101561516c576040805162461bcd60e51b81526020600482015260156024820152744552525f42504f575f424153455f544f4f5f4c4f5760581b604482015290519081900360640190fd5b671bc16d674ec7ffff8311156151c2576040805162461bcd60e51b815260206004820152601660248201527508aa4a4be84a09eaebe8482a68abea89e9ebe90928e960531b604482015290519081900360640190fd5b60006151cd8361563e565b905060006151db8483614727565b905060006151f1866151ec85615659565b615667565b90508161520257925061129b915050565b600061521387846305f5e1006156be565b905061521f82826144d6565b979650505050505050565b600c54604080516323b872dd60e01b81526001600160a01b03858116600483015292831660248201526044810184905290516000928616916323b872dd91606480830192602092919082900301818787803b1580156147f957600080fd5b336001600160a01b03166000356001600160e01b0319166001600160e01b03191660003660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a26152f1614318565b6005805461ff0019166101001790556153086148bb565b6153118161447a565b6001600160a01b0381166000908152600e60205260409020600381015460029091015461533d906144d3565b6001600160a01b0382166000908152600e6020526040902060010154600d8054600019810191908290811061536e57fe5b600091825260209091200154600d80546001600160a01b03909216918490811061539457fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555081600e6000600d85815481106153d457fe5b60009182526020808320909101546001600160a01b03168352820192909252604001902060010155600d80548061540757fe5b60008281526020808220600019908401810180546001600160a01b031916905590920190925560408051608081018252838152808301848152818301858152606083018681526001600160a01b038b168752600e909552929094209051815460ff1916901515178155925160018401555160028301555160039091015561548f8433856147a0565b50506005805461ff00191690555050565b6000808585116154b9576154b48686614727565b6154c3565b6154c38587614727565b90506154d8816154d38587614727565b61579c565b9695505050505050565b6000808284106154f85750508082036000615500565b505081810360015b9250929050565b61479382308361496c565b3060009081526020819052604090205481111561556d576040805162461bcd60e51b815260206004820152601460248201527311549497d25394d551919250d251539517d0905360621b604482015290519081900360640190fd5b306000908152602081905260409020546155879082614727565b306000908152602081905260409020556002546155a49082614727565b60025560408051828152905160009130916000805160206158548339815191529181900360200190a350565b306000908152602081905260409020546155ea908261506f565b30600090815260208190526040902055600254615607908261506f565b60025560408051828152905130916000916000805160206158548339815191529181900360200190a350565b61479330838361496c565b6000670de0b6b3a764000061565283615659565b0292915050565b670de0b6b3a7640000900490565b6000806002830661568057670de0b6b3a7640000615682565b835b90506002830492505b82156150bc5761569b84856144d6565b935060028306156156b3576156b081856144d6565b90505b60028304925061568b565b60008281806156d587670de0b6b3a76400006154e2565b9092509050670de0b6b3a764000080600060015b88841061578d576000670de0b6b3a76400008202905060008061571d8a61571885670de0b6b3a7640000614727565b6154e2565b9150915061572f876132ae848c6144d6565b965061573b8784614f67565b96508661574a5750505061578d565b8715615754579315935b801561575e579315935b84156157755761576e8688614727565b9550615782565b61577f868861506f565b95505b5050506001016156e9565b50909998505050505050505050565b60008082116157e1576040805162461bcd60e51b815260206004820152600c60248201526b4552525f4449565f5a45524f60a01b604482015290519081900360640190fd5b8183816157ea57fe5b049392505050565b6040518060600160405280600081526020016000815260200160008152509056fe63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed5b5ddc912843b56bbfa1620dc5a27cc3b1b82c88ab626118af8dc1319b4a86568c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a264697066735822122062589b3b35fe5b3ab79b385208b3967cb5281ecde120ea0669764a48e9b0608264736f6c634300060c0033000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000004b3090ab80100000000000000000000000000000000000000000000000000000d287fb79cd10000000000000000000000000000000000000000000000000000000000000016506f77657220496e64657820506f6f6c20546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000045049505400000000000000000000000000000000000000000000000000000000

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

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.