false
true
0

Contract Address Details

0xaE34574AC03A15cd58A92DC79De7B1A0800F1CE3

Contract Name
Vyper_contract
Creator
0xe6da68–137a17 at 0x0778fe–ef0bb7
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
649 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26217433
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.3.7+commit.6020b8bb




Verified at
2025-05-12T11:27:50.661133Z

Constructor Arguments

0x000000000000000000000000ecb456ea5365865ebab8a2661b0c503410e9b347000000000000000000000000853d955acef822db058eb8505911ed77f175b99e0000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1000000000000000000000000fc2838a17d8e8b1d5456e0a351b0708a0921114700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000012a05f200
              

Vyper_contract.vy

# @version 0.3.7
"""
@title StableSwap
@author Curve.Fi
@license Copyright (c) Curve.Fi, 2020 - all rights reserved
@notice Optimized pool implementation with no lending, for 2 coins
        with 18 decimals
"""
from vyper.interfaces import ERC20


interface CurveToken:
    def totalSupply() -> uint256: view
    def mint(_to: address, _value: uint256) -> bool: nonpayable
    def burnFrom(_to: address, _value: uint256) -> bool: nonpayable


# Events
event TokenExchange:
    buyer: indexed(address)
    sold_id: int128
    tokens_sold: uint256
    bought_id: int128
    tokens_bought: uint256

event AddLiquidity:
    provider: indexed(address)
    token_amounts: uint256[N_COINS]
    fees: uint256[N_COINS]
    invariant: uint256
    token_supply: uint256

event RemoveLiquidity:
    provider: indexed(address)
    token_amounts: uint256[N_COINS]
    fees: uint256[N_COINS]
    token_supply: uint256

event RemoveLiquidityOne:
    provider: indexed(address)
    token_amount: uint256
    coin_amount: uint256
    token_supply: uint256

event RemoveLiquidityImbalance:
    provider: indexed(address)
    token_amounts: uint256[N_COINS]
    fees: uint256[N_COINS]
    invariant: uint256
    token_supply: uint256

event CommitNewAdmin:
    deadline: indexed(uint256)
    admin: indexed(address)

event NewAdmin:
    admin: indexed(address)

event CommitNewFee:
    deadline: indexed(uint256)
    fee: uint256
    admin_fee: uint256

event NewFee:
    fee: uint256
    admin_fee: uint256

event RampA:
    old_A: uint256
    new_A: uint256
    initial_time: uint256
    future_time: uint256

event StopRampA:
    A: uint256
    t: uint256


# These constants must be set prior to compiling
N_COINS: constant(uint256) = 2

# fixed constants
FEE_DENOMINATOR: constant(uint256) = 10 ** 10
PRECISION: constant(uint256) = 10 ** 18  # The precision to convert to

A_PRECISION: constant(uint256) = 100
MAX_ADMIN_FEE: constant(uint256) = 10 * 10 ** 9
MAX_FEE: constant(uint256) = 5 * 10 ** 9
MAX_A: constant(uint256) = 10 ** 6
MAX_A_CHANGE: constant(uint256) = 10

ADMIN_ACTIONS_DELAY: constant(uint256) = 3 * 86400
MIN_RAMP_TIME: constant(uint256) = 86400

coins: public(address[N_COINS])
balances: public(uint256[N_COINS])
fee: public(uint256)  # fee * 1e10
admin_fee: public(uint256)  # admin_fee * 1e10

owner: public(address)
lp_token: public(address)

initial_A: public(uint256)
future_A: public(uint256)
initial_A_time: public(uint256)
future_A_time: public(uint256)

admin_actions_deadline: public(uint256)
transfer_ownership_deadline: public(uint256)
future_fee: public(uint256)
future_admin_fee: public(uint256)
future_owner: public(address)

is_killed: bool
kill_deadline: uint256
KILL_DEADLINE_DT: constant(uint256) = 2 * 30 * 86400


@external
def __init__(
    _owner: address,
    _coins: address[N_COINS],
    _pool_token: address,
    _A: uint256,
    _fee: uint256,
    _admin_fee: uint256
):
    """
    @notice Contract constructor
    @param _owner Contract owner address
    @param _coins Addresses of ERC20 conracts of coins
    @param _pool_token Address of the token representing LP share
    @param _A Amplification coefficient multiplied by n * (n - 1)
    @param _fee Fee to charge for exchanges
    @param _admin_fee Admin fee
    """
    for i in range(N_COINS):
        assert _coins[i] != empty(address)
    self.coins = _coins
    self.initial_A = _A * A_PRECISION
    self.future_A = _A * A_PRECISION
    self.fee = _fee
    self.admin_fee = _admin_fee
    self.owner = _owner
    self.kill_deadline = block.timestamp + KILL_DEADLINE_DT
    self.lp_token = _pool_token


@view
@internal
def _A() -> uint256:
    """
    Handle ramping A up or down
    """
    t1: uint256 = self.future_A_time
    A1: uint256 = self.future_A

    if block.timestamp < t1:
        A0: uint256 = self.initial_A
        t0: uint256 = self.initial_A_time
        # Expressions in uint256 cannot have negative numbers, thus "if"
        if A1 > A0:
            return A0 + (A1 - A0) * (block.timestamp - t0) / (t1 - t0)
        else:
            return A0 - (A0 - A1) * (block.timestamp - t0) / (t1 - t0)

    else:  # when t1 == 0 or block.timestamp >= t1
        return A1


@view
@external
def A() -> uint256:
    return self._A() / A_PRECISION


@view
@external
def A_precise() -> uint256:
    return self._A()


@pure
@internal
def _get_D(_xp: uint256[N_COINS], _amp: uint256) -> uint256:
    """
    D invariant calculation in non-overflowing integer operations
    iteratively

    A * sum(x_i) * n**n + D = A * D * n**n + D**(n+1) / (n**n * prod(x_i))

    Converging solution:
    D[j+1] = (A * n**n * sum(x_i) - D[j]**(n+1) / (n**n prod(x_i))) / (A * n**n - 1)
    """
    S: uint256 = 0
    Dprev: uint256 = 0

    for _x in _xp:
        S += _x
    if S == 0:
        return 0

    D: uint256 = S
    Ann: uint256 = _amp * N_COINS
    for _i in range(255):
        D_P: uint256 = D
        for _x in _xp:
            D_P = D_P * D / (_x * N_COINS)  # If division by 0, this will be borked: only withdrawal will work. And that is good
        Dprev = D
        D = (Ann * S / A_PRECISION + D_P * N_COINS) * D / ((Ann - A_PRECISION) * D / A_PRECISION + (N_COINS + 1) * D_P)
        # Equality with the precision of 1
        if D > Dprev:
            if D - Dprev <= 1:
                return D
        else:
            if Dprev - D <= 1:
                return D
    # convergence typically occurs in 4 rounds or less, this should be unreachable!
    # if it does happen the pool is borked and LPs can withdraw via `remove_liquidity`
    raise


@view
@external
def get_virtual_price() -> uint256:
    """
    @notice The current virtual price of the pool LP token
    @dev Useful for calculating profits
    @return LP token virtual price normalized to 1e18
    """
    D: uint256 = self._get_D(self.balances, self._A())
    # D is in the units similar to DAI (e.g. converted to precision 1e18)
    # When balanced, D = n * x_u - total virtual value of the portfolio
    token_supply: uint256 = ERC20(self.lp_token).totalSupply()
    return D * PRECISION / token_supply


@view
@external
def calc_token_amount(_amounts: uint256[N_COINS], _is_deposit: bool) -> uint256:
    """
    @notice Calculate addition or reduction in token supply from a deposit or withdrawal
    @dev This calculation accounts for slippage, but not fees.
         Needed to prevent front-running, not for precise calculations!
    @param _amounts Amount of each coin being deposited
    @param _is_deposit set True for deposits, False for withdrawals
    @return Expected amount of LP tokens received
    """
    amp: uint256 = self._A()
    balances: uint256[N_COINS] = self.balances
    D0: uint256 = self._get_D(balances, amp)
    for i in range(N_COINS):
        if _is_deposit:
            balances[i] += _amounts[i]
        else:
            balances[i] -= _amounts[i]
    D1: uint256 = self._get_D(balances, amp)
    token_amount: uint256 = CurveToken(self.lp_token).totalSupply()
    diff: uint256 = 0
    if _is_deposit:
        diff = D1 - D0
    else:
        diff = D0 - D1
    return diff * token_amount / D0


@external
@nonreentrant('lock')
def add_liquidity(_amounts: uint256[N_COINS], _min_mint_amount: uint256) -> uint256:
    """
    @notice Deposit coins into the pool
    @param _amounts List of amounts of coins to deposit
    @param _min_mint_amount Minimum amount of LP tokens to mint from the deposit
    @return Amount of LP tokens received by depositing
    """
    assert not self.is_killed  # dev: is killed

    amp: uint256 = self._A()
    old_balances: uint256[N_COINS] = self.balances

    # Initial invariant
    D0: uint256 = self._get_D(old_balances, amp)

    lp_token: address = self.lp_token
    token_supply: uint256 = CurveToken(lp_token).totalSupply()
    new_balances: uint256[N_COINS] = old_balances
    for i in range(N_COINS):
        if token_supply == 0:
            assert _amounts[i] > 0  # dev: initial deposit requires all coins
        # balances store amounts of c-tokens
        new_balances[i] += _amounts[i]

    # Invariant after change
    D1: uint256 = self._get_D(new_balances, amp)
    assert D1 > D0

    # We need to recalculate the invariant accounting for fees
    # to calculate fair user's share
    D2: uint256 = D1
    fees: uint256[N_COINS] = empty(uint256[N_COINS])
    mint_amount: uint256 = 0
    if token_supply > 0:
        # Only account for fees if we are not the first to deposit
        fee: uint256 = self.fee * N_COINS / (4 * (N_COINS - 1))
        admin_fee: uint256 = self.admin_fee
        for i in range(N_COINS):
            ideal_balance: uint256 = D1 * old_balances[i] / D0
            difference: uint256 = 0
            new_balance: uint256 = new_balances[i]
            if ideal_balance > new_balance:
                difference = ideal_balance - new_balance
            else:
                difference = new_balance - ideal_balance
            fees[i] = fee * difference / FEE_DENOMINATOR
            self.balances[i] = new_balance - (fees[i] * admin_fee / FEE_DENOMINATOR)
            new_balances[i] -= fees[i]
        D2 = self._get_D(new_balances, amp)
        mint_amount = token_supply * (D2 - D0) / D0
    else:
        self.balances = new_balances
        mint_amount = D1  # Take the dust if there was any
    assert mint_amount >= _min_mint_amount, "Slippage screwed you"

    # Take coins from the sender
    for i in range(N_COINS):
        if _amounts[i] > 0:
            # "safeTransferFrom" which works for ERC20s which return bool or not
            _response: Bytes[32] = raw_call(
                self.coins[i],
                concat(
                    method_id("transferFrom(address,address,uint256)"),
                    convert(msg.sender, bytes32),
                    convert(self, bytes32),
                    convert(_amounts[i], bytes32),
                ),
                max_outsize=32,
            )
            if len(_response) > 0:
                assert convert(_response, bool)  # dev: failed transfer
            # end "safeTransferFrom"

    # Mint pool tokens
    CurveToken(lp_token).mint(msg.sender, mint_amount)

    log AddLiquidity(msg.sender, _amounts, fees, D1, token_supply + mint_amount)

    return mint_amount


