false
true
0

Contract Address Details

0xB9fC157394Af804a3578134A6585C0dc9cc990d4

Contract Name
Vyper_contract
Creator
0x7eeac6–07289a at 0x4682d2–de47c8
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
384 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26039474
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Vyper_contract




Optimization enabled
true
Compiler version
v0.2.15+commit.6e7dba7




Verified at
2024-05-13T01:31:13.253112Z

Constructor Arguments

0x000000000000000000000000ecb456ea5365865ebab8a2661b0c503410e9b347

Arg [0] (address) : 0xecb456ea5365865ebab8a2661b0c503410e9b347

              

Contract source code

# @version 0.2.15
"""
@title Curve Factory
@license MIT
@author Curve.Fi
@notice Permissionless pool deployer and registry
"""

struct PoolArray:
    base_pool: address
    implementation: address
    liquidity_gauge: address
    coins: address[MAX_PLAIN_COINS]
    decimals: uint256[MAX_PLAIN_COINS]
    n_coins: uint256
    asset_type: uint256

struct BasePoolArray:
    implementations: address[10]
    lp_token: address
    fee_receiver: address
    coins: address[MAX_COINS]
    decimals: uint256
    n_coins: uint256
    asset_type: uint256


interface AddressProvider:
    def admin() -> address: view
    def get_registry() -> address: view

interface Registry:
    def get_lp_token(pool: address) -> address: view
    def get_n_coins(pool: address) -> uint256: view
    def get_coins(pool: address) -> address[MAX_COINS]: view
    def get_pool_from_lp_token(lp_token: address) -> address: view

interface ERC20:
    def balanceOf(_addr: address) -> uint256: view
    def decimals() -> uint256: view
    def totalSupply() -> uint256: view
    def approve(_spender: address, _amount: uint256): nonpayable

interface CurvePlainPool:
    def initialize(
        _name: String[32],
        _symbol: String[10],
        _coins: address[4],
        _rate_multipliers: uint256[4],
        _A: uint256,
        _fee: uint256,
    ): nonpayable

interface CurvePool:
    def A() -> uint256: view
    def fee() -> uint256: view
    def admin_fee() -> uint256: view
    def balances(i: uint256) -> uint256: view
    def admin_balances(i: uint256) -> uint256: view
    def get_virtual_price() -> uint256: view
    def initialize(
        _name: String[32],
        _symbol: String[10],
        _coin: address,
        _rate_multiplier: uint256,
        _A: uint256,
        _fee: uint256,
    ): nonpayable
    def exchange(
        i: int128,
        j: int128,
        dx: uint256,
        min_dy: uint256,
        _receiver: address,
    ) -> uint256: nonpayable

interface CurveFactoryMetapool:
    def coins(i :uint256) -> address: view
    def decimals() -> uint256: view

interface OldFactory:
    def get_coins(_pool: address) -> address[2]: view

interface LiquidityGauge:
    def initialize(_lp_token: address): nonpayable


event BasePoolAdded:
    base_pool: address

event PlainPoolDeployed:
    coins: address[MAX_PLAIN_COINS]
    A: uint256
    fee: uint256
    deployer: address

event MetaPoolDeployed:
    coin: address
    base_pool: address
    A: uint256
    fee: uint256
    deployer: address

event LiquidityGaugeDeployed:
    pool: address
    gauge: address


MAX_COINS: constant(int128) = 8
MAX_PLAIN_COINS: constant(int128) = 4  # max coins in a plain pool
ADDRESS_PROVIDER: constant(address) = 0x0000000022D53366457F9d5E68Ec105046FC4383
OLD_FACTORY: constant(address) = 0x0959158b6040D32d04c301A72CBFD6b39E21c9AE

admin: public(address)
future_admin: public(address)
manager: public(address)

pool_list: public(address[4294967296])   # master list of pools
pool_count: public(uint256)              # actual length of pool_list
pool_data: HashMap[address, PoolArray]

base_pool_list: public(address[4294967296])   # master list of pools
base_pool_count: public(uint256)         # actual length of pool_list
base_pool_data: HashMap[address, BasePoolArray]

# asset -> is used in a metapool?
base_pool_assets: public(HashMap[address, bool])

# number of coins -> implementation addresses
# for "plain pools" (as opposed to metapools), implementation contracts
# are organized according to the number of coins in the pool
plain_implementations: public(HashMap[uint256, address[10]])

# fee receiver for plain pools
fee_receiver: address

gauge_implementation: public(address)

# mapping of coins -> pools for trading
# a mapping key is generated for each pair of addresses via
# `bitwise_xor(convert(a, uint256), convert(b, uint256))`
markets: HashMap[uint256, address[4294967296]]
market_counts: HashMap[uint256, uint256]


@external
def __init__(_fee_receiver: address):
    self.admin = msg.sender
    self.manager = msg.sender
    self.fee_receiver = _fee_receiver


# <--- Factory Getters --->

@view
@external
def metapool_implementations(_base_pool: address) -> address[10]:
    """
    @notice Get a list of implementation contracts for metapools targetting the given base pool
    @dev A base pool is the pool for the LP token contained within the metapool
    @param _base_pool Address of the base pool
    @return List of implementation contract addresses
    """
    return self.base_pool_data[_base_pool].implementations


@view
@external
def find_pool_for_coins(_from: address, _to: address, i: uint256 = 0) -> address:
    """
    @notice Find an available pool for exchanging two coins
    @param _from Address of coin to be sent
    @param _to Address of coin to be received
    @param i Index value. When multiple pools are available
            this value is used to return the n'th address.
    @return Pool address
    """
    key: uint256 = bitwise_xor(convert(_from, uint256), convert(_to, uint256))
    return self.markets[key][i]


# <--- Pool Getters --->

@view
@external
def get_base_pool(_pool: address) -> address:
    """
    @notice Get the base pool for a given factory metapool
    @param _pool Metapool address
    @return Address of base pool
    """
    return self.pool_data[_pool].base_pool


@view
@external
def get_n_coins(_pool: address) -> (uint256):
    """
    @notice Get the number of coins in a pool
    @param _pool Pool address
    @return Number of coins
    """
    return self.pool_data[_pool].n_coins


@view
@external
def get_meta_n_coins(_pool: address) -> (uint256, uint256):
    """
    @notice Get the number of coins in a metapool
    @param _pool Pool address
    @return Number of wrapped coins, number of underlying coins
    """
    base_pool: address = self.pool_data[_pool].base_pool
    return 2, self.base_pool_data[base_pool].n_coins + 1


@view
@external
def get_coins(_pool: address) -> address[MAX_PLAIN_COINS]:
    """
    @notice Get the coins within a pool
    @param _pool Pool address
    @return List of coin addresses
    """
    return self.pool_data[_pool].coins


@view
@external
def get_underlying_coins(_pool: address) -> address[MAX_COINS]:
    """
    @notice Get the underlying coins within a pool
    @dev Reverts if a pool does not exist or is not a metapool
    @param _pool Pool address
    @return List of coin addresses
    """
    coins: address[MAX_COINS] = empty(address[MAX_COINS])
    base_pool: address = self.pool_data[_pool].base_pool
    assert base_pool != ZERO_ADDRESS  # dev: pool is not metapool
    coins[0] = self.pool_data[_pool].coins[0]
    for i in range(1, MAX_COINS):
        coins[i] = self.base_pool_data[base_pool].coins[i - 1]
        if coins[i] == ZERO_ADDRESS:
            break

    return coins


@view
@external
def get_decimals(_pool: address) -> uint256[MAX_PLAIN_COINS]:
    """
    @notice Get decimal places for each coin within a pool
    @param _pool Pool address
    @return uint256 list of decimals
    """
    if self.pool_data[_pool].base_pool != ZERO_ADDRESS:
        decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
        decimals = self.pool_data[_pool].decimals
        decimals[1] = 18
        return decimals
    return self.pool_data[_pool].decimals


@view
@external
def get_underlying_decimals(_pool: address) -> uint256[MAX_COINS]:
    """
    @notice Get decimal places for each underlying coin within a pool
    @param _pool Pool address
    @return uint256 list of decimals
    """
    # decimals are tightly packed as a series of uint8 within a little-endian bytes32
    # the packed value is stored as uint256 to simplify unpacking via shift and modulo
    pool_decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
    pool_decimals = self.pool_data[_pool].decimals
    decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS])
    decimals[0] = pool_decimals[0]
    base_pool: address = self.pool_data[_pool].base_pool
    packed_decimals: uint256 = self.base_pool_data[base_pool].decimals
    for i in range(MAX_COINS):
        unpacked: uint256 = shift(packed_decimals, -8 * i) % 256
        if unpacked == 0:
            break
        decimals[i+1] = unpacked

    return decimals


@view
@external
def get_metapool_rates(_pool: address) -> uint256[2]:
    """
    @notice Get rates for coins within a metapool
    @param _pool Pool address
    @return Rates for each coin, precision normalized to 10**18
    """
    rates: uint256[2] = [10**18, 0]
    rates[1] = CurvePool(self.pool_data[_pool].base_pool).get_virtual_price()
    return rates


@view
@external
def get_balances(_pool: address) -> uint256[MAX_PLAIN_COINS]:
    """
    @notice Get balances for each coin within a pool
    @dev For pools using lending, these are the wrapped coin balances
    @param _pool Pool address
    @return uint256 list of balances
    """
    if self.pool_data[_pool].base_pool != ZERO_ADDRESS:
        return [CurvePool(_pool).balances(0), CurvePool(_pool).balances(1), 0, 0]
    n_coins: uint256 = self.pool_data[_pool].n_coins
    balances: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
    for i in range(MAX_PLAIN_COINS):
        if i < n_coins:
            balances[i] = CurvePool(_pool).balances(i)
        else:
            balances[i] = 0
    return balances


@view
@external
def get_underlying_balances(_pool: address) -> uint256[MAX_COINS]:
    """
    @notice Get balances for each underlying coin within a metapool
    @param _pool Metapool address
    @return uint256 list of underlying balances
    """

    underlying_balances: uint256[MAX_COINS] = empty(uint256[MAX_COINS])
    underlying_balances[0] = CurvePool(_pool).balances(0)

    base_total_supply: uint256 = ERC20(self.pool_data[_pool].coins[1]).totalSupply()
    if base_total_supply > 0:
        underlying_pct: uint256 = CurvePool(_pool).balances(1) * 10**36 / base_total_supply
        base_pool: address = self.pool_data[_pool].base_pool
        assert base_pool != ZERO_ADDRESS  # dev: pool is not a metapool
        n_coins: uint256 = self.base_pool_data[base_pool].n_coins
        for i in range(MAX_COINS):
            if i == n_coins:
                break
            underlying_balances[i + 1] = CurvePool(base_pool).balances(i) * underlying_pct / 10**36

    return underlying_balances


@view
@external
def get_A(_pool: address) -> uint256:
    """
    @notice Get the amplfication co-efficient for a pool
    @param _pool Pool address
    @return uint256 A
    """
    return CurvePool(_pool).A()


@view
@external
def get_fees(_pool: address) -> (uint256, uint256):
    """
    @notice Get the fees for a pool
    @dev Fees are expressed as integers
    @return Pool fee and admin fee as uint256 with 1e10 precision
    """
    return CurvePool(_pool).fee(), CurvePool(_pool).admin_fee()