@view
@internal
def _get_y(i: int128, j: int128, x: uint256, _xp: uint256[N_COINS]) -> uint256:
    """
    Calculate x[j] if one makes x[i] = x

    Done by solving quadratic equation iteratively.
    x_1**2 + x_1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)
    x_1**2 + b*x_1 = c

    x_1 = (x_1**2 + c) / (2*x_1 + b)
    """
    # x in the input is converted to the same price/precision

    assert i != j       # dev: same coin
    assert j >= 0       # dev: j below zero
    assert j < convert(N_COINS, int128)  # dev: j above N_COINS

    # should be unreachable, but good for safety
    assert i >= 0
    assert i < convert(N_COINS, int128)

    A: uint256 = self._A()
    D: uint256 = self._get_D(_xp, A)
    Ann: uint256 = A * N_COINS
    c: uint256 = D
    S: uint256 = 0
    _x: uint256 = 0
    y_prev: uint256 = 0

    for _i in range(N_COINS):
        if _i == convert(i, uint256):
            _x = x
        elif _i != convert(j, uint256):
            _x = _xp[_i]
        else:
            continue
        S += _x
        c = c * D / (_x * N_COINS)
    c = c * D * A_PRECISION / (Ann * N_COINS)
    b: uint256 = S + D * A_PRECISION / Ann  # - D
    y: uint256 = D
    for _i in range(255):
        y_prev = y
        y = (y*y + c) / (2 * y + b - D)
        # Equality with the precision of 1
        if y > y_prev:
            if y - y_prev <= 1:
                return y
        else:
            if y_prev - y <= 1:
                return y
    raise


@view
@external
def get_dy(i: int128, j: int128, _dx: uint256) -> uint256:
    xp: uint256[N_COINS] = self.balances

    x: uint256 = xp[i] + _dx
    y: uint256 = self._get_y(i, j, x, xp)
    dy: uint256 = xp[j] - y - 1
    fee: uint256 = self.fee * dy / FEE_DENOMINATOR
    return dy - fee


@external
@nonreentrant('lock')
def exchange(i: int128, j: int128, _dx: uint256, _min_dy: uint256) -> uint256:
    """
    @notice Perform an exchange between two coins
    @dev Index values can be found via the `coins` public getter method
    @param i Index value for the coin to send
    @param j Index valie of the coin to recieve
    @param _dx Amount of `i` being exchanged
    @param _min_dy Minimum amount of `j` to receive
    @return Actual amount of `j` received
    """
    assert not self.is_killed  # dev: is killed

    old_balances: uint256[N_COINS] = self.balances
    xp: uint256[N_COINS] = old_balances

    x: uint256 = xp[i] + _dx
    y: uint256 = self._get_y(i, j, x, xp)

    dy: uint256 = xp[j] - y - 1  # -1 just in case there were some rounding errors
    dy_fee: uint256 = dy * self.fee / FEE_DENOMINATOR

    # Convert all to real units
    dy = dy - dy_fee
    assert dy >= _min_dy, "Exchange resulted in fewer coins than expected"

    dy_admin_fee: uint256 = dy_fee * self.admin_fee / FEE_DENOMINATOR

    # Change balances exactly in same way as we change actual ERC20 coin amounts
    self.balances[i] = old_balances[i] + _dx
    # When rounding errors happen, we undercharge admin fee in favor of LP
    self.balances[j] = old_balances[j] - dy - dy_admin_fee

    _response: Bytes[32] = raw_call(
        self.coins[i],
        concat(
            method_id("transferFrom(address,address,uint256)"),
            convert(msg.sender, bytes32),
            convert(self, bytes32),
            convert(_dx, bytes32),
        ),
        max_outsize=32,
    )
    if len(_response) > 0:
        assert convert(_response, bool)

    _response = raw_call(
        self.coins[j],
        concat(
            method_id("transfer(address,uint256)"),
            convert(msg.sender, bytes32),
            convert(dy, bytes32),
        ),
        max_outsize=32,
    )
    if len(_response) > 0:
        assert convert(_response, bool)

    log TokenExchange(msg.sender, i, _dx, j, dy)

    return dy


@external
@nonreentrant('lock')
def remove_liquidity(_amount: uint256, _min_amounts: uint256[N_COINS]) -> uint256[N_COINS]:
    """
    @notice Withdraw coins from the pool
    @dev Withdrawal amounts are based on current deposit ratios
    @param _amount Quantity of LP tokens to burn in the withdrawal
    @param _min_amounts Minimum amounts of underlying coins to receive
    @return List of amounts of coins that were withdrawn
    """
    lp_token: address = self.lp_token
    total_supply: uint256 = CurveToken(lp_token).totalSupply()
    amounts: uint256[N_COINS] = empty(uint256[N_COINS])

    for i in range(N_COINS):
        old_balance: uint256 = self.balances[i]
        value: uint256 = old_balance * _amount / total_supply
        assert value >= _min_amounts[i], "Withdrawal resulted in fewer coins than expected"
        self.balances[i] = old_balance - value
        amounts[i] = value
        _response: Bytes[32] = raw_call(
            self.coins[i],
            concat(
                method_id("transfer(address,uint256)"),
                convert(msg.sender, bytes32),
                convert(value, bytes32),
            ),
            max_outsize=32,
        )
        if len(_response) > 0:
            assert convert(_response, bool)

    CurveToken(lp_token).burnFrom(msg.sender, _amount)  # dev: insufficient funds

    log RemoveLiquidity(msg.sender, amounts, empty(uint256[N_COINS]), total_supply - _amount)

    return amounts


@external
@nonreentrant('lock')
def remove_liquidity_imbalance(_amounts: uint256[N_COINS], _max_burn_amount: uint256) -> uint256:
    """
    @notice Withdraw coins from the pool in an imbalanced amount
    @param _amounts List of amounts of underlying coins to withdraw
    @param _max_burn_amount Maximum amount of LP token to burn in the withdrawal
    @return Actual amount of the LP token burned in the withdrawal
    """
    assert not self.is_killed  # dev: is killed

    amp: uint256 = self._A()
    old_balances: uint256[N_COINS] = self.balances
    D0: uint256 = self._get_D(old_balances, amp)
    new_balances: uint256[N_COINS] = old_balances
    for i in range(N_COINS):
        new_balances[i] -= _amounts[i]
    D1: uint256 = self._get_D(new_balances, amp)

    fee: uint256 = self.fee * N_COINS / (4 * (N_COINS - 1))
    admin_fee: uint256 = self.admin_fee
    fees: uint256[N_COINS] = empty(uint256[N_COINS])
    for i in range(N_COINS):
        new_balance: uint256 = new_balances[i]
        ideal_balance: uint256 = D1 * old_balances[i] / D0
        difference: uint256 = 0
        if ideal_balance > new_balance:
            difference = ideal_balance - new_balance
        else:
            difference = new_balance - ideal_balance
        fees[i] = fee * difference / FEE_DENOMINATOR
        self.balances[i] = new_balance - (fees[i] * admin_fee / FEE_DENOMINATOR)
        new_balances[i] = new_balance - fees[i]
    D2: uint256 = self._get_D(new_balances, amp)

    lp_token: address = self.lp_token
    token_supply: uint256 = CurveToken(lp_token).totalSupply()
    token_amount: uint256 = (D0 - D2) * token_supply / D0
    assert token_amount != 0  # dev: zero tokens burned
    token_amount += 1  # In case of rounding errors - make it unfavorable for the "attacker"
    assert token_amount <= _max_burn_amount, "Slippage screwed you"

    CurveToken(lp_token).burnFrom(msg.sender, token_amount)  # dev: insufficient funds
    for i in range(N_COINS):
        if _amounts[i] != 0:
            _response: Bytes[32] = raw_call(
                self.coins[i],
                concat(
                    method_id("transfer(address,uint256)"),
                    convert(msg.sender, bytes32),
                    convert(_amounts[i], bytes32),
                ),
                max_outsize=32,
            )
            if len(_response) > 0:
                assert convert(_response, bool)

    log RemoveLiquidityImbalance(msg.sender, _amounts, fees, D1, token_supply - token_amount)

    return token_amount


@pure
@internal
def _get_y_D(A: uint256, i: int128, _xp: uint256[N_COINS], D: uint256) -> uint256:
    """
    Calculate x[i] if one reduces D from being calculated for xp to D

    Done by solving quadratic equation iteratively.
    x_1**2 + x_1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)
    x_1**2 + b*x_1 = c

    x_1 = (x_1**2 + c) / (2*x_1 + b)
    """
    # x in the input is converted to the same price/precision

    assert i >= 0  # dev: i below zero
    assert i < convert(N_COINS, int128)  # dev: i above N_COINS

    Ann: uint256 = A * N_COINS
    c: uint256 = D
    S: uint256 = 0
    _x: uint256 = 0
    y_prev: uint256 = 0

    for _i in range(N_COINS):
        if _i != convert(i, uint256):
            _x = _xp[_i]
        else:
            continue
        S += _x
        c = c * D / (_x * N_COINS)
    c = c * D * A_PRECISION / (Ann * N_COINS)
    b: uint256 = S + D * A_PRECISION / Ann
    y: uint256 = D

    for _i in range(255):
        y_prev = y
        y = (y*y + c) / (2 * y + b - D)
        # Equality with the precision of 1
        if y > y_prev:
            if y - y_prev <= 1:
                return y
        else:
            if y_prev - y <= 1:
                return y
    raise


@view
@internal
def _calc_withdraw_one_coin(_token_amount: uint256, i: int128) -> (uint256, uint256, uint256):
    # First, need to calculate
    # * Get current D
    # * Solve Eqn against y_i for D - _token_amount
    amp: uint256 = self._A()
    xp: uint256[N_COINS] = self.balances
    D0: uint256 = self._get_D(xp, amp)

    total_supply: uint256 = CurveToken(self.lp_token).totalSupply()
    D1: uint256 = D0 - _token_amount * D0 / total_supply
    new_y: uint256 = self._get_y_D(amp, i, xp, D1)
    xp_reduced: uint256[N_COINS] = xp
    fee: uint256 = self.fee * N_COINS / (4 * (N_COINS - 1))
    for j in range(N_COINS):
        dx_expected: uint256 = 0
        if j == convert(i, uint256):
            dx_expected = xp[j] * D1 / D0 - new_y
        else:
            dx_expected = xp[j] - xp[j] * D1 / D0
        xp_reduced[j] -= fee * dx_expected / FEE_DENOMINATOR

    dy: uint256 = xp_reduced[i] - self._get_y_D(amp, i, xp_reduced, D1)
    dy = dy - 1  # Withdraw less to account for rounding errors
    dy_0: uint256 = xp[i] - new_y  # w/o fees

    return dy, dy_0 - dy, total_supply


@view
@external
def calc_withdraw_one_coin(_token_amount: uint256, i: int128) -> uint256:
    """
    @notice Calculate the amount received when withdrawing a single coin
    @param _token_amount Amount of LP tokens to burn in the withdrawal
    @param i Index value of the coin to withdraw
    @return Amount of coin received
    """
    return self._calc_withdraw_one_coin(_token_amount, i)[0]


@external
@nonreentrant('lock')
def remove_liquidity_one_coin(_token_amount: uint256, i: int128, _min_amount: uint256) -> uint256:
    """
    @notice Withdraw a single coin from the pool
    @param _token_amount Amount of LP tokens to burn in the withdrawal
    @param i Index value of the coin to withdraw
    @param _min_amount Minimum amount of coin to receive
    @return Amount of coin received
    """
    assert not self.is_killed  # dev: is killed

    dy: uint256 = 0
    dy_fee: uint256 = 0
    total_supply: uint256 = 0
    dy, dy_fee, total_supply = self._calc_withdraw_one_coin(_token_amount, i)
    assert dy >= _min_amount, "Not enough coins removed"

    self.balances[i] -= (dy + dy_fee * self.admin_fee / FEE_DENOMINATOR)
    CurveToken(self.lp_token).burnFrom(msg.sender, _token_amount)  # dev: insufficient funds

    _response: Bytes[32] = raw_call(
        self.coins[i],
        concat(
            method_id("transfer(address,uint256)"),
            convert(msg.sender, bytes32),
            convert(dy, bytes32),
        ),
        max_outsize=32,
    )
    if len(_response) > 0:
        assert convert(_response, bool)

    log RemoveLiquidityOne(msg.sender, _token_amount, dy, total_supply - _token_amount)

    return dy


### Admin functions ###
@external
def ramp_A(_future_A: uint256, _future_time: uint256):
    assert msg.sender == self.owner  # dev: only owner
    assert block.timestamp >= self.initial_A_time + MIN_RAMP_TIME
    assert _future_time >= block.timestamp + MIN_RAMP_TIME  # dev: insufficient time

    initial_A: uint256 = self._A()
    future_A_p: uint256 = _future_A * A_PRECISION

    assert _future_A > 0 and _future_A < MAX_A
    if future_A_p < initial_A:
        assert future_A_p * MAX_A_CHANGE >= initial_A
    else:
        assert future_A_p <= initial_A * MAX_A_CHANGE

    self.initial_A = initial_A
    self.future_A = future_A_p
    self.initial_A_time = block.timestamp
    self.future_A_time = _future_time

    log RampA(initial_A, future_A_p, block.timestamp, _future_time)


@external
def stop_ramp_A():
    assert msg.sender == self.owner  # dev: only owner

    current_A: uint256 = self._A()
    self.initial_A = current_A
    self.future_A = current_A
    self.initial_A_time = block.timestamp
    self.future_A_time = block.timestamp
    # now (block.timestamp < t1) is always False, so we return saved A

    log StopRampA(current_A, block.timestamp)


@external
def commit_new_fee(_new_fee: uint256, _new_admin_fee: uint256):
    assert msg.sender == self.owner  # dev: only owner
    assert self.admin_actions_deadline == 0  # dev: active action
    assert _new_fee <= MAX_FEE  # dev: fee exceeds maximum
    assert _new_admin_fee <= MAX_ADMIN_FEE  # dev: admin fee exceeds maximum

    deadline: uint256 = block.timestamp + ADMIN_ACTIONS_DELAY
    self.admin_actions_deadline = deadline
    self.future_fee = _new_fee
    self.future_admin_fee = _new_admin_fee

    log CommitNewFee(deadline, _new_fee, _new_admin_fee)


@external
def apply_new_fee():
    assert msg.sender == self.owner  # dev: only owner
    assert block.timestamp >= self.admin_actions_deadline  # dev: insufficient time
    assert self.admin_actions_deadline != 0  # dev: no active action

    self.admin_actions_deadline = 0
    fee: uint256 = self.future_fee
    admin_fee: uint256 = self.future_admin_fee
    self.fee = fee
    self.admin_fee = admin_fee

    log NewFee(fee, admin_fee)


@external
def revert_new_parameters():
    assert msg.sender == self.owner  # dev: only owner

    self.admin_actions_deadline = 0


@external
def commit_transfer_ownership(_owner: address):
    assert msg.sender == self.owner  # dev: only owner
    assert self.transfer_ownership_deadline == 0  # dev: active transfer

    deadline: uint256 = block.timestamp + ADMIN_ACTIONS_DELAY
    self.transfer_ownership_deadline = deadline
    self.future_owner = _owner

    log CommitNewAdmin(deadline, _owner)


@external
def apply_transfer_ownership():
    assert msg.sender == self.owner  # dev: only owner
    assert block.timestamp >= self.transfer_ownership_deadline  # dev: insufficient time
    assert self.transfer_ownership_deadline != 0  # dev: no active transfer

    self.transfer_ownership_deadline = 0
    owner: address = self.future_owner
    self.owner = owner

    log NewAdmin(owner)


@external
def revert_transfer_ownership():
    assert msg.sender == self.owner  # dev: only owner

    self.transfer_ownership_deadline = 0


@view
@external
def admin_balances(i: uint256) -> uint256:
    return ERC20(self.coins[i]).balanceOf(self) - self.balances[i]


@external
def withdraw_admin_fees():
    assert msg.sender == self.owner  # dev: only owner

    for i in range(N_COINS):
        coin: address = self.coins[i]
        value: uint256 = ERC20(coin).balanceOf(self) - self.balances[i]
        if value > 0:
            _response: Bytes[32] = raw_call(
                coin,
                concat(
                    method_id("transfer(address,uint256)"),
                    convert(msg.sender, bytes32),
                    convert(value, bytes32),
                ),
                max_outsize=32,
            )  # dev: failed transfer
            if len(_response) > 0:
                assert convert(_response, bool)


@external
def donate_admin_fees():
    assert msg.sender == self.owner  # dev: only owner
    for i in range(N_COINS):
        self.balances[i] = ERC20(self.coins[i]).balanceOf(self)


@external
def kill_me():
    assert msg.sender == self.owner  # dev: only owner
    assert self.kill_deadline > block.timestamp  # dev: deadline has passed
    self.is_killed = True


@external
def unkill_me():
    assert msg.sender == self.owner  # dev: only owner
    self.is_killed = False
        

Compiler Settings

{"search_paths":["."],"outputSelection":{"Vyper_contract.vy":["abi","ast","interface","ir","userdoc","devdoc","evm.bytecode.object","evm.bytecode.opcodes","evm.deployedBytecode.object","evm.deployedBytecode.opcodes","evm.deployedBytecode.sourceMap","evm.methodIdentifiers"]}}
              

Contract ABI