@view
@external
def get_admin_balances(_pool: address) -> uint256[MAX_PLAIN_COINS]:
    """
    @notice Get the current admin balances (uncollected fees) for a pool
    @param _pool Pool address
    @return List of uint256 admin balances
    """
    n_coins: uint256 = self.pool_data[_pool].n_coins
    admin_balances: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
    for i in range(MAX_PLAIN_COINS):
        if i == n_coins:
            break
        admin_balances[i] = CurvePool(_pool).admin_balances(i)
    return admin_balances


@view
@external
def get_coin_indices(
    _pool: address,
    _from: address,
    _to: address
) -> (int128, int128, bool):
    """
    @notice Convert coin addresses to indices for use with pool methods
    @param _pool Pool address
    @param _from Coin address to be used as `i` within a pool
    @param _to Coin address to be used as `j` within a pool
    @return int128 `i`, int128 `j`, boolean indicating if `i` and `j` are underlying coins
    """
    coin: address = self.pool_data[_pool].coins[0]
    base_pool: address = self.pool_data[_pool].base_pool
    if coin in [_from, _to] and base_pool != ZERO_ADDRESS:
        base_lp_token: address = self.pool_data[_pool].coins[1]
        if base_lp_token in [_from, _to]:
            # True and False convert to 1 and 0 - a bit of voodoo that
            # works because we only ever have 2 non-underlying coins if base pool is ZERO_ADDRESS
            return convert(_to == coin, int128), convert(_from == coin, int128), False

    found_market: bool = False
    i: int128 = 0
    j: int128 = 0
    for x in range(MAX_COINS):
        if base_pool == ZERO_ADDRESS:
            if x >= MAX_PLAIN_COINS:
                raise "No available market"
            if x != 0:
                coin = self.pool_data[_pool].coins[x]
        else:
            if x != 0:
                coin = self.base_pool_data[base_pool].coins[x-1]
        if coin == ZERO_ADDRESS:
            raise "No available market"
        if coin == _from:
            i = x
        elif coin == _to:
            j = x
        else:
            continue
        if found_market:
            # the second time we find a match, break out of the loop
            break
        # the first time we find a match, set `found_market` to True
        found_market = True

    return i, j, True


@view
@external
def get_gauge(_pool: address) -> address:
    """
    @notice Get the address of the liquidity gauge contract for a factory pool
    @dev Returns `ZERO_ADDRESS` if a gauge has not been deployed
    @param _pool Pool address
    @return Implementation contract address
    """
    return self.pool_data[_pool].liquidity_gauge


@view
@external
def get_implementation_address(_pool: address) -> address:
    """
    @notice Get the address of the implementation contract used for a factory pool
    @param _pool Pool address
    @return Implementation contract address
    """
    return self.pool_data[_pool].implementation


@view
@external
def is_meta(_pool: address) -> bool:
    """
    @notice Verify `_pool` is a metapool
    @param _pool Pool address
    @return True if `_pool` is a metapool
    """
    return self.pool_data[_pool].base_pool != ZERO_ADDRESS


@view
@external
def get_pool_asset_type(_pool: address) -> uint256:
    """
    @notice Query the asset type of `_pool`
    @dev 0 = USD, 1 = ETH, 2 = BTC, 3 = Other
    @param _pool Pool Address
    @return Integer indicating the pool asset type
    """
    base_pool: address = self.pool_data[_pool].base_pool
    if base_pool == ZERO_ADDRESS:
        return self.pool_data[_pool].asset_type
    else:
        return self.base_pool_data[base_pool].asset_type


@view
@external
def get_fee_receiver(_pool: address) -> address:
    base_pool: address = self.pool_data[_pool].base_pool
    if base_pool == ZERO_ADDRESS:
        return self.fee_receiver
    else:
        return self.base_pool_data[base_pool].fee_receiver


# <--- Pool Deployers --->

@external
def deploy_plain_pool(
    _name: String[32],
    _symbol: String[10],
    _coins: address[MAX_PLAIN_COINS],
    _A: uint256,
    _fee: uint256,
    _asset_type: uint256 = 0,
    _implementation_idx: uint256 = 0,
) -> address:
    """
    @notice Deploy a new plain pool
    @param _name Name of the new plain pool
    @param _symbol Symbol for the new plain pool - will be
                   concatenated with factory symbol
    @param _coins List of addresses of the coins being used in the pool.
    @param _A Amplification co-efficient - a lower value here means
              less tolerance for imbalance within the pool's assets.
              Suggested values include:
               * Uncollateralized algorithmic stablecoins: 5-10
               * Non-redeemable, collateralized assets: 100
               * Redeemable assets: 200-400
    @param _fee Trade fee, given as an integer with 1e10 precision. The
                minimum fee is 0.04% (4000000), the maximum is 1% (100000000).
                50% of the fee is distributed to veCRV holders.
    @param _asset_type Asset type for pool, as an integer
                       0 = USD, 1 = ETH, 2 = BTC, 3 = Other
    @param _implementation_idx Index of the implementation to use. All possible
                implementations for a pool of N_COINS can be publicly accessed
                via `plain_implementations(N_COINS)`
    @return Address of the deployed pool
    """
    # fee must be between 0.04% and 1%
    assert _fee >= 4000000 and _fee <= 100000000, "Invalid fee"

    n_coins: uint256 = MAX_PLAIN_COINS
    rate_multipliers: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
    decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])

    for i in range(MAX_PLAIN_COINS):
        coin: address = _coins[i]
        if coin == ZERO_ADDRESS:
            assert i > 1, "Insufficient coins"
            n_coins = i
            break
        assert self.base_pool_assets[coin] == False, "Invalid asset, deploy a metapool"

        if _coins[i] == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE:
            assert i == 0, "ETH must be first coin"
            decimals[0] = 18
        else:
            decimals[i] = ERC20(coin).decimals()
            assert decimals[i] < 19, "Max 18 decimals for coins"

        rate_multipliers[i] = 10 ** (36 - decimals[i])

        for x in range(i, i+MAX_PLAIN_COINS):
            if x+1 == MAX_PLAIN_COINS:
                break
            if _coins[x+1] == ZERO_ADDRESS:
                break
            assert coin != _coins[x+1], "Duplicate coins"

    implementation: address = self.plain_implementations[n_coins][_implementation_idx]
    assert implementation != ZERO_ADDRESS, "Invalid implementation index"
    pool: address = create_forwarder_to(implementation)
    CurvePlainPool(pool).initialize(_name, _symbol, _coins, rate_multipliers, _A, _fee)

    length: uint256 = self.pool_count
    self.pool_list[length] = pool
    self.pool_count = length + 1
    self.pool_data[pool].decimals = decimals
    self.pool_data[pool].n_coins = n_coins
    self.pool_data[pool].base_pool = ZERO_ADDRESS
    self.pool_data[pool].implementation = implementation
    if _asset_type != 0:
        self.pool_data[pool].asset_type = _asset_type

    for i in range(MAX_PLAIN_COINS):
        coin: address = _coins[i]
        if coin == ZERO_ADDRESS:
            break
        self.pool_data[pool].coins[i] = coin
        raw_call(
            coin,
            concat(
                method_id("approve(address,uint256)"),
                convert(pool, bytes32),
                convert(MAX_UINT256, bytes32)
            )
        )
        for j in range(MAX_PLAIN_COINS):
            if i < j:
                swappable_coin: address = _coins[j]
                key: uint256 = bitwise_xor(convert(coin, uint256), convert(swappable_coin, uint256))
                length = self.market_counts[key]
                self.markets[key][length] = pool
                self.market_counts[key] = length + 1

    log PlainPoolDeployed(_coins, _A, _fee, msg.sender)
    return pool


@external
def deploy_metapool(
    _base_pool: address,
    _name: String[32],
    _symbol: String[10],
    _coin: address,
    _A: uint256,
    _fee: uint256,
    _implementation_idx: uint256 = 0,
) -> address:
    """
    @notice Deploy a new metapool
    @param _base_pool Address of the base pool to use
                      within the metapool
    @param _name Name of the new metapool
    @param _symbol Symbol for the new metapool - will be
                   concatenated with the base pool symbol
    @param _coin Address of the coin being used in the metapool
    @param _A Amplification co-efficient - a higher value here means
              less tolerance for imbalance within the pool's assets.
              Suggested values include:
               * Uncollateralized algorithmic stablecoins: 5-10
               * Non-redeemable, collateralized assets: 100
               * Redeemable assets: 200-400
    @param _fee Trade fee, given as an integer with 1e10 precision. The
                minimum fee is 0.04% (4000000), the maximum is 1% (100000000).
                50% of the fee is distributed to veCRV holders.
    @param _implementation_idx Index of the implementation to use. All possible
                implementations for a BASE_POOL can be publicly accessed
                via `metapool_implementations(BASE_POOL)`
    @return Address of the deployed pool
    """
    # fee must be between 0.04% and 1%
    assert _fee >= 4000000 and _fee <= 100000000, "Invalid fee"

    implementation: address = self.base_pool_data[_base_pool].implementations[_implementation_idx]
    assert implementation != ZERO_ADDRESS, "Invalid implementation index"

    # things break if a token has >18 decimals
    decimals: uint256 = ERC20(_coin).decimals()
    assert decimals < 19, "Max 18 decimals for coins"

    pool: address = create_forwarder_to(implementation)
    CurvePool(pool).initialize(_name, _symbol, _coin, 10 ** (36 - decimals), _A, _fee)
    ERC20(_coin).approve(pool, MAX_UINT256)

    # add pool to pool_list
    length: uint256 = self.pool_count
    self.pool_list[length] = pool
    self.pool_count = length + 1

    base_lp_token: address = self.base_pool_data[_base_pool].lp_token

    self.pool_data[pool].decimals = [decimals, 0, 0, 0]
    self.pool_data[pool].n_coins = 2
    self.pool_data[pool].base_pool = _base_pool
    self.pool_data[pool].coins[0] = _coin
    self.pool_data[pool].coins[1] = self.base_pool_data[_base_pool].lp_token
    self.pool_data[pool].implementation = implementation

    is_finished: bool = False
    for i in range(MAX_COINS):
        swappable_coin: address = self.base_pool_data[_base_pool].coins[i]
        if swappable_coin == ZERO_ADDRESS:
            is_finished = True
            swappable_coin = base_lp_token

        key: uint256 = bitwise_xor(convert(_coin, uint256), convert(swappable_coin, uint256))
        length = self.market_counts[key]
        self.markets[key][length] = pool
        self.market_counts[key] = length + 1
        if is_finished:
            break

    log MetaPoolDeployed(_coin, _base_pool, _A, _fee, msg.sender)
    return pool


@external
def deploy_gauge(_pool: address) -> address:
    """
    @notice Deploy a liquidity gauge for a factory pool
    @param _pool Factory pool address to deploy a gauge for
    @return Address of the deployed gauge
    """
    assert self.pool_data[_pool].coins[0] != ZERO_ADDRESS, "Unknown pool"
    assert self.pool_data[_pool].liquidity_gauge == ZERO_ADDRESS, "Gauge already deployed"
    implementation: address = self.gauge_implementation
    assert implementation != ZERO_ADDRESS, "Gauge implementation not set"

    gauge: address = create_forwarder_to(implementation)
    LiquidityGauge(gauge).initialize(_pool)
    self.pool_data[_pool].liquidity_gauge = gauge

    log LiquidityGaugeDeployed(_pool, gauge)
    return gauge


# <--- Admin / Guarded Functionality --->

@external
def add_base_pool(
    _base_pool: address,
    _fee_receiver: address,
    _asset_type: uint256,
    _implementations: address[10],
):
    """
    @notice Add a base pool to the registry, which may be used in factory metapools
    @dev Only callable by admin
    @param _base_pool Pool address to add
    @param _fee_receiver Admin fee receiver address for metapools using this base pool
    @param _asset_type Asset type for pool, as an integer  0 = USD, 1 = ETH, 2 = BTC, 3 = Other
    @param _implementations List of implementation addresses that can be used with this base pool
    """
    assert msg.sender == self.admin  # dev: admin-only function
    assert self.base_pool_data[_base_pool].coins[0] == ZERO_ADDRESS  # dev: pool exists

    registry: address = AddressProvider(ADDRESS_PROVIDER).get_registry()
    n_coins: uint256 = Registry(registry).get_n_coins(_base_pool)

    # add pool to pool_list
    length: uint256 = self.base_pool_count
    self.base_pool_list[length] = _base_pool
    self.base_pool_count = length + 1
    self.base_pool_data[_base_pool].lp_token = Registry(registry).get_lp_token(_base_pool)
    self.base_pool_data[_base_pool].n_coins = n_coins
    self.base_pool_data[_base_pool].fee_receiver = _fee_receiver
    if _asset_type != 0:
        self.base_pool_data[_base_pool].asset_type = _asset_type

    for i in range(10):
        implementation: address = _implementations[i]
        if implementation == ZERO_ADDRESS:
            break
        self.base_pool_data[_base_pool].implementations[i] = implementation

    decimals: uint256 = 0
    coins: address[MAX_COINS] = Registry(registry).get_coins(_base_pool)
    for i in range(MAX_COINS):
        if i == n_coins:
            break
        coin: address = coins[i]
        self.base_pool_data[_base_pool].coins[i] = coin
        self.base_pool_assets[coin] = True
        decimals += shift(ERC20(coin).decimals(), convert(i*8, int128))
    self.base_pool_data[_base_pool].decimals = decimals

    log BasePoolAdded(_base_pool)


@external
def set_metapool_implementations(
    _base_pool: address,
    _implementations: address[10],
):
    """
    @notice Set implementation contracts for a metapool
    @dev Only callable by admin
    @param _base_pool Pool address to add
    @param _implementations Implementation address to use when deploying metapools
    """
    assert msg.sender == self.admin  # dev: admin-only function
    assert self.base_pool_data[_base_pool].coins[0] != ZERO_ADDRESS  # dev: base pool does not exist

    for i in range(10):
        new_imp: address = _implementations[i]
        current_imp: address = self.base_pool_data[_base_pool].implementations[i]
        if new_imp == current_imp:
            if new_imp == ZERO_ADDRESS:
                break
        else:
            self.base_pool_data[_base_pool].implementations[i] = new_imp


@external
def set_plain_implementations(
    _n_coins: uint256,
    _implementations: address[10],
):
    assert msg.sender == self.admin  # dev: admin-only function

    for i in range(10):
        new_imp: address = _implementations[i]
        current_imp: address = self.plain_implementations[_n_coins][i]
        if new_imp == current_imp:
            if new_imp == ZERO_ADDRESS:
                break
        else:
            self.plain_implementations[_n_coins][i] = new_imp


@external
def set_gauge_implementation(_gauge_implementation: address):
    assert msg.sender == self.admin  # dev: admin-only function

    self.gauge_implementation = _gauge_implementation


@external
def batch_set_pool_asset_type(_pools: address[32], _asset_types: uint256[32]):
    """
    @notice Batch set the asset type for factory pools
    @dev Used to modify asset types that were set incorrectly at deployment
    """
    assert msg.sender in [self.manager, self.admin]  # dev: admin-only function

    for i in range(32):
        if _pools[i] == ZERO_ADDRESS:
            break
        self.pool_data[_pools[i]].asset_type = _asset_types[i]


@external
def commit_transfer_ownership(_addr: address):
    """
    @notice Transfer ownership of this contract to `addr`
    @param _addr Address of the new owner
    """
    assert msg.sender == self.admin  # dev: admin only

    self.future_admin = _addr


@external
def accept_transfer_ownership():
    """
    @notice Accept a pending ownership transfer
    @dev Only callable by the new owner
    """
    _admin: address = self.future_admin
    assert msg.sender == _admin  # dev: future admin only

    self.admin = _admin
    self.future_admin = ZERO_ADDRESS


@external
def set_manager(_manager: address):
    """
    @notice Set the manager
    @dev Callable by the admin or existing manager
    @param _manager Manager address
    """
    assert msg.sender in [self.manager, self.admin]  # dev: admin-only function

    self.manager = _manager


@external
def set_fee_receiver(_base_pool: address, _fee_receiver: address):
    """
    @notice Set fee receiver for base and plain pools
    @param _base_pool Address of base pool to set fee receiver for.
                      For plain pools, leave as `ZERO_ADDRESS`.
    @param _fee_receiver Address that fees are sent to
    """
    assert msg.sender == self.admin  # dev: admin only
    if _base_pool == ZERO_ADDRESS:
        self.fee_receiver = _fee_receiver
    else:
        self.base_pool_data[_base_pool].fee_receiver = _fee_receiver


@external
def convert_metapool_fees() -> bool:
    """
    @notice Convert the fees of a metapool and transfer to
            the metapool's fee receiver
    @dev All fees are converted to LP token of base pool
    """
    base_pool: address = self.pool_data[msg.sender].base_pool
    assert base_pool != ZERO_ADDRESS  # dev: sender must be metapool
    coin: address = self.pool_data[msg.sender].coins[0]

    amount: uint256 = ERC20(coin).balanceOf(self)
    receiver: address = self.base_pool_data[base_pool].fee_receiver

    CurvePool(msg.sender).exchange(0, 1, amount, 0, receiver)
    return True


# <--- Pool Migration --->

@external
def add_existing_metapools(_pools: address[10]) -> bool:
    """
    @notice Add existing metapools from the old factory
    @dev Base pools that are used by the pools to be added must
         be added separately with `add_base_pool`
    @param _pools Addresses of existing pools to add
    """

    length: uint256 = self.pool_count
    for pool in _pools:
        if pool == ZERO_ADDRESS:
            break

        assert self.pool_data[pool].coins[0] == ZERO_ADDRESS  # dev: pool already exists

        coins: address[2] = OldFactory(OLD_FACTORY).get_coins(pool)
        assert coins[0] != ZERO_ADDRESS # dev: pool not in old factory

        # add pool to pool list
        self.pool_list[length] = pool
        length += 1

        base_pool: address = ZERO_ADDRESS
        implementation: address = ZERO_ADDRESS

        if coins[1] == 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490:
            # 3pool
            base_pool = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7
            implementation = 0x5F890841f657d90E081bAbdB532A05996Af79Fe6
        elif coins[1] == 0x075b1bb99792c9E1041bA13afEf80C91a1e70fB3:
            # sbtc
            base_pool = 0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714
            implementation = 0x2f956eEe002B0dEbD468CF2E0490d1aEc65e027F
            self.pool_data[pool].asset_type = 2
        else:
            raise

        # update pool data
        self.pool_data[pool].decimals[0] = ERC20(coins[0]).decimals()
        self.pool_data[pool].base_pool = base_pool
        meta_coin: address = CurveFactoryMetapool(pool).coins(0)
        self.pool_data[pool].coins[0] = coins[0]
        self.pool_data[pool].coins[1] = coins[1]
        self.pool_data[pool].implementation = implementation

        base_pool_coins: address[MAX_COINS] = self.base_pool_data[base_pool].coins
        assert base_pool_coins[0] != ZERO_ADDRESS # dev: unknown base pool

        is_finished: bool = False
        for i in range(MAX_COINS):
            swappable_coin: address = base_pool_coins[i]
            if swappable_coin == ZERO_ADDRESS:
                is_finished = True
                swappable_coin = coins[1]

            key: uint256 = bitwise_xor(convert(meta_coin, uint256), convert(swappable_coin, uint256))
            market_idx: uint256 = self.market_counts[key]
            self.markets[key][market_idx] = pool
            self.market_counts[key] = market_idx + 1
            if is_finished:
                break

    self.pool_count = length
    return True
        

Contract ABI