[{"type":"event","name":"TokenExchange","inputs":[{"type":"address","name":"buyer","indexed":true},{"type":"int128","name":"sold_id","indexed":false},{"type":"uint256","name":"tokens_sold","indexed":false},{"type":"int128","name":"bought_id","indexed":false},{"type":"uint256","name":"tokens_bought","indexed":false}],"anonymous":false},{"type":"event","name":"AddLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[2]","name":"token_amounts","indexed":false},{"type":"uint256[2]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveLiquidity","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[2]","name":"token_amounts","indexed":false},{"type":"uint256[2]","name":"fees","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveLiquidityOne","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256","name":"token_amount","indexed":false},{"type":"uint256","name":"coin_amount","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveLiquidityImbalance","inputs":[{"type":"address","name":"provider","indexed":true},{"type":"uint256[2]","name":"token_amounts","indexed":false},{"type":"uint256[2]","name":"fees","indexed":false},{"type":"uint256","name":"invariant","indexed":false},{"type":"uint256","name":"token_supply","indexed":false}],"anonymous":false},{"type":"event","name":"CommitNewAdmin","inputs":[{"type":"uint256","name":"deadline","indexed":true},{"type":"address","name":"admin","indexed":true}],"anonymous":false},{"type":"event","name":"NewAdmin","inputs":[{"type":"address","name":"admin","indexed":true}],"anonymous":false},{"type":"event","name":"CommitNewFee","inputs":[{"type":"uint256","name":"deadline","indexed":true},{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false},{"type":"event","name":"NewFee","inputs":[{"type":"uint256","name":"fee","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false}],"anonymous":false},{"type":"event","name":"RampA","inputs":[{"type":"uint256","name":"old_A","indexed":false},{"type":"uint256","name":"new_A","indexed":false},{"type":"uint256","name":"initial_time","indexed":false},{"type":"uint256","name":"future_time","indexed":false}],"anonymous":false},{"type":"event","name":"StopRampA","inputs":[{"type":"uint256","name":"A","indexed":false},{"type":"uint256","name":"t","indexed":false}],"anonymous":false},{"type":"constructor","stateMutability":"nonpayable","outputs":[],"inputs":[{"type":"address","name":"_owner"},{"type":"address[2]","name":"_coins"},{"type":"address","name":"_pool_token"},{"type":"uint256","name":"_A"},{"type":"uint256","name":"_fee"},{"type":"uint256","name":"_admin_fee"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"A","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"A_precise","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"get_virtual_price","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"calc_token_amount","inputs":[{"type":"uint256[2]","name":"_amounts"},{"type":"bool","name":"_is_deposit"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":""}],"name":"add_liquidity","inputs":[{"type":"uint256[2]","name":"_amounts"},{"type":"uint256","name":"_min_mint_amount"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"get_dy","inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"_dx"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":""}],"name":"exchange","inputs":[{"type":"int128","name":"i"},{"type":"int128","name":"j"},{"type":"uint256","name":"_dx"},{"type":"uint256","name":"_min_dy"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[2]","name":""}],"name":"remove_liquidity","inputs":[{"type":"uint256","name":"_amount"},{"type":"uint256[2]","name":"_min_amounts"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":""}],"name":"remove_liquidity_imbalance","inputs":[{"type":"uint256[2]","name":"_amounts"},{"type":"uint256","name":"_max_burn_amount"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"calc_withdraw_one_coin","inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":""}],"name":"remove_liquidity_one_coin","inputs":[{"type":"uint256","name":"_token_amount"},{"type":"int128","name":"i"},{"type":"uint256","name":"_min_amount"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ramp_A","inputs":[{"type":"uint256","name":"_future_A"},{"type":"uint256","name":"_future_time"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stop_ramp_A","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"commit_new_fee","inputs":[{"type":"uint256","name":"_new_fee"},{"type":"uint256","name":"_new_admin_fee"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"apply_new_fee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revert_new_parameters","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"commit_transfer_ownership","inputs":[{"type":"address","name":"_owner"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"apply_transfer_ownership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revert_transfer_ownership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"admin_balances","inputs":[{"type":"uint256","name":"i"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw_admin_fees","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"donate_admin_fees","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"kill_me","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unkill_me","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"coins","inputs":[{"type":"uint256","name":"arg0"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"balances","inputs":[{"type":"uint256","name":"arg0"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"fee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"admin_fee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"lp_token","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"initial_A","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"future_A","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"initial_A_time","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"future_A_time","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"admin_actions_deadline","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"transfer_ownership_deadline","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"future_fee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"future_admin_fee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"future_owner","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x60206130aa6000396000518060a01c6130a55760405260206130ca6000396000518060a01c6130a55760605260206130ea6000396000518060a01c6130a557608052602061310a6000396000518060a01c6130a55760a052346130a55760006002905b8060c05260c051600181116130a55760051b60600151156130a557600101818118610062575050606051600155608051600255602061312a600039600051606481028160648204186130a5579050600955602061312a600039600051606481028160648204186130a5579050600a55602061314a600039600051600555602061316a60003960005160065560405160075542624f1a0081018181106130a557905060135560a051600855612f8661011e61000039612f86610000f36003361161000c576123a7565b60003560e01c34612f745763f446c1d081186100465760043610612f745761003460c06123ad565b60c05160648104905060e052602060e0f35b6376a2f0f081186100695760043610612f7457602061006560c06123ad565b60c0f35b63bb7b8b80811861013d5760043610612f74576003546101e052600454610200526100956101a06123ad565b6101a051610220526101e05160405261020051606052610220516080526100bd6101c06124d2565b6101c051610180526008546318160ddd6101c05260206101c060046101dc845afa6100ed573d600060003e3d6000fd5b60203d10612f74576101c09050516101a05261018051670de0b6b3a7640000810281670de0b6b3a7640000820418612f745790506101a0518015612f7457808204905090506101c05260206101c0f35b63ed8e84f381186103215760643610612f74576044358060011c612f74576101805261016a6101c06123ad565b6101c0516101a0526003546101c0526004546101e0526101c0516040526101e0516060526101a0516080526101a06102206124d2565b610220516102005260006002905b8061022052610180516101f9576102205160018111612f745760051b6101c00180516102205160018111612f745760051b60040135808203828111612f745790509050815250610233565b6102205160018111612f745760051b6101c00180516102205160018111612f745760051b60040135808201828110612f7457905090508152505b6001018181186101ae5750506101c0516040526101e0516060526101a05160805261025f6102406124d2565b61024051610220526008546318160ddd610260526020610260600461027c845afa61028f573d600060003e3d6000fd5b60203d10612f745761026090505161024052600061026052610180516102ce576102005161022051808203828111612f745790509050610260526102e9565b6102205161020051808203828111612f745790509050610260525b6102605161024051808202811583838304141715612f745790509050610200518015612f745780820490509050610280526020610280f35b630b4c7e4d811861093b5760643610612f7457600054600214612f74576002600055601254612f74576103556101a06123ad565b6101a051610180526003546101a0526004546101c0526101a0516040526101c0516060526101805160805261038b6102006124d2565b610200516101e05260085461020052610200516318160ddd610240526020610240600461025c845afa6103c3573d600060003e3d6000fd5b60203d10612f7457610240905051610220526101a051610240526101c0516102605260006002905b806102805261022051610411576102805160018111612f745760051b6004013515612f74575b6102805160018111612f745760051b6102400180516102805160018111612f745760051b60040135808201828110612f7457905090508152506001018181186103eb5750506102405160405261026051606052610180516080526104766102a06124d2565b6102a051610280526101e051610280511115612f7457610280516102a0526060366102c03761022051156106c1576005548060011b818160011c18612f745790508060021c9050610320526006546103405260006002905b8061036052610280516103605160018111612f745760051b6101a00151808202811583838304141715612f7457905090506101e0518015612f7457808204905090506103805260006103a0526103605160018111612f745760051b61024001516103c0526103c051610380511161055e576103c05161038051808203828111612f7457905090506103a052610579565b610380516103c051808203828111612f7457905090506103a0525b610320516103a051808202811583838304141715612f7457905090506402540be400810490506103605160018111612f745760051b6102c001526103c0516103605160018111612f745760051b6102c0015161034051808202811583838304141715612f7457905090506402540be40081049050808203828111612f7457905090506103605160018111612f7457600301556103605160018111612f745760051b6102400180516103605160018111612f745760051b6102c00151808203828111612f7457905090508152506001018181186104ce5750506102405160405261026051606052610180516080526106716103606124d2565b610360516102a052610220516102a0516101e051808203828111612f745790509050808202811583838304141715612f7457905090506101e0518015612f745780820490509050610300526106d8565b610240516003556102605160045561028051610300525b60443561030051101561074b576014610320527f536c697070616765207363726577656420796f750000000000000000000000006103405261032050610320518061034001601f826000031636823750506308c379a06102e052602061030052601f19601f6103205101166044016102fcfd5b60006002905b80610320526103205160018111612f745760051b600401351561086c5760006004610380527f23b872dd000000000000000000000000000000000000000000000000000000006103a052610380805160208201836103e0018151815250508083019250505033816103e0015260208101905030816103e001526020810190506103205160018111612f745760051b60040135816103e00152602081019050806103c0526103c0505060206104806103c0516103e060006103205160018111612f7457600101545af1610828573d600060003e3d6000fd5b3d602081183d6020100218610460526104608051806103405260208201805161036052505050610340511561086c57610360516103405160200360031b1c15612f74575b600101818118610751575050610200516340c10f1961032052336103405261030051610360526020610320604461033c6000855af16108b0573d600060003e3d6000fd5b60203d10612f7457610320518060011c612f7457610380526103805050337f26f55a85081d24974e85c6c00045d0f0453991e95873f52bff0d21af4079a76860406004610320376102c051610360526102e05161038052610280516103a0526102205161030051808201828110612f7457905090506103c05260c0610320a260206103006003600055f35b635e0d443f8118610a635760643610612f745760043580600f0b8118612f74576103605260243580600f0b8118612f7457610380526003546103a0526004546103c0526103605160018111612f745760051b6103a00151604435808201828110612f7457905090506103e0526103605161018052610380516101a0526103e0516101c0526103a0516101e0526103c051610200526109da6104206126dd565b61042051610400526103805160018111612f745760051b6103a0015161040051808203828111612f74579050905060018103818111612f745790506104205260055461042051808202811583838304141715612f7457905090506402540be40081049050610440526104205161044051808203828111612f745790509050610460526020610460f35b633df021248118610f0b5760843610612f745760043580600f0b8118612f74576103605260243580600f0b8118612f745761038052600054600214612f74576002600055601254612f74576003546103a0526004546103c0526103a0516103e0526103c051610400526103605160018111612f745760051b6103e00151604435808201828110612f745790509050610420526103605161018052610380516101a052610420516101c0526103e0516101e0526104005161020052610b286104606126dd565b61046051610440526103805160018111612f745760051b6103e0015161044051808203828111612f74579050905060018103818111612f745790506104605261046051600554808202811583838304141715612f7457905090506402540be40081049050610480526104605161048051808203828111612f74579050905061046052606435610460511015610c4257602e6104a0527f45786368616e676520726573756c74656420696e20666577657220636f696e736104c0527f207468616e2065787065637465640000000000000000000000000000000000006104e0526104a0506104a051806104c001601f826000031636823750506308c379a061046052602061048052601f19601f6104a051011660440161047cfd5b61048051600654808202811583838304141715612f7457905090506402540be400810490506104a0526103605160018111612f745760051b6103a00151604435808201828110612f7457905090506103605160018111612f7457600301556103805160018111612f745760051b6103a0015161046051808203828111612f7457905090506104a051808203828111612f7457905090506103805160018111612f74576003015560006004610500527f23b872dd000000000000000000000000000000000000000000000000000000006105205261050080516020820183610560018151815250508083019250505033816105600152602081019050308161056001526020810190506044358161056001526020810190508061054052610540505060206106006105405161056060006103605160018111612f7457600101545af1610d92573d600060003e3d6000fd5b3d602081183d60201002186105e0526105e08051806104c0526020820180516104e0525050506104c05115610dd6576104e0516104c05160200360031b1c15612f74575b60006004610500527fa9059cbb000000000000000000000000000000000000000000000000000000006105205261050080516020820183610560018151815250508083019250505033816105600152602081019050610460518161056001526020810190508061054052610540505060206105e06105405161056060006103805160018111612f7457600101545af1610e74573d600060003e3d6000fd5b3d602081183d60201002186105c0526105c08051806104c0526020820180516104e0525050506104c05115610eb8576104e0516104c05160200360031b1c15612f74575b337f8b3e96f2b889fa771c53c981b40daf005f63f637f1869f707052d15a3dd97140610360516105005260443561052052610380516105405261046051610560526080610500a260206104606003600055f35b635b36389c811861122f5760643610612f7457600054600214612f745760026000556008546040526040516318160ddd608052602060806004609c845afa610f58573d600060003e3d6000fd5b60203d10612f7457608090505160605260403660803760006002905b8060c05260c05160018111612f74576003015460e05260e051600435808202811583838304141715612f7457905090506060518015612f7457808204905090506101005260c05160018111612f745760051b6024013561010051101561105d576030610120527f5769746864726177616c20726573756c74656420696e20666577657220636f69610140527f6e73207468616e206578706563746564000000000000000000000000000000006101605261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60e05161010051808203828111612f74579050905060c05160018111612f7457600301556101005160c05160018111612f745760051b6080015260006004610160527fa9059cbb0000000000000000000000000000000000000000000000000000000061018052610160805160208201836101c0018151815250508083019250505033816101c0015260208101905061010051816101c00152602081019050806101a0526101a0505060206102406101a0516101c0600060c05160018111612f7457600101545af1611134573d600060003e3d6000fd5b3d602081183d6020100218610220526102208051806101205260208201805161014052505050610120511561117857610140516101205160200360031b1c15612f74575b600101818118610f745750506040516379cc679060c0523360e05260043561010052602060c0604460dc6000855af16111b6573d600060003e3d6000fd5b60203d10612f745760c0518060011c612f7457610120526101205050337f7c363854ccf79623411f8995b362bce5eddff18c927edc6f5dbbb5e05819a82c60805160c05260a05160e05260403661010037606051600435808203828111612f7457905090506101405260a060c0a2604060806003600055f35b63e310327381186117fe5760643610612f7457600054600214612f74576002600055601254612f74576112636101a06123ad565b6101a051610180526003546101a0526004546101c0526101a0516040526101c051606052610180516080526112996102006124d2565b610200516101e0526101a051610200526101c0516102205260006002905b80610240526102405160018111612f745760051b6102000180516102405160018111612f745760051b60040135808203828111612f7457905090508152506001018181186112b75750506102005160405261022051606052610180516080526113216102606124d2565b61026051610240526005548060011b818160011c18612f745790508060021c905061026052600654610280526040366102a03760006002905b806102e0526102e05160018111612f745760051b610200015161030052610240516102e05160018111612f745760051b6101a00151808202811583838304141715612f7457905090506101e0518015612f745780820490509050610320526000610340526103005161032051116113ea576103005161032051808203828111612f74579050905061034052611405565b6103205161030051808203828111612f745790509050610340525b6102605161034051808202811583838304141715612f7457905090506402540be400810490506102e05160018111612f745760051b6102a00152610300516102e05160018111612f745760051b6102a0015161028051808202811583838304141715612f7457905090506402540be40081049050808203828111612f7457905090506102e05160018111612f745760030155610300516102e05160018111612f745760051b6102a00151808203828111612f7457905090506102e05160018111612f745760051b610200015260010181811861135a5750506102005160405261022051606052610180516080526114fd6103006124d2565b610300516102e05260085461030052610300516318160ddd610340526020610340600461035c845afa611535573d600060003e3d6000fd5b60203d10612f7457610340905051610320526101e0516102e051808203828111612f74579050905061032051808202811583838304141715612f7457905090506101e0518015612f745780820490509050610340526103405115612f74576103405160018101818110612f745790506103405260443561034051111561161b576014610360527f536c697070616765207363726577656420796f750000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b610300516379cc6790610360523361038052610340516103a0526020610360604461037c6000855af1611653573d600060003e3d6000fd5b60203d10612f7457610360518060011c612f74576103c0526103c0505060006002905b80610360526103605160018111612f745760051b600401351561178457600060046103c0527fa9059cbb000000000000000000000000000000000000000000000000000000006103e0526103c0805160208201836104200181518152505080830192505050338161042001526020810190506103605160018111612f745760051b600401358161042001526020810190508061040052610400505060206104a06104005161042060006103605160018111612f7457600101545af1611740573d600060003e3d6000fd5b3d602081183d602010021861048052610480805180610380526020820180516103a0525050506103805115611784576103a0516103805160200360031b1c15612f74575b600101818118611676575050337f2b5508378d7e19e0d5fa338419034731416c4f5b219a10379956f764317fd47e60406004610360376102a0516103a0526102c0516103c052610240516103e0526103205161034051808203828111612f7457905090506104005260c0610360a260206103406003600055f35b63cc2b27d781186118435760443610612f745760243580600f0b8118612f74576103a05260206004356101e0526103a0516102005261183e6103c0612c4d565b6103c0f35b631a4d01d28118611b175760643610612f745760243580600f0b8118612f74576103a052600054600214612f74576002600055601254612f74576060366103c0376004356101e0526103a0516102005261189e610420612c4d565b61042080516103c05260208101516103e052604081015161040052506044356103c051101561192d576018610420527f4e6f7420656e6f75676820636f696e732072656d6f76656400000000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b6103a05160018111612f745760030180546103c0516103e051600654808202811583838304141715612f7457905090506402540be40081049050808201828110612f745790509050808203828111612f7457905090508155506008546379cc6790610420523361044052600435610460526020610420604461043c6000855af16119bc573d600060003e3d6000fd5b60203d10612f7457610420518060011c612f745761048052610480505060006004610460527fa9059cbb0000000000000000000000000000000000000000000000000000000061048052610460805160208201836104c0018151815250508083019250505033816104c001526020810190506103c051816104c00152602081019050806104a0526104a0505060206105406104a0516104c060006103a05160018111612f7457600101545af1611a77573d600060003e3d6000fd5b3d602081183d60201002186105205261052080518061042052602082018051610440525050506104205115611abb57610440516104205160200360031b1c15612f74575b337f5ad056f2e28a8cec232015406b843668c1e36cda598127ec3b8c59b8c72773a0600435610460526103c0516104805261040051600435808203828111612f7457905090506104a0526060610460a260206103c06003600055f35b633c157e648118611c475760443610612f74576007543318612f7457600b54620151808101818110612f745790504210612f745742620151808101818110612f7457905060243510612f7457611b6d60e06123ad565b60e05160c05260043560648102816064820418612f7457905060e05260043515611b9f57620f423f6004351115611ba2565b60005b15612f745760c05160e05110611bd25760c051600a810281600a820418612f7457905060e05111612f7457611bee565b60c05160e051600a810281600a820418612f7457905010612f74575b60c05160095560e051600a5542600b55602435600c557fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c25460c0516101005260e051610120524261014052602435610160526080610100a1005b63551a65888118611cba5760043610612f74576007543318612f7457611c6d60e06123ad565b60e05160c05260c05160095560c051600a5542600b5542600c557f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193860c05160e0524261010052604060e0a1005b635b5a14678118611d505760443610612f74576007543318612f7457600d54612f745764012a05f20060043511612f74576402540be40060243511612f7457426203f4808101818110612f74579050604052604051600d55600435600f556024356010556040517f351fc5da2fbf480f2225debf3664a4bc90fa9923743aad58b4603f648e931fe06040600460603760406060a2005b634f12fe978118611dce5760043610612f74576007543318612f7457600d544210612f7457600d5415612f74576000600d55600f546040526010546060526040516005556060516006557fbe12859b636aed607d5230b2cc2711f68d70e51060e6cca1f575ef5d2fcc95d160405160805260605160a05260406080a1005b63226840fb8118611df15760043610612f74576007543318612f74576000600d55005b636b441a408118611e6f5760243610612f74576004358060a01c612f74576040526007543318612f7457600e54612f7457426203f4808101818110612f74579050606052606051600e556040516011556040516060517f181aa3aa17d4cbf99265dd4443eba009433d3cde79d60164fde1d1a192beb93560006080a3005b636a1c05ae8118611ed85760043610612f74576007543318612f7457600e544210612f7457600e5415612f74576000600e556011546040526040516007556040517f71614071b88dee5e0b2ae578a9dd7b2ebbe9ae832ba419dc0242cd065a290b6c60006060a2005b6386fbf1938118611efb5760043610612f74576007543318612f74576000600e55005b63e2e7d2648118611f765760243610612f745760043560018111612f7457600101546370a0823160405230606052602060406024605c845afa611f43573d600060003e3d6000fd5b60203d10612f7457604090505160043560018111612f745760030154808203828111612f74579050905060805260206080f35b6330c5408581186120e75760043610612f74576007543318612f745760006002905b8060405260405160018111612f7457600101546060526060516370a0823160a0523060c052602060a0602460bc845afa611fd7573d600060003e3d6000fd5b60203d10612f745760a090505160405160018111612f745760030154808203828111612f745790509050608052608051156120d9576000600460e0527fa9059cbb000000000000000000000000000000000000000000000000000000006101005260e0805160208201836101400181518152505080830192505050338161014001526020810190506080518161014001526020810190508061012052610120505060206101c06101205161014060006060515af161209a573d600060003e3d6000fd5b3d602081183d60201002186101a0526101a080518060a05260208201805160c05250505060a051156120d95760c05160a05160200360031b1c15612f74575b600101818118611f98575050005b63524c3901811861216c5760043610612f74576007543318612f745760006002905b8060405260405160018111612f7457600101546370a0823160605230608052602060606024607c845afa612142573d600060003e3d6000fd5b60203d10612f7457606090505160405160018111612f745760030155600101818118612109575050005b63e369885381186121995760043610612f74576007543318612f7457426013541115612f74576001601255005b633046f97281186121bc5760043610612f74576007543318612f74576000601255005b63c661065781186121e75760243610612f745760043560018111612f74576001015460405260206040f35b634903b0d181186122125760243610612f745760043560018111612f74576003015460405260206040f35b63ddca3f4381186122315760043610612f745760055460405260206040f35b63fee3f7f981186122505760043610612f745760065460405260206040f35b638da5cb5b811861226f5760043610612f745760075460405260206040f35b6382c63066811861228e5760043610612f745760085460405260206040f35b635409491a81186122ad5760043610612f745760095460405260206040f35b63b4b577ad81186122cc5760043610612f7457600a5460405260206040f35b632081066c81186122eb5760043610612f7457600b5460405260206040f35b6314052288811861230a5760043610612f7457600c5460405260206040f35b63405e28f881186123295760043610612f7457600d5460405260206040f35b63e0a0b58681186123485760043610612f7457600e5460405260206040f35b6358680d0b81186123675760043610612f7457600f5460405260206040f35b63e382446281186123865760043610612f745760105460405260206040f35b631ec0cdc181186123a55760043610612f745760115460405260206040f35b505b60006000fd5b600c54604052600a5460605260405142106123d1576060518152506124d0566124d0565b600954608052600b5460a0526080516060511161246057608051608051606051808203828111612f7457905090504260a051808203828111612f745790509050808202811583838304141715612f74579050905060405160a051808203828111612f7457905090508015612f745780820490509050808203828111612f7457905090508152506124d0566124d0565b608051606051608051808203828111612f7457905090504260a051808203828111612f745790509050808202811583838304141715612f74579050905060405160a051808203828111612f7457905090508015612f745780820490509050808201828110612f7457905090508152505b565b60403660a03760006002905b8060051b6040015160e05260a05160e051808201828110612f74579050905060a0526001018181186124de57505060a05161251d5760008152506126db565b60a05160e0526080518060011b818160011c18612f7457905061010052600060ff905b806101205260e0516101405260006002905b8060051b60400151610160526101405160e051808202811583838304141715612f745790509050610160518060011b818160011c18612f745790508015612f7457808204905090506101405260010181811861255257505060e05160c0526101005160a051808202811583838304141715612f745790509050606481049050610140518060011b818160011c18612f74579050808201828110612f74579050905060e051808202811583838304141715612f7457905090506101005160648103818111612f7457905060e051808202811583838304141715612f7457905090506064810490506101405160038102816003820418612f74579050808201828110612f7457905090508015612f74578082049050905060e05260c05160e051116126a157600160c05160e051808203828111612f745790509050116126c95760e05183525050506126db566126c9565b600160e05160c051808203828111612f745790509050116126c95760e05183525050506126db565b60010181811861254057505060006000fd5b565b6101a0516101805114612f745760006101a05112612f745760016101a05113612f745760006101805112612f745760016101805113612f74576127216102406123ad565b61024051610220526101e05160405261020051606052610220516080526127496102606124d2565b6102605161024052610220518060011b818160011c18612f745790506102605261024051610280526060366102a03760006002905b80610300526101805160008112612f745761030051186127a5576101c0516102c0526127db565b6101a05160008112612f74576103005114612837576103005160018111612f745760051b6101e001516102c0526127db56612837565b6102a0516102c051808201828110612f7457905090506102a0526102805161024051808202811583838304141715612f7457905090506102c0518060011b818160011c18612f745790508015612f745780820490509050610280525b60010181811861277e5750506102805161024051808202811583838304141715612f74579050905060648102816064820418612f74579050610260518060011b818160011c18612f745790508015612f745780820490509050610280526102a0516102405160648102816064820418612f74579050610260518015612f745780820490509050808201828110612f745790509050610300526102405161032052600060ff905b8061034052610320516102e0526103205161032051808202811583838304141715612f74579050905061028051808201828110612f745790509050610320518060011b818160011c18612f7457905061030051808201828110612f74579050905061024051808203828111612f7457905090508015612f745780820490509050610320526102e051610320511161299d5760016102e05161032051808203828111612f745790509050116129c8576103205183525050506129da566129c8565b6001610320516102e051808203828111612f745790509050116129c8576103205183525050506129da565b6001018181186128dd57505060006000fd5b565b600060605112612f7457600160605113612f74576040518060011b818160011c18612f7457905060e05260c051610100526060366101203760006002905b806101805260605160008112612f74576101805114612aae576101805160018111612f745760051b6080015161014052612a5356612aae565b6101205161014051808201828110612f745790509050610120526101005160c051808202811583838304141715612f745790509050610140518060011b818160011c18612f745790508015612f745780820490509050610100525b600101818118612a1a5750506101005160c051808202811583838304141715612f74579050905060648102816064820418612f7457905060e0518060011b818160011c18612f745790508015612f745780820490509050610100526101205160c05160648102816064820418612f7457905060e0518015612f745780820490509050808201828110612f7457905090506101805260c0516101a052600060ff905b806101c0526101a051610160526101a0516101a051808202811583838304141715612f74579050905061010051808201828110612f7457905090506101a0518060011b818160011c18612f7457905061018051808201828110612f74579050905060c051808203828111612f7457905090508015612f7457808204905090506101a052610160516101a05111612c0e576001610160516101a051808203828111612f74579050905011612c39576101a0518352505050612c4b56612c39565b60016101a05161016051808203828111612f74579050905011612c39576101a0518352505050612c4b565b600101818118612b4f57505060006000fd5b565b612c586102406123ad565b61024051610220526003546102405260045461026052610240516040526102605160605261022051608052612c8e6102a06124d2565b6102a051610280526008546318160ddd6102c05260206102c060046102dc845afa612cbe573d600060003e3d6000fd5b60203d10612f74576102c09050516102a052610280516101e05161028051808202811583838304141715612f7457905090506102a0518015612f745780820490509050808203828111612f7457905090506102c0526102205160405261020051606052610240516080526102605160a0526102c05160c052612d416103006129dc565b610300516102e052610240516103005261026051610320526005548060011b818160011c18612f745790508060021c90506103405260006002905b80610360526000610380526102005160008112612f74576103605118612df4576103605160018111612f745760051b61024001516102c051808202811583838304141715612f745790509050610280518015612f7457808204905090506102e051808203828111612f74579050905061038052612e58565b6103605160018111612f745760051b61024001516103605160018111612f745760051b61024001516102c051808202811583838304141715612f745790509050610280518015612f745780820490509050808203828111612f745790509050610380525b6103605160018111612f745760051b6103000180516103405161038051808202811583838304141715612f7457905090506402540be40081049050808203828111612f745790509050815250600101818118612d7c5750506102005160018111612f745760051b61030001516102205160405261020051606052610300516080526103205160a0526102c05160c052612ef26103806129dc565b61038051808203828111612f745790509050610360526103605160018103818111612f74579050610360526102005160018111612f745760051b61024001516102e051808203828111612f745790509050610380526103605181526103805161036051808203828111612f74579050905060208201526102a051604082015250565b600080fda165767970657283000307000b005b600080fd000000000000000000000000ecb456ea5365865ebab8a2661b0c503410e9b347000000000000000000000000853d955acef822db058eb8505911ed77f175b99e0000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1000000000000000000000000fc2838a17d8e8b1d5456e0a351b0708a0921114700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000012a05f200

Deployed ByteCode

0x6003361161000c576123a7565b60003560e01c34612f745763f446c1d081186100465760043610612f745761003460c06123ad565b60c05160648104905060e052602060e0f35b6376a2f0f081186100695760043610612f7457602061006560c06123ad565b60c0f35b63bb7b8b80811861013d5760043610612f74576003546101e052600454610200526100956101a06123ad565b6101a051610220526101e05160405261020051606052610220516080526100bd6101c06124d2565b6101c051610180526008546318160ddd6101c05260206101c060046101dc845afa6100ed573d600060003e3d6000fd5b60203d10612f74576101c09050516101a05261018051670de0b6b3a7640000810281670de0b6b3a7640000820418612f745790506101a0518015612f7457808204905090506101c05260206101c0f35b63ed8e84f381186103215760643610612f74576044358060011c612f74576101805261016a6101c06123ad565b6101c0516101a0526003546101c0526004546101e0526101c0516040526101e0516060526101a0516080526101a06102206124d2565b610220516102005260006002905b8061022052610180516101f9576102205160018111612f745760051b6101c00180516102205160018111612f745760051b60040135808203828111612f745790509050815250610233565b6102205160018111612f745760051b6101c00180516102205160018111612f745760051b60040135808201828110612f7457905090508152505b6001018181186101ae5750506101c0516040526101e0516060526101a05160805261025f6102406124d2565b61024051610220526008546318160ddd610260526020610260600461027c845afa61028f573d600060003e3d6000fd5b60203d10612f745761026090505161024052600061026052610180516102ce576102005161022051808203828111612f745790509050610260526102e9565b6102205161020051808203828111612f745790509050610260525b6102605161024051808202811583838304141715612f745790509050610200518015612f745780820490509050610280526020610280f35b630b4c7e4d811861093b5760643610612f7457600054600214612f74576002600055601254612f74576103556101a06123ad565b6101a051610180526003546101a0526004546101c0526101a0516040526101c0516060526101805160805261038b6102006124d2565b610200516101e05260085461020052610200516318160ddd610240526020610240600461025c845afa6103c3573d600060003e3d6000fd5b60203d10612f7457610240905051610220526101a051610240526101c0516102605260006002905b806102805261022051610411576102805160018111612f745760051b6004013515612f74575b6102805160018111612f745760051b6102400180516102805160018111612f745760051b60040135808201828110612f7457905090508152506001018181186103eb5750506102405160405261026051606052610180516080526104766102a06124d2565b6102a051610280526101e051610280511115612f7457610280516102a0526060366102c03761022051156106c1576005548060011b818160011c18612f745790508060021c9050610320526006546103405260006002905b8061036052610280516103605160018111612f745760051b6101a00151808202811583838304141715612f7457905090506101e0518015612f7457808204905090506103805260006103a0526103605160018111612f745760051b61024001516103c0526103c051610380511161055e576103c05161038051808203828111612f7457905090506103a052610579565b610380516103c051808203828111612f7457905090506103a0525b610320516103a051808202811583838304141715612f7457905090506402540be400810490506103605160018111612f745760051b6102c001526103c0516103605160018111612f745760051b6102c0015161034051808202811583838304141715612f7457905090506402540be40081049050808203828111612f7457905090506103605160018111612f7457600301556103605160018111612f745760051b6102400180516103605160018111612f745760051b6102c00151808203828111612f7457905090508152506001018181186104ce5750506102405160405261026051606052610180516080526106716103606124d2565b610360516102a052610220516102a0516101e051808203828111612f745790509050808202811583838304141715612f7457905090506101e0518015612f745780820490509050610300526106d8565b610240516003556102605160045561028051610300525b60443561030051101561074b576014610320527f536c697070616765207363726577656420796f750000000000000000000000006103405261032050610320518061034001601f826000031636823750506308c379a06102e052602061030052601f19601f6103205101166044016102fcfd5b60006002905b80610320526103205160018111612f745760051b600401351561086c5760006004610380527f23b872dd000000000000000000000000000000000000000000000000000000006103a052610380805160208201836103e0018151815250508083019250505033816103e0015260208101905030816103e001526020810190506103205160018111612f745760051b60040135816103e00152602081019050806103c0526103c0505060206104806103c0516103e060006103205160018111612f7457600101545af1610828573d600060003e3d6000fd5b3d602081183d6020100218610460526104608051806103405260208201805161036052505050610340511561086c57610360516103405160200360031b1c15612f74575b600101818118610751575050610200516340c10f1961032052336103405261030051610360526020610320604461033c6000855af16108b0573d600060003e3d6000fd5b60203d10612f7457610320518060011c612f7457610380526103805050337f26f55a85081d24974e85c6c00045d0f0453991e95873f52bff0d21af4079a76860406004610320376102c051610360526102e05161038052610280516103a0526102205161030051808201828110612f7457905090506103c05260c0610320a260206103006003600055f35b635e0d443f8118610a635760643610612f745760043580600f0b8118612f74576103605260243580600f0b8118612f7457610380526003546103a0526004546103c0526103605160018111612f745760051b6103a00151604435808201828110612f7457905090506103e0526103605161018052610380516101a0526103e0516101c0526103a0516101e0526103c051610200526109da6104206126dd565b61042051610400526103805160018111612f745760051b6103a0015161040051808203828111612f74579050905060018103818111612f745790506104205260055461042051808202811583838304141715612f7457905090506402540be40081049050610440526104205161044051808203828111612f745790509050610460526020610460f35b633df021248118610f0b5760843610612f745760043580600f0b8118612f74576103605260243580600f0b8118612f745761038052600054600214612f74576002600055601254612f74576003546103a0526004546103c0526103a0516103e0526103c051610400526103605160018111612f745760051b6103e00151604435808201828110612f745790509050610420526103605161018052610380516101a052610420516101c0526103e0516101e0526104005161020052610b286104606126dd565b61046051610440526103805160018111612f745760051b6103e0015161044051808203828111612f74579050905060018103818111612f745790506104605261046051600554808202811583838304141715612f7457905090506402540be40081049050610480526104605161048051808203828111612f74579050905061046052606435610460511015610c4257602e6104a0527f45786368616e676520726573756c74656420696e20666577657220636f696e736104c0527f207468616e2065787065637465640000000000000000000000000000000000006104e0526104a0506104a051806104c001601f826000031636823750506308c379a061046052602061048052601f19601f6104a051011660440161047cfd5b61048051600654808202811583838304141715612f7457905090506402540be400810490506104a0526103605160018111612f745760051b6103a00151604435808201828110612f7457905090506103605160018111612f7457600301556103805160018111612f745760051b6103a0015161046051808203828111612f7457905090506104a051808203828111612f7457905090506103805160018111612f74576003015560006004610500527f23b872dd000000000000000000000000000000000000000000000000000000006105205261050080516020820183610560018151815250508083019250505033816105600152602081019050308161056001526020810190506044358161056001526020810190508061054052610540505060206106006105405161056060006103605160018111612f7457600101545af1610d92573d600060003e3d6000fd5b3d602081183d60201002186105e0526105e08051806104c0526020820180516104e0525050506104c05115610dd6576104e0516104c05160200360031b1c15612f74575b60006004610500527fa9059cbb000000000000000000000000000000000000000000000000000000006105205261050080516020820183610560018151815250508083019250505033816105600152602081019050610460518161056001526020810190508061054052610540505060206105e06105405161056060006103805160018111612f7457600101545af1610e74573d600060003e3d6000fd5b3d602081183d60201002186105c0526105c08051806104c0526020820180516104e0525050506104c05115610eb8576104e0516104c05160200360031b1c15612f74575b337f8b3e96f2b889fa771c53c981b40daf005f63f637f1869f707052d15a3dd97140610360516105005260443561052052610380516105405261046051610560526080610500a260206104606003600055f35b635b36389c811861122f5760643610612f7457600054600214612f745760026000556008546040526040516318160ddd608052602060806004609c845afa610f58573d600060003e3d6000fd5b60203d10612f7457608090505160605260403660803760006002905b8060c05260c05160018111612f74576003015460e05260e051600435808202811583838304141715612f7457905090506060518015612f7457808204905090506101005260c05160018111612f745760051b6024013561010051101561105d576030610120527f5769746864726177616c20726573756c74656420696e20666577657220636f69610140527f6e73207468616e206578706563746564000000000000000000000000000000006101605261012050610120518061014001601f826000031636823750506308c379a060e052602061010052601f19601f61012051011660440160fcfd5b60e05161010051808203828111612f74579050905060c05160018111612f7457600301556101005160c05160018111612f745760051b6080015260006004610160527fa9059cbb0000000000000000000000000000000000000000000000000000000061018052610160805160208201836101c0018151815250508083019250505033816101c0015260208101905061010051816101c00152602081019050806101a0526101a0505060206102406101a0516101c0600060c05160018111612f7457600101545af1611134573d600060003e3d6000fd5b3d602081183d6020100218610220526102208051806101205260208201805161014052505050610120511561117857610140516101205160200360031b1c15612f74575b600101818118610f745750506040516379cc679060c0523360e05260043561010052602060c0604460dc6000855af16111b6573d600060003e3d6000fd5b60203d10612f745760c0518060011c612f7457610120526101205050337f7c363854ccf79623411f8995b362bce5eddff18c927edc6f5dbbb5e05819a82c60805160c05260a05160e05260403661010037606051600435808203828111612f7457905090506101405260a060c0a2604060806003600055f35b63e310327381186117fe5760643610612f7457600054600214612f74576002600055601254612f74576112636101a06123ad565b6101a051610180526003546101a0526004546101c0526101a0516040526101c051606052610180516080526112996102006124d2565b610200516101e0526101a051610200526101c0516102205260006002905b80610240526102405160018111612f745760051b6102000180516102405160018111612f745760051b60040135808203828111612f7457905090508152506001018181186112b75750506102005160405261022051606052610180516080526113216102606124d2565b61026051610240526005548060011b818160011c18612f745790508060021c905061026052600654610280526040366102a03760006002905b806102e0526102e05160018111612f745760051b610200015161030052610240516102e05160018111612f745760051b6101a00151808202811583838304141715612f7457905090506101e0518015612f745780820490509050610320526000610340526103005161032051116113ea576103005161032051808203828111612f74579050905061034052611405565b6103205161030051808203828111612f745790509050610340525b6102605161034051808202811583838304141715612f7457905090506402540be400810490506102e05160018111612f745760051b6102a00152610300516102e05160018111612f745760051b6102a0015161028051808202811583838304141715612f7457905090506402540be40081049050808203828111612f7457905090506102e05160018111612f745760030155610300516102e05160018111612f745760051b6102a00151808203828111612f7457905090506102e05160018111612f745760051b610200015260010181811861135a5750506102005160405261022051606052610180516080526114fd6103006124d2565b610300516102e05260085461030052610300516318160ddd610340526020610340600461035c845afa611535573d600060003e3d6000fd5b60203d10612f7457610340905051610320526101e0516102e051808203828111612f74579050905061032051808202811583838304141715612f7457905090506101e0518015612f745780820490509050610340526103405115612f74576103405160018101818110612f745790506103405260443561034051111561161b576014610360527f536c697070616765207363726577656420796f750000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b610300516379cc6790610360523361038052610340516103a0526020610360604461037c6000855af1611653573d600060003e3d6000fd5b60203d10612f7457610360518060011c612f74576103c0526103c0505060006002905b80610360526103605160018111612f745760051b600401351561178457600060046103c0527fa9059cbb000000000000000000000000000000000000000000000000000000006103e0526103c0805160208201836104200181518152505080830192505050338161042001526020810190506103605160018111612f745760051b600401358161042001526020810190508061040052610400505060206104a06104005161042060006103605160018111612f7457600101545af1611740573d600060003e3d6000fd5b3d602081183d602010021861048052610480805180610380526020820180516103a0525050506103805115611784576103a0516103805160200360031b1c15612f74575b600101818118611676575050337f2b5508378d7e19e0d5fa338419034731416c4f5b219a10379956f764317fd47e60406004610360376102a0516103a0526102c0516103c052610240516103e0526103205161034051808203828111612f7457905090506104005260c0610360a260206103406003600055f35b63cc2b27d781186118435760443610612f745760243580600f0b8118612f74576103a05260206004356101e0526103a0516102005261183e6103c0612c4d565b6103c0f35b631a4d01d28118611b175760643610612f745760243580600f0b8118612f74576103a052600054600214612f74576002600055601254612f74576060366103c0376004356101e0526103a0516102005261189e610420612c4d565b61042080516103c05260208101516103e052604081015161040052506044356103c051101561192d576018610420527f4e6f7420656e6f75676820636f696e732072656d6f76656400000000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b6103a05160018111612f745760030180546103c0516103e051600654808202811583838304141715612f7457905090506402540be40081049050808201828110612f745790509050808203828111612f7457905090508155506008546379cc6790610420523361044052600435610460526020610420604461043c6000855af16119bc573d600060003e3d6000fd5b60203d10612f7457610420518060011c612f745761048052610480505060006004610460527fa9059cbb0000000000000000000000000000000000000000000000000000000061048052610460805160208201836104c0018151815250508083019250505033816104c001526020810190506103c051816104c00152602081019050806104a0526104a0505060206105406104a0516104c060006103a05160018111612f7457600101545af1611a77573d600060003e3d6000fd5b3d602081183d60201002186105205261052080518061042052602082018051610440525050506104205115611abb57610440516104205160200360031b1c15612f74575b337f5ad056f2e28a8cec232015406b843668c1e36cda598127ec3b8c59b8c72773a0600435610460526103c0516104805261040051600435808203828111612f7457905090506104a0526060610460a260206103c06003600055f35b633c157e648118611c475760443610612f74576007543318612f7457600b54620151808101818110612f745790504210612f745742620151808101818110612f7457905060243510612f7457611b6d60e06123ad565b60e05160c05260043560648102816064820418612f7457905060e05260043515611b9f57620f423f6004351115611ba2565b60005b15612f745760c05160e05110611bd25760c051600a810281600a820418612f7457905060e05111612f7457611bee565b60c05160e051600a810281600a820418612f7457905010612f74575b60c05160095560e051600a5542600b55602435600c557fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c25460c0516101005260e051610120524261014052602435610160526080610100a1005b63551a65888118611cba5760043610612f74576007543318612f7457611c6d60e06123ad565b60e05160c05260c05160095560c051600a5542600b5542600c557f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193860c05160e0524261010052604060e0a1005b635b5a14678118611d505760443610612f74576007543318612f7457600d54612f745764012a05f20060043511612f74576402540be40060243511612f7457426203f4808101818110612f74579050604052604051600d55600435600f556024356010556040517f351fc5da2fbf480f2225debf3664a4bc90fa9923743aad58b4603f648e931fe06040600460603760406060a2005b634f12fe978118611dce5760043610612f74576007543318612f7457600d544210612f7457600d5415612f74576000600d55600f546040526010546060526040516005556060516006557fbe12859b636aed607d5230b2cc2711f68d70e51060e6cca1f575ef5d2fcc95d160405160805260605160a05260406080a1005b63226840fb8118611df15760043610612f74576007543318612f74576000600d55005b636b441a408118611e6f5760243610612f74576004358060a01c612f74576040526007543318612f7457600e54612f7457426203f4808101818110612f74579050606052606051600e556040516011556040516060517f181aa3aa17d4cbf99265dd4443eba009433d3cde79d60164fde1d1a192beb93560006080a3005b636a1c05ae8118611ed85760043610612f74576007543318612f7457600e544210612f7457600e5415612f74576000600e556011546040526040516007556040517f71614071b88dee5e0b2ae578a9dd7b2ebbe9ae832ba419dc0242cd065a290b6c60006060a2005b6386fbf1938118611efb5760043610612f74576007543318612f74576000600e55005b63e2e7d2648118611f765760243610612f745760043560018111612f7457600101546370a0823160405230606052602060406024605c845afa611f43573d600060003e3d6000fd5b60203d10612f7457604090505160043560018111612f745760030154808203828111612f74579050905060805260206080f35b6330c5408581186120e75760043610612f74576007543318612f745760006002905b8060405260405160018111612f7457600101546060526060516370a0823160a0523060c052602060a0602460bc845afa611fd7573d600060003e3d6000fd5b60203d10612f745760a090505160405160018111612f745760030154808203828111612f745790509050608052608051156120d9576000600460e0527fa9059cbb000000000000000000000000000000000000000000000000000000006101005260e0805160208201836101400181518152505080830192505050338161014001526020810190506080518161014001526020810190508061012052610120505060206101c06101205161014060006060515af161209a573d600060003e3d6000fd5b3d602081183d60201002186101a0526101a080518060a05260208201805160c05250505060a051156120d95760c05160a05160200360031b1c15612f74575b600101818118611f98575050005b63524c3901811861216c5760043610612f74576007543318612f745760006002905b8060405260405160018111612f7457600101546370a0823160605230608052602060606024607c845afa612142573d600060003e3d6000fd5b60203d10612f7457606090505160405160018111612f745760030155600101818118612109575050005b63e369885381186121995760043610612f74576007543318612f7457426013541115612f74576001601255005b633046f97281186121bc5760043610612f74576007543318612f74576000601255005b63c661065781186121e75760243610612f745760043560018111612f74576001015460405260206040f35b634903b0d181186122125760243610612f745760043560018111612f74576003015460405260206040f35b63ddca3f4381186122315760043610612f745760055460405260206040f35b63fee3f7f981186122505760043610612f745760065460405260206040f35b638da5cb5b811861226f5760043610612f745760075460405260206040f35b6382c63066811861228e5760043610612f745760085460405260206040f35b635409491a81186122ad5760043610612f745760095460405260206040f35b63b4b577ad81186122cc5760043610612f7457600a5460405260206040f35b632081066c81186122eb5760043610612f7457600b5460405260206040f35b6314052288811861230a5760043610612f7457600c5460405260206040f35b63405e28f881186123295760043610612f7457600d5460405260206040f35b63e0a0b58681186123485760043610612f7457600e5460405260206040f35b6358680d0b81186123675760043610612f7457600f5460405260206040f35b63e382446281186123865760043610612f745760105460405260206040f35b631ec0cdc181186123a55760043610612f745760115460405260206040f35b505b60006000fd5b600c54604052600a5460605260405142106123d1576060518152506124d0566124d0565b600954608052600b5460a0526080516060511161246057608051608051606051808203828111612f7457905090504260a051808203828111612f745790509050808202811583838304141715612f74579050905060405160a051808203828111612f7457905090508015612f745780820490509050808203828111612f7457905090508152506124d0566124d0565b608051606051608051808203828111612f7457905090504260a051808203828111612f745790509050808202811583838304141715612f74579050905060405160a051808203828111612f7457905090508015612f745780820490509050808201828110612f7457905090508152505b565b60403660a03760006002905b8060051b6040015160e05260a05160e051808201828110612f74579050905060a0526001018181186124de57505060a05161251d5760008152506126db565b60a05160e0526080518060011b818160011c18612f7457905061010052600060ff905b806101205260e0516101405260006002905b8060051b60400151610160526101405160e051808202811583838304141715612f745790509050610160518060011b818160011c18612f745790508015612f7457808204905090506101405260010181811861255257505060e05160c0526101005160a051808202811583838304141715612f745790509050606481049050610140518060011b818160011c18612f74579050808201828110612f74579050905060e051808202811583838304141715612f7457905090506101005160648103818111612f7457905060e051808202811583838304141715612f7457905090506064810490506101405160038102816003820418612f74579050808201828110612f7457905090508015612f74578082049050905060e05260c05160e051116126a157600160c05160e051808203828111612f745790509050116126c95760e05183525050506126db566126c9565b600160e05160c051808203828111612f745790509050116126c95760e05183525050506126db565b60010181811861254057505060006000fd5b565b6101a0516101805114612f745760006101a05112612f745760016101a05113612f745760006101805112612f745760016101805113612f74576127216102406123ad565b61024051610220526101e05160405261020051606052610220516080526127496102606124d2565b6102605161024052610220518060011b818160011c18612f745790506102605261024051610280526060366102a03760006002905b80610300526101805160008112612f745761030051186127a5576101c0516102c0526127db565b6101a05160008112612f74576103005114612837576103005160018111612f745760051b6101e001516102c0526127db56612837565b6102a0516102c051808201828110612f7457905090506102a0526102805161024051808202811583838304141715612f7457905090506102c0518060011b818160011c18612f745790508015612f745780820490509050610280525b60010181811861277e5750506102805161024051808202811583838304141715612f74579050905060648102816064820418612f74579050610260518060011b818160011c18612f745790508015612f745780820490509050610280526102a0516102405160648102816064820418612f74579050610260518015612f745780820490509050808201828110612f745790509050610300526102405161032052600060ff905b8061034052610320516102e0526103205161032051808202811583838304141715612f74579050905061028051808201828110612f745790509050610320518060011b818160011c18612f7457905061030051808201828110612f74579050905061024051808203828111612f7457905090508015612f745780820490509050610320526102e051610320511161299d5760016102e05161032051808203828111612f745790509050116129c8576103205183525050506129da566129c8565b6001610320516102e051808203828111612f745790509050116129c8576103205183525050506129da565b6001018181186128dd57505060006000fd5b565b600060605112612f7457600160605113612f74576040518060011b818160011c18612f7457905060e05260c051610100526060366101203760006002905b806101805260605160008112612f74576101805114612aae576101805160018111612f745760051b6080015161014052612a5356612aae565b6101205161014051808201828110612f745790509050610120526101005160c051808202811583838304141715612f745790509050610140518060011b818160011c18612f745790508015612f745780820490509050610100525b600101818118612a1a5750506101005160c051808202811583838304141715612f74579050905060648102816064820418612f7457905060e0518060011b818160011c18612f745790508015612f745780820490509050610100526101205160c05160648102816064820418612f7457905060e0518015612f745780820490509050808201828110612f7457905090506101805260c0516101a052600060ff905b806101c0526101a051610160526101a0516101a051808202811583838304141715612f74579050905061010051808201828110612f7457905090506101a0518060011b818160011c18612f7457905061018051808201828110612f74579050905060c051808203828111612f7457905090508015612f7457808204905090506101a052610160516101a05111612c0e576001610160516101a051808203828111612f74579050905011612c39576101a0518352505050612c4b56612c39565b60016101a05161016051808203828111612f74579050905011612c39576101a0518352505050612c4b565b600101818118612b4f57505060006000fd5b565b612c586102406123ad565b61024051610220526003546102405260045461026052610240516040526102605160605261022051608052612c8e6102a06124d2565b6102a051610280526008546318160ddd6102c05260206102c060046102dc845afa612cbe573d600060003e3d6000fd5b60203d10612f74576102c09050516102a052610280516101e05161028051808202811583838304141715612f7457905090506102a0518015612f745780820490509050808203828111612f7457905090506102c0526102205160405261020051606052610240516080526102605160a0526102c05160c052612d416103006129dc565b610300516102e052610240516103005261026051610320526005548060011b818160011c18612f745790508060021c90506103405260006002905b80610360526000610380526102005160008112612f74576103605118612df4576103605160018111612f745760051b61024001516102c051808202811583838304141715612f745790509050610280518015612f7457808204905090506102e051808203828111612f74579050905061038052612e58565b6103605160018111612f745760051b61024001516103605160018111612f745760051b61024001516102c051808202811583838304141715612f745790509050610280518015612f745780820490509050808203828111612f745790509050610380525b6103605160018111612f745760051b6103000180516103405161038051808202811583838304141715612f7457905090506402540be40081049050808203828111612f745790509050815250600101818118612d7c5750506102005160018111612f745760051b61030001516102205160405261020051606052610300516080526103205160a0526102c05160c052612ef26103806129dc565b61038051808203828111612f745790509050610360526103605160018103818111612f74579050610360526102005160018111612f745760051b61024001516102e051808203828111612f745790509050610380526103605181526103805161036051808203828111612f74579050905060208201526102a051604082015250565b600080fda165767970657283000307000b