[{"type":"event","name":"BasePoolAdded","inputs":[{"type":"address","name":"base_pool","indexed":false}],"anonymous":false},{"type":"event","name":"PlainPoolDeployed","inputs":[{"type":"address[4]","name":"coins","indexed":false},{"type":"uint256","name":"A","indexed":false},{"type":"uint256","name":"fee","indexed":false},{"type":"address","name":"deployer","indexed":false}],"anonymous":false},{"type":"event","name":"MetaPoolDeployed","inputs":[{"type":"address","name":"coin","indexed":false},{"type":"address","name":"base_pool","indexed":false},{"type":"uint256","name":"A","indexed":false},{"type":"uint256","name":"fee","indexed":false},{"type":"address","name":"deployer","indexed":false}],"anonymous":false},{"type":"event","name":"LiquidityGaugeDeployed","inputs":[{"type":"address","name":"pool","indexed":false},{"type":"address","name":"gauge","indexed":false}],"anonymous":false},{"type":"constructor","stateMutability":"nonpayable","outputs":[],"inputs":[{"type":"address","name":"_fee_receiver"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[10]","name":""}],"name":"metapool_implementations","inputs":[{"type":"address","name":"_base_pool"}],"gas":21716},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"find_pool_for_coins","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"find_pool_for_coins","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"i"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"get_base_pool","inputs":[{"type":"address","name":"_pool"}],"gas":2663},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"get_n_coins","inputs":[{"type":"address","name":"_pool"}],"gas":2699},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"get_meta_n_coins","inputs":[{"type":"address","name":"_pool"}],"gas":5201},{"type":"function","stateMutability":"view","outputs":[{"type":"address[4]","name":""}],"name":"get_coins","inputs":[{"type":"address","name":"_pool"}],"gas":9164},{"type":"function","stateMutability":"view","outputs":[{"type":"address[8]","name":""}],"name":"get_underlying_coins","inputs":[{"type":"address","name":"_pool"}],"gas":21345},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[4]","name":""}],"name":"get_decimals","inputs":[{"type":"address","name":"_pool"}],"gas":20185},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[8]","name":""}],"name":"get_underlying_decimals","inputs":[{"type":"address","name":"_pool"}],"gas":19730},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[2]","name":""}],"name":"get_metapool_rates","inputs":[{"type":"address","name":"_pool"}],"gas":5281},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[4]","name":""}],"name":"get_balances","inputs":[{"type":"address","name":"_pool"}],"gas":20435},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[8]","name":""}],"name":"get_underlying_balances","inputs":[{"type":"address","name":"_pool"}],"gas":39733},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"get_A","inputs":[{"type":"address","name":"_pool"}],"gas":3135},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"get_fees","inputs":[{"type":"address","name":"_pool"}],"gas":5821},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[4]","name":""}],"name":"get_admin_balances","inputs":[{"type":"address","name":"_pool"}],"gas":13535},{"type":"function","stateMutability":"view","outputs":[{"type":"int128","name":""},{"type":"int128","name":""},{"type":"bool","name":""}],"name":"get_coin_indices","inputs":[{"type":"address","name":"_pool"},{"type":"address","name":"_from"},{"type":"address","name":"_to"}],"gas":33407},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"get_gauge","inputs":[{"type":"address","name":"_pool"}],"gas":3089},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"get_implementation_address","inputs":[{"type":"address","name":"_pool"}],"gas":3119},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":""}],"name":"is_meta","inputs":[{"type":"address","name":"_pool"}],"gas":3152},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"get_pool_asset_type","inputs":[{"type":"address","name":"_pool"}],"gas":5450},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"get_fee_receiver","inputs":[{"type":"address","name":"_pool"}],"gas":5480},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_plain_pool","inputs":[{"type":"string","name":"_name"},{"type":"string","name":"_symbol"},{"type":"address[4]","name":"_coins"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_plain_pool","inputs":[{"type":"string","name":"_name"},{"type":"string","name":"_symbol"},{"type":"address[4]","name":"_coins"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"},{"type":"uint256","name":"_asset_type"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_plain_pool","inputs":[{"type":"string","name":"_name"},{"type":"string","name":"_symbol"},{"type":"address[4]","name":"_coins"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"},{"type":"uint256","name":"_asset_type"},{"type":"uint256","name":"_implementation_idx"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_metapool","inputs":[{"type":"address","name":"_base_pool"},{"type":"string","name":"_name"},{"type":"string","name":"_symbol"},{"type":"address","name":"_coin"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_metapool","inputs":[{"type":"address","name":"_base_pool"},{"type":"string","name":"_name"},{"type":"string","name":"_symbol"},{"type":"address","name":"_coin"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"},{"type":"uint256","name":"_implementation_idx"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_gauge","inputs":[{"type":"address","name":"_pool"}],"gas":93079},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"add_base_pool","inputs":[{"type":"address","name":"_base_pool"},{"type":"address","name":"_fee_receiver"},{"type":"uint256","name":"_asset_type"},{"type":"address[10]","name":"_implementations"}],"gas":1206132},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_metapool_implementations","inputs":[{"type":"address","name":"_base_pool"},{"type":"address[10]","name":"_implementations"}],"gas":382072},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_plain_implementations","inputs":[{"type":"uint256","name":"_n_coins"},{"type":"address[10]","name":"_implementations"}],"gas":379687},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_gauge_implementation","inputs":[{"type":"address","name":"_gauge_implementation"}],"gas":38355},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"batch_set_pool_asset_type","inputs":[{"type":"address[32]","name":"_pools"},{"type":"uint256[32]","name":"_asset_types"}],"gas":1139545},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"commit_transfer_ownership","inputs":[{"type":"address","name":"_addr"}],"gas":38415},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"accept_transfer_ownership","inputs":[],"gas":58366},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_manager","inputs":[{"type":"address","name":"_manager"}],"gas":40996},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_fee_receiver","inputs":[{"type":"address","name":"_base_pool"},{"type":"address","name":"_fee_receiver"}],"gas":38770},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":""}],"name":"convert_metapool_fees","inputs":[],"gas":12880},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":""}],"name":"add_existing_metapools","inputs":[{"type":"address[10]","name":"_pools"}],"gas":8610792},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"admin","inputs":[],"gas":3438},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"future_admin","inputs":[],"gas":3468},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"manager","inputs":[],"gas":3498},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"pool_list","inputs":[{"type":"uint256","name":"arg0"}],"gas":3573},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"pool_count","inputs":[],"gas":3558},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"base_pool_list","inputs":[{"type":"uint256","name":"arg0"}],"gas":3633},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"base_pool_count","inputs":[],"gas":3618},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":""}],"name":"base_pool_assets","inputs":[{"type":"address","name":"arg0"}],"gas":3863},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"plain_implementations","inputs":[{"type":"uint256","name":"arg0"},{"type":"uint256","name":"arg1"}],"gas":3838},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"gauge_implementation","inputs":[],"gas":3708}]
              

Contract Creation Code

Verify & Publish
0x6f7fffffffffffffffffffffffffffffff604052602061323e61014039602061323e60c03960c05160a01c613239573360005533600255610140516402000000095561322156600436101561000d576131d0565b600035601c526f7fffffffffffffffffffffffffffffff604052600051346131d65763970fa3f38114156100b95760043560a01c6131d65764020000000660043560e05260c052604060c02080546101605260018101546101805260028101546101a05260038101546101c05260048101546101e05260058101546102005260068101546102205260078101546102405260088101546102605260098101546102805250610140610160f35b63a87df06c8114156100d0576000610140526100f1565b636982eb0b8114156100ec5760206044610140376000506100f1565b610144565b60043560a01c6131d65760243560a01c6131d65760243560043518610160526001610140516401000000008110156131d6570264020000000b6101605160e05260c052604060c020015460005260206000f35b636f20d6dd8114156101785760043560a01c6131d65764010000000460043560e05260c052604060c0205460005260206000f35b63940494f18114156101af5760043560a01c6131d657600b64010000000460043560e05260c052604060c020015460005260206000f35b63eb73f37d81141561021d5760043560a01c6131d65764010000000460043560e05260c052604060c02054610140526101a06002815260156402000000066101405160e05260c052604060c0200154600181818301106131d6578082019050905081602001525060406101a0f35b639ac90d3d8114156102735760043560a01c6131d657600364010000000460043560e05260c052604060c0200180546101605260018101546101805260028101546101a05260038101546101c052506080610160f35b63a77576ef8114156103665760043560a01c6131d657610100366101403764010000000460043560e05260c052604060c020546102405260006102405118156131d657600364010000000460043560e05260c052604060c02001546101405261026060016007818352015b60016102605160018082106131d6578082039050905060088110156131d65702600c6402000000066102405160e05260c052604060c0200101546101406102605160088110156131d65760200201526101406102605160088110156131d657602002015161034b5761035c565b5b81516001018083528114156102de575b5050610100610140f35b6352b515558114156104265760043560a01c6131d657600064010000000460043560e05260c052604060c0205418156103e65760803661014037600764010000000460043560e05260c052604060c0200180546101405260018101546101605260028101546101805260038101546101a052506012610160526080610140f35b600764010000000460043560e05260c052604060c0200180546101605260018101546101805260028101546101a05260038101546101c052506080610160f35b634cb088f181141561058b5760043560a01c6131d65760803661014037600764010000000460043560e05260c052604060c0200180546101405260018101546101605260028101546101805260038101546101a05250610100366101c037610140516101c05264010000000460043560e05260c052604060c020546102c05260146402000000066102c05160e05260c052604060c02001546102e05261030060006008818352015b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8610300518082028215828483051417156131d657809050905090506000811215610521576102e051816000031c610528565b6102e051811b5b905061010080820690509050610320526103205161054557610581565b610320516101c061030051600181818301126131d6578082019050905060088110156131d65760200201525b81516001018083528114156104ce575b50506101006101c0f35b6306d8f1608114156105fe5760043560a01c6131d657670de0b6b3a76400006101405260006101605260206101e0600463bb7b8b806101805261019c64010000000460043560e05260c052604060c020545afa156131d657601f3d11156131d6576000506101e051610160526040610140f35b6392e3cc2d8114156107805760043560a01c6131d657600064010000000460043560e05260c052604060c0205418156106c25760206101c06024634903b0d16101405260006101605261015c6004355afa156131d657601f3d11156131d6576000506101c0516101e05260206102806024634903b0d16102005260016102205261021c6004355afa156131d657601f3d11156131d657600050610280516102a0526101e0516102e0526102a0516103005260006103205260006103405260806102e0f35b600b64010000000460043560e05260c052604060c020015461014052608036610160376101e060006004818352015b610140516101e051101561074e5760206102806024634903b0d1610200526101e0516102205261021c6004355afa156131d657601f3d11156131d657600050610280516101606101e05160048110156131d6576020020152610766565b60006101606101e05160048110156131d65760200201525b5b81516001018083528114156106f1575b50506080610160f35b6359f4f3518114156109a55760043560a01c6131d657610100366101403760206102c06024634903b0d16102405260006102605261025c6004355afa156131d657601f3d11156131d6576000506102c0516101405260206102c060046318160ddd6102605261027c6001600364010000000460043560e05260c052604060c0200101545afa156131d657601f3d11156131d6576000506102c05161024052600061024051111561099d5760206103006024634903b0d16102805260016102a05261029c6004355afa156131d657601f3d11156131d657600050610300516ec097ce7bc90715b34b9f10000000008082028215828483041417156131d65780905090509050610240518080156131d6578204905090506102605264010000000460043560e05260c052604060c020546102805260006102805118156131d65760156402000000066102805160e05260c052604060c02001546102a0526102c060006008818352015b6102a0516102c05114156108fa5761099a565b60206103606024634903b0d16102e0526102c051610300526102fc610280515afa156131d657601f3d11156131d65760005061036051610260518082028215828483041417156131d657809050905090506ec097ce7bc90715b34b9f1000000000808204905090506101406102c051600181818301106131d6578082019050905060088110156131d65760200201525b81516001018083528114156108e7575b50505b610100610140f35b6355b30b198114156109f15760043560a01c6131d65760206101a0600463f446c1d06101405261015c6004355afa156131d657601f3d11156131d6576000506101a05160005260206000f35b637cdb72b0811415610a985760043560a01c6131d65760206101a0600463ddca3f436101405261015c6004355afa156131d657601f3d11156131d6576000506101a0516101c0526020610240600463fee3f7f96101e0526101fc6004355afa156131d657601f3d11156131d65760005061024051610260526102808080806101c051815250506020810190508080610260518152505060409050905060c05260c051610280f35b63c11e45b8811415610b545760043560a01c6131d657600b64010000000460043560e05260c052604060c020015461014052608036610160376101e060006004818352015b610140516101e0511415610af057610b4b565b6020610280602463e2e7d264610200526101e0516102205261021c6004355afa156131d657601f3d11156131d657600050610280516101606101e05160048110156131d65760200201525b8151600101808352811415610add575b50506080610160f35b63eb85226d811415610ecf5760043560a01c6131d65760243560a01c6131d65760443560a01c6131d657600364010000000460043560e05260c052604060c02001546101405264010000000460043560e05260c052604060c0205461016052602435610200526044356102205260006101e0526101e061012060006002818352015b610120516020026102000151610140511415610bf55760018352610c06565b5b8151600101808352811415610bd6575b5050506101e05115610c1f576000610160511415610c22565b60005b15610cfb576001600364010000000460043560e05260c052604060c02001015461024052602435610280526044356102a05260006102605261026061012060006002818352015b610120516020026102800151610240511415610c885760018352610c99565b5b8151600101808352811415610c69575b5050506102605115610cfa5761014051604435146102c05261014051602435146102e0526103008080806102c0518152505060208101905080806102e05181525050602081019050808060008152505060609050905060c05260c051610300f35b5b606036610180376101e060006008818352015b61016051610da55760046101e05112610d66576308c379a06103605260206103805260136103a0527f4e6f20617661696c61626c65206d61726b6574000000000000000000000000006103c0526103a050606461037cfd5b60006101e0511815610da05760016101e05160048110156131d65702600364010000000460043560e05260c052604060c020010154610140525b610e00565b60006101e0511815610dff5760016101e051600180820380806000811215610dc957195b607f1c6131d65790509050905060088110156131d65702600c6402000000066101605160e05260c052604060c020010154610140525b5b61014051610e4d576308c379a06103605260206103805260136103a0527f4e6f20617661696c61626c65206d61726b6574000000000000000000000000006103c0526103a050606461037cfd5b602435610140511415610e67576101e0516101a052610e87565b604435610140511415610e81576101e0516101c052610e86565b610e9c565b5b6101805115610e9557610eac565b6001610180525b8151600101808352811415610d0e575b50506103c06101a05181526101c0518160200152600181604001525060606103c0f35b63daf297b9811415610f065760043560a01c6131d657600264010000000460043560e05260c052604060c020015460005260206000f35b63510d98a4811415610f3d5760043560a01c6131d657600164010000000460043560e05260c052604060c020015460005260206000f35b63e4d332a9811415610f755760043560a01c6131d657600064010000000460043560e05260c052604060c02054141560005260206000f35b6366d3966c811415610ff55760043560a01c6131d65764010000000460043560e05260c052604060c020546101405261014051610fd157600c64010000000460043560e05260c052604060c020015460005260206000f3610ff3565b60166402000000066101405160e05260c052604060c020015460005260206000f35b005b63154aa8f58114156110645760043560a01c6131d65764010000000460043560e05260c052604060c020546101405261014051611040576402000000095460005260206000f3611062565b600b6402000000066101405160e05260c052604060c020015460005260206000f35b005b63cd419bb5811415611081576000610200526000610220526110cf565b635c16487b8114156110a4576000610220526020610104610200376000506110cf565b6352f2db698114156110ca576020610104610200376020610124610220376000506110cf565b611a13565b604060043560040161014037602060043560040135116131d657602a6024356004016101a037600a60243560040135116131d65760443560a01c6131d65760643560a01c6131d65760843560a01c6131d65760a43560a01c6131d657623d090060e43510611146576305f5e10060e4351115611149565b60005b611192576308c379a061024052602061026052600b610280527f496e76616c6964206665650000000000000000000000000000000000000000006102a05261028050606461025cfd5b600461024052610100366102603761036060006004818352015b60446103605160048110156131d65760200201356103805261038051611229576001610360511161121c576308c379a06103a05260206103c05260126103e0527f496e73756666696369656e7420636f696e730000000000000000000000000000610400526103e05060646103bcfd5b6103605161024052611519565b6402000000076103805160e05260c052604060c0205415611289576308c379a06103a05260206103c05260206103e0527f496e76616c69642061737365742c206465706c6f792061206d657461706f6f6c610400526103e05060646103bcfd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60446103605160048110156131d65760200201351415611311576103605115611306576308c379a06103a05260206103c05260166103e0527f455448206d75737420626520666972737420636f696e00000000000000000000610400526103e05060646103bcfd5b60126102e0526113b6565b6020610400600463313ce5676103a0526103bc610380515afa156131d657601f3d11156131d657600050610400516102e06103605160048110156131d657602002015260136102e06103605160048110156131d6576020020151106113b5576308c379a06103a05260206103c05260196103e0527f4d617820313820646563696d616c7320666f7220636f696e7300000000000000610400526103e05060646103bcfd5b5b604e60246102e06103605160048110156131d65760200201518082106131d6578082039050905010156131d65760246102e06103605160048110156131d65760200201518082106131d65780820390509050600a0a6102606103605160048110156131d65760200201526103a0610360516004818352015b60046103a051600181818301106131d65780820190509050141561145157611506565b60446103a051600181818301106131d6578082019050905060048110156131d657602002013561148057611506565b60446103a051600181818301106131d6578082019050905060048110156131d65760200201356103805114156114f5576308c379a06103c05260206103e052600f610400527f4475706c696361746520636f696e730000000000000000000000000000000000610420526104005060646103dcfd5b5b815160010180835281141561142e575b50505b81516001018083528114156111ac575b5050600161022051600a8110156131d657026402000000086102405160e05260c052604060c0200154610360526000610360511415611597576308c379a06103805260206103a052601c6103c0527f496e76616c696420696d706c656d656e746174696f6e20696e646578000000006103e0526103c050606461039cfd5b7f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006103a0526103605160601b6103b3527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006103c75260366103a06000f061038052610380513b156131d6576000600061020461018063a461b3c86103a052806103c05261014080805160200180846103c0018284600060045af1156131d65750508051820160206001820306601f8201039050602001915050806103e0526101a080805160200180846103c0018284600060045af1156131d6575050506044803561040052806020013561042052806040013561044052806060013561046052506102605161048052610280516104a0526102a0516104c0526102c0516104e052604060c4610500376103bc90506000610380515af1156131d657640100000003546103a0526103805160016103a0516401000000008110156131d65702600301556103a051600181818301106131d657808201905090506401000000035560076401000000046103805160e05260c052604060c020016102e05181556103005160018201556103205160028201556103405160038201555061024051600b6401000000046103805160e05260c052604060c020015560006401000000046103805160e05260c052604060c020556103605160016401000000046103805160e05260c052604060c020015560006102005118156117cc5761020051600c6401000000046103805160e05260c052604060c02001555b6103c060006004818352015b60446103c05160048110156131d65760200201356103e0526103e0516117fd576119d0565b6103e05160016103c05160048110156131d6570260036401000000046103805160e05260c052604060c02001015560006004610400527f095ea7b3000000000000000000000000000000000000000000000000000000006104205261040060048060208461046001018260208501600060045af1505080518201915050610380516020826104600101526020810190507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602082610460010152602081019050806104605261046090508051602001806105008284600060045af1156131d6575050600060006105005161052060006103e0515af1156131d65761040060006004818352015b610400516103c05110156119ac5760446104005160048110156131d657602002013561042052610420516103e051186104405264020000000c6104405160e05260c052604060c020546103a0526103805160016103a0516401000000008110156131d6570264020000000b6104405160e05260c052604060c02001556103a051600181818301106131d6578082019050905064020000000c6104405160e05260c052604060c020555b5b8151600101808352811415611903575b50505b81516001018083528114156117d8575b505060c060446103c03733610480527f5b4a28c940282b5bf183df6a046b8119cf6edeb62859f75e835eb7ba834cce8d60e06103c0a16103805160005260206000f35b63e339eb4f811415611a2a57600061020052611a4b565b63de7fe3bf811415611a4657602060c461020037600050611a4b565b611ffa565b60043560a01c6131d657604060243560040161014037602060243560040135116131d657602a6044356004016101a037600a60443560040135116131d65760643560a01c6131d657623d090060a43510611aae576305f5e10060a4351115611ab1565b60005b611afa576308c379a061022052602061024052600b610260527f496e76616c6964206665650000000000000000000000000000000000000000006102805261026050606461023cfd5b600161020051600a8110156131d6570264020000000660043560e05260c052604060c0200154610220526000610220511415611b75576308c379a061024052602061026052601c610280527f496e76616c696420696d706c656d656e746174696f6e20696e646578000000006102a05261028050606461025cfd5b60206102c0600463313ce5676102605261027c6064355afa156131d657601f3d11156131d6576000506102c0516102405260136102405110611bf6576308c379a06102605260206102805260196102a0527f4d617820313820646563696d616c7320666f7220636f696e73000000000000006102c0526102a050606461027cfd5b7f602d3d8160093d39f3363d3d373d3d3d363d7300000000000000000000000000610280526102205160601b610293527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006102a75260366102806000f061026052610260513b156131d6576000600061014460c06398094be061028052806102a05261014080805160200180846102a0018284600060045af1156131d65750508051820160206001820306601f8201039050602001915050806102c0526101a080805160200180846102a0018284600060045af1156131d6575050506064356102e052604e6024610240518082106131d6578082039050905010156131d6576024610240518082106131d65780820390509050600a0a61030052604060846103203761029c90506000610260515af1156131d6576064353b156131d65760006000604463095ea7b361028052610260516102a0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102c05261029c60006064355af1156131d6576401000000035461028052610260516001610280516401000000008110156131d657026003015561028051600181818301106131d6578082019050905064010000000355600a64020000000660043560e05260c052604060c02001546102a05260076401000000046102605160e05260c052604060c02001610240518155600060018201556000600282015560006003820155506002600b6401000000046102605160e05260c052604060c02001556004356401000000046102605160e05260c052604060c0205560643560036401000000046102605160e05260c052604060c0200155600a64020000000660043560e05260c052604060c0200154600160036401000000046102605160e05260c052604060c0200101556102205160016401000000046102605160e05260c052604060c020015560006102c0526102e060006008818352015b60016102e05160088110156131d65702600c64020000000660043560e05260c052604060c0200101546103005261030051611f095760016102c0526102a051610300525b61030051606435186103205264020000000c6103205160e05260c052604060c0205461028052610260516001610280516401000000008110156131d6570264020000000b6103205160e05260c052604060c020015561028051600181818301106131d6578082019050905064020000000c6103205160e05260c052604060c020556102c05115611f9857611fa9565b5b8151600101808352811415611ec5575b50506064356102e05260043561030052604060846103203733610360527f01f31cd2abdeb4e5e10ba500f2db0f937d9e8c735ab04681925441b4ea37eda560a06102e0a16102605160005260206000f35b6396bebb348114156122235760043560a01c6131d6576000600364010000000460043560e05260c052604060c02001541415612075576308c379a061014052602061016052600c610180527f556e6b6e6f776e20706f6f6c00000000000000000000000000000000000000006101a05261018050606461015cfd5b600264010000000460043560e05260c052604060c0200154156120d7576308c379a0610140526020610160526016610180527f476175676520616c7265616479206465706c6f796564000000000000000000006101a05261018050606461015cfd5b64020000000a54610140526000610140511415612133576308c379a061016052602061018052601c6101a0527f476175676520696d706c656d656e746174696f6e206e6f7420736574000000006101c0526101a050606461017cfd5b7f602d3d8160093d39f3363d3d373d3d3d363d7300000000000000000000000000610180526101405160601b610193527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006101a75260366101806000f061016052610160513b156131d65760006000602463c4d66de8610180526004356101a05261019c6000610160515af1156131d65761016051600264010000000460043560e05260c052604060c020015560043561018052610160516101a0527f656bb34c20491970a8c163f3bd62ead82022b379c3924960ec60f6dbfc5aab3b6040610180a16101605160005260206000f35b632fc056538114156126835760043560a01c6131d65760243560a01c6131d6576000610120525b610120516064013560a01c6131d65760206101205101610120526101406101205110156122765761224a565b6000543314156131d657600c64020000000660043560e05260c052604060c02001546131d65760206101c0600463a262904b6101605261017c6f22d53366457f9d5e68ec105046fc43835afa156131d657601f3d11156131d6576000506101c051610140526020610200602463940494f1610180526004356101a05261019c610140515afa156131d657601f3d11156131d657600050610200516101605264020000000554610180526004356001610180516401000000008110156131d65702640100000005015561018051600181818301106131d65780820190509050640200000005556020610220602463379510496101a0526004356101c0526101bc610140515afa156131d657601f3d11156131d65760005061022051600a64020000000660043560e05260c052604060c020015561016051601564020000000660043560e05260c052604060c0200155602435600b64020000000660043560e05260c052604060c02001556000604435181561240657604435601664020000000660043560e05260c052604060c02001555b6101a06000600a818352015b60646101a051600a8110156131d65760200201356101c0526101c05161243757612472565b6101c05160016101a051600a8110156131d6570264020000000660043560e05260c052604060c02001555b8151600101808352811415612412575b505060006101a0526101006103406024639ac90d3d6102c0526004356102e0526102dc610140515afa156131d65760ff3d11156131d65760005061034080516101c05280602001516101e0528060400151610200528060600151610220528060800151610240528060a00151610260528060c00151610280528060e001516102a052506102c060006008818352015b610160516102c051141561251457612635565b6101c06102c05160088110156131d65760200201516102e0526102e05160016102c05160088110156131d65702600c64020000000660043560e05260c052604060c02001015560016402000000076102e05160e05260c052604060c020556101a080516102c05160088082028215828483041417156131d6578090509050905060405181116131d65760008112156125de576020610360600463313ce5676103005261031c6102e0515afa156131d657601f3d11156131d65760005061036051816000031c61260f565b6020610360600463313ce5676103005261031c6102e0515afa156131d657601f3d11156131d65760005061036051811b5b905081818301106131d657808201905090508152505b8151600101808352811415612501575b50506101a051601464020000000660043560e05260c052604060c02001556004356102c0527fcc6afdfec79da6be08142ecee25cf14b665961e25d30d8eba45959be9547635f60206102c0a1005b63cb956b468114156127a45760043560a01c6131d6576000610120525b610120516024013560a01c6131d65760206101205101610120526101406101205110156126cc576126a0565b6000543314156131d6576000600c64020000000660043560e05260c052604060c020015418156131d6576101406000600a818352015b602461014051600a8110156131d657602002013561016052600161014051600a8110156131d6570264020000000660043560e05260c052604060c02001546101805261018051610160511415612764576101605161275f576127a0565b61278f565b61016051600161014051600a8110156131d6570264020000000660043560e05260c052604060c02001555b5b8151600101808352811415612702575b5050005b639ddbf4b981141561289b576000610120525b610120516024013560a01c6131d65760206101205101610120526101406101205110156127e3576127b7565b6000543314156131d6576101406000600a818352015b602461014051600a8110156131d657602002013561016052600161014051600a8110156131d6570264020000000860043560e05260c052604060c0200154610180526101805161016051141561285b576101605161285657612897565b612886565b61016051600161014051600a8110156131d6570264020000000860043560e05260c052604060c02001555b5b81516001018083528114156127f9575b5050005b638f03182c8114156128c75760043560a01c6131d6576000543314156131d65760043564020000000a55005b637542f0788114156129de576000610120525b610120516004013560a01c6131d6576020610120510161012052610400610120511015612906576128da565b600254610160526000546101805260006101405261014061012060006002818352015b6101205160200261016001513314156129455760018352612956565b5b8151600101808352811415612929575b50505061014051156131d65761014060006020818352015b60046101405160208110156131d657602002013561298b576129da565b6104046101405160208110156131d6576020020135600c64010000000460046101405160208110156131d657602002013560e05260c052604060c02001555b815160010180835281141561296e575b5050005b636b441a40811415612a065760043560a01c6131d6576000543314156131d657600435600155005b63e5ea47b8811415612a325760015461014052610140513314156131d657610140516000556000600155005b639aece83e811415612aac5760043560a01c6131d657600254610160526000546101805260006101405261014061012060006002818352015b610120516020026101600151331415612a875760018352612a98565b5b8151600101808352811415612a6b575b50505061014051156131d657600435600255005b6336d2b77a811415612b0a5760043560a01c6131d65760243560a01c6131d6576000543314156131d657600435612aec5760243564020000000955612b08565b602435600b64020000000660043560e05260c052604060c02001555b005b63bcc981d2811415612c01576401000000043360e05260c052604060c020546101405260006101405118156131d65760036401000000043360e05260c052604060c020015461016052602061022060246370a082316101a052306101c0526101bc610160515afa156131d657601f3d11156131d6576000506102205161018052600b6402000000066101405160e05260c052604060c02001546101a05260206102c060a463ddc1f59d6101c05260006101e05260016102005261018051610220526000610240526101a051610260526101dc6000335af1156131d657601f3d11156131d6576000506102c050600160005260206000f35b63db89fabc811415613068576000610120525b610120516004013560a01c6131d6576020610120510161012052610140610120511015612c4057612c14565b64010000000354610140526101806000600a818352015b60206101805102600401356101605261016051612c7357613050565b60036401000000046101605160e05260c052604060c02001546131d65760406102606024639ac90d3d6101e05261016051610200526101fc730959158b6040d32d04c301a72cbfd6b39e21c9ae5afa156131d657603f3d11156131d65760005061026080516101a05280602001516101c0525060006101a05118156131d657610160516001610140516401000000008110156131d65702600301556101408051600181818301106131d657808201905090508152506040366101e037736c3f90f043a72fa612cbac8115ee7e52bde6e4906101c0511415612d855773bebc44782c7db0a1a60cb6fe97d0b483032ff1c76101e052735f890841f657d90e081babdb532a05996af79fe661020052612dfd565b73075b1bb99792c9e1041ba13afef80c91a1e70fb36101c0511415612df657737fc77b5c7614e1533320ea6ddc2eb61fa00a97146101e052732f956eee002b0debd468cf2e0490d1aec65e027f610200526002600c6401000000046101605160e05260c052604060c0200155612dfc565b60006000fd5b5b6020610280600463313ce5676102205261023c6101a0515afa156131d657601f3d11156131d6576000506102805160076401000000046101605160e05260c052604060c02001556101e0516401000000046101605160e05260c052604060c0205560206102c0602463c66106576102405260006102605261025c610160515afa156131d657601f3d11156131d6576000506102c051610220526101a05160036401000000046101605160e05260c052604060c02001556101c051600160036401000000046101605160e05260c052604060c0200101556102005160016401000000046101605160e05260c052604060c0200155600c6402000000066101e05160e05260c052604060c0200180546102405260018101546102605260028101546102805260038101546102a05260048101546102c05260058101546102e0526006810154610300526007810154610320525060006102405118156131d65760006103405261036060006008818352015b6102406103605160088110156131d65760200201516103805261038051612f9c576001610340526101c051610380525b6103805161022051186103a05264020000000c6103a05160e05260c052604060c020546103c0526101605160016103c0516401000000008110156131d6570264020000000b6103a05160e05260c052604060c02001556103c051600181818301106131d6578082019050905064020000000c6103a05160e05260c052604060c02055610340511561302c5761303d565b5b8151600101808352811415612f6c575b50505b8151600101808352811415612c57575b50506101405164010000000355600160005260206000f35b63f851a4408114156130805760005460005260206000f35b6317f7182a8114156130985760015460005260206000f35b63481c6a758114156130b05760025460005260206000f35b633a1d5d8e8114156130dc5760016004356401000000008110156131d657026003015460005260206000f35b63956aae3a8114156130f8576401000000035460005260206000f35b6322fe56718114156131285760016004356401000000008110156131d65702640100000005015460005260206000f35b63de5e4a3b811415613144576402000000055460005260206000f35b6310a002df8114156131785760043560a01c6131d65764020000000760043560e05260c052604060c0205460005260206000f35b6331a4f8658114156131b2576001602435600a8110156131d6570264020000000860043560e05260c052604060c020015460005260206000f35b638df242078114156131ce5764020000000a5460005260206000f35b505b60006000fd5b600080fd5b61004661322103610046600039610046613221036000f35b600080fd000000000000000000000000ecb456ea5365865ebab8a2661b0c503410e9b347

Deployed ByteCode

0x600436101561000d576131d0565b600035601c526f7fffffffffffffffffffffffffffffff604052600051346131d65763970fa3f38114156100b95760043560a01c6131d65764020000000660043560e05260c052604060c02080546101605260018101546101805260028101546101a05260038101546101c05260048101546101e05260058101546102005260068101546102205260078101546102405260088101546102605260098101546102805250610140610160f35b63a87df06c8114156100d0576000610140526100f1565b636982eb0b8114156100ec5760206044610140376000506100f1565b610144565b60043560a01c6131d65760243560a01c6131d65760243560043518610160526001610140516401000000008110156131d6570264020000000b6101605160e05260c052604060c020015460005260206000f35b636f20d6dd8114156101785760043560a01c6131d65764010000000460043560e05260c052604060c0205460005260206000f35b63940494f18114156101af5760043560a01c6131d657600b64010000000460043560e05260c052604060c020015460005260206000f35b63eb73f37d81141561021d5760043560a01c6131d65764010000000460043560e05260c052604060c02054610140526101a06002815260156402000000066101405160e05260c052604060c0200154600181818301106131d6578082019050905081602001525060406101a0f35b639ac90d3d8114156102735760043560a01c6131d657600364010000000460043560e05260c052604060c0200180546101605260018101546101805260028101546101a05260038101546101c052506080610160f35b63a77576ef8114156103665760043560a01c6131d657610100366101403764010000000460043560e05260c052604060c020546102405260006102405118156131d657600364010000000460043560e05260c052604060c02001546101405261026060016007818352015b60016102605160018082106131d6578082039050905060088110156131d65702600c6402000000066102405160e05260c052604060c0200101546101406102605160088110156131d65760200201526101406102605160088110156131d657602002015161034b5761035c565b5b81516001018083528114156102de575b5050610100610140f35b6352b515558114156104265760043560a01c6131d657600064010000000460043560e05260c052604060c0205418156103e65760803661014037600764010000000460043560e05260c052604060c0200180546101405260018101546101605260028101546101805260038101546101a052506012610160526080610140f35b600764010000000460043560e05260c052604060c0200180546101605260018101546101805260028101546101a05260038101546101c052506080610160f35b634cb088f181141561058b5760043560a01c6131d65760803661014037600764010000000460043560e05260c052604060c0200180546101405260018101546101605260028101546101805260038101546101a05250610100366101c037610140516101c05264010000000460043560e05260c052604060c020546102c05260146402000000066102c05160e05260c052604060c02001546102e05261030060006008818352015b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8610300518082028215828483051417156131d657809050905090506000811215610521576102e051816000031c610528565b6102e051811b5b905061010080820690509050610320526103205161054557610581565b610320516101c061030051600181818301126131d6578082019050905060088110156131d65760200201525b81516001018083528114156104ce575b50506101006101c0f35b6306d8f1608114156105fe5760043560a01c6131d657670de0b6b3a76400006101405260006101605260206101e0600463bb7b8b806101805261019c64010000000460043560e05260c052604060c020545afa156131d657601f3d11156131d6576000506101e051610160526040610140f35b6392e3cc2d8114156107805760043560a01c6131d657600064010000000460043560e05260c052604060c0205418156106c25760206101c06024634903b0d16101405260006101605261015c6004355afa156131d657601f3d11156131d6576000506101c0516101e05260206102806024634903b0d16102005260016102205261021c6004355afa156131d657601f3d11156131d657600050610280516102a0526101e0516102e0526102a0516103005260006103205260006103405260806102e0f35b600b64010000000460043560e05260c052604060c020015461014052608036610160376101e060006004818352015b610140516101e051101561074e5760206102806024634903b0d1610200526101e0516102205261021c6004355afa156131d657601f3d11156131d657600050610280516101606101e05160048110156131d6576020020152610766565b60006101606101e05160048110156131d65760200201525b5b81516001018083528114156106f1575b50506080610160f35b6359f4f3518114156109a55760043560a01c6131d657610100366101403760206102c06024634903b0d16102405260006102605261025c6004355afa156131d657601f3d11156131d6576000506102c0516101405260206102c060046318160ddd6102605261027c6001600364010000000460043560e05260c052604060c0200101545afa156131d657601f3d11156131d6576000506102c05161024052600061024051111561099d5760206103006024634903b0d16102805260016102a05261029c6004355afa156131d657601f3d11156131d657600050610300516ec097ce7bc90715b34b9f10000000008082028215828483041417156131d65780905090509050610240518080156131d6578204905090506102605264010000000460043560e05260c052604060c020546102805260006102805118156131d65760156402000000066102805160e05260c052604060c02001546102a0526102c060006008818352015b6102a0516102c05114156108fa5761099a565b60206103606024634903b0d16102e0526102c051610300526102fc610280515afa156131d657601f3d11156131d65760005061036051610260518082028215828483041417156131d657809050905090506ec097ce7bc90715b34b9f1000000000808204905090506101406102c051600181818301106131d6578082019050905060088110156131d65760200201525b81516001018083528114156108e7575b50505b610100610140f35b6355b30b198114156109f15760043560a01c6131d65760206101a0600463f446c1d06101405261015c6004355afa156131d657601f3d11156131d6576000506101a05160005260206000f35b637cdb72b0811415610a985760043560a01c6131d65760206101a0600463ddca3f436101405261015c6004355afa156131d657601f3d11156131d6576000506101a0516101c0526020610240600463fee3f7f96101e0526101fc6004355afa156131d657601f3d11156131d65760005061024051610260526102808080806101c051815250506020810190508080610260518152505060409050905060c05260c051610280f35b63c11e45b8811415610b545760043560a01c6131d657600b64010000000460043560e05260c052604060c020015461014052608036610160376101e060006004818352015b610140516101e0511415610af057610b4b565b6020610280602463e2e7d264610200526101e0516102205261021c6004355afa156131d657601f3d11156131d657600050610280516101606101e05160048110156131d65760200201525b8151600101808352811415610add575b50506080610160f35b63eb85226d811415610ecf5760043560a01c6131d65760243560a01c6131d65760443560a01c6131d657600364010000000460043560e05260c052604060c02001546101405264010000000460043560e05260c052604060c0205461016052602435610200526044356102205260006101e0526101e061012060006002818352015b610120516020026102000151610140511415610bf55760018352610c06565b5b8151600101808352811415610bd6575b5050506101e05115610c1f576000610160511415610c22565b60005b15610cfb576001600364010000000460043560e05260c052604060c02001015461024052602435610280526044356102a05260006102605261026061012060006002818352015b610120516020026102800151610240511415610c885760018352610c99565b5b8151600101808352811415610c69575b5050506102605115610cfa5761014051604435146102c05261014051602435146102e0526103008080806102c0518152505060208101905080806102e05181525050602081019050808060008152505060609050905060c05260c051610300f35b5b606036610180376101e060006008818352015b61016051610da55760046101e05112610d66576308c379a06103605260206103805260136103a0527f4e6f20617661696c61626c65206d61726b6574000000000000000000000000006103c0526103a050606461037cfd5b60006101e0511815610da05760016101e05160048110156131d65702600364010000000460043560e05260c052604060c020010154610140525b610e00565b60006101e0511815610dff5760016101e051600180820380806000811215610dc957195b607f1c6131d65790509050905060088110156131d65702600c6402000000066101605160e05260c052604060c020010154610140525b5b61014051610e4d576308c379a06103605260206103805260136103a0527f4e6f20617661696c61626c65206d61726b6574000000000000000000000000006103c0526103a050606461037cfd5b602435610140511415610e67576101e0516101a052610e87565b604435610140511415610e81576101e0516101c052610e86565b610e9c565b5b6101805115610e9557610eac565b6001610180525b8151600101808352811415610d0e575b50506103c06101a05181526101c0518160200152600181604001525060606103c0f35b63daf297b9811415610f065760043560a01c6131d657600264010000000460043560e05260c052604060c020015460005260206000f35b63510d98a4811415610f3d5760043560a01c6131d657600164010000000460043560e05260c052604060c020015460005260206000f35b63e4d332a9811415610f755760043560a01c6131d657600064010000000460043560e05260c052604060c02054141560005260206000f35b6366d3966c811415610ff55760043560a01c6131d65764010000000460043560e05260c052604060c020546101405261014051610fd157600c64010000000460043560e05260c052604060c020015460005260206000f3610ff3565b60166402000000066101405160e05260c052604060c020015460005260206000f35b005b63154aa8f58114156110645760043560a01c6131d65764010000000460043560e05260c052604060c020546101405261014051611040576402000000095460005260206000f3611062565b600b6402000000066101405160e05260c052604060c020015460005260206000f35b005b63cd419bb5811415611081576000610200526000610220526110cf565b635c16487b8114156110a4576000610220526020610104610200376000506110cf565b6352f2db698114156110ca576020610104610200376020610124610220376000506110cf565b611a13565b604060043560040161014037602060043560040135116131d657602a6024356004016101a037600a60243560040135116131d65760443560a01c6131d65760643560a01c6131d65760843560a01c6131d65760a43560a01c6131d657623d090060e43510611146576305f5e10060e4351115611149565b60005b611192576308c379a061024052602061026052600b610280527f496e76616c6964206665650000000000000000000000000000000000000000006102a05261028050606461025cfd5b600461024052610100366102603761036060006004818352015b60446103605160048110156131d65760200201356103805261038051611229576001610360511161121c576308c379a06103a05260206103c05260126103e0527f496e73756666696369656e7420636f696e730000000000000000000000000000610400526103e05060646103bcfd5b6103605161024052611519565b6402000000076103805160e05260c052604060c0205415611289576308c379a06103a05260206103c05260206103e0527f496e76616c69642061737365742c206465706c6f792061206d657461706f6f6c610400526103e05060646103bcfd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60446103605160048110156131d65760200201351415611311576103605115611306576308c379a06103a05260206103c05260166103e0527f455448206d75737420626520666972737420636f696e00000000000000000000610400526103e05060646103bcfd5b60126102e0526113b6565b6020610400600463313ce5676103a0526103bc610380515afa156131d657601f3d11156131d657600050610400516102e06103605160048110156131d657602002015260136102e06103605160048110156131d6576020020151106113b5576308c379a06103a05260206103c05260196103e0527f4d617820313820646563696d616c7320666f7220636f696e7300000000000000610400526103e05060646103bcfd5b5b604e60246102e06103605160048110156131d65760200201518082106131d6578082039050905010156131d65760246102e06103605160048110156131d65760200201518082106131d65780820390509050600a0a6102606103605160048110156131d65760200201526103a0610360516004818352015b60046103a051600181818301106131d65780820190509050141561145157611506565b60446103a051600181818301106131d6578082019050905060048110156131d657602002013561148057611506565b60446103a051600181818301106131d6578082019050905060048110156131d65760200201356103805114156114f5576308c379a06103c05260206103e052600f610400527f4475706c696361746520636f696e730000000000000000000000000000000000610420526104005060646103dcfd5b5b815160010180835281141561142e575b50505b81516001018083528114156111ac575b5050600161022051600a8110156131d657026402000000086102405160e05260c052604060c0200154610360526000610360511415611597576308c379a06103805260206103a052601c6103c0527f496e76616c696420696d706c656d656e746174696f6e20696e646578000000006103e0526103c050606461039cfd5b7f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006103a0526103605160601b6103b3527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006103c75260366103a06000f061038052610380513b156131d6576000600061020461018063a461b3c86103a052806103c05261014080805160200180846103c0018284600060045af1156131d65750508051820160206001820306601f8201039050602001915050806103e0526101a080805160200180846103c0018284600060045af1156131d6575050506044803561040052806020013561042052806040013561044052806060013561046052506102605161048052610280516104a0526102a0516104c0526102c0516104e052604060c4610500376103bc90506000610380515af1156131d657640100000003546103a0526103805160016103a0516401000000008110156131d65702600301556103a051600181818301106131d657808201905090506401000000035560076401000000046103805160e05260c052604060c020016102e05181556103005160018201556103205160028201556103405160038201555061024051600b6401000000046103805160e05260c052604060c020015560006401000000046103805160e05260c052604060c020556103605160016401000000046103805160e05260c052604060c020015560006102005118156117cc5761020051600c6401000000046103805160e05260c052604060c02001555b6103c060006004818352015b60446103c05160048110156131d65760200201356103e0526103e0516117fd576119d0565b6103e05160016103c05160048110156131d6570260036401000000046103805160e05260c052604060c02001015560006004610400527f095ea7b3000000000000000000000000000000000000000000000000000000006104205261040060048060208461046001018260208501600060045af1505080518201915050610380516020826104600101526020810190507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602082610460010152602081019050806104605261046090508051602001806105008284600060045af1156131d6575050600060006105005161052060006103e0515af1156131d65761040060006004818352015b610400516103c05110156119ac5760446104005160048110156131d657602002013561042052610420516103e051186104405264020000000c6104405160e05260c052604060c020546103a0526103805160016103a0516401000000008110156131d6570264020000000b6104405160e05260c052604060c02001556103a051600181818301106131d6578082019050905064020000000c6104405160e05260c052604060c020555b5b8151600101808352811415611903575b50505b81516001018083528114156117d8575b505060c060446103c03733610480527f5b4a28c940282b5bf183df6a046b8119cf6edeb62859f75e835eb7ba834cce8d60e06103c0a16103805160005260206000f35b63e339eb4f811415611a2a57600061020052611a4b565b63de7fe3bf811415611a4657602060c461020037600050611a4b565b611ffa565b60043560a01c6131d657604060243560040161014037602060243560040135116131d657602a6044356004016101a037600a60443560040135116131d65760643560a01c6131d657623d090060a43510611aae576305f5e10060a4351115611ab1565b60005b611afa576308c379a061022052602061024052600b610260527f496e76616c6964206665650000000000000000000000000000000000000000006102805261026050606461023cfd5b600161020051600a8110156131d6570264020000000660043560e05260c052604060c0200154610220526000610220511415611b75576308c379a061024052602061026052601c610280527f496e76616c696420696d706c656d656e746174696f6e20696e646578000000006102a05261028050606461025cfd5b60206102c0600463313ce5676102605261027c6064355afa156131d657601f3d11156131d6576000506102c0516102405260136102405110611bf6576308c379a06102605260206102805260196102a0527f4d617820313820646563696d616c7320666f7220636f696e73000000000000006102c0526102a050606461027cfd5b7f602d3d8160093d39f3363d3d373d3d3d363d7300000000000000000000000000610280526102205160601b610293527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006102a75260366102806000f061026052610260513b156131d6576000600061014460c06398094be061028052806102a05261014080805160200180846102a0018284600060045af1156131d65750508051820160206001820306601f8201039050602001915050806102c0526101a080805160200180846102a0018284600060045af1156131d6575050506064356102e052604e6024610240518082106131d6578082039050905010156131d6576024610240518082106131d65780820390509050600a0a61030052604060846103203761029c90506000610260515af1156131d6576064353b156131d65760006000604463095ea7b361028052610260516102a0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102c05261029c60006064355af1156131d6576401000000035461028052610260516001610280516401000000008110156131d657026003015561028051600181818301106131d6578082019050905064010000000355600a64020000000660043560e05260c052604060c02001546102a05260076401000000046102605160e05260c052604060c02001610240518155600060018201556000600282015560006003820155506002600b6401000000046102605160e05260c052604060c02001556004356401000000046102605160e05260c052604060c0205560643560036401000000046102605160e05260c052604060c0200155600a64020000000660043560e05260c052604060c0200154600160036401000000046102605160e05260c052604060c0200101556102205160016401000000046102605160e05260c052604060c020015560006102c0526102e060006008818352015b60016102e05160088110156131d65702600c64020000000660043560e05260c052604060c0200101546103005261030051611f095760016102c0526102a051610300525b61030051606435186103205264020000000c6103205160e05260c052604060c0205461028052610260516001610280516401000000008110156131d6570264020000000b6103205160e05260c052604060c020015561028051600181818301106131d6578082019050905064020000000c6103205160e05260c052604060c020556102c05115611f9857611fa9565b5b8151600101808352811415611ec5575b50506064356102e05260043561030052604060846103203733610360527f01f31cd2abdeb4e5e10ba500f2db0f937d9e8c735ab04681925441b4ea37eda560a06102e0a16102605160005260206000f35b6396bebb348114156122235760043560a01c6131d6576000600364010000000460043560e05260c052604060c02001541415612075576308c379a061014052602061016052600c610180527f556e6b6e6f776e20706f6f6c00000000000000000000000000000000000000006101a05261018050606461015cfd5b600264010000000460043560e05260c052604060c0200154156120d7576308c379a0610140526020610160526016610180527f476175676520616c7265616479206465706c6f796564000000000000000000006101a05261018050606461015cfd5b64020000000a54610140526000610140511415612133576308c379a061016052602061018052601c6101a0527f476175676520696d706c656d656e746174696f6e206e6f7420736574000000006101c0526101a050606461017cfd5b7f602d3d8160093d39f3363d3d373d3d3d363d7300000000000000000000000000610180526101405160601b610193527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006101a75260366101806000f061016052610160513b156131d65760006000602463c4d66de8610180526004356101a05261019c6000610160515af1156131d65761016051600264010000000460043560e05260c052604060c020015560043561018052610160516101a0527f656bb34c20491970a8c163f3bd62ead82022b379c3924960ec60f6dbfc5aab3b6040610180a16101605160005260206000f35b632fc056538114156126835760043560a01c6131d65760243560a01c6131d6576000610120525b610120516064013560a01c6131d65760206101205101610120526101406101205110156122765761224a565b6000543314156131d657600c64020000000660043560e05260c052604060c02001546131d65760206101c0600463a262904b6101605261017c6f22d53366457f9d5e68ec105046fc43835afa156131d657601f3d11156131d6576000506101c051610140526020610200602463940494f1610180526004356101a05261019c610140515afa156131d657601f3d11156131d657600050610200516101605264020000000554610180526004356001610180516401000000008110156131d65702640100000005015561018051600181818301106131d65780820190509050640200000005556020610220602463379510496101a0526004356101c0526101bc610140515afa156131d657601f3d11156131d65760005061022051600a64020000000660043560e05260c052604060c020015561016051601564020000000660043560e05260c052604060c0200155602435600b64020000000660043560e05260c052604060c02001556000604435181561240657604435601664020000000660043560e05260c052604060c02001555b6101a06000600a818352015b60646101a051600a8110156131d65760200201356101c0526101c05161243757612472565b6101c05160016101a051600a8110156131d6570264020000000660043560e05260c052604060c02001555b8151600101808352811415612412575b505060006101a0526101006103406024639ac90d3d6102c0526004356102e0526102dc610140515afa156131d65760ff3d11156131d65760005061034080516101c05280602001516101e0528060400151610200528060600151610220528060800151610240528060a00151610260528060c00151610280528060e001516102a052506102c060006008818352015b610160516102c051141561251457612635565b6101c06102c05160088110156131d65760200201516102e0526102e05160016102c05160088110156131d65702600c64020000000660043560e05260c052604060c02001015560016402000000076102e05160e05260c052604060c020556101a080516102c05160088082028215828483041417156131d6578090509050905060405181116131d65760008112156125de576020610360600463313ce5676103005261031c6102e0515afa156131d657601f3d11156131d65760005061036051816000031c61260f565b6020610360600463313ce5676103005261031c6102e0515afa156131d657601f3d11156131d65760005061036051811b5b905081818301106131d657808201905090508152505b8151600101808352811415612501575b50506101a051601464020000000660043560e05260c052604060c02001556004356102c0527fcc6afdfec79da6be08142ecee25cf14b665961e25d30d8eba45959be9547635f60206102c0a1005b63cb956b468114156127a45760043560a01c6131d6576000610120525b610120516024013560a01c6131d65760206101205101610120526101406101205110156126cc576126a0565b6000543314156131d6576000600c64020000000660043560e05260c052604060c020015418156131d6576101406000600a818352015b602461014051600a8110156131d657602002013561016052600161014051600a8110156131d6570264020000000660043560e05260c052604060c02001546101805261018051610160511415612764576101605161275f576127a0565b61278f565b61016051600161014051600a8110156131d6570264020000000660043560e05260c052604060c02001555b5b8151600101808352811415612702575b5050005b639ddbf4b981141561289b576000610120525b610120516024013560a01c6131d65760206101205101610120526101406101205110156127e3576127b7565b6000543314156131d6576101406000600a818352015b602461014051600a8110156131d657602002013561016052600161014051600a8110156131d6570264020000000860043560e05260c052604060c0200154610180526101805161016051141561285b576101605161285657612897565b612886565b61016051600161014051600a8110156131d6570264020000000860043560e05260c052604060c02001555b5b81516001018083528114156127f9575b5050005b638f03182c8114156128c75760043560a01c6131d6576000543314156131d65760043564020000000a55005b637542f0788114156129de576000610120525b610120516004013560a01c6131d6576020610120510161012052610400610120511015612906576128da565b600254610160526000546101805260006101405261014061012060006002818352015b6101205160200261016001513314156129455760018352612956565b5b8151600101808352811415612929575b50505061014051156131d65761014060006020818352015b60046101405160208110156131d657602002013561298b576129da565b6104046101405160208110156131d6576020020135600c64010000000460046101405160208110156131d657602002013560e05260c052604060c02001555b815160010180835281141561296e575b5050005b636b441a40811415612a065760043560a01c6131d6576000543314156131d657600435600155005b63e5ea47b8811415612a325760015461014052610140513314156131d657610140516000556000600155005b639aece83e811415612aac5760043560a01c6131d657600254610160526000546101805260006101405261014061012060006002818352015b610120516020026101600151331415612a875760018352612a98565b5b8151600101808352811415612a6b575b50505061014051156131d657600435600255005b6336d2b77a811415612b0a5760043560a01c6131d65760243560a01c6131d6576000543314156131d657600435612aec5760243564020000000955612b08565b602435600b64020000000660043560e05260c052604060c02001555b005b63bcc981d2811415612c01576401000000043360e05260c052604060c020546101405260006101405118156131d65760036401000000043360e05260c052604060c020015461016052602061022060246370a082316101a052306101c0526101bc610160515afa156131d657601f3d11156131d6576000506102205161018052600b6402000000066101405160e05260c052604060c02001546101a05260206102c060a463ddc1f59d6101c05260006101e05260016102005261018051610220526000610240526101a051610260526101dc6000335af1156131d657601f3d11156131d6576000506102c050600160005260206000f35b63db89fabc811415613068576000610120525b610120516004013560a01c6131d6576020610120510161012052610140610120511015612c4057612c14565b64010000000354610140526101806000600a818352015b60206101805102600401356101605261016051612c7357613050565b60036401000000046101605160e05260c052604060c02001546131d65760406102606024639ac90d3d6101e05261016051610200526101fc730959158b6040d32d04c301a72cbfd6b39e21c9ae5afa156131d657603f3d11156131d65760005061026080516101a05280602001516101c0525060006101a05118156131d657610160516001610140516401000000008110156131d65702600301556101408051600181818301106131d657808201905090508152506040366101e037736c3f90f043a72fa612cbac8115ee7e52bde6e4906101c0511415612d855773bebc44782c7db0a1a60cb6fe97d0b483032ff1c76101e052735f890841f657d90e081babdb532a05996af79fe661020052612dfd565b73075b1bb99792c9e1041ba13afef80c91a1e70fb36101c0511415612df657737fc77b5c7614e1533320ea6ddc2eb61fa00a97146101e052732f956eee002b0debd468cf2e0490d1aec65e027f610200526002600c6401000000046101605160e05260c052604060c0200155612dfc565b60006000fd5b5b6020610280600463313ce5676102205261023c6101a0515afa156131d657601f3d11156131d6576000506102805160076401000000046101605160e05260c052604060c02001556101e0516401000000046101605160e05260c052604060c0205560206102c0602463c66106576102405260006102605261025c610160515afa156131d657601f3d11156131d6576000506102c051610220526101a05160036401000000046101605160e05260c052604060c02001556101c051600160036401000000046101605160e05260c052604060c0200101556102005160016401000000046101605160e05260c052604060c0200155600c6402000000066101e05160e05260c052604060c0200180546102405260018101546102605260028101546102805260038101546102a05260048101546102c05260058101546102e0526006810154610300526007810154610320525060006102405118156131d65760006103405261036060006008818352015b6102406103605160088110156131d65760200201516103805261038051612f9c576001610340526101c051610380525b6103805161022051186103a05264020000000c6103a05160e05260c052604060c020546103c0526101605160016103c0516401000000008110156131d6570264020000000b6103a05160e05260c052604060c02001556103c051600181818301106131d6578082019050905064020000000c6103a05160e05260c052604060c02055610340511561302c5761303d565b5b8151600101808352811415612f6c575b50505b8151600101808352811415612c57575b50506101405164010000000355600160005260206000f35b63f851a4408114156130805760005460005260206000f35b6317f7182a8114156130985760015460005260206000f35b63481c6a758114156130b05760025460005260206000f35b633a1d5d8e8114156130dc5760016004356401000000008110156131d657026003015460005260206000f35b63956aae3a8114156130f8576401000000035460005260206000f35b6322fe56718114156131285760016004356401000000008110156131d65702640100000005015460005260206000f35b63de5e4a3b811415613144576402000000055460005260206000f35b6310a002df8114156131785760043560a01c6131d65764020000000760043560e05260c052604060c0205460005260206000f35b6331a4f8658114156131b2576001602435600a8110156131d6570264020000000860043560e05260c052604060c020015460005260206000f35b638df242078114156131ce5764020000000a5460005260206000f35b505b60006000fd5b600080fd