Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 8,899 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Add_collateral | 21179564 | 14 hrs ago | IN | 0 ETH | 0.08299925 | ||||
Add_collateral | 21179526 | 14 hrs ago | IN | 0 ETH | 0.09113584 | ||||
Borrow_more | 21179505 | 14 hrs ago | IN | 0 ETH | 0.09865484 | ||||
Borrow_more | 21179489 | 14 hrs ago | IN | 0 ETH | 0.09370151 | ||||
Borrow_more | 21172370 | 38 hrs ago | IN | 0 ETH | 0.03379966 | ||||
Borrow_more | 21170951 | 43 hrs ago | IN | 0 ETH | 0.03830045 | ||||
Repay_extended | 21157370 | 3 days ago | IN | 0 ETH | 0.02577218 | ||||
Add_collateral | 21157089 | 3 days ago | IN | 0 ETH | 0.01259738 | ||||
Borrow_more | 21157076 | 3 days ago | IN | 0 ETH | 0.0126596 | ||||
Borrow_more | 21155704 | 3 days ago | IN | 0 ETH | 0.00881994 | ||||
Add_collateral | 21148737 | 4 days ago | IN | 0 ETH | 0.00931259 | ||||
Borrow_more | 21148712 | 4 days ago | IN | 0 ETH | 0.01046015 | ||||
Borrow_more | 21146171 | 5 days ago | IN | 0 ETH | 0.00838941 | ||||
Add_collateral | 21142274 | 5 days ago | IN | 0 ETH | 0.01117277 | ||||
Add_collateral | 21142264 | 5 days ago | IN | 0 ETH | 0.01154274 | ||||
Borrow_more | 21142241 | 5 days ago | IN | 0 ETH | 0.01351885 | ||||
Borrow_more | 21142226 | 5 days ago | IN | 0 ETH | 0.01273433 | ||||
Add_collateral | 21142157 | 5 days ago | IN | 0 ETH | 0.00805163 | ||||
Add_collateral | 21142138 | 5 days ago | IN | 0 ETH | 0.00889168 | ||||
Borrow_more | 21142120 | 5 days ago | IN | 0 ETH | 0.00926979 | ||||
Borrow_more | 21142112 | 5 days ago | IN | 0 ETH | 0.01164207 | ||||
Add_collateral | 21132905 | 7 days ago | IN | 0 ETH | 0.01789263 | ||||
Add_collateral | 21132764 | 7 days ago | IN | 0 ETH | 0.01600548 | ||||
Borrow_more | 21132699 | 7 days ago | IN | 0 ETH | 0.01745073 | ||||
Borrow_more | 21132682 | 7 days ago | IN | 0 ETH | 0.0169972 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
17432225 | 525 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
crvUSD Controller
Compiler Version
vyper:0.3.7
Contract Source Code (Vyper language format)
# @version 0.3.7 """ @title crvUSD Controller @author Curve.Fi @license Copyright (c) Curve.Fi, 2020-2023 - all rights reserved """ interface LLAMMA: def A() -> uint256: view def get_p() -> uint256: view def get_base_price() -> uint256: view def active_band() -> int256: view def active_band_with_skip() -> int256: view def p_oracle_up(n: int256) -> uint256: view def p_oracle_down(n: int256) -> uint256: view def deposit_range(user: address, amount: uint256, n1: int256, n2: int256): nonpayable def read_user_tick_numbers(_for: address) -> int256[2]: view def get_sum_xy(user: address) -> uint256[2]: view def withdraw(user: address, frac: uint256) -> uint256[2]: nonpayable def get_x_down(user: address) -> uint256: view def get_rate_mul() -> uint256: view def set_rate(rate: uint256) -> uint256: nonpayable def set_fee(fee: uint256): nonpayable def set_admin_fee(fee: uint256): nonpayable def price_oracle() -> uint256: view def can_skip_bands(n_end: int256) -> bool: view def set_price_oracle(price_oracle: PriceOracle): nonpayable def admin_fees_x() -> uint256: view def admin_fees_y() -> uint256: view def reset_admin_fees(): nonpayable def has_liquidity(user: address) -> bool: view def bands_x(n: int256) -> uint256: view def bands_y(n: int256) -> uint256: view def set_callback(user: address): nonpayable interface ERC20: def transferFrom(_from: address, _to: address, _value: uint256) -> bool: nonpayable def transfer(_to: address, _value: uint256) -> bool: nonpayable def decimals() -> uint256: view def approve(_spender: address, _value: uint256) -> bool: nonpayable def balanceOf(_from: address) -> uint256: view interface WETH: def deposit(): payable def withdraw(_amount: uint256): nonpayable interface MonetaryPolicy: def rate_write() -> uint256: nonpayable interface Factory: def stablecoin() -> address: view def admin() -> address: view def fee_receiver() -> address: view def WETH() -> address: view interface PriceOracle: def price() -> uint256: view def price_w() -> uint256: nonpayable event UserState: user: indexed(address) collateral: uint256 debt: uint256 n1: int256 n2: int256 liquidation_discount: uint256 event Borrow: user: indexed(address) collateral_increase: uint256 loan_increase: uint256 event Repay: user: indexed(address) collateral_decrease: uint256 loan_decrease: uint256 event RemoveCollateral: user: indexed(address) collateral_decrease: uint256 event Liquidate: liquidator: indexed(address) user: indexed(address) collateral_received: uint256 stablecoin_received: uint256 debt: uint256 event SetMonetaryPolicy: monetary_policy: address event SetBorrowingDiscounts: loan_discount: uint256 liquidation_discount: uint256 event CollectFees: amount: uint256 new_supply: uint256 struct Loan: initial_debt: uint256 rate_mul: uint256 struct Position: user: address x: uint256 y: uint256 debt: uint256 health: int256 struct CallbackData: active_band: int256 stablecoins: uint256 collateral: uint256 FACTORY: immutable(Factory) STABLECOIN: immutable(ERC20) MAX_LOAN_DISCOUNT: constant(uint256) = 5 * 10**17 MIN_LIQUIDATION_DISCOUNT: constant(uint256) = 10**16 # Start liquidating when threshold reached MAX_TICKS: constant(int256) = 50 MAX_TICKS_UINT: constant(uint256) = 50 MIN_TICKS: constant(int256) = 4 MAX_SKIP_TICKS: constant(uint256) = 1024 MAX_P_BASE_BANDS: constant(int256) = 5 MAX_RATE: constant(uint256) = 43959106799 # 400% APY loan: HashMap[address, Loan] liquidation_discounts: public(HashMap[address, uint256]) _total_debt: Loan loans: public(address[2**64 - 1]) # Enumerate existing loans loan_ix: public(HashMap[address, uint256]) # Position of the loan in the list n_loans: public(uint256) # Number of nonzero loans minted: public(uint256) redeemed: public(uint256) monetary_policy: public(MonetaryPolicy) liquidation_discount: public(uint256) loan_discount: public(uint256) COLLATERAL_TOKEN: immutable(ERC20) COLLATERAL_PRECISION: immutable(uint256) AMM: immutable(LLAMMA) A: immutable(uint256) Aminus1: immutable(uint256) LOG2_A_RATIO: immutable(int256) # log(A / (A - 1)) SQRT_BAND_RATIO: immutable(uint256) MAX_ADMIN_FEE: constant(uint256) = 10**18 # 100% MIN_FEE: constant(uint256) = 10**6 # 1e-12, still needs to be above 0 MAX_FEE: constant(uint256) = 10**17 # 10% USE_ETH: immutable(bool) CALLBACK_DEPOSIT: constant(bytes4) = method_id("callback_deposit(address,uint256,uint256,uint256,uint256[])", output_type=bytes4) CALLBACK_REPAY: constant(bytes4) = method_id("callback_repay(address,uint256,uint256,uint256,uint256[])", output_type=bytes4) CALLBACK_LIQUIDATE: constant(bytes4) = method_id("callback_liquidate(address,uint256,uint256,uint256,uint256[])", output_type=bytes4) DEAD_SHARES: constant(uint256) = 1000 MAX_ETH_GAS: constant(uint256) = 10000 # Forward this much gas to ETH transfers (2300 is what send() does) @external def __init__( collateral_token: address, monetary_policy: address, loan_discount: uint256, liquidation_discount: uint256, amm: address): """ @notice Controller constructor deployed by the factory from blueprint @param collateral_token Token to use for collateral @param monetary_policy Address of monetary policy @param loan_discount Discount of the maximum loan size compare to get_x_down() value @param liquidation_discount Discount of the maximum loan size compare to get_x_down() for "bad liquidation" purposes @param amm AMM address (Already deployed from blueprint) """ FACTORY = Factory(msg.sender) stablecoin: ERC20 = ERC20(Factory(msg.sender).stablecoin()) STABLECOIN = stablecoin assert stablecoin.decimals() == 18 self.monetary_policy = MonetaryPolicy(monetary_policy) self.liquidation_discount = liquidation_discount self.loan_discount = loan_discount self._total_debt.rate_mul = 10**18 AMM = LLAMMA(amm) _A: uint256 = LLAMMA(amm).A() A = _A Aminus1 = _A - 1 LOG2_A_RATIO = self.log2(_A * 10**18 / unsafe_sub(_A, 1)) COLLATERAL_TOKEN = ERC20(collateral_token) COLLATERAL_PRECISION = pow_mod256(10, 18 - ERC20(collateral_token).decimals()) SQRT_BAND_RATIO = isqrt(unsafe_div(10**36 * _A, unsafe_sub(_A, 1))) stablecoin.approve(msg.sender, max_value(uint256)) if Factory(msg.sender).WETH() == collateral_token: USE_ETH = True @payable @external def __default__(): if msg.value > 0: assert USE_ETH assert len(msg.data) == 0 @internal @pure def log2(_x: uint256) -> int256: """ @notice int(1e18 * log2(_x / 1e18)) """ # adapted from: https://medium.com/coinmonks/9aef8515136e # and vyper log implementation # Might use more optimal solmate's log inverse: bool = _x < 10**18 res: uint256 = 0 x: uint256 = _x if inverse: x = 10**36 / x t: uint256 = 2**7 for i in range(8): p: uint256 = pow_mod256(2, t) if x >= unsafe_mul(p, 10**18): x = unsafe_div(x, p) res = unsafe_add(unsafe_mul(t, 10**18), res) t = unsafe_div(t, 2) d: uint256 = 10**18 for i in range(34): # 10 decimals: math.log(10**10, 2) == 33.2. Need more? if (x >= 2 * 10**18): res = unsafe_add(res, d) x = unsafe_div(x, 2) x = unsafe_div(unsafe_mul(x, x), 10**18) d = unsafe_div(d, 2) if inverse: return -convert(res, int256) else: return convert(res, int256) @external @view def factory() -> Factory: """ @notice Address of the factory """ return FACTORY @external @view def amm() -> LLAMMA: """ @notice Address of the AMM """ return AMM @external @view def collateral_token() -> ERC20: """ @notice Address of the collateral token """ return COLLATERAL_TOKEN @internal def _rate_mul_w() -> uint256: """ @notice Getter for rate_mul (the one which is 1.0+) from the AMM """ rate: uint256 = min(self.monetary_policy.rate_write(), MAX_RATE) return AMM.set_rate(rate) @internal def _debt(user: address) -> (uint256, uint256): """ @notice Get the value of debt and rate_mul and update the rate_mul counter @param user User address @return (debt, rate_mul) """ rate_mul: uint256 = self._rate_mul_w() loan: Loan = self.loan[user] if loan.initial_debt == 0: return (0, rate_mul) else: return (loan.initial_debt * rate_mul / loan.rate_mul, rate_mul) @internal @view def _debt_ro(user: address) -> uint256: """ @notice Get the value of debt without changing the state @param user User address @return Value of debt """ rate_mul: uint256 = AMM.get_rate_mul() loan: Loan = self.loan[user] if loan.initial_debt == 0: return 0 else: return loan.initial_debt * rate_mul / loan.rate_mul @external @view @nonreentrant('lock') def debt(user: address) -> uint256: """ @notice Get the value of debt without changing the state @param user User address @return Value of debt """ return self._debt_ro(user) @external @view @nonreentrant('lock') def loan_exists(user: address) -> bool: """ @notice Check whether there is a loan of `user` in existence """ return self.loan[user].initial_debt > 0 # No decorator because used in monetary policy @external @view def total_debt() -> uint256: """ @notice Total debt of this controller """ rate_mul: uint256 = AMM.get_rate_mul() loan: Loan = self._total_debt return loan.initial_debt * rate_mul / loan.rate_mul @internal @view def get_y_effective(collateral: uint256, N: uint256, discount: uint256) -> uint256: """ @notice Intermediary method which calculates y_effective defined as x_effective / p_base, however discounted by loan_discount. x_effective is an amount which can be obtained from collateral when liquidating @param collateral Amount of collateral to get the value for @param N Number of bands the deposit is made into @param discount Loan discount at 1e18 base (e.g. 1e18 == 100%) @return y_effective """ # x_effective = sum_{i=0..N-1}(y / N * p(n_{n1+i})) = # = y / N * p_oracle_up(n1) * sqrt((A - 1) / A) * sum_{0..N-1}(((A-1) / A)**k) # === d_y_effective * p_oracle_up(n1) * sum(...) === y_effective * p_oracle_up(n1) # d_y_effective = y / N / sqrt(A / (A - 1)) # d_y_effective: uint256 = collateral * unsafe_sub(10**18, discount) / (SQRT_BAND_RATIO * N) # Make some extra discount to always deposit lower when we have DEAD_SHARES rounding d_y_effective: uint256 = collateral * unsafe_sub( 10**18, min(discount + (DEAD_SHARES * 10**18) / max(collateral / N, DEAD_SHARES), 10**18) ) / (SQRT_BAND_RATIO * N) y_effective: uint256 = d_y_effective for i in range(1, MAX_TICKS_UINT): if i == N: break d_y_effective = unsafe_div(d_y_effective * Aminus1, A) y_effective = unsafe_add(y_effective, d_y_effective) return y_effective @internal @view def _calculate_debt_n1(collateral: uint256, debt: uint256, N: uint256) -> int256: """ @notice Calculate the upper band number for the deposit to sit in to support the given debt. Reverts if requested debt is too high. @param collateral Amount of collateral (at its native precision) @param debt Amount of requested debt @param N Number of bands to deposit into @return Upper band n1 (n1 <= n2) to deposit into. Signed integer """ assert debt > 0, "No loan" n0: int256 = AMM.active_band() p_base: uint256 = AMM.p_oracle_up(n0) # x_effective = y / N * p_oracle_up(n1) * sqrt((A - 1) / A) * sum_{0..N-1}(((A-1) / A)**k) # === d_y_effective * p_oracle_up(n1) * sum(...) === y_effective * p_oracle_up(n1) # d_y_effective = y / N / sqrt(A / (A - 1)) y_effective: uint256 = self.get_y_effective(collateral * COLLATERAL_PRECISION, N, self.loan_discount) # p_oracle_up(n1) = base_price * ((A - 1) / A)**n1 # We borrow up until min band touches p_oracle, # or it touches non-empty bands which cannot be skipped. # We calculate required n1 for given (collateral, debt), # and if n1 corresponds to price_oracle being too high, or unreachable band # - we revert. # n1 is band number based on adiabatic trading, e.g. when p_oracle ~ p y_effective = y_effective * p_base / (debt + 1) # Now it's a ratio # n1 = floor(log2(y_effective) / self.logAratio) # EVM semantics is not doing floor unlike Python, so we do this assert y_effective > 0, "Amount too low" n1: int256 = self.log2(y_effective) # <- switch to faster ln() XXX? if n1 < 0: n1 -= LOG2_A_RATIO - 1 # This is to deal with vyper's rounding of negative numbers n1 /= LOG2_A_RATIO n1 = min(n1, 1024 - convert(N, int256)) + n0 if n1 <= n0: assert AMM.can_skip_bands(n1 - 1), "Debt too high" # Let's not rely on active_band corresponding to price_oracle: # this will be not correct if we are in the area of empty bands assert AMM.p_oracle_up(n1) < AMM.price_oracle(), "Debt too high" return n1 @internal @view def max_p_base() -> uint256: """ @notice Calculate max base price including skipping bands """ p_oracle: uint256 = AMM.price_oracle() # Should be correct unless price changes suddenly by MAX_P_BASE_BANDS+ bands n1: int256 = unsafe_div(self.log2(AMM.get_base_price() * 10**18 / p_oracle), LOG2_A_RATIO) + MAX_P_BASE_BANDS p_base: uint256 = AMM.p_oracle_up(n1) n_min: int256 = AMM.active_band_with_skip() for i in range(MAX_SKIP_TICKS + 1): n1 -= 1 if n1 <= n_min: break p_base_prev: uint256 = p_base p_base = unsafe_div(p_base * A, Aminus1) if p_base > p_oracle: return p_base_prev return p_base @external @view @nonreentrant('lock') def max_borrowable(collateral: uint256, N: uint256) -> uint256: """ @notice Calculation of maximum which can be borrowed (details in comments) @param collateral Collateral amount against which to borrow @param N number of bands to have the deposit into @return Maximum amount of stablecoin to borrow """ # Calculation of maximum which can be borrowed. # It corresponds to a minimum between the amount corresponding to price_oracle # and the one given by the min reachable band. # # Given by p_oracle (perhaps needs to be multiplied by (A - 1) / A to account for mid-band effects) # x_max ~= y_effective * p_oracle # # Given by band number: # if n1 is the lowest empty band in the AMM # xmax ~= y_effective * amm.p_oracle_up(n1) # # When n1 -= 1: # p_oracle_up *= A / (A - 1) y_effective: uint256 = self.get_y_effective(collateral * COLLATERAL_PRECISION, N, self.loan_discount) x: uint256 = unsafe_sub(max(unsafe_div(y_effective * self.max_p_base(), 10**18), 1), 1) x = unsafe_div(x * (10**18 - 10**14), 10**18) # Make it a bit smaller return min(x, STABLECOIN.balanceOf(self)) # Cannot borrow beyond the amount of coins Controller has @external @view @nonreentrant('lock') def min_collateral(debt: uint256, N: uint256) -> uint256: """ @notice Minimal amount of collateral required to support debt @param debt The debt to support @param N Number of bands to deposit into @return Minimal collateral required """ # Add N**2 to account for precision loss in multiple bands, e.g. N * 1 / (y/N) = N**2 / y return unsafe_div(unsafe_div(debt * 10**18 / self.max_p_base() * 10**18 / self.get_y_effective(10**18, N, self.loan_discount) + N * (N + 2 * DEAD_SHARES), COLLATERAL_PRECISION) * 10**18, 10**18 - 10**14) @external @view @nonreentrant('lock') def calculate_debt_n1(collateral: uint256, debt: uint256, N: uint256) -> int256: """ @notice Calculate the upper band number for the deposit to sit in to support the given debt. Reverts if requested debt is too high. @param collateral Amount of collateral (at its native precision) @param debt Amount of requested debt @param N Number of bands to deposit into @return Upper band n1 (n1 <= n2) to deposit into. Signed integer """ return self._calculate_debt_n1(collateral, debt, N) @internal def _deposit_collateral(amount: uint256, mvalue: uint256): """ Deposits raw ETH, WETH or both at the same time """ if not USE_ETH: assert mvalue == 0 # dev: Not accepting ETH diff: uint256 = amount - mvalue # dev: Incorrect ETH amount if mvalue > 0: WETH(COLLATERAL_TOKEN.address).deposit(value=mvalue) assert COLLATERAL_TOKEN.transfer(AMM.address, mvalue) if diff > 0: assert COLLATERAL_TOKEN.transferFrom(msg.sender, AMM.address, diff, default_return_value=True) @internal def _withdraw_collateral(_for: address, amount: uint256, use_eth: bool): if use_eth and USE_ETH: assert COLLATERAL_TOKEN.transferFrom(AMM.address, self, amount) WETH(COLLATERAL_TOKEN.address).withdraw(amount) raw_call(_for, b"", value=amount, gas=MAX_ETH_GAS) else: assert COLLATERAL_TOKEN.transferFrom(AMM.address, _for, amount, default_return_value=True) @internal def execute_callback(callbacker: address, callback_sig: bytes4, user: address, stablecoins: uint256, collateral: uint256, debt: uint256, callback_args: DynArray[uint256, 5]) -> CallbackData: assert callbacker != COLLATERAL_TOKEN.address data: CallbackData = empty(CallbackData) data.active_band = AMM.active_band() band_x: uint256 = AMM.bands_x(data.active_band) band_y: uint256 = AMM.bands_y(data.active_band) # Callback response: Bytes[64] = raw_call( callbacker, concat(callback_sig, _abi_encode(user, stablecoins, collateral, debt, callback_args)), max_outsize=64 ) data.stablecoins = convert(slice(response, 0, 32), uint256) data.collateral = convert(slice(response, 32, 32), uint256) # Checks after callback assert data.active_band == AMM.active_band() assert band_x == AMM.bands_x(data.active_band) assert band_y == AMM.bands_y(data.active_band) return data @internal def _create_loan(mvalue: uint256, collateral: uint256, debt: uint256, N: uint256, transfer_coins: bool): assert self.loan[msg.sender].initial_debt == 0, "Loan already created" assert N > MIN_TICKS-1, "Need more ticks" assert N < MAX_TICKS+1, "Need less ticks" n1: int256 = self._calculate_debt_n1(collateral, debt, N) n2: int256 = n1 + convert(N - 1, int256) rate_mul: uint256 = self._rate_mul_w() self.loan[msg.sender] = Loan({initial_debt: debt, rate_mul: rate_mul}) liquidation_discount: uint256 = self.liquidation_discount self.liquidation_discounts[msg.sender] = liquidation_discount n_loans: uint256 = self.n_loans self.loans[n_loans] = msg.sender self.loan_ix[msg.sender] = n_loans self.n_loans = unsafe_add(n_loans, 1) total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul + debt self._total_debt.initial_debt = total_debt self._total_debt.rate_mul = rate_mul AMM.deposit_range(msg.sender, collateral, n1, n2) self.minted += debt if transfer_coins: self._deposit_collateral(collateral, mvalue) STABLECOIN.transfer(msg.sender, debt) log UserState(msg.sender, collateral, debt, n1, n2, liquidation_discount) log Borrow(msg.sender, collateral, debt) @payable @external @nonreentrant('lock') def create_loan(collateral: uint256, debt: uint256, N: uint256): """ @notice Create loan @param collateral Amount of collateral to use @param debt Stablecoin debt to take @param N Number of bands to deposit into (to do autoliquidation-deliquidation), can be from MIN_TICKS to MAX_TICKS """ self._create_loan(msg.value, collateral, debt, N, True) @payable @external @nonreentrant('lock') def create_loan_extended(collateral: uint256, debt: uint256, N: uint256, callbacker: address, callback_args: DynArray[uint256,5]): """ @notice Create loan but pass stablecoin to a callback first so that it can build leverage @param collateral Amount of collateral to use @param debt Stablecoin debt to take @param N Number of bands to deposit into (to do autoliquidation-deliquidation), can be from MIN_TICKS to MAX_TICKS @param callbacker Address of the callback contract @param callback_args Extra arguments for the callback (up to 5) such as min_amount etc """ # Before callback STABLECOIN.transfer(callbacker, debt) # Callback # If there is any unused debt, callbacker can send it to the user more_collateral: uint256 = self.execute_callback( callbacker, CALLBACK_DEPOSIT, msg.sender, 0, collateral, debt, callback_args).collateral # After callback self._deposit_collateral(collateral, msg.value) assert COLLATERAL_TOKEN.transferFrom(callbacker, AMM.address, more_collateral, default_return_value=True) self._create_loan(0, collateral + more_collateral, debt, N, False) @internal def _add_collateral_borrow(d_collateral: uint256, d_debt: uint256, _for: address, remove_collateral: bool): """ @notice Internal method to borrow and add or remove collateral @param d_collateral Amount of collateral to add @param d_debt Amount of debt increase @param _for Address to transfer tokens to @param remove_collateral Remove collateral instead of adding """ debt: uint256 = 0 rate_mul: uint256 = 0 debt, rate_mul = self._debt(_for) assert debt > 0, "Loan doesn't exist" debt += d_debt ns: int256[2] = AMM.read_user_tick_numbers(_for) size: uint256 = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256) xy: uint256[2] = AMM.withdraw(_for, 10**18) assert xy[0] == 0, "Already in underwater mode" if remove_collateral: xy[1] -= d_collateral else: xy[1] += d_collateral n1: int256 = self._calculate_debt_n1(xy[1], debt, size) n2: int256 = n1 + unsafe_sub(ns[1], ns[0]) AMM.deposit_range(_for, xy[1], n1, n2) self.loan[_for] = Loan({initial_debt: debt, rate_mul: rate_mul}) liquidation_discount: uint256 = self.liquidation_discount self.liquidation_discounts[_for] = liquidation_discount if d_debt != 0: total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul + d_debt self._total_debt.initial_debt = total_debt self._total_debt.rate_mul = rate_mul if remove_collateral: log RemoveCollateral(_for, d_collateral) else: log Borrow(_for, d_collateral, d_debt) log UserState(_for, xy[1], debt, n1, n2, liquidation_discount) @payable @external @nonreentrant('lock') def add_collateral(collateral: uint256, _for: address = msg.sender): """ @notice Add extra collateral to avoid bad liqidations @param collateral Amount of collateral to add @param _for Address to add collateral for """ if collateral == 0: return self._add_collateral_borrow(collateral, 0, _for, False) self._deposit_collateral(collateral, msg.value) @external @nonreentrant('lock') def remove_collateral(collateral: uint256, use_eth: bool = True): """ @notice Remove some collateral without repaying the debt @param collateral Amount of collateral to remove @param use_eth Use wrapping/unwrapping if collateral is ETH """ if collateral == 0: return self._add_collateral_borrow(collateral, 0, msg.sender, True) self._withdraw_collateral(msg.sender, collateral, use_eth) @payable @external @nonreentrant('lock') def borrow_more(collateral: uint256, debt: uint256): """ @notice Borrow more stablecoins while adding more collateral (not necessary) @param collateral Amount of collateral to add @param debt Amount of stablecoin debt to take """ if debt == 0: return self._add_collateral_borrow(collateral, debt, msg.sender, False) if collateral != 0: self._deposit_collateral(collateral, msg.value) STABLECOIN.transfer(msg.sender, debt) self.minted += debt @internal def _remove_from_list(_for: address): last_loan_ix: uint256 = self.n_loans - 1 loan_ix: uint256 = self.loan_ix[_for] assert self.loans[loan_ix] == _for # dev: should never fail but safety first self.loan_ix[_for] = 0 if loan_ix < last_loan_ix: # Need to replace last_loan: address = self.loans[last_loan_ix] self.loans[loan_ix] = last_loan self.loan_ix[last_loan] = loan_ix self.n_loans = last_loan_ix @payable @external @nonreentrant('lock') def repay(_d_debt: uint256, _for: address = msg.sender, max_active_band: int256 = 2**255-1, use_eth: bool = True): """ @notice Repay debt (partially or fully) @param _d_debt The amount of debt to repay. If higher than the current debt - will do full repayment @param _for The user to repay the debt for @param max_active_band Don't allow active band to be higher than this (to prevent front-running the repay) @param use_eth Use wrapping/unwrapping if collateral is ETH """ if _d_debt == 0: return # Or repay all for MAX_UINT256 # Withdraw if debt become 0 debt: uint256 = 0 rate_mul: uint256 = 0 debt, rate_mul = self._debt(_for) assert debt > 0, "Loan doesn't exist" d_debt: uint256 = min(debt, _d_debt) debt = unsafe_sub(debt, d_debt) if debt == 0: # Allow to withdraw all assets even when underwater xy: uint256[2] = AMM.withdraw(_for, 10**18) if xy[0] > 0: # Only allow full repayment when underwater for the sender to do assert _for == msg.sender STABLECOIN.transferFrom(AMM.address, _for, xy[0]) if xy[1] > 0: self._withdraw_collateral(_for, xy[1], use_eth) log UserState(_for, 0, 0, 0, 0, 0) log Repay(_for, xy[1], d_debt) self._remove_from_list(_for) else: active_band: int256 = AMM.active_band_with_skip() assert active_band <= max_active_band ns: int256[2] = AMM.read_user_tick_numbers(_for) size: uint256 = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256) liquidation_discount: uint256 = 0 if ns[0] > active_band: # Not in liquidation - can move bands xy: uint256[2] = AMM.withdraw(_for, 10**18) n1: int256 = self._calculate_debt_n1(xy[1], debt, size) n2: int256 = n1 + unsafe_sub(ns[1], ns[0]) AMM.deposit_range(_for, xy[1], n1, n2) liquidation_discount = self.liquidation_discount self.liquidation_discounts[_for] = liquidation_discount log UserState(_for, xy[1], debt, n1, n2, liquidation_discount) log Repay(_for, 0, d_debt) else: # Underwater - cannot move band but can avoid a bad liquidation liquidation_discount = self.liquidation_discounts[_for] log UserState(_for, max_value(uint256), debt, ns[0], ns[1], liquidation_discount) log Repay(_for, 0, d_debt) if _for != msg.sender: # Doesn't allow non-sender to repay in a way which ends with unhealthy state # full = False to make this condition non-manipulatable (and also cheaper on gas) assert self._health(_for, debt, False, liquidation_discount) > 0 # If we withdrew already - will burn less! STABLECOIN.transferFrom(msg.sender, self, d_debt) # fail: insufficient funds self.redeemed += d_debt self.loan[_for] = Loan({initial_debt: debt, rate_mul: rate_mul}) total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul self._total_debt.initial_debt = unsafe_sub(max(total_debt, d_debt), d_debt) self._total_debt.rate_mul = rate_mul @external @nonreentrant('lock') def repay_extended(callbacker: address, callback_args: DynArray[uint256,5]): """ @notice Repay loan but get a stablecoin for that from callback (to deleverage) @param callbacker Address of the callback contract @param callback_args Extra arguments for the callback (up to 5) such as min_amount etc """ # Before callback ns: int256[2] = AMM.read_user_tick_numbers(msg.sender) xy: uint256[2] = AMM.withdraw(msg.sender, 10**18) debt: uint256 = 0 rate_mul: uint256 = 0 debt, rate_mul = self._debt(msg.sender) COLLATERAL_TOKEN.transferFrom(AMM.address, callbacker, xy[1], default_return_value=True) cb: CallbackData = self.execute_callback( callbacker, CALLBACK_REPAY, msg.sender, xy[0], xy[1], debt, callback_args) # After callback total_stablecoins: uint256 = cb.stablecoins + xy[0] assert total_stablecoins > 0 # dev: no coins to repay # d_debt: uint256 = min(debt, total_stablecoins) d_debt: uint256 = 0 # If we have more stablecoins than the debt - full repayment and closing the position if total_stablecoins >= debt: d_debt = debt debt = 0 self._remove_from_list(msg.sender) # Transfer debt to self, everything else to sender if cb.stablecoins > 0: STABLECOIN.transferFrom(callbacker, self, cb.stablecoins) if xy[0] > 0: STABLECOIN.transferFrom(AMM.address, self, xy[0]) if total_stablecoins > d_debt: STABLECOIN.transfer(msg.sender, unsafe_sub(total_stablecoins, d_debt)) if cb.collateral > 0: assert COLLATERAL_TOKEN.transferFrom(callbacker, msg.sender, cb.collateral, default_return_value=True) log UserState(msg.sender, 0, 0, 0, 0, 0) # Else - partial repayment -> deleverage, but only if we are not underwater else: size: uint256 = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256) assert ns[0] > cb.active_band d_debt = cb.stablecoins # cb.stablecoins <= total_stablecoins < debt debt = unsafe_sub(debt, cb.stablecoins) # Not in liquidation - can move bands n1: int256 = self._calculate_debt_n1(cb.collateral, debt, size) n2: int256 = n1 + unsafe_sub(ns[1], ns[0]) AMM.deposit_range(msg.sender, cb.collateral, n1, n2) liquidation_discount: uint256 = self.liquidation_discount self.liquidation_discounts[msg.sender] = liquidation_discount assert COLLATERAL_TOKEN.transferFrom(callbacker, AMM.address, cb.collateral, default_return_value=True) # Stablecoin is all spent to repay debt -> all goes to self STABLECOIN.transferFrom(callbacker, self, cb.stablecoins) # We are above active band, so xy[0] is 0 anyway log UserState(msg.sender, cb.collateral, debt, n1, n2, liquidation_discount) xy[1] = 0 # No need to check _health() because it's the sender # Common calls which we will do regardless of whether it's a full repay or not log Repay(msg.sender, xy[1], d_debt) self.redeemed += d_debt self.loan[msg.sender] = Loan({initial_debt: debt, rate_mul: rate_mul}) total_debt: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul self._total_debt.initial_debt = unsafe_sub(max(total_debt, d_debt), d_debt) self._total_debt.rate_mul = rate_mul @internal @view def _health(user: address, debt: uint256, full: bool, liquidation_discount: uint256) -> int256: """ @notice Returns position health normalized to 1e18 for the user. Liquidation starts when < 0, however devaluation of collateral doesn't cause liquidation @param user User address to calculate health for @param debt The amount of debt to calculate health for @param full Whether to take into account the price difference above the highest user's band @param liquidation_discount Liquidation discount to use (can be 0) @return Health: > 0 = good. """ assert debt > 0, "Loan doesn't exist" health: int256 = 10**18 if liquidation_discount > 0: health -= convert(liquidation_discount, int256) health = unsafe_div(convert(AMM.get_x_down(user), int256) * health, convert(debt, int256)) - 10**18 if full: ns: int256[2] = AMM.read_user_tick_numbers(user) # ns[1] > ns[0] if ns[0] > AMM.active_band(): # We are not in liquidation mode p: uint256 = AMM.price_oracle() p_up: uint256 = AMM.p_oracle_up(ns[0]) if p > p_up: health += convert(unsafe_div((p - p_up) * AMM.get_sum_xy(user)[1] * COLLATERAL_PRECISION, debt), int256) return health @external @view @nonreentrant('lock') def health_calculator(user: address, d_collateral: int256, d_debt: int256, full: bool, N: uint256 = 0) -> int256: """ @notice Health predictor in case user changes the debt or collateral @param user Address of the user @param d_collateral Change in collateral amount (signed) @param d_debt Change in debt amount (signed) @param full Whether it's a 'full' health or not @param N Number of bands in case loan doesn't yet exist @return Signed health value """ xy: uint256[2] = AMM.get_sum_xy(user) xy[1] *= COLLATERAL_PRECISION ns: int256[2] = AMM.read_user_tick_numbers(user) debt: int256 = convert(self._debt_ro(user), int256) n: uint256 = N ld: int256 = 0 if debt != 0: ld = convert(self.liquidation_discounts[user], int256) n = convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256) else: ld = convert(self.liquidation_discount, int256) ns[0] = max_value(int256) # This will trigger a "re-deposit" n1: int256 = 0 collateral: int256 = 0 x_eff: int256 = 0 debt += d_debt assert debt > 0, "Non-positive debt" active_band: int256 = AMM.active_band_with_skip() if ns[0] > active_band and (d_collateral != 0 or d_debt != 0): # re-deposit collateral = convert(xy[1], int256) + d_collateral n1 = self._calculate_debt_n1(convert(collateral, uint256), convert(debt, uint256), n) else: n1 = ns[0] x_eff = convert(AMM.get_x_down(user) * 10**18, int256) p0: int256 = convert(AMM.p_oracle_up(n1), int256) if ns[0] > active_band: x_eff = convert(self.get_y_effective(convert(collateral, uint256), n, 0), int256) * p0 health: int256 = unsafe_div(x_eff, debt) health = health - unsafe_div(health * ld, 10**18) - 10**18 if full: if n1 > active_band: # We are not in liquidation mode p_diff: int256 = max(p0, convert(AMM.price_oracle(), int256)) - p0 if p_diff > 0: health += unsafe_div(p_diff * collateral, debt) return health @internal @view def _get_f_remove(frac: uint256, health_limit: uint256) -> uint256: # f_remove = ((1 + h / 2) / (1 + h) * (1 - frac) + frac) * frac f_remove: uint256 = 10 ** 18 if frac < 10 ** 18: f_remove = unsafe_div(unsafe_mul(unsafe_add(10 ** 18, unsafe_div(health_limit, 2)), unsafe_sub(10 ** 18, frac)), unsafe_add(10 ** 18, health_limit)) f_remove = unsafe_div(unsafe_mul(unsafe_add(f_remove, frac), frac), 10 ** 18) return f_remove @internal def _liquidate(user: address, min_x: uint256, health_limit: uint256, frac: uint256, use_eth: bool, callbacker: address, callback_args: DynArray[uint256,5]): """ @notice Perform a bad liquidation of user if the health is too bad @param user Address of the user @param min_x Minimal amount of stablecoin withdrawn (to avoid liquidators being sandwiched) @param health_limit Minimal health to liquidate at @param frac Fraction to liquidate; 100% = 10**18 @param use_eth Use wrapping/unwrapping if collateral is ETH @param callbacker Address of the callback contract @param callback_args Extra arguments for the callback (up to 5) such as min_amount etc """ debt: uint256 = 0 rate_mul: uint256 = 0 debt, rate_mul = self._debt(user) if health_limit != 0: assert self._health(user, debt, True, health_limit) < 0, "Not enough rekt" final_debt: uint256 = debt debt = unsafe_div(debt * frac, 10**18) assert debt > 0 final_debt = unsafe_sub(final_debt, debt) # Withdraw sender's stablecoin and collateral to our contract # When frac is set - we withdraw a bit less for the same debt fraction # f_remove = ((1 + h/2) / (1 + h) * (1 - frac) + frac) * frac # where h is health limit. # This is less than full h discount but more than no discount f_remove: uint256 = self._get_f_remove(frac, health_limit) xy: uint256[2] = AMM.withdraw(user, f_remove) # [stable, collateral] # x increase in same block -> price up -> good # x decrease in same block -> price down -> bad assert xy[0] >= min_x, "Slippage" min_amm_burn: uint256 = min(xy[0], debt) if min_amm_burn != 0: STABLECOIN.transferFrom(AMM.address, self, min_amm_burn) if debt > xy[0]: to_repay: uint256 = unsafe_sub(debt, xy[0]) if callbacker == empty(address): # Withdraw collateral if no callback is present self._withdraw_collateral(msg.sender, xy[1], use_eth) # Request what's left from user STABLECOIN.transferFrom(msg.sender, self, to_repay) else: # Move collateral to callbacker, call it and remove everything from it back in if xy[1] > 0: assert COLLATERAL_TOKEN.transferFrom(AMM.address, callbacker, xy[1], default_return_value=True) # Callback cb: CallbackData = self.execute_callback( callbacker, CALLBACK_LIQUIDATE, user, xy[0], xy[1], debt, callback_args) assert cb.stablecoins >= to_repay, "not enough proceeds" if cb.stablecoins > to_repay: STABLECOIN.transferFrom(callbacker, msg.sender, unsafe_sub(cb.stablecoins, to_repay)) STABLECOIN.transferFrom(callbacker, self, to_repay) if cb.collateral > 0: assert COLLATERAL_TOKEN.transferFrom(callbacker, msg.sender, cb.collateral) else: # Withdraw collateral self._withdraw_collateral(msg.sender, xy[1], use_eth) # Return what's left to user if xy[0] > debt: STABLECOIN.transferFrom(AMM.address, msg.sender, unsafe_sub(xy[0], debt)) self.redeemed += debt self.loan[user] = Loan({initial_debt: final_debt, rate_mul: rate_mul}) log Repay(user, xy[1], debt) log Liquidate(msg.sender, user, xy[1], xy[0], debt) if final_debt == 0: log UserState(user, 0, 0, 0, 0, 0) # Not logging partial removeal b/c we have not enough info self._remove_from_list(user) d: uint256 = self._total_debt.initial_debt * rate_mul / self._total_debt.rate_mul self._total_debt.initial_debt = unsafe_sub(max(d, debt), debt) self._total_debt.rate_mul = rate_mul @external @nonreentrant('lock') def liquidate(user: address, min_x: uint256, use_eth: bool = True): """ @notice Peform a bad liquidation (or self-liquidation) of user if health is not good @param min_x Minimal amount of stablecoin to receive (to avoid liquidators being sandwiched) @param use_eth Use wrapping/unwrapping if collateral is ETH """ discount: uint256 = 0 if user != msg.sender: discount = self.liquidation_discounts[user] self._liquidate(user, min_x, discount, 10**18, use_eth, empty(address), []) @external @nonreentrant('lock') def liquidate_extended(user: address, min_x: uint256, frac: uint256, use_eth: bool, callbacker: address, callback_args: DynArray[uint256,5]): """ @notice Peform a bad liquidation (or self-liquidation) of user if health is not good @param min_x Minimal amount of stablecoin to receive (to avoid liquidators being sandwiched) @param frac Fraction to liquidate; 100% = 10**18 @param use_eth Use wrapping/unwrapping if collateral is ETH @param callbacker Address of the callback contract @param callback_args Extra arguments for the callback (up to 5) such as min_amount etc """ discount: uint256 = 0 if user != msg.sender: discount = self.liquidation_discounts[user] self._liquidate(user, min_x, discount, min(frac, 10**18), use_eth, callbacker, callback_args) @view @external @nonreentrant('lock') def tokens_to_liquidate(user: address, frac: uint256 = 10 ** 18) -> uint256: """ @notice Calculate the amount of stablecoins to have in liquidator's wallet to liquidate a user @param user Address of the user to liquidate @param frac Fraction to liquidate; 100% = 10**18 @return The amount of stablecoins needed """ health_limit: uint256 = 0 if user != msg.sender: health_limit = self.liquidation_discounts[user] f_remove: uint256 = self._get_f_remove(frac, health_limit) stablecoins: uint256 = unsafe_div(AMM.get_sum_xy(user)[0] * f_remove, 10 ** 18) debt: uint256 = unsafe_div(self._debt_ro(user) * frac, 10 ** 18) return unsafe_sub(max(debt, stablecoins), stablecoins) @view @external @nonreentrant('lock') def health(user: address, full: bool = False) -> int256: """ @notice Returns position health normalized to 1e18 for the user. Liquidation starts when < 0, however devaluation of collateral doesn't cause liquidation """ return self._health(user, self._debt_ro(user), full, self.liquidation_discounts[user]) @view @external @nonreentrant('lock') def users_to_liquidate(_from: uint256=0, _limit: uint256=0) -> DynArray[Position, 1000]: """ @notice Returns a dynamic array of users who can be "hard-liquidated". This method is designed for convenience of liquidation bots. @param _from Loan index to start iteration from @param _limit Number of loans to look over @return Dynamic array with detailed info about positions of users """ n_loans: uint256 = self.n_loans limit: uint256 = _limit if _limit == 0: limit = n_loans ix: uint256 = _from out: DynArray[Position, 1000] = [] for i in range(10**6): if ix >= n_loans or i == limit: break user: address = self.loans[ix] debt: uint256 = self._debt_ro(user) health: int256 = self._health(user, debt, True, self.liquidation_discounts[user]) if health < 0: xy: uint256[2] = AMM.get_sum_xy(user) out.append(Position({ user: user, x: xy[0], y: xy[1], debt: debt, health: health })) ix += 1 return out # AMM has a nonreentrant decorator @view @external def amm_price() -> uint256: """ @notice Current price from the AMM """ return AMM.get_p() @view @external @nonreentrant('lock') def user_prices(user: address) -> uint256[2]: # Upper, lower """ @notice Lowest price of the lower band and highest price of the upper band the user has deposit in the AMM @param user User address @return (upper_price, lower_price) """ assert AMM.has_liquidity(user) ns: int256[2] = AMM.read_user_tick_numbers(user) # ns[1] > ns[0] return [AMM.p_oracle_up(ns[0]), AMM.p_oracle_down(ns[1])] @view @external @nonreentrant('lock') def user_state(user: address) -> uint256[4]: """ @notice Return the user state in one call @param user User to return the state for @return (collateral, stablecoin, debt, N) """ xy: uint256[2] = AMM.get_sum_xy(user) ns: int256[2] = AMM.read_user_tick_numbers(user) # ns[1] > ns[0] return [xy[1], xy[0], self._debt_ro(user), convert(unsafe_add(unsafe_sub(ns[1], ns[0]), 1), uint256)] # AMM has nonreentrant decorator @external def set_amm_fee(fee: uint256): """ @notice Set the AMM fee (factory admin only) @param fee The fee which should be no higher than MAX_FEE """ assert msg.sender == FACTORY.admin() assert fee <= MAX_FEE and fee >= MIN_FEE, "Fee" AMM.set_fee(fee) # AMM has nonreentrant decorator @external def set_amm_admin_fee(fee: uint256): """ @notice Set AMM's admin fee @param fee New admin fee (not higher than MAX_ADMIN_FEE) """ assert msg.sender == FACTORY.admin() assert fee <= MAX_ADMIN_FEE, "High fee" AMM.set_admin_fee(fee) @nonreentrant('lock') @external def set_monetary_policy(monetary_policy: address): """ @notice Set monetary policy contract @param monetary_policy Address of the monetary policy contract """ assert msg.sender == FACTORY.admin() self.monetary_policy = MonetaryPolicy(monetary_policy) MonetaryPolicy(monetary_policy).rate_write() log SetMonetaryPolicy(monetary_policy) @nonreentrant('lock') @external def set_borrowing_discounts(loan_discount: uint256, liquidation_discount: uint256): """ @notice Set discounts at which we can borrow (defines max LTV) and where bad liquidation starts @param loan_discount Discount which defines LTV @param liquidation_discount Discount where bad liquidation starts """ assert msg.sender == FACTORY.admin() assert loan_discount > liquidation_discount assert liquidation_discount >= MIN_LIQUIDATION_DISCOUNT assert loan_discount <= MAX_LOAN_DISCOUNT self.liquidation_discount = liquidation_discount self.loan_discount = loan_discount log SetBorrowingDiscounts(loan_discount, liquidation_discount) @external @nonreentrant('lock') def set_callback(cb: address): """ @notice Set liquidity mining callback """ assert msg.sender == FACTORY.admin() AMM.set_callback(cb) @external @view def admin_fees() -> uint256: """ @notice Calculate the amount of fees obtained from the interest """ rate_mul: uint256 = AMM.get_rate_mul() loan: Loan = self._total_debt loan.initial_debt = loan.initial_debt * rate_mul / loan.rate_mul loan.initial_debt += self.redeemed minted: uint256 = self.minted return unsafe_sub(max(loan.initial_debt, minted), minted) @external @nonreentrant('lock') def collect_fees() -> uint256: """ @notice Collect the fees charged as interest """ _to: address = FACTORY.fee_receiver() # AMM-based fees borrowed_fees: uint256 = AMM.admin_fees_x() collateral_fees: uint256 = AMM.admin_fees_y() if borrowed_fees > 0: STABLECOIN.transferFrom(AMM.address, _to, borrowed_fees) if collateral_fees > 0: assert COLLATERAL_TOKEN.transferFrom(AMM.address, _to, collateral_fees, default_return_value=True) AMM.reset_admin_fees() # Borrowing-based fees rate_mul: uint256 = self._rate_mul_w() loan: Loan = self._total_debt loan.initial_debt = loan.initial_debt * rate_mul / loan.rate_mul loan.rate_mul = rate_mul self._total_debt = loan # Amount which would have been redeemed if all the debt was repaid now to_be_redeemed: uint256 = loan.initial_debt + self.redeemed # Amount which was minted when borrowing + all previously claimed admin fees minted: uint256 = self.minted # Difference between to_be_redeemed and minted amount is exactly due to interest charged if to_be_redeemed > minted: self.minted = to_be_redeemed to_be_redeemed = unsafe_sub(to_be_redeemed, minted) # Now this is the fees to charge STABLECOIN.transfer(_to, to_be_redeemed) log CollectFees(to_be_redeemed, loan.initial_debt) return to_be_redeemed else: log CollectFees(0, loan.initial_debt) return 0
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"name":"UserState","inputs":[{"name":"user","type":"address","indexed":true},{"name":"collateral","type":"uint256","indexed":false},{"name":"debt","type":"uint256","indexed":false},{"name":"n1","type":"int256","indexed":false},{"name":"n2","type":"int256","indexed":false},{"name":"liquidation_discount","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Borrow","inputs":[{"name":"user","type":"address","indexed":true},{"name":"collateral_increase","type":"uint256","indexed":false},{"name":"loan_increase","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Repay","inputs":[{"name":"user","type":"address","indexed":true},{"name":"collateral_decrease","type":"uint256","indexed":false},{"name":"loan_decrease","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveCollateral","inputs":[{"name":"user","type":"address","indexed":true},{"name":"collateral_decrease","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Liquidate","inputs":[{"name":"liquidator","type":"address","indexed":true},{"name":"user","type":"address","indexed":true},{"name":"collateral_received","type":"uint256","indexed":false},{"name":"stablecoin_received","type":"uint256","indexed":false},{"name":"debt","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetMonetaryPolicy","inputs":[{"name":"monetary_policy","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetBorrowingDiscounts","inputs":[{"name":"loan_discount","type":"uint256","indexed":false},{"name":"liquidation_discount","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"CollectFees","inputs":[{"name":"amount","type":"uint256","indexed":false},{"name":"new_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"collateral_token","type":"address"},{"name":"monetary_policy","type":"address"},{"name":"loan_discount","type":"uint256"},{"name":"liquidation_discount","type":"uint256"},{"name":"amm","type":"address"}],"outputs":[]},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"view","type":"function","name":"factory","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"amm","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"collateral_token","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"debt","inputs":[{"name":"user","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"loan_exists","inputs":[{"name":"user","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"total_debt","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"max_borrowable","inputs":[{"name":"collateral","type":"uint256"},{"name":"N","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"min_collateral","inputs":[{"name":"debt","type":"uint256"},{"name":"N","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"calculate_debt_n1","inputs":[{"name":"collateral","type":"uint256"},{"name":"debt","type":"uint256"},{"name":"N","type":"uint256"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"payable","type":"function","name":"create_loan","inputs":[{"name":"collateral","type":"uint256"},{"name":"debt","type":"uint256"},{"name":"N","type":"uint256"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"create_loan_extended","inputs":[{"name":"collateral","type":"uint256"},{"name":"debt","type":"uint256"},{"name":"N","type":"uint256"},{"name":"callbacker","type":"address"},{"name":"callback_args","type":"uint256[]"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"add_collateral","inputs":[{"name":"collateral","type":"uint256"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"add_collateral","inputs":[{"name":"collateral","type":"uint256"},{"name":"_for","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"remove_collateral","inputs":[{"name":"collateral","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"remove_collateral","inputs":[{"name":"collateral","type":"uint256"},{"name":"use_eth","type":"bool"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"borrow_more","inputs":[{"name":"collateral","type":"uint256"},{"name":"debt","type":"uint256"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"repay","inputs":[{"name":"_d_debt","type":"uint256"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"repay","inputs":[{"name":"_d_debt","type":"uint256"},{"name":"_for","type":"address"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"repay","inputs":[{"name":"_d_debt","type":"uint256"},{"name":"_for","type":"address"},{"name":"max_active_band","type":"int256"}],"outputs":[]},{"stateMutability":"payable","type":"function","name":"repay","inputs":[{"name":"_d_debt","type":"uint256"},{"name":"_for","type":"address"},{"name":"max_active_band","type":"int256"},{"name":"use_eth","type":"bool"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"repay_extended","inputs":[{"name":"callbacker","type":"address"},{"name":"callback_args","type":"uint256[]"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"health_calculator","inputs":[{"name":"user","type":"address"},{"name":"d_collateral","type":"int256"},{"name":"d_debt","type":"int256"},{"name":"full","type":"bool"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"view","type":"function","name":"health_calculator","inputs":[{"name":"user","type":"address"},{"name":"d_collateral","type":"int256"},{"name":"d_debt","type":"int256"},{"name":"full","type":"bool"},{"name":"N","type":"uint256"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"nonpayable","type":"function","name":"liquidate","inputs":[{"name":"user","type":"address"},{"name":"min_x","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"liquidate","inputs":[{"name":"user","type":"address"},{"name":"min_x","type":"uint256"},{"name":"use_eth","type":"bool"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"liquidate_extended","inputs":[{"name":"user","type":"address"},{"name":"min_x","type":"uint256"},{"name":"frac","type":"uint256"},{"name":"use_eth","type":"bool"},{"name":"callbacker","type":"address"},{"name":"callback_args","type":"uint256[]"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"tokens_to_liquidate","inputs":[{"name":"user","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"tokens_to_liquidate","inputs":[{"name":"user","type":"address"},{"name":"frac","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"health","inputs":[{"name":"user","type":"address"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"view","type":"function","name":"health","inputs":[{"name":"user","type":"address"},{"name":"full","type":"bool"}],"outputs":[{"name":"","type":"int256"}]},{"stateMutability":"view","type":"function","name":"users_to_liquidate","inputs":[],"outputs":[{"name":"","type":"tuple[]","components":[{"name":"user","type":"address"},{"name":"x","type":"uint256"},{"name":"y","type":"uint256"},{"name":"debt","type":"uint256"},{"name":"health","type":"int256"}]}]},{"stateMutability":"view","type":"function","name":"users_to_liquidate","inputs":[{"name":"_from","type":"uint256"}],"outputs":[{"name":"","type":"tuple[]","components":[{"name":"user","type":"address"},{"name":"x","type":"uint256"},{"name":"y","type":"uint256"},{"name":"debt","type":"uint256"},{"name":"health","type":"int256"}]}]},{"stateMutability":"view","type":"function","name":"users_to_liquidate","inputs":[{"name":"_from","type":"uint256"},{"name":"_limit","type":"uint256"}],"outputs":[{"name":"","type":"tuple[]","components":[{"name":"user","type":"address"},{"name":"x","type":"uint256"},{"name":"y","type":"uint256"},{"name":"debt","type":"uint256"},{"name":"health","type":"int256"}]}]},{"stateMutability":"view","type":"function","name":"amm_price","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"user_prices","inputs":[{"name":"user","type":"address"}],"outputs":[{"name":"","type":"uint256[2]"}]},{"stateMutability":"view","type":"function","name":"user_state","inputs":[{"name":"user","type":"address"}],"outputs":[{"name":"","type":"uint256[4]"}]},{"stateMutability":"nonpayable","type":"function","name":"set_amm_fee","inputs":[{"name":"fee","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_amm_admin_fee","inputs":[{"name":"fee","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_monetary_policy","inputs":[{"name":"monetary_policy","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_borrowing_discounts","inputs":[{"name":"loan_discount","type":"uint256"},{"name":"liquidation_discount","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_callback","inputs":[{"name":"cb","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"admin_fees","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"collect_fees","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"liquidation_discounts","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"loans","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"loan_ix","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"n_loans","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"minted","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"redeemed","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"monetary_policy","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"liquidation_discount","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"loan_discount","inputs":[],"outputs":[{"name":"","type":"uint256"}]}]
Contract Creation Code
6020615ff36000396000518060a01c615fee576101205260206160136000396000518060a01c615fee576101405260206160736000396000518060a01c615fee576101605234615fee5733615a71523363e9cbd8226101a05260206101a060046101bc845afa610074573d600060003e3d6000fd5b60203d10615fee576101a0518060a01c615fee576101e0526101e09050516101805261018051615a915260126101805163313ce5676101a05260206101a060046101bc845afa6100c9573d600060003e3d6000fd5b60203d10615fee576101a090505118615fee5761014051680100000000000000095560206160536000396000516801000000000000000a5560206160336000396000516801000000000000000b55670de0b6b3a764000060045561016051615af1526101605163f446c1d06101c05260206101c060046101dc845afa610154573d600060003e3d6000fd5b60203d10615fee576101c09050516101a0526101a051615b11526101a05160018103818111615fee579050615b31526101a051670de0b6b3a7640000810281670de0b6b3a7640000820418615fee57905060016101a051038015615fee57808204905090506040526101c76101c0615e88565b6101c051615b515261012051615ab1526101205163313ce5676101c05260206101c060046101dc845afa610200573d600060003e3d6000fd5b60203d10615fee576101c09050518060120360128111615fee579050600a0a615ad15260016101a051036101a0516ec097ce7bc90715b34b9f10000000008102816ec097ce7bc90715b34b9f1000000000820418615fee579050048060b5710100000000000000000000000000000000008210610284578160801c91508060401b90505b690100000000000000000082106102a2578160401c91508060201b90505b6501000000000082106102bc578160201c91508060101b90505b630100000082106102d4578160101c91508060081b90505b620100008201810260121c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c90508083048082811882841002189050905090509050615b71526101805163095ea7b36101c052336101e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102005260206101c060446101dc6000855af1610394573d600060003e3d6000fd5b60203d10615fee576101c0518060011c615fee57610220526102205050610120513363ad5c46486101c05260206101c060046101dc845afa6103db573d600060003e3d6000fd5b60203d10615fee576101c0518060a01c615fee576102005261020090505118610405576001615b91525b615a7161041761000039615bb1610000f36003361161000c576133c5565b60003560e01c6323cfed0381186100565760643610615a5f57600054600214615a5f576002600055346102c052606060046102e03760016103405261004f614527565b6003600055005b63bc61ea2381186102575760c43610615a5f576064358060a01c615a5f57610640526084356004016005813511615a5f5780358061066052602082018160051b80826106803750505050600054600214615a5f5760026000556020615a9160003960005163a9059cbb610720526106405161074052602435610760526020610720604461073c6000855af16100f0573d600060003e3d6000fd5b60203d10615a5f57610720518060011c615a5f57610780526107805050610640516040527fe62214fe0000000000000000000000000000000000000000000000000000000060605233608052600060a0526040600460c0376106605180610100528060051b806101208261068060045afa50505061016f6107406141d5565b61074060408101905051610720526004356040523460605261018f613efa565b6020615ab16000396000516323b872dd6107405261064051610760526020615af160003960005161078052610720516107a0526020610740606461075c6000855af16101e0573d600060003e3d6000fd5b3d6101f757803b15615a5f5760016107c052610210565b60203d10615a5f57610740518060011c615a5f576107c0525b6107c090505115615a5f5760006102c05260043561072051808201828110615a5f57905090506102e0526040602461030037600061034052610250614527565b6003600055005b636f972f1281186102745760243610615a5f573361052052610297565b6324049e5781186102ee5760443610615a5f576024358060a01c615a5f57610520525b600054600214615a5f5760026000556004356102b2576102e7565b6004356102c05260006102e05261052051610300526000610320526102d561495f565b600435604052346060526102e7613efa565b6003600055005b63dd171e7c81186103db5760443610615a5f57600054600214615a5f57600260005560243561031c576103d4565b604060046102c037336103005260006103205261033761495f565b600435156103515760043560405234606052610351613efa565b6020615a9160003960005163a9059cbb610520523361054052602435610560526020610520604461053c6000855af161038f573d600060003e3d6000fd5b60203d10615a5f57610520518060011c615a5f576105805261058050506801000000000000000754602435808201828110615a5f579050905068010000000000000007555b6003600055005b63371fd8e681186104235760243610615a5f57336102c0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102e0526001610300526104e2565b63acb7081581186104755760443610615a5f576024358060a01c615a5f576102c0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102e0526001610300526104e2565b63b4440df481186104a95760643610615a5f576024358060a01c615a5f576102c0526044356102e0526001610300526104e2565b6337671f938118610be25760843610615a5f576024358060a01c615a5f576102c0526044356102e0526064358060011c615a5f57610300525b600054600214615a5f5760026000556004356104fd57610bdb565b604036610320376102c05160a0526105166103606135e4565b6103608051610320526020810151610340525061032051610597576012610360527f4c6f616e20646f65736e277420657869737400000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b6103205160043580828118828410021890509050610360526103605161032051036103205261032051610750576020615af160003960005163f3fef3a36103c0526102c0516103e052670de0b6b3a76400006104005260406103c060446103dc6000855af161060b573d600060003e3d6000fd5b60403d10615a5f576103c0905080516103805260208101516103a0525061038051156106aa57336102c05118615a5f576020615a916000396000516323b872dd6103c0526020615af16000396000516103e0526102c05161040052610380516104205260206103c060646103dc6000855af161068c573d600060003e3d6000fd5b60203d10615a5f576103c0518060011c615a5f576104405261044050505b6103a051156106d0576102c0516040526103a051606052610300516080526106d061405b565b6102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366103c03760a06103c0a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d06103a0516103c052610360516103e05260406103c0a26102c051604052610add614dae56610add565b6020615af160003960005163c16ef2646103a05260206103a060046103bc845afa610780573d600060003e3d6000fd5b60203d10615a5f576103a0905051610380526102e0516103805113615a5f576020615af160003960005163b461100d6103e0526102c0516104005260406103e060246103fc845afa6107d7573d600060003e3d6000fd5b60403d10615a5f576103e0905080516103a05260208101516103c0525060016103a0516103c051030160008112615a5f576103e052600061040052610380516103a051136108e35760026102c051602052600052604060002054610400526102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6104205261032051610440526103a051610460526103c05161048052610400516104a05260a0610420a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d060006104205261036051610440526040610420a2610aa2565b6020615af160003960005163f3fef3a3610460526102c05161048052670de0b6b3a76400006104a0526040610460604461047c6000855af161092a573d600060003e3d6000fd5b60403d10615a5f57610460905080516104205260208101516104405250610440516101205261032051610140526103e0516101605261096a610480613830565b6104805161046052610460516103a0516103c051038082018281126000831218615a5f5790509050610480526020615af160003960005163ab047e006104a0526102c0516104c052610440516104e05261046051610500526104805161052052803b15615a5f5760006104a060846104bc6000855af16109ef573d600060003e3d6000fd5b506801000000000000000a54610400526104005160026102c0516020526000526040600020556102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f2610440516104a052610320516104c052610460516104e0526104805161050052610400516105205260a06104a0a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d060006104a052610360516104c05260406104a0a25b336102c05114610add5760016102c0516040526103205160605260006080526104005160a052610ad3610420614e89565b6104205112615a5f575b6020615a916000396000516323b872dd61038052336103a052306103c052610360516103e0526020610380606461039c6000855af1610b21573d600060003e3d6000fd5b60203d10615a5f57610380518060011c615a5f57610400526104005050680100000000000000085461036051808201828110615a5f5790509050680100000000000000085560016102c05160205260005260406000206103205181556103405160018201555060035461034051808202811583838304141715615a5f57905090506004548015615a5f5780820490509050610380526103605161038051610360518082811882841102189050905003600355610340516004555b6003600055005b63c45a01558118610c0e5760043610615a5f5734615a5f576020615a7160003960005160405260206040f35b632a9439458118610c3a5760043610615a5f5734615a5f576020615af160003960005160405260206040f35b632621db2f8118610c665760043610615a5f5734615a5f576020615ab160003960005160405260206040f35b639b6c56ec8118610cac5760243610615a5f576004358060a01c615a5f5760c05234615a5f57600054600214615a5f57602060c051604052610ca860e0613669565b60e0f35b63a21adb9e8118610cf85760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f576001604051602052600052604060002054151560605260206060f35b6331dc3ca88118610d8c5760043610615a5f5734615a5f576020615af160003960005163095a0fc6606052602060606004607c845afa610d3d573d600060003e3d6000fd5b60203d10615a5f576060905051604052600354606052600454608052606051604051808202811583838304141715615a5f57905090506080518015615a5f578082049050905060a052602060a0f35b639a4971968118610ece5760443610615a5f5734615a5f57600054600214615a5f576004356020615ad1600039600051808202811583838304141715615a5f57905090506040526024356060526801000000000000000b54608052610df2610200613709565b610200516101e0526001670de0b6b3a76400006101e051610e14610220613cef565b61022051808202811583838304141715615a5f579050905004600181811860018311021890500361020052670de0b6b3a764000061020051670de05bc096e9c000810281670de05bc096e9c000820418615a5f5790500461020052610200516020615a916000396000516370a082316102205230610240526020610220602461023c845afa610ea8573d600060003e3d6000fd5b60203d10615a5f5761022090505180828118828410021890509050610260526020610260f35b63a75732068118610ffc5760443610615a5f5734615a5f57600054600214615a5f57670de05bc096e9c0006020615ad1600039600051600435670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f579050610f306101e0613cef565b6101e0518015615a5f5780820490509050670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f579050670de0b6b3a76400006040526024356060526801000000000000000b54608052610f8a610200613709565b610200518015615a5f57808204905090506024356024356107d08101818110615a5f579050808202811583838304141715615a5f5790509050808201828110615a5f579050905004670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f57905004610220526020610220f35b63720fb25481186110385760643610615a5f5734615a5f57600054600214615a5f57602060606004610120376110336102c0613830565b6102c0f35b63d14ff5b681186110565760243610615a5f57600161052052611079565b632e4af52a81186110d95760443610615a5f576024358060011c615a5f57610520525b34615a5f57600054600214615a5f576002600055600435611099576110d2565b6004356102c05260006102e05233610300526001610320526110b961495f565b33604052600435606052610520516080526110d261405b565b6003600055005b63152f65cb81186118a65760643610615a5f576004358060a01c615a5f57610640526024356004016005813511615a5f5780358061066052602082018160051b8082610680375050505034615a5f57600054600214615a5f5760026000556020615af160003960005163b461100d6107605233610780526040610760602461077c845afa61116c573d600060003e3d6000fd5b60403d10615a5f576107609050805161072052602081015161074052506020615af160003960005163f3fef3a36107a052336107c052670de0b6b3a76400006107e05260406107a060446107bc6000855af16111cd573d600060003e3d6000fd5b60403d10615a5f576107a09050805161076052602081015161078052506040366107a0373360a0526112006107e06135e4565b6107e080516107a05260208101516107c052506020615ab16000396000516323b872dd6107e0526020615af1600039600051610800526106405161082052610780516108405260206107e060646107fc6000855af1611264573d600060003e3d6000fd5b3d61127b57803b15615a5f57600161086052611294565b60203d10615a5f576107e0518060011c615a5f57610860525b6108605050610640516040527fef67dc7400000000000000000000000000000000000000000000000000000000606052336080526107605160a0526107805160c0526107a05160e0526106605180610100528060051b806101208261068060045afa5050506113046108406141d5565b61084080516107e052602081015161080052604081015161082052506108005161076051808201828110615a5f5790509050610840526108405115615a5f576000610860526107a0516108405110156115a55760016107205161074051030160008112615a5f57610880526107e051610720511315615a5f576108005161086052610800516107a051036107a05261082051610120526107a0516101405261088051610160526113b56108c0613830565b6108c0516108a0526108a0516107205161074051038082018281126000831218615a5f57905090506108c0526020615af160003960005163ab047e006108e052336109005261082051610920526108a051610940526108c05161096052803b15615a5f5760006108e060846108fc6000855af1611437573d600060003e3d6000fd5b506801000000000000000a546108e0526108e0516002336020526000526040600020556020615ab16000396000516323b872dd6109005261064051610920526020615af16000396000516109405261082051610960526020610900606461091c6000855af16114ab573d600060003e3d6000fd5b3d6114c257803b15615a5f576001610980526114db565b60203d10615a5f57610900518060011c615a5f57610980525b61098090505115615a5f576020615a916000396000516323b872dd610900526106405161092052306109405261080051610960526020610900606461091c6000855af161152d573d600060003e3d6000fd5b60203d10615a5f57610900518060011c615a5f57610980526109805050337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f261082051610900526107a051610920526108a051610940526108c051610960526108e0516109805260a0610900a26000610780526117ce565b6107a0516108605260006107a052336040526115bf614dae565b610800511561162d576020615a916000396000516323b872dd61088052610640516108a052306108c052610800516108e0526020610880606461089c6000855af161160f573d600060003e3d6000fd5b60203d10615a5f57610880518060011c615a5f576109005261090050505b61076051156116a2576020615a916000396000516323b872dd610880526020615af16000396000516108a052306108c052610760516108e0526020610880606461089c6000855af1611684573d600060003e3d6000fd5b60203d10615a5f57610880518060011c615a5f576109005261090050505b61086051610840511115611712576020615a9160003960005163a9059cbb61088052336108a0526108605161084051036108c0526020610880604461089c6000855af16116f4573d600060003e3d6000fd5b60203d10615a5f57610880518060011c615a5f576108e0526108e050505b610820511561179e576020615ab16000396000516323b872dd61088052610640516108a052336108c052610820516108e0526020610880606461089c6000855af1611762573d600060003e3d6000fd5b3d61177957803b15615a5f57600161090052611792565b60203d10615a5f57610880518060011c615a5f57610900525b61090090505115615a5f575b337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366108803760a0610880a25b337f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d06107805161088052610860516108a0526040610880a2680100000000000000085461086051808201828110615a5f5790509050680100000000000000085560013360205260005260406000206107a05181556107c0516001820155506003546107c051808202811583838304141715615a5f57905090506004548015615a5f57808204905090506108805261086051610880516108605180828118828411021890509050036003556107c0516004556003600055005b630b8db68181186118c45760843610615a5f576000610300526118df565b6322c714538118611e865760a43610615a5f57608435610300525b6004358060a01c615a5f576102c0526064358060011c615a5f576102e05234615a5f57600054600214615a5f576020615af160003960005163544fb5c1610360526102c051610380526040610360602461037c845afa611944573d600060003e3d6000fd5b60403d10615a5f57610360905080516103205260208101516103405250610340516020615ad1600039600051808202811583838304141715615a5f5790509050610340526020615af160003960005163b461100d6103a0526102c0516103c05260406103a060246103bc845afa6119c0573d600060003e3d6000fd5b60403d10615a5f576103a09050805161036052602081015161038052506102c0516040526119ef6103c0613669565b6103c0518060ff1c615a5f576103a052610300516103c05260006103e0526103a05115611a515760026102c0516020526000526040600020548060ff1c615a5f576103e05260016103605161038051030160008112615a5f576103c052611a8e565b6801000000000000000a548060ff1c615a5f576103e0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610360525b606036610400376103a0516044358082018281126000831218615a5f57905090506103a05260016103a0511215611b25576011610460527f4e6f6e2d706f73697469766520646562740000000000000000000000000000006104805261046050610460518061048001601f826000031636823750506308c379a061042052602061044052601f19601f61046051011660440161043cfd5b6020615af160003960005163c16ef264610480526020610480600461049c845afa611b55573d600060003e3d6000fd5b60203d10615a5f5761048090505161046052610460516103605113611b7b576000611b90565b60243515611b8a576001611b90565b60443515155b611c115761036051610400526020615af16000396000516362ca4b18610480526102c0516104a0526020610480602461049c845afa611bd4573d600060003e3d6000fd5b60203d10615a5f57610480905051670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f5790508060ff1c615a5f5761044052611c73565b610340518060ff1c615a5f576024358082018281126000831218615a5f5790509050610420526104205160008112615a5f57610120526103a05160008112615a5f57610140526103c05161016052611c6a610480613830565b61048051610400525b6020615af1600039600051632eb858e76104a052610400516104c05260206104a060246104bc845afa611cab573d600060003e3d6000fd5b60203d10615a5f576104a09050518060ff1c615a5f576104805261046051610360511315611d30576104205160008112615a5f576040526103c0516060526000608052611cf96104a0613709565b6104a0518060ff1c615a5f576104805180820281191515600160ff1b8414151782158484840514171615615a5f5790509050610440525b6103a05161044051056104a0526104a051670de0b6b3a76400006104a0516103e05180820281191515600160ff1b8414151782158484840514171615615a5f5790509050058082038281136000831218615a5f5790509050670de0b6b3a76400008103818113615a5f5790506104a0526102e05115611e7f5761046051610400511315611e7f57610480516020615af16000396000516386fc88d36104e05260206104e060046104fc845afa611deb573d600060003e3d6000fd5b60203d10615a5f576104e09050518060ff1c615a5f5780828118828413021890509050610480518082038281136000831218615a5f57905090506104c05260016104c05112611e7f576104a0516103a0516104c0516104205180820281191515600160ff1b8414151782158484840514171615615a5f5790509050058082018281126000831218615a5f57905090506104a0525b60206104a0f35b63bcbaf4878118611ea45760443610615a5f5760016109e052611ec7565b633ecdb8288118611f535760643610615a5f576044358060011c615a5f576109e0525b6004358060a01c615a5f576109c05234615a5f57600054600214615a5f5760026000556000610a0052336109c05114611f115760026109c051602052600052604060002054610a00525b6109c0516106405260243561066052610a005161068052670de0b6b3a76400006106a0526109e0516106c0526040366106e037611f4c615221565b6003600055005b63036aed88811861206a5760e43610615a5f576004358060a01c615a5f576109c0526064358060011c615a5f576109e0526084358060a01c615a5f57610a005260a4356004016005813511615a5f57803580610a2052602082018160051b8082610a40375050505034615a5f57600054600214615a5f5760026000556000610ae052336109c05114611ff65760026109c051602052600052604060002054610ae0525b6109c0516106405260243561066052610ae05161068052604435670de0b6b3a7640000818118670de0b6b3a76400008310021890506106a0526109e0516106c052610a00516106e052610a205180610700528060051b8061072082610a4060045afa505050612063615221565b6003600055005b631b25cdaf811861208e5760243610615a5f57670de0b6b3a764000060e0526120a8565b63546e040d81186121d45760443610615a5f5760243560e0525b6004358060a01c615a5f5760c05234615a5f57600054600214615a5f576000610100523360c051146120ea57600260c051602052600052604060002054610100525b60e051604052610100516060526121026101406151b4565b6101405161012052670de0b6b3a76400006020615af160003960005163544fb5c16101605260c051610180526040610160602461017c845afa61214a573d600060003e3d6000fd5b60403d10615a5f5761016090505161012051808202811583838304141715615a5f57905090500461014052670de0b6b3a764000060c05160405261218f610180613669565b6101805160e051808202811583838304141715615a5f579050905004610160526101405161016051610140518082811882841102189050905003610180526020610180f35b63e2d8ebee81186121f25760243610615a5f57600061022052612215565b638908ea8281186122a15760443610615a5f576024358060011c615a5f57610220525b6004358060a01c615a5f576102005234615a5f57600054600214615a5f57602061020051610280526102005160405261224f610240613669565b610240516102a052610220516102c0526002610200516020526000526040600020546102e052610280516040526102a0516060526102c0516080526102e05160a05261229c610260614e89565b610260f35b627c98ab81186122bf5760043610615a5f5760403661020037612300565b6380e8f6ec81186122e45760243610615a5f5760043561020052600061022052612300565b6390f8667d81186125815760443610615a5f5760406004610200375b34615a5f57600054600214615a5f576801000000000000000654610240526102205161026052610220516123375761024051610260525b610200516102805260006102a0526000620f4240905b80620273c052610240516102805110156123715761026051620273c0511815612374565b60015b1561237e576124f0565b6102805167fffffffffffffffe8111615a5f5760050154620273e052620273e0516040526123ae62027420613669565b62027420516202740052620273e051604052620274005160605260016080526002620273e05160205260005260406000205460a0526123ef62027440614e89565b620274405162027420527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6202742051136124d0576020615af160003960005163544fb5c16202748052620273e051620274a05260406202748060246202749c845afa612461573d600060003e3d6000fd5b60403d10615a5f576202748090508051620274405260208101516202746052506102a0516103e78111615a5f57600181016102a05260a081026102c001620273e05181526202744051602082015262027460516040820152620274005160608201526202742051608082015250505b6102805160018101818110615a5f5790506102805260010181811861234d575b5050602080620273c05280620273c00160006102a05180835260a081026000826103e88111615a5f57801561256b57905b60a08102602087010160a082026102c00180518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050600101818118612521575b50508201602001915050905081019050620273c0f35b63d9f11a6481186125d65760043610615a5f5734615a5f5760206020615af160003960005163f2388acb604052602060406004605c845afa6125c8573d600060003e3d6000fd5b60203d10615a5f5760409050f35b632c5089c381186127365760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f576020615af160003960005163e8dd1ef1606052604051608052602060606024607c845afa612639573d600060003e3d6000fd5b60203d10615a5f576060518060011c615a5f5760a05260a090505115615a5f576020615af160003960005163b461100d60a05260405160c052604060a0602460bc845afa61268c573d600060003e3d6000fd5b60403d10615a5f5760a0905080516060526020810151608052506020615af1600039600051632eb858e760a05260605160c052602060a0602460bc845afa6126d9573d600060003e3d6000fd5b60203d10615a5f5760a0905051610120526020615af16000396000516324299b7a60e05260805161010052602060e0602460fc845afa61271e573d600060003e3d6000fd5b60203d10615a5f5760e0905051610140526040610120f35b63ec74d0a881186128545760243610615a5f576004358060a01c615a5f5760c05234615a5f57600054600214615a5f576020615af160003960005163544fb5c16101205260c051610140526040610120602461013c845afa61279d573d600060003e3d6000fd5b60403d10615a5f576101209050805160e052602081015161010052506020615af160003960005163b461100d6101605260c051610180526040610160602461017c845afa6127f0573d600060003e3d6000fd5b60403d10615a5f57610160905080516101205260208101516101405250610100516101805260e0516101a05260c05160405261282d610160613669565b610160516101c05260016101205161014051030160008112615a5f576101e0526080610180f35b634189617d811861297d5760243610615a5f5734615a5f576020615a7160003960005163f851a440604052602060406004605c845afa612899573d600060003e3d6000fd5b60203d10615a5f576040518060a01c615a5f5760805260809050513318615a5f5767016345785d8a000060043511156128d35760006128dd565b620f424060043510155b61293e5760036040527f466565000000000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6020615af1600039600051631aa02d59604052600435606052803b15615a5f57600060406024605c6000855af161297a573d600060003e3d6000fd5b50005b63a5b4804a8118612a915760243610615a5f5734615a5f576020615a7160003960005163f851a440604052602060406004605c845afa6129c2573d600060003e3d6000fd5b60203d10615a5f576040518060a01c615a5f5760805260809050513318615a5f57670de0b6b3a76400006004351115612a525760086040527f486967682066656500000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6020615af1600039600051633217902f604052600435606052803b15615a5f57600060406024605c6000855af1612a8e573d600060003e3d6000fd5b50005b6381d2f1b78118612b885760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f5760026000556020615a7160003960005163f851a440606052602060606004607c845afa612af3573d600060003e3d6000fd5b60203d10615a5f576060518060a01c615a5f5760a05260a09050513318615a5f57604051680100000000000000095560405163e91f2f4c606052602060606004607c6000855af1612b49573d600060003e3d6000fd5b60203d10615a5f57606050507f51fabb88f7860c9dbcc2a5a9b69a8b9476d63b87124591f97254e29f0e8daaeb60405160605260206060a16003600055005b632a0c35868118612c7a5760443610615a5f5734615a5f57600054600214615a5f5760026000556020615a7160003960005163f851a440604052602060406004605c845afa612bdc573d600060003e3d6000fd5b60203d10615a5f576040518060a01c615a5f5760805260809050513318615a5f576024356004351115615a5f57662386f26fc1000060243510615a5f576706f05b59d3b2000060043511615a5f576024356801000000000000000a556004356801000000000000000b557fe2750bf9a7458977fcc01c1a0b615d12162f63b18cad78441bd64c590b337eca6040600460403760406040a16003600055005b63cc1891c78118612d415760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f5760026000556020615a7160003960005163f851a440606052602060606004607c845afa612cdc573d600060003e3d6000fd5b60203d10615a5f576060518060a01c615a5f5760a05260a09050513318615a5f576020615af160003960005163cc1891c7606052604051608052803b15615a5f57600060606024607c6000855af1612d39573d600060003e3d6000fd5b506003600055005b631b1800e38118612e1c5760043610615a5f5734615a5f576020615af160003960005163095a0fc6606052602060606004607c845afa612d86573d600060003e3d6000fd5b60203d10615a5f576060905051604052600354606052600454608052606051604051808202811583838304141715615a5f57905090506080518015615a5f57808204905090506060526060516801000000000000000854808201828110615a5f5790509050606052680100000000000000075460a05260a05160605160a051808281188284110218905090500360c052602060c0f35b631e0cfcef81186131fc5760043610615a5f5734615a5f57600054600214615a5f5760026000556020615a7160003960005163cab4d3db60c052602060c0600460dc845afa612e70573d600060003e3d6000fd5b60203d10615a5f5760c0518060a01c615a5f576101005261010090505160a0526020615af160003960005163d1fea73360e052602060e0600460fc845afa612ebd573d600060003e3d6000fd5b60203d10615a5f5760e090505160c0526020615af16000396000516389960ba7610100526020610100600461011c845afa612efd573d600060003e3d6000fd5b60203d10615a5f5761010090505160e05260c05115612f83576020615a916000396000516323b872dd610100526020615af16000396000516101205260a0516101405260c051610160526020610100606461011c6000855af1612f65573d600060003e3d6000fd5b60203d10615a5f57610100518060011c615a5f576101805261018050505b60e05115613016576020615ab16000396000516323b872dd610100526020615af16000396000516101205260a0516101405260e051610160526020610100606461011c6000855af1612fda573d600060003e3d6000fd5b3d612ff157803b15615a5f5760016101805261300a565b60203d10615a5f57610100518060011c615a5f57610180525b61018090505115615a5f575b6020615af160003960005163822fe50761010052803b15615a5f576000610100600461011c6000855af161304f573d600060003e3d6000fd5b5061305b610120613549565b610120516101005260035461012052600454610140526101205161010051808202811583838304141715615a5f5790509050610140518015615a5f57808204905090506101205261010051610140526101205160035561014051600455610120516801000000000000000854808201828110615a5f57905090506101605268010000000000000007546101805261018051610160511161313e577f5393ab6ef9bb40d91d1b04bbbeb707fbf3d1eb73f46744e2d179e4996026283f60006101a052610120516101c05260406101a0a160006101a05260206101a06131f5566131f5565b610160516801000000000000000755610180516101605103610160526020615a9160003960005163a9059cbb6101a05260a0516101c052610160516101e05260206101a060446101bc6000855af161319b573d600060003e3d6000fd5b60203d10615a5f576101a0518060011c615a5f576102005261020050507f5393ab6ef9bb40d91d1b04bbbeb707fbf3d1eb73f46744e2d179e4996026283f610160516101a052610120516101c05260406101a0a160206101605b6003600055f35b635457ff7b811861323c5760243610615a5f576004358060a01c615a5f5760405234615a5f57600260405160205260005260406000205460605260206060f35b63e1ec3c6881186132735760243610615a5f5734615a5f5760043567fffffffffffffffe8111615a5f576005015460405260206040f35b637128f3b881186132bb5760243610615a5f576004358060a01c615a5f5760405234615a5f576801000000000000000560405160205260005260406000205460605260206060f35b636cce39be81186132e75760043610615a5f5734615a5f57680100000000000000065460405260206040f35b634f02c42081186133135760043610615a5f5734615a5f57680100000000000000075460405260206040f35b63e231bff0811861333f5760043610615a5f5734615a5f57680100000000000000085460405260206040f35b63adfae4ce811861336b5760043610615a5f5734615a5f57680100000000000000095460405260206040f35b63627d2b8381186133975760043610615a5f5734615a5f576801000000000000000a5460405260206040f35b635449b9cb81186133c35760043610615a5f5734615a5f576801000000000000000b5460405260206040f35b505b34156133dc576020615b9160003960005115615a5f575b36615a5f57005b670de0b6b3a764000060405110606052600060805260405160a052606051156134275760a0518015615a5f57806ec097ce7bc90715b34b9f100000000004905060a0525b608060c05260006008905b8060e05260c05160020a61010052670de0b6b3a7640000610100510260a05110613476576101005160a0510460a052608051670de0b6b3a764000060c05102016080525b60c05160011c60c052600101818118613432575050670de0b6b3a764000060e05260006022905b8061010052671bc16d674ec8000060a051106134c75760e0516080510160805260a05160011c60a0525b670de0b6b3a764000060a05160a051020460a05260e05160011c60e05260010181811861349d57505060605161350e576080518060ff1c615a5f5781525061354756613547565b6080518060ff1c615a5f577f80000000000000000000000000000000000000000000000000000000000000008114615a5f576000038152505b565b680100000000000000095463e91f2f4c606052602060606004607c6000855af1613578573d600060003e3d6000fd5b60203d10615a5f576060905051640a3c2abcef818118640a3c2abcef8310021890506040526020615af160003960005163d4387a99606052604051608052602060606024607c6000855af16135d2573d600060003e3d6000fd5b60203d10615a5f576060905051815250565b6135ee60e0613549565b60e05160c052600160a0516020526000526040600020805460e0526001810154610100525060e051613630576000815260c05160208201525061366756613667565b60e05160c051808202811583838304141715615a5f5790509050610100518015615a5f5780820490509050815260c0516020820152505b565b6020615af160003960005163095a0fc6608052602060806004609c845afa613696573d600060003e3d6000fd5b60203d10615a5f576080905051606052600160405160205260005260406000208054608052600181015460a052506080516136d957600081525061370756613707565b608051606051808202811583838304141715615a5f579050905060a0518015615a5f57808204905090508152505b565b6040516080516040516060518015615a5f57808204905090506103e88181186103e88311021890508015615a5f5780683635c9adc5dea00000049050808201828110615a5f5790509050670de0b6b3a7640000818118670de0b6b3a7640000831002189050670de0b6b3a764000003808202811583838304141715615a5f57905090506020615b71600039600051606051808202811583838304141715615a5f57905090508015615a5f578082049050905060a05260a05160c052600160318101905b8060e05260605160e051186137e057613826565b6020615b1160003960005160a0516020615b31600039600051808202811583838304141715615a5f57905090500460a05260a05160c0510160c0526001018181186137cc575b505060c051815250565b6101405161389e576007610180527f4e6f206c6f616e000000000000000000000000000000000000000000000000006101a0526101805061018051806101a001601f826000031636823750506308c379a061014052602061016052601f19601f61018051011660440161015cfd5b6020615af1600039600051638f8654c56101a05260206101a060046101bc845afa6138ce573d600060003e3d6000fd5b60203d10615a5f576101a0905051610180526020615af1600039600051632eb858e76101c052610180516101e05260206101c060246101dc845afa613918573d600060003e3d6000fd5b60203d10615a5f576101c09050516101a052610120516020615ad1600039600051808202811583838304141715615a5f5790509050604052610160516060526801000000000000000b546080526139706101e0613709565b6101e0516101c0526101c0516101a051808202811583838304141715615a5f57905090506101405160018101818110615a5f5790508015615a5f57808204905090506101c0526101c051613a2457600e6101e0527f416d6f756e7420746f6f206c6f77000000000000000000000000000000000000610200526101e0506101e0518061020001601f826000031636823750506308c379a06101a05260206101c052601f19601f6101e05101166044016101bcfd5b6101c051604052613a366102006133e3565b610200516101e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101e05113613a9c576101e0516020615b5160003960005160018103818113615a5f5790508082038281136000831218615a5f57905090506101e0525b6101e0516020615b516000396000518015615a5f57808205600160ff1b8314156000198314151715615a5f57905090506101e0526101e051610160518060ff1c615a5f57806104000361040081136000831218615a5f57905080828118828412021890509050610180518082018281126000831218615a5f57905090506101e052610180516101e05113613bf7576020615af160003960005163ec654706610200526101e05160018103818113615a5f579050610220526020610200602461021c845afa613b6f573d600060003e3d6000fd5b60203d10615a5f57610200518060011c615a5f5761024052610240905051613bf757600d610260527f4465627420746f6f2068696768000000000000000000000000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b6020615af16000396000516386fc88d3610240526020610240600461025c845afa613c27573d600060003e3d6000fd5b60203d10615a5f576102409050516020615af1600039600051632eb858e7610200526101e051610220526020610200602461021c845afa613c6d573d600060003e3d6000fd5b60203d10615a5f5761020090505110613ce657600d610280527f4465627420746f6f2068696768000000000000000000000000000000000000006102a0526102805061028051806102a001601f826000031636823750506308c379a061024052602061026052601f19601f61028051011660440161025cfd5b6101e051815250565b6020615af16000396000516386fc88d3610140526020610140600461015c845afa613d1f573d600060003e3d6000fd5b60203d10615a5f57610140905051610120526020615b516000396000516020615af160003960005163a7db79a5610160526020610160600461017c845afa613d6c573d600060003e3d6000fd5b60203d10615a5f57610160905051670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f579050610120518015615a5f5780820490509050604052613db76101a06133e3565b6101a0510560058101818112615a5f579050610140526020615af1600039600051632eb858e761018052610140516101a0526020610180602461019c845afa613e05573d600060003e3d6000fd5b60203d10615a5f57610180905051610160526020615af160003960005163c16ef2646101a05260206101a060046101bc845afa613e47573d600060003e3d6000fd5b60203d10615a5f576101a0905051610180526000610401905b806101a0526101405160018103818113615a5f57905061014052610180516101405113613e8c57613eee565b610160516101c0526020615b31600039600051610160516020615b11600039600051808202811583838304141715615a5f5790509050046101605261012051610160511115613ee3576101c0518352505050613ef8565b600101818118613e60575b5050610160518152505b565b6020615b91600039600051613f1157606051615a5f575b604051606051808203828111615a5f579050905060805260605115613fce576020615ab160003960005163d0e30db060a052803b15615a5f57600060a0600460bc606051855af1613f67573d600060003e3d6000fd5b506020615ab160003960005163a9059cbb60a0526020615af160003960005160c05260605160e052602060a0604460bc6000855af1613fab573d600060003e3d6000fd5b60203d10615a5f5760a0518060011c615a5f576101005261010090505115615a5f575b60805115614059576020615ab16000396000516323b872dd60a0523360c0526020615af160003960005160e05260805161010052602060a0606460bc6000855af161401e573d600060003e3d6000fd5b3d61403557803b15615a5f5760016101205261404d565b60203d10615a5f5760a0518060011c615a5f57610120525b61012090505115615a5f575b565b608051614069576000614075565b6020615b916000396000515b614102576020615ab16000396000516323b872dd60a0526020615af160003960005160c05260405160e05260605161010052602060a0606460bc6000855af16140c3573d600060003e3d6000fd5b3d6140da57803b15615a5f576001610120526140f2565b60203d10615a5f5760a0518060011c615a5f57610120525b61012090505115615a5f576141d3565b6020615ab16000396000516323b872dd60a0526020615af160003960005160c0523060e05260605161010052602060a0606460bc6000855af161414a573d600060003e3d6000fd5b60203d10615a5f5760a0518060011c615a5f576101205261012090505115615a5f576020615ab1600039600051632e1a7d4d60a05260605160c052803b15615a5f57600060a0602460bc6000855af16141a8573d600060003e3d6000fd5b50600060a05260a0506000600060a05160c0606051604051612710f16141d3573d600060003e3d6000fd5b565b6020615ab160003960005160405114615a5f576060366101c0376020615af1600039600051638f8654c5610220526020610220600461023c845afa61421f573d600060003e3d6000fd5b60203d10615a5f576102209050516101c0526020615af160003960005163ebcb0067610240526101c051610260526020610240602461025c845afa614269573d600060003e3d6000fd5b60203d10615a5f57610240905051610220526020615af16000396000516331f7e306610260526101c051610280526020610260602461027c845afa6142b3573d600060003e3d6000fd5b60203d10615a5f5761026090505161024052600060605181610460015260048101905060a06080516102e05260a0516103005260c0516103205260e051610340528061036052806102e0016000610100518083528060051b60008260058111615a5f57801561433c57905b8060051b61012001518160051b60208801015260010181811861431e575b505082016020019150509050810190506102c0526102c080516020820183610460018281848460045afa505050808301925050508061044052610440505060406106006104405161046060006040515af161439c573d600060003e3d6000fd5b3d604081183d60401002186105e0526105e0805180610260526020820181610280838360045afa5050505061026051602011615a5f57610280516102e05260206102c0526102c06020810151815160200360031b1c90506101e05261026051604011615a5f576102a0516102e05260206102c0526102c06020810151815160200360031b1c9050610200526020615af1600039600051638f8654c56102c05260206102c060046102dc845afa614457573d600060003e3d6000fd5b60203d10615a5f576102c09050516101c05118615a5f576020615af160003960005163ebcb00676102c0526101c0516102e05260206102c060246102dc845afa6144a6573d600060003e3d6000fd5b60203d10615a5f576102c09050516102205118615a5f576020615af16000396000516331f7e3066102c0526101c0516102e05260206102c060246102dc845afa6144f5573d600060003e3d6000fd5b60203d10615a5f576102c09050516102405118615a5f576101c05181526101e051602082015261020051604082015250565b600133602052600052604060002054156145a1576014610360527f4c6f616e20616c726561647920637265617465640000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b600461032051101561461357600f610360527f4e656564206d6f7265207469636b7300000000000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b603261032051111561468557600f610360527f4e656564206c657373207469636b7300000000000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b6102e05161012052610300516101405261032051610160526146a8610380613830565b6103805161036052610360516103205160018103818111615a5f5790508060ff1c615a5f578082018281126000831218615a5f5790509050610380526146ef6103c0613549565b6103c0516103a05260013360205260005260406000206103005181556103a0516001820155506801000000000000000a546103c0526103c05160023360205260005260406000205568010000000000000006546103e052336103e05167fffffffffffffffe8111615a5f57600501556103e051680100000000000000053360205260005260406000205560016103e0510168010000000000000006556003546103a051808202811583838304141715615a5f57905090506004548015615a5f578082049050905061030051808201828110615a5f579050905061040052610400516003556103a0516004556020615af160003960005163ab047e006104205233610440526102e051610460526103605161048052610380516104a052803b15615a5f576000610420608461043c6000855af1614830573d600060003e3d6000fd5b50680100000000000000075461030051808201828110615a5f5790509050680100000000000000075561034051156148d5576102e0516040526102c051606052614878613efa565b6020615a9160003960005163a9059cbb61042052336104405261030051610460526020610420604461043c6000855af16148b7573d600060003e3d6000fd5b60203d10615a5f57610420518060011c615a5f576104805261048050505b337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f26102e051610420526103005161044052610360516104605261038051610480526103c0516104a05260a0610420a2337fe1979fe4c35e0cef342fef5668e2c8e7a7e9f5d5d1ca8fee0ac6c427fa4153af6102e0516104205261030051610440526040610420a2565b604036610340376103005160a0526149786103806135e4565b61038080516103405260208101516103605250610340516149f9576012610380527f4c6f616e20646f65736e277420657869737400000000000000000000000000006103a0526103805061038051806103a001601f826000031636823750506308c379a061034052602061036052601f19601f61038051011660440161035cfd5b610340516102e051808201828110615a5f5790509050610340526020615af160003960005163b461100d6103c052610300516103e05260406103c060246103dc845afa614a4b573d600060003e3d6000fd5b60403d10615a5f576103c0905080516103805260208101516103a052506001610380516103a051030160008112615a5f576103c0526020615af160003960005163f3fef3a3610420526103005161044052670de0b6b3a7640000610460526040610420604461043c6000855af1614ac7573d600060003e3d6000fd5b60403d10615a5f57610420905080516103e052602081015161040052506103e05115614b5357601a610420527f416c726561647920696e20756e6465727761746572206d6f64650000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b61032051614b7a57610400516102c051808201828110615a5f579050905061040052614b95565b610400516102c051808203828111615a5f5790509050610400525b610400516101205261034051610140526103c05161016052614bb8610440613830565b610440516104205261042051610380516103a051038082018281126000831218615a5f5790509050610440526020615af160003960005163ab047e00610460526103005161048052610400516104a052610420516104c052610440516104e052803b15615a5f576000610460608461047c6000855af1614c3d573d600060003e3d6000fd5b506001610300516020526000526040600020610340518155610360516001820155506801000000000000000a5461046052610460516002610300516020526000526040600020556102e05115614cdd5760035461036051808202811583838304141715615a5f57905090506004548015615a5f57808204905090506102e051808201828110615a5f57905090506104805261048051600355610360516004555b61032051614d2557610300517fe1979fe4c35e0cef342fef5668e2c8e7a7e9f5d5d1ca8fee0ac6c427fa4153af6102c051610480526102e0516104a0526040610480a2614d59565b610300517fe25410a4059619c9594dc6f022fe231b02aaea733f689e7ab0cd21b3d4d0eb546102c051610480526020610480a25b610300517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f26104005161048052610340516104a052610420516104c052610440516104e052610460516105005260a0610480a2565b680100000000000000065460018103818111615a5f5790506060526801000000000000000560405160205260005260406000205460805260405160805167fffffffffffffffe8111615a5f576005015418615a5f576000680100000000000000056040516020526000526040600020556060516080511015614e795760605167fffffffffffffffe8111615a5f576005015460a05260a05160805167fffffffffffffffe8111615a5f57600501556080516801000000000000000560a0516020526000526040600020555b6060516801000000000000000655565b606051614eed57601260c0527f4c6f616e20646f65736e2774206578697374000000000000000000000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b670de0b6b3a764000060c05260a05115614f265760c05160a0518060ff1c615a5f578082038281136000831218615a5f579050905060c0525b6060518060ff1c615a5f576020615af16000396000516362ca4b1860e05260405161010052602060e0602460fc845afa614f65573d600060003e3d6000fd5b60203d10615a5f5760e09050518060ff1c615a5f5760c05180820281191515600160ff1b8414151782158484840514171615615a5f579050905005670de0b6b3a76400008103818113615a5f57905060c052608051156151ac576020615af160003960005163b461100d61012052604051610140526040610120602461013c845afa614ff6573d600060003e3d6000fd5b60403d10615a5f576101209050805160e052602081015161010052506020615af1600039600051638f8654c5610120526020610120600461013c845afa615042573d600060003e3d6000fd5b60203d10615a5f5761012090505160e05113156151ac576020615af16000396000516386fc88d3610180526020610180600461019c845afa615089573d600060003e3d6000fd5b60203d10615a5f57610180905051610160526020615af1600039600051632eb858e76101a05260e0516101c05260206101a060246101bc845afa6150d2573d600060003e3d6000fd5b60203d10615a5f576101a090505161018052610180516101605111156151ac5760c0516060516101605161018051808203828111615a5f57905090506020615af160003960005163544fb5c16101a0526040516101c05260406101a060246101bc845afa615145573d600060003e3d6000fd5b60403d10615a5f576101a0905060208101905051808202811583838304141715615a5f57905090506020615ad1600039600051808202811583838304141715615a5f5790509050048060ff1c615a5f578082018281126000831218615a5f579050905060c0525b60c051815250565b670de0b6b3a7640000608052670de0b6b3a763ffff6040511161521957606051670de0b6b3a764000001604051670de0b6b3a76400000360605160011c670de0b6b3a7640000010204608052670de0b6b3a76400006040516040516080510102046080525b608051815250565b6040366107c0376106405160a05261523a6108006135e4565b61080080516107c05260208101516107e05250610680511561530c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610640516040526107c05160605260016080526106805160a05261529c610800614e89565b61080051131561530c57600f610820527f4e6f7420656e6f7567682072656b7400000000000000000000000000000000006108405261082050610820518061084001601f826000031636823750506308c379a06107e052602061080052601f19601f6108205101166044016107fcfd5b6107c05161080052670de0b6b3a76400006107c0516106a051808202811583838304141715615a5f5790509050046107c0526107c05115615a5f576107c0516108005103610800526106a0516040526106805160605261536d6108406151b4565b61084051610820526020615af160003960005163f3fef3a361088052610640516108a052610820516108c0526040610880604461089c6000855af16153b7573d600060003e3d6000fd5b60403d10615a5f5761088090508051610840526020810151610860525061066051610840511015615448576008610880527f536c6970706167650000000000000000000000000000000000000000000000006108a0526108805061088051806108a001601f826000031636823750506308c379a061084052602061086052601f19601f61088051011660440161085cfd5b610840516107c051808281188284100218905090506108805261088051156154d6576020615a916000396000516323b872dd6108a0526020615af16000396000516108c052306108e052610880516109005260206108a060646108bc6000855af16154b8573d600060003e3d6000fd5b60203d10615a5f576108a0518060011c615a5f576109205261092050505b610840516107c051116155805733604052610860516060526106c0516080526154fd61405b565b6107c0516108405111156158f9576020615a916000396000516323b872dd6108a0526020615af16000396000516108c052336108e0526107c05161084051036109005260206108a060646108bc6000855af161555e573d600060003e3d6000fd5b60203d10615a5f576108a0518060011c615a5f576109205261092050506158f9565b610840516107c051036108a0526106e0516156155733604052610860516060526106c0516080526155af61405b565b6020615a916000396000516323b872dd6108c052336108e05230610900526108a0516109205260206108c060646108dc6000855af16155f3573d600060003e3d6000fd5b60203d10615a5f576108c0518060011c615a5f576109405261094050506158f9565b61086051156156ab576020615ab16000396000516323b872dd6108c0526020615af16000396000516108e0526106e05161090052610860516109205260206108c060646108dc6000855af161566f573d600060003e3d6000fd5b3d61568657803b15615a5f5760016109405261569f565b60203d10615a5f576108c0518060011c615a5f57610940525b61094090505115615a5f575b6106e0516040527f4ea696bb00000000000000000000000000000000000000000000000000000000606052610640516080526108405160a0526108605160c0526107c05160e0526107005180610100528060051b806101208261072060045afa5050506157196109206141d5565b61092080516108c05260208101516108e052604081015161090052506108a0516108e05110156157a9576013610920527f6e6f7420656e6f7567682070726f6365656473000000000000000000000000006109405261092050610920518061094001601f826000031636823750506308c379a06108e052602061090052601f19601f6109205101166044016108fcfd5b6108a0516108e0511115615821576020615a916000396000516323b872dd610920526106e0516109405233610960526108a0516108e05103610980526020610920606461093c6000855af1615803573d600060003e3d6000fd5b60203d10615a5f57610920518060011c615a5f576109a0526109a050505b6020615a916000396000516323b872dd610920526106e0516109405230610960526108a051610980526020610920606461093c6000855af1615868573d600060003e3d6000fd5b60203d10615a5f57610920518060011c615a5f576109a0526109a0505061090051156158f9576020615ab16000396000516323b872dd610920526106e05161094052336109605261090051610980526020610920606461093c6000855af16158d5573d600060003e3d6000fd5b60203d10615a5f57610920518060011c615a5f576109a0526109a090505115615a5f575b68010000000000000008546107c051808201828110615a5f5790509050680100000000000000085560016106405160205260005260406000206108005181556107e051600182015550610640517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d0610860516108a0526107c0516108c05260406108a0a261064051337f642dd4d37ddd32036b9797cec464c0045dd2118c549066ae6b0f88e32240c2d0610860516108a052610840516108c0526107c0516108e05260606108a0a361080051615a0a57610640517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366108a03760a06108a0a261064051604052615a0a614dae565b6003546107e051808202811583838304141715615a5f57905090506004548015615a5f57808204905090506108a0526107c0516108a0516107c05180828118828411021890509050036003556107e051600455565b600080fda165767970657283000307000b5b670de0b6b3a764000060405110606052600060805260405160a05260605115615ecc5760a0518015615fee57806ec097ce7bc90715b34b9f100000000004905060a0525b608060c05260006008905b8060e05260c05160020a61010052670de0b6b3a7640000610100510260a05110615f1b576101005160a0510460a052608051670de0b6b3a764000060c05102016080525b60c05160011c60c052600101818118615ed7575050670de0b6b3a764000060e05260006022905b8061010052671bc16d674ec8000060a05110615f6c5760e0516080510160805260a05160011c60a0525b670de0b6b3a764000060a05160a051020460a05260e05160011c60e052600101818118615f42575050606051615fb3576080518060ff1c615fee57815250615fec56615fec565b6080518060ff1c615fee577f80000000000000000000000000000000000000000000000000000000000000008114615fee576000038152505b565b600080fd0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca00000000000000000000000001e7d3bf98d3f8d8ce193236c3e0ec4b00e32daae000000000000000000000000000000000000000000000000013fbe85edc9000000000000000000000000000000000000000000000000000000d529ae9e86000000000000000000000000000037417b2238aa52d0dd2d6252d989e728e8f706e4
Deployed Bytecode
0x6003361161000c576133c5565b60003560e01c6323cfed0381186100565760643610615a5f57600054600214615a5f576002600055346102c052606060046102e03760016103405261004f614527565b6003600055005b63bc61ea2381186102575760c43610615a5f576064358060a01c615a5f57610640526084356004016005813511615a5f5780358061066052602082018160051b80826106803750505050600054600214615a5f5760026000556020615a9160003960005163a9059cbb610720526106405161074052602435610760526020610720604461073c6000855af16100f0573d600060003e3d6000fd5b60203d10615a5f57610720518060011c615a5f57610780526107805050610640516040527fe62214fe0000000000000000000000000000000000000000000000000000000060605233608052600060a0526040600460c0376106605180610100528060051b806101208261068060045afa50505061016f6107406141d5565b61074060408101905051610720526004356040523460605261018f613efa565b6020615ab16000396000516323b872dd6107405261064051610760526020615af160003960005161078052610720516107a0526020610740606461075c6000855af16101e0573d600060003e3d6000fd5b3d6101f757803b15615a5f5760016107c052610210565b60203d10615a5f57610740518060011c615a5f576107c0525b6107c090505115615a5f5760006102c05260043561072051808201828110615a5f57905090506102e0526040602461030037600061034052610250614527565b6003600055005b636f972f1281186102745760243610615a5f573361052052610297565b6324049e5781186102ee5760443610615a5f576024358060a01c615a5f57610520525b600054600214615a5f5760026000556004356102b2576102e7565b6004356102c05260006102e05261052051610300526000610320526102d561495f565b600435604052346060526102e7613efa565b6003600055005b63dd171e7c81186103db5760443610615a5f57600054600214615a5f57600260005560243561031c576103d4565b604060046102c037336103005260006103205261033761495f565b600435156103515760043560405234606052610351613efa565b6020615a9160003960005163a9059cbb610520523361054052602435610560526020610520604461053c6000855af161038f573d600060003e3d6000fd5b60203d10615a5f57610520518060011c615a5f576105805261058050506801000000000000000754602435808201828110615a5f579050905068010000000000000007555b6003600055005b63371fd8e681186104235760243610615a5f57336102c0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102e0526001610300526104e2565b63acb7081581186104755760443610615a5f576024358060a01c615a5f576102c0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102e0526001610300526104e2565b63b4440df481186104a95760643610615a5f576024358060a01c615a5f576102c0526044356102e0526001610300526104e2565b6337671f938118610be25760843610615a5f576024358060a01c615a5f576102c0526044356102e0526064358060011c615a5f57610300525b600054600214615a5f5760026000556004356104fd57610bdb565b604036610320376102c05160a0526105166103606135e4565b6103608051610320526020810151610340525061032051610597576012610360527f4c6f616e20646f65736e277420657869737400000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b6103205160043580828118828410021890509050610360526103605161032051036103205261032051610750576020615af160003960005163f3fef3a36103c0526102c0516103e052670de0b6b3a76400006104005260406103c060446103dc6000855af161060b573d600060003e3d6000fd5b60403d10615a5f576103c0905080516103805260208101516103a0525061038051156106aa57336102c05118615a5f576020615a916000396000516323b872dd6103c0526020615af16000396000516103e0526102c05161040052610380516104205260206103c060646103dc6000855af161068c573d600060003e3d6000fd5b60203d10615a5f576103c0518060011c615a5f576104405261044050505b6103a051156106d0576102c0516040526103a051606052610300516080526106d061405b565b6102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366103c03760a06103c0a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d06103a0516103c052610360516103e05260406103c0a26102c051604052610add614dae56610add565b6020615af160003960005163c16ef2646103a05260206103a060046103bc845afa610780573d600060003e3d6000fd5b60203d10615a5f576103a0905051610380526102e0516103805113615a5f576020615af160003960005163b461100d6103e0526102c0516104005260406103e060246103fc845afa6107d7573d600060003e3d6000fd5b60403d10615a5f576103e0905080516103a05260208101516103c0525060016103a0516103c051030160008112615a5f576103e052600061040052610380516103a051136108e35760026102c051602052600052604060002054610400526102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6104205261032051610440526103a051610460526103c05161048052610400516104a05260a0610420a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d060006104205261036051610440526040610420a2610aa2565b6020615af160003960005163f3fef3a3610460526102c05161048052670de0b6b3a76400006104a0526040610460604461047c6000855af161092a573d600060003e3d6000fd5b60403d10615a5f57610460905080516104205260208101516104405250610440516101205261032051610140526103e0516101605261096a610480613830565b6104805161046052610460516103a0516103c051038082018281126000831218615a5f5790509050610480526020615af160003960005163ab047e006104a0526102c0516104c052610440516104e05261046051610500526104805161052052803b15615a5f5760006104a060846104bc6000855af16109ef573d600060003e3d6000fd5b506801000000000000000a54610400526104005160026102c0516020526000526040600020556102c0517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f2610440516104a052610320516104c052610460516104e0526104805161050052610400516105205260a06104a0a26102c0517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d060006104a052610360516104c05260406104a0a25b336102c05114610add5760016102c0516040526103205160605260006080526104005160a052610ad3610420614e89565b6104205112615a5f575b6020615a916000396000516323b872dd61038052336103a052306103c052610360516103e0526020610380606461039c6000855af1610b21573d600060003e3d6000fd5b60203d10615a5f57610380518060011c615a5f57610400526104005050680100000000000000085461036051808201828110615a5f5790509050680100000000000000085560016102c05160205260005260406000206103205181556103405160018201555060035461034051808202811583838304141715615a5f57905090506004548015615a5f5780820490509050610380526103605161038051610360518082811882841102189050905003600355610340516004555b6003600055005b63c45a01558118610c0e5760043610615a5f5734615a5f576020615a7160003960005160405260206040f35b632a9439458118610c3a5760043610615a5f5734615a5f576020615af160003960005160405260206040f35b632621db2f8118610c665760043610615a5f5734615a5f576020615ab160003960005160405260206040f35b639b6c56ec8118610cac5760243610615a5f576004358060a01c615a5f5760c05234615a5f57600054600214615a5f57602060c051604052610ca860e0613669565b60e0f35b63a21adb9e8118610cf85760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f576001604051602052600052604060002054151560605260206060f35b6331dc3ca88118610d8c5760043610615a5f5734615a5f576020615af160003960005163095a0fc6606052602060606004607c845afa610d3d573d600060003e3d6000fd5b60203d10615a5f576060905051604052600354606052600454608052606051604051808202811583838304141715615a5f57905090506080518015615a5f578082049050905060a052602060a0f35b639a4971968118610ece5760443610615a5f5734615a5f57600054600214615a5f576004356020615ad1600039600051808202811583838304141715615a5f57905090506040526024356060526801000000000000000b54608052610df2610200613709565b610200516101e0526001670de0b6b3a76400006101e051610e14610220613cef565b61022051808202811583838304141715615a5f579050905004600181811860018311021890500361020052670de0b6b3a764000061020051670de05bc096e9c000810281670de05bc096e9c000820418615a5f5790500461020052610200516020615a916000396000516370a082316102205230610240526020610220602461023c845afa610ea8573d600060003e3d6000fd5b60203d10615a5f5761022090505180828118828410021890509050610260526020610260f35b63a75732068118610ffc5760443610615a5f5734615a5f57600054600214615a5f57670de05bc096e9c0006020615ad1600039600051600435670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f579050610f306101e0613cef565b6101e0518015615a5f5780820490509050670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f579050670de0b6b3a76400006040526024356060526801000000000000000b54608052610f8a610200613709565b610200518015615a5f57808204905090506024356024356107d08101818110615a5f579050808202811583838304141715615a5f5790509050808201828110615a5f579050905004670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f57905004610220526020610220f35b63720fb25481186110385760643610615a5f5734615a5f57600054600214615a5f57602060606004610120376110336102c0613830565b6102c0f35b63d14ff5b681186110565760243610615a5f57600161052052611079565b632e4af52a81186110d95760443610615a5f576024358060011c615a5f57610520525b34615a5f57600054600214615a5f576002600055600435611099576110d2565b6004356102c05260006102e05233610300526001610320526110b961495f565b33604052600435606052610520516080526110d261405b565b6003600055005b63152f65cb81186118a65760643610615a5f576004358060a01c615a5f57610640526024356004016005813511615a5f5780358061066052602082018160051b8082610680375050505034615a5f57600054600214615a5f5760026000556020615af160003960005163b461100d6107605233610780526040610760602461077c845afa61116c573d600060003e3d6000fd5b60403d10615a5f576107609050805161072052602081015161074052506020615af160003960005163f3fef3a36107a052336107c052670de0b6b3a76400006107e05260406107a060446107bc6000855af16111cd573d600060003e3d6000fd5b60403d10615a5f576107a09050805161076052602081015161078052506040366107a0373360a0526112006107e06135e4565b6107e080516107a05260208101516107c052506020615ab16000396000516323b872dd6107e0526020615af1600039600051610800526106405161082052610780516108405260206107e060646107fc6000855af1611264573d600060003e3d6000fd5b3d61127b57803b15615a5f57600161086052611294565b60203d10615a5f576107e0518060011c615a5f57610860525b6108605050610640516040527fef67dc7400000000000000000000000000000000000000000000000000000000606052336080526107605160a0526107805160c0526107a05160e0526106605180610100528060051b806101208261068060045afa5050506113046108406141d5565b61084080516107e052602081015161080052604081015161082052506108005161076051808201828110615a5f5790509050610840526108405115615a5f576000610860526107a0516108405110156115a55760016107205161074051030160008112615a5f57610880526107e051610720511315615a5f576108005161086052610800516107a051036107a05261082051610120526107a0516101405261088051610160526113b56108c0613830565b6108c0516108a0526108a0516107205161074051038082018281126000831218615a5f57905090506108c0526020615af160003960005163ab047e006108e052336109005261082051610920526108a051610940526108c05161096052803b15615a5f5760006108e060846108fc6000855af1611437573d600060003e3d6000fd5b506801000000000000000a546108e0526108e0516002336020526000526040600020556020615ab16000396000516323b872dd6109005261064051610920526020615af16000396000516109405261082051610960526020610900606461091c6000855af16114ab573d600060003e3d6000fd5b3d6114c257803b15615a5f576001610980526114db565b60203d10615a5f57610900518060011c615a5f57610980525b61098090505115615a5f576020615a916000396000516323b872dd610900526106405161092052306109405261080051610960526020610900606461091c6000855af161152d573d600060003e3d6000fd5b60203d10615a5f57610900518060011c615a5f57610980526109805050337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f261082051610900526107a051610920526108a051610940526108c051610960526108e0516109805260a0610900a26000610780526117ce565b6107a0516108605260006107a052336040526115bf614dae565b610800511561162d576020615a916000396000516323b872dd61088052610640516108a052306108c052610800516108e0526020610880606461089c6000855af161160f573d600060003e3d6000fd5b60203d10615a5f57610880518060011c615a5f576109005261090050505b61076051156116a2576020615a916000396000516323b872dd610880526020615af16000396000516108a052306108c052610760516108e0526020610880606461089c6000855af1611684573d600060003e3d6000fd5b60203d10615a5f57610880518060011c615a5f576109005261090050505b61086051610840511115611712576020615a9160003960005163a9059cbb61088052336108a0526108605161084051036108c0526020610880604461089c6000855af16116f4573d600060003e3d6000fd5b60203d10615a5f57610880518060011c615a5f576108e0526108e050505b610820511561179e576020615ab16000396000516323b872dd61088052610640516108a052336108c052610820516108e0526020610880606461089c6000855af1611762573d600060003e3d6000fd5b3d61177957803b15615a5f57600161090052611792565b60203d10615a5f57610880518060011c615a5f57610900525b61090090505115615a5f575b337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366108803760a0610880a25b337f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d06107805161088052610860516108a0526040610880a2680100000000000000085461086051808201828110615a5f5790509050680100000000000000085560013360205260005260406000206107a05181556107c0516001820155506003546107c051808202811583838304141715615a5f57905090506004548015615a5f57808204905090506108805261086051610880516108605180828118828411021890509050036003556107c0516004556003600055005b630b8db68181186118c45760843610615a5f576000610300526118df565b6322c714538118611e865760a43610615a5f57608435610300525b6004358060a01c615a5f576102c0526064358060011c615a5f576102e05234615a5f57600054600214615a5f576020615af160003960005163544fb5c1610360526102c051610380526040610360602461037c845afa611944573d600060003e3d6000fd5b60403d10615a5f57610360905080516103205260208101516103405250610340516020615ad1600039600051808202811583838304141715615a5f5790509050610340526020615af160003960005163b461100d6103a0526102c0516103c05260406103a060246103bc845afa6119c0573d600060003e3d6000fd5b60403d10615a5f576103a09050805161036052602081015161038052506102c0516040526119ef6103c0613669565b6103c0518060ff1c615a5f576103a052610300516103c05260006103e0526103a05115611a515760026102c0516020526000526040600020548060ff1c615a5f576103e05260016103605161038051030160008112615a5f576103c052611a8e565b6801000000000000000a548060ff1c615a5f576103e0527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610360525b606036610400376103a0516044358082018281126000831218615a5f57905090506103a05260016103a0511215611b25576011610460527f4e6f6e2d706f73697469766520646562740000000000000000000000000000006104805261046050610460518061048001601f826000031636823750506308c379a061042052602061044052601f19601f61046051011660440161043cfd5b6020615af160003960005163c16ef264610480526020610480600461049c845afa611b55573d600060003e3d6000fd5b60203d10615a5f5761048090505161046052610460516103605113611b7b576000611b90565b60243515611b8a576001611b90565b60443515155b611c115761036051610400526020615af16000396000516362ca4b18610480526102c0516104a0526020610480602461049c845afa611bd4573d600060003e3d6000fd5b60203d10615a5f57610480905051670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f5790508060ff1c615a5f5761044052611c73565b610340518060ff1c615a5f576024358082018281126000831218615a5f5790509050610420526104205160008112615a5f57610120526103a05160008112615a5f57610140526103c05161016052611c6a610480613830565b61048051610400525b6020615af1600039600051632eb858e76104a052610400516104c05260206104a060246104bc845afa611cab573d600060003e3d6000fd5b60203d10615a5f576104a09050518060ff1c615a5f576104805261046051610360511315611d30576104205160008112615a5f576040526103c0516060526000608052611cf96104a0613709565b6104a0518060ff1c615a5f576104805180820281191515600160ff1b8414151782158484840514171615615a5f5790509050610440525b6103a05161044051056104a0526104a051670de0b6b3a76400006104a0516103e05180820281191515600160ff1b8414151782158484840514171615615a5f5790509050058082038281136000831218615a5f5790509050670de0b6b3a76400008103818113615a5f5790506104a0526102e05115611e7f5761046051610400511315611e7f57610480516020615af16000396000516386fc88d36104e05260206104e060046104fc845afa611deb573d600060003e3d6000fd5b60203d10615a5f576104e09050518060ff1c615a5f5780828118828413021890509050610480518082038281136000831218615a5f57905090506104c05260016104c05112611e7f576104a0516103a0516104c0516104205180820281191515600160ff1b8414151782158484840514171615615a5f5790509050058082018281126000831218615a5f57905090506104a0525b60206104a0f35b63bcbaf4878118611ea45760443610615a5f5760016109e052611ec7565b633ecdb8288118611f535760643610615a5f576044358060011c615a5f576109e0525b6004358060a01c615a5f576109c05234615a5f57600054600214615a5f5760026000556000610a0052336109c05114611f115760026109c051602052600052604060002054610a00525b6109c0516106405260243561066052610a005161068052670de0b6b3a76400006106a0526109e0516106c0526040366106e037611f4c615221565b6003600055005b63036aed88811861206a5760e43610615a5f576004358060a01c615a5f576109c0526064358060011c615a5f576109e0526084358060a01c615a5f57610a005260a4356004016005813511615a5f57803580610a2052602082018160051b8082610a40375050505034615a5f57600054600214615a5f5760026000556000610ae052336109c05114611ff65760026109c051602052600052604060002054610ae0525b6109c0516106405260243561066052610ae05161068052604435670de0b6b3a7640000818118670de0b6b3a76400008310021890506106a0526109e0516106c052610a00516106e052610a205180610700528060051b8061072082610a4060045afa505050612063615221565b6003600055005b631b25cdaf811861208e5760243610615a5f57670de0b6b3a764000060e0526120a8565b63546e040d81186121d45760443610615a5f5760243560e0525b6004358060a01c615a5f5760c05234615a5f57600054600214615a5f576000610100523360c051146120ea57600260c051602052600052604060002054610100525b60e051604052610100516060526121026101406151b4565b6101405161012052670de0b6b3a76400006020615af160003960005163544fb5c16101605260c051610180526040610160602461017c845afa61214a573d600060003e3d6000fd5b60403d10615a5f5761016090505161012051808202811583838304141715615a5f57905090500461014052670de0b6b3a764000060c05160405261218f610180613669565b6101805160e051808202811583838304141715615a5f579050905004610160526101405161016051610140518082811882841102189050905003610180526020610180f35b63e2d8ebee81186121f25760243610615a5f57600061022052612215565b638908ea8281186122a15760443610615a5f576024358060011c615a5f57610220525b6004358060a01c615a5f576102005234615a5f57600054600214615a5f57602061020051610280526102005160405261224f610240613669565b610240516102a052610220516102c0526002610200516020526000526040600020546102e052610280516040526102a0516060526102c0516080526102e05160a05261229c610260614e89565b610260f35b627c98ab81186122bf5760043610615a5f5760403661020037612300565b6380e8f6ec81186122e45760243610615a5f5760043561020052600061022052612300565b6390f8667d81186125815760443610615a5f5760406004610200375b34615a5f57600054600214615a5f576801000000000000000654610240526102205161026052610220516123375761024051610260525b610200516102805260006102a0526000620f4240905b80620273c052610240516102805110156123715761026051620273c0511815612374565b60015b1561237e576124f0565b6102805167fffffffffffffffe8111615a5f5760050154620273e052620273e0516040526123ae62027420613669565b62027420516202740052620273e051604052620274005160605260016080526002620273e05160205260005260406000205460a0526123ef62027440614e89565b620274405162027420527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6202742051136124d0576020615af160003960005163544fb5c16202748052620273e051620274a05260406202748060246202749c845afa612461573d600060003e3d6000fd5b60403d10615a5f576202748090508051620274405260208101516202746052506102a0516103e78111615a5f57600181016102a05260a081026102c001620273e05181526202744051602082015262027460516040820152620274005160608201526202742051608082015250505b6102805160018101818110615a5f5790506102805260010181811861234d575b5050602080620273c05280620273c00160006102a05180835260a081026000826103e88111615a5f57801561256b57905b60a08102602087010160a082026102c00180518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050600101818118612521575b50508201602001915050905081019050620273c0f35b63d9f11a6481186125d65760043610615a5f5734615a5f5760206020615af160003960005163f2388acb604052602060406004605c845afa6125c8573d600060003e3d6000fd5b60203d10615a5f5760409050f35b632c5089c381186127365760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f576020615af160003960005163e8dd1ef1606052604051608052602060606024607c845afa612639573d600060003e3d6000fd5b60203d10615a5f576060518060011c615a5f5760a05260a090505115615a5f576020615af160003960005163b461100d60a05260405160c052604060a0602460bc845afa61268c573d600060003e3d6000fd5b60403d10615a5f5760a0905080516060526020810151608052506020615af1600039600051632eb858e760a05260605160c052602060a0602460bc845afa6126d9573d600060003e3d6000fd5b60203d10615a5f5760a0905051610120526020615af16000396000516324299b7a60e05260805161010052602060e0602460fc845afa61271e573d600060003e3d6000fd5b60203d10615a5f5760e0905051610140526040610120f35b63ec74d0a881186128545760243610615a5f576004358060a01c615a5f5760c05234615a5f57600054600214615a5f576020615af160003960005163544fb5c16101205260c051610140526040610120602461013c845afa61279d573d600060003e3d6000fd5b60403d10615a5f576101209050805160e052602081015161010052506020615af160003960005163b461100d6101605260c051610180526040610160602461017c845afa6127f0573d600060003e3d6000fd5b60403d10615a5f57610160905080516101205260208101516101405250610100516101805260e0516101a05260c05160405261282d610160613669565b610160516101c05260016101205161014051030160008112615a5f576101e0526080610180f35b634189617d811861297d5760243610615a5f5734615a5f576020615a7160003960005163f851a440604052602060406004605c845afa612899573d600060003e3d6000fd5b60203d10615a5f576040518060a01c615a5f5760805260809050513318615a5f5767016345785d8a000060043511156128d35760006128dd565b620f424060043510155b61293e5760036040527f466565000000000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6020615af1600039600051631aa02d59604052600435606052803b15615a5f57600060406024605c6000855af161297a573d600060003e3d6000fd5b50005b63a5b4804a8118612a915760243610615a5f5734615a5f576020615a7160003960005163f851a440604052602060406004605c845afa6129c2573d600060003e3d6000fd5b60203d10615a5f576040518060a01c615a5f5760805260809050513318615a5f57670de0b6b3a76400006004351115612a525760086040527f486967682066656500000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6020615af1600039600051633217902f604052600435606052803b15615a5f57600060406024605c6000855af1612a8e573d600060003e3d6000fd5b50005b6381d2f1b78118612b885760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f5760026000556020615a7160003960005163f851a440606052602060606004607c845afa612af3573d600060003e3d6000fd5b60203d10615a5f576060518060a01c615a5f5760a05260a09050513318615a5f57604051680100000000000000095560405163e91f2f4c606052602060606004607c6000855af1612b49573d600060003e3d6000fd5b60203d10615a5f57606050507f51fabb88f7860c9dbcc2a5a9b69a8b9476d63b87124591f97254e29f0e8daaeb60405160605260206060a16003600055005b632a0c35868118612c7a5760443610615a5f5734615a5f57600054600214615a5f5760026000556020615a7160003960005163f851a440604052602060406004605c845afa612bdc573d600060003e3d6000fd5b60203d10615a5f576040518060a01c615a5f5760805260809050513318615a5f576024356004351115615a5f57662386f26fc1000060243510615a5f576706f05b59d3b2000060043511615a5f576024356801000000000000000a556004356801000000000000000b557fe2750bf9a7458977fcc01c1a0b615d12162f63b18cad78441bd64c590b337eca6040600460403760406040a16003600055005b63cc1891c78118612d415760243610615a5f576004358060a01c615a5f5760405234615a5f57600054600214615a5f5760026000556020615a7160003960005163f851a440606052602060606004607c845afa612cdc573d600060003e3d6000fd5b60203d10615a5f576060518060a01c615a5f5760a05260a09050513318615a5f576020615af160003960005163cc1891c7606052604051608052803b15615a5f57600060606024607c6000855af1612d39573d600060003e3d6000fd5b506003600055005b631b1800e38118612e1c5760043610615a5f5734615a5f576020615af160003960005163095a0fc6606052602060606004607c845afa612d86573d600060003e3d6000fd5b60203d10615a5f576060905051604052600354606052600454608052606051604051808202811583838304141715615a5f57905090506080518015615a5f57808204905090506060526060516801000000000000000854808201828110615a5f5790509050606052680100000000000000075460a05260a05160605160a051808281188284110218905090500360c052602060c0f35b631e0cfcef81186131fc5760043610615a5f5734615a5f57600054600214615a5f5760026000556020615a7160003960005163cab4d3db60c052602060c0600460dc845afa612e70573d600060003e3d6000fd5b60203d10615a5f5760c0518060a01c615a5f576101005261010090505160a0526020615af160003960005163d1fea73360e052602060e0600460fc845afa612ebd573d600060003e3d6000fd5b60203d10615a5f5760e090505160c0526020615af16000396000516389960ba7610100526020610100600461011c845afa612efd573d600060003e3d6000fd5b60203d10615a5f5761010090505160e05260c05115612f83576020615a916000396000516323b872dd610100526020615af16000396000516101205260a0516101405260c051610160526020610100606461011c6000855af1612f65573d600060003e3d6000fd5b60203d10615a5f57610100518060011c615a5f576101805261018050505b60e05115613016576020615ab16000396000516323b872dd610100526020615af16000396000516101205260a0516101405260e051610160526020610100606461011c6000855af1612fda573d600060003e3d6000fd5b3d612ff157803b15615a5f5760016101805261300a565b60203d10615a5f57610100518060011c615a5f57610180525b61018090505115615a5f575b6020615af160003960005163822fe50761010052803b15615a5f576000610100600461011c6000855af161304f573d600060003e3d6000fd5b5061305b610120613549565b610120516101005260035461012052600454610140526101205161010051808202811583838304141715615a5f5790509050610140518015615a5f57808204905090506101205261010051610140526101205160035561014051600455610120516801000000000000000854808201828110615a5f57905090506101605268010000000000000007546101805261018051610160511161313e577f5393ab6ef9bb40d91d1b04bbbeb707fbf3d1eb73f46744e2d179e4996026283f60006101a052610120516101c05260406101a0a160006101a05260206101a06131f5566131f5565b610160516801000000000000000755610180516101605103610160526020615a9160003960005163a9059cbb6101a05260a0516101c052610160516101e05260206101a060446101bc6000855af161319b573d600060003e3d6000fd5b60203d10615a5f576101a0518060011c615a5f576102005261020050507f5393ab6ef9bb40d91d1b04bbbeb707fbf3d1eb73f46744e2d179e4996026283f610160516101a052610120516101c05260406101a0a160206101605b6003600055f35b635457ff7b811861323c5760243610615a5f576004358060a01c615a5f5760405234615a5f57600260405160205260005260406000205460605260206060f35b63e1ec3c6881186132735760243610615a5f5734615a5f5760043567fffffffffffffffe8111615a5f576005015460405260206040f35b637128f3b881186132bb5760243610615a5f576004358060a01c615a5f5760405234615a5f576801000000000000000560405160205260005260406000205460605260206060f35b636cce39be81186132e75760043610615a5f5734615a5f57680100000000000000065460405260206040f35b634f02c42081186133135760043610615a5f5734615a5f57680100000000000000075460405260206040f35b63e231bff0811861333f5760043610615a5f5734615a5f57680100000000000000085460405260206040f35b63adfae4ce811861336b5760043610615a5f5734615a5f57680100000000000000095460405260206040f35b63627d2b8381186133975760043610615a5f5734615a5f576801000000000000000a5460405260206040f35b635449b9cb81186133c35760043610615a5f5734615a5f576801000000000000000b5460405260206040f35b505b34156133dc576020615b9160003960005115615a5f575b36615a5f57005b670de0b6b3a764000060405110606052600060805260405160a052606051156134275760a0518015615a5f57806ec097ce7bc90715b34b9f100000000004905060a0525b608060c05260006008905b8060e05260c05160020a61010052670de0b6b3a7640000610100510260a05110613476576101005160a0510460a052608051670de0b6b3a764000060c05102016080525b60c05160011c60c052600101818118613432575050670de0b6b3a764000060e05260006022905b8061010052671bc16d674ec8000060a051106134c75760e0516080510160805260a05160011c60a0525b670de0b6b3a764000060a05160a051020460a05260e05160011c60e05260010181811861349d57505060605161350e576080518060ff1c615a5f5781525061354756613547565b6080518060ff1c615a5f577f80000000000000000000000000000000000000000000000000000000000000008114615a5f576000038152505b565b680100000000000000095463e91f2f4c606052602060606004607c6000855af1613578573d600060003e3d6000fd5b60203d10615a5f576060905051640a3c2abcef818118640a3c2abcef8310021890506040526020615af160003960005163d4387a99606052604051608052602060606024607c6000855af16135d2573d600060003e3d6000fd5b60203d10615a5f576060905051815250565b6135ee60e0613549565b60e05160c052600160a0516020526000526040600020805460e0526001810154610100525060e051613630576000815260c05160208201525061366756613667565b60e05160c051808202811583838304141715615a5f5790509050610100518015615a5f5780820490509050815260c0516020820152505b565b6020615af160003960005163095a0fc6608052602060806004609c845afa613696573d600060003e3d6000fd5b60203d10615a5f576080905051606052600160405160205260005260406000208054608052600181015460a052506080516136d957600081525061370756613707565b608051606051808202811583838304141715615a5f579050905060a0518015615a5f57808204905090508152505b565b6040516080516040516060518015615a5f57808204905090506103e88181186103e88311021890508015615a5f5780683635c9adc5dea00000049050808201828110615a5f5790509050670de0b6b3a7640000818118670de0b6b3a7640000831002189050670de0b6b3a764000003808202811583838304141715615a5f57905090506020615b71600039600051606051808202811583838304141715615a5f57905090508015615a5f578082049050905060a05260a05160c052600160318101905b8060e05260605160e051186137e057613826565b6020615b1160003960005160a0516020615b31600039600051808202811583838304141715615a5f57905090500460a05260a05160c0510160c0526001018181186137cc575b505060c051815250565b6101405161389e576007610180527f4e6f206c6f616e000000000000000000000000000000000000000000000000006101a0526101805061018051806101a001601f826000031636823750506308c379a061014052602061016052601f19601f61018051011660440161015cfd5b6020615af1600039600051638f8654c56101a05260206101a060046101bc845afa6138ce573d600060003e3d6000fd5b60203d10615a5f576101a0905051610180526020615af1600039600051632eb858e76101c052610180516101e05260206101c060246101dc845afa613918573d600060003e3d6000fd5b60203d10615a5f576101c09050516101a052610120516020615ad1600039600051808202811583838304141715615a5f5790509050604052610160516060526801000000000000000b546080526139706101e0613709565b6101e0516101c0526101c0516101a051808202811583838304141715615a5f57905090506101405160018101818110615a5f5790508015615a5f57808204905090506101c0526101c051613a2457600e6101e0527f416d6f756e7420746f6f206c6f77000000000000000000000000000000000000610200526101e0506101e0518061020001601f826000031636823750506308c379a06101a05260206101c052601f19601f6101e05101166044016101bcfd5b6101c051604052613a366102006133e3565b610200516101e0527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101e05113613a9c576101e0516020615b5160003960005160018103818113615a5f5790508082038281136000831218615a5f57905090506101e0525b6101e0516020615b516000396000518015615a5f57808205600160ff1b8314156000198314151715615a5f57905090506101e0526101e051610160518060ff1c615a5f57806104000361040081136000831218615a5f57905080828118828412021890509050610180518082018281126000831218615a5f57905090506101e052610180516101e05113613bf7576020615af160003960005163ec654706610200526101e05160018103818113615a5f579050610220526020610200602461021c845afa613b6f573d600060003e3d6000fd5b60203d10615a5f57610200518060011c615a5f5761024052610240905051613bf757600d610260527f4465627420746f6f2068696768000000000000000000000000000000000000006102805261026050610260518061028001601f826000031636823750506308c379a061022052602061024052601f19601f61026051011660440161023cfd5b6020615af16000396000516386fc88d3610240526020610240600461025c845afa613c27573d600060003e3d6000fd5b60203d10615a5f576102409050516020615af1600039600051632eb858e7610200526101e051610220526020610200602461021c845afa613c6d573d600060003e3d6000fd5b60203d10615a5f5761020090505110613ce657600d610280527f4465627420746f6f2068696768000000000000000000000000000000000000006102a0526102805061028051806102a001601f826000031636823750506308c379a061024052602061026052601f19601f61028051011660440161025cfd5b6101e051815250565b6020615af16000396000516386fc88d3610140526020610140600461015c845afa613d1f573d600060003e3d6000fd5b60203d10615a5f57610140905051610120526020615b516000396000516020615af160003960005163a7db79a5610160526020610160600461017c845afa613d6c573d600060003e3d6000fd5b60203d10615a5f57610160905051670de0b6b3a7640000810281670de0b6b3a7640000820418615a5f579050610120518015615a5f5780820490509050604052613db76101a06133e3565b6101a0510560058101818112615a5f579050610140526020615af1600039600051632eb858e761018052610140516101a0526020610180602461019c845afa613e05573d600060003e3d6000fd5b60203d10615a5f57610180905051610160526020615af160003960005163c16ef2646101a05260206101a060046101bc845afa613e47573d600060003e3d6000fd5b60203d10615a5f576101a0905051610180526000610401905b806101a0526101405160018103818113615a5f57905061014052610180516101405113613e8c57613eee565b610160516101c0526020615b31600039600051610160516020615b11600039600051808202811583838304141715615a5f5790509050046101605261012051610160511115613ee3576101c0518352505050613ef8565b600101818118613e60575b5050610160518152505b565b6020615b91600039600051613f1157606051615a5f575b604051606051808203828111615a5f579050905060805260605115613fce576020615ab160003960005163d0e30db060a052803b15615a5f57600060a0600460bc606051855af1613f67573d600060003e3d6000fd5b506020615ab160003960005163a9059cbb60a0526020615af160003960005160c05260605160e052602060a0604460bc6000855af1613fab573d600060003e3d6000fd5b60203d10615a5f5760a0518060011c615a5f576101005261010090505115615a5f575b60805115614059576020615ab16000396000516323b872dd60a0523360c0526020615af160003960005160e05260805161010052602060a0606460bc6000855af161401e573d600060003e3d6000fd5b3d61403557803b15615a5f5760016101205261404d565b60203d10615a5f5760a0518060011c615a5f57610120525b61012090505115615a5f575b565b608051614069576000614075565b6020615b916000396000515b614102576020615ab16000396000516323b872dd60a0526020615af160003960005160c05260405160e05260605161010052602060a0606460bc6000855af16140c3573d600060003e3d6000fd5b3d6140da57803b15615a5f576001610120526140f2565b60203d10615a5f5760a0518060011c615a5f57610120525b61012090505115615a5f576141d3565b6020615ab16000396000516323b872dd60a0526020615af160003960005160c0523060e05260605161010052602060a0606460bc6000855af161414a573d600060003e3d6000fd5b60203d10615a5f5760a0518060011c615a5f576101205261012090505115615a5f576020615ab1600039600051632e1a7d4d60a05260605160c052803b15615a5f57600060a0602460bc6000855af16141a8573d600060003e3d6000fd5b50600060a05260a0506000600060a05160c0606051604051612710f16141d3573d600060003e3d6000fd5b565b6020615ab160003960005160405114615a5f576060366101c0376020615af1600039600051638f8654c5610220526020610220600461023c845afa61421f573d600060003e3d6000fd5b60203d10615a5f576102209050516101c0526020615af160003960005163ebcb0067610240526101c051610260526020610240602461025c845afa614269573d600060003e3d6000fd5b60203d10615a5f57610240905051610220526020615af16000396000516331f7e306610260526101c051610280526020610260602461027c845afa6142b3573d600060003e3d6000fd5b60203d10615a5f5761026090505161024052600060605181610460015260048101905060a06080516102e05260a0516103005260c0516103205260e051610340528061036052806102e0016000610100518083528060051b60008260058111615a5f57801561433c57905b8060051b61012001518160051b60208801015260010181811861431e575b505082016020019150509050810190506102c0526102c080516020820183610460018281848460045afa505050808301925050508061044052610440505060406106006104405161046060006040515af161439c573d600060003e3d6000fd5b3d604081183d60401002186105e0526105e0805180610260526020820181610280838360045afa5050505061026051602011615a5f57610280516102e05260206102c0526102c06020810151815160200360031b1c90506101e05261026051604011615a5f576102a0516102e05260206102c0526102c06020810151815160200360031b1c9050610200526020615af1600039600051638f8654c56102c05260206102c060046102dc845afa614457573d600060003e3d6000fd5b60203d10615a5f576102c09050516101c05118615a5f576020615af160003960005163ebcb00676102c0526101c0516102e05260206102c060246102dc845afa6144a6573d600060003e3d6000fd5b60203d10615a5f576102c09050516102205118615a5f576020615af16000396000516331f7e3066102c0526101c0516102e05260206102c060246102dc845afa6144f5573d600060003e3d6000fd5b60203d10615a5f576102c09050516102405118615a5f576101c05181526101e051602082015261020051604082015250565b600133602052600052604060002054156145a1576014610360527f4c6f616e20616c726561647920637265617465640000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b600461032051101561461357600f610360527f4e656564206d6f7265207469636b7300000000000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b603261032051111561468557600f610360527f4e656564206c657373207469636b7300000000000000000000000000000000006103805261036050610360518061038001601f826000031636823750506308c379a061032052602061034052601f19601f61036051011660440161033cfd5b6102e05161012052610300516101405261032051610160526146a8610380613830565b6103805161036052610360516103205160018103818111615a5f5790508060ff1c615a5f578082018281126000831218615a5f5790509050610380526146ef6103c0613549565b6103c0516103a05260013360205260005260406000206103005181556103a0516001820155506801000000000000000a546103c0526103c05160023360205260005260406000205568010000000000000006546103e052336103e05167fffffffffffffffe8111615a5f57600501556103e051680100000000000000053360205260005260406000205560016103e0510168010000000000000006556003546103a051808202811583838304141715615a5f57905090506004548015615a5f578082049050905061030051808201828110615a5f579050905061040052610400516003556103a0516004556020615af160003960005163ab047e006104205233610440526102e051610460526103605161048052610380516104a052803b15615a5f576000610420608461043c6000855af1614830573d600060003e3d6000fd5b50680100000000000000075461030051808201828110615a5f5790509050680100000000000000075561034051156148d5576102e0516040526102c051606052614878613efa565b6020615a9160003960005163a9059cbb61042052336104405261030051610460526020610420604461043c6000855af16148b7573d600060003e3d6000fd5b60203d10615a5f57610420518060011c615a5f576104805261048050505b337feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f26102e051610420526103005161044052610360516104605261038051610480526103c0516104a05260a0610420a2337fe1979fe4c35e0cef342fef5668e2c8e7a7e9f5d5d1ca8fee0ac6c427fa4153af6102e0516104205261030051610440526040610420a2565b604036610340376103005160a0526149786103806135e4565b61038080516103405260208101516103605250610340516149f9576012610380527f4c6f616e20646f65736e277420657869737400000000000000000000000000006103a0526103805061038051806103a001601f826000031636823750506308c379a061034052602061036052601f19601f61038051011660440161035cfd5b610340516102e051808201828110615a5f5790509050610340526020615af160003960005163b461100d6103c052610300516103e05260406103c060246103dc845afa614a4b573d600060003e3d6000fd5b60403d10615a5f576103c0905080516103805260208101516103a052506001610380516103a051030160008112615a5f576103c0526020615af160003960005163f3fef3a3610420526103005161044052670de0b6b3a7640000610460526040610420604461043c6000855af1614ac7573d600060003e3d6000fd5b60403d10615a5f57610420905080516103e052602081015161040052506103e05115614b5357601a610420527f416c726561647920696e20756e6465727761746572206d6f64650000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b61032051614b7a57610400516102c051808201828110615a5f579050905061040052614b95565b610400516102c051808203828111615a5f5790509050610400525b610400516101205261034051610140526103c05161016052614bb8610440613830565b610440516104205261042051610380516103a051038082018281126000831218615a5f5790509050610440526020615af160003960005163ab047e00610460526103005161048052610400516104a052610420516104c052610440516104e052803b15615a5f576000610460608461047c6000855af1614c3d573d600060003e3d6000fd5b506001610300516020526000526040600020610340518155610360516001820155506801000000000000000a5461046052610460516002610300516020526000526040600020556102e05115614cdd5760035461036051808202811583838304141715615a5f57905090506004548015615a5f57808204905090506102e051808201828110615a5f57905090506104805261048051600355610360516004555b61032051614d2557610300517fe1979fe4c35e0cef342fef5668e2c8e7a7e9f5d5d1ca8fee0ac6c427fa4153af6102c051610480526102e0516104a0526040610480a2614d59565b610300517fe25410a4059619c9594dc6f022fe231b02aaea733f689e7ab0cd21b3d4d0eb546102c051610480526020610480a25b610300517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f26104005161048052610340516104a052610420516104c052610440516104e052610460516105005260a0610480a2565b680100000000000000065460018103818111615a5f5790506060526801000000000000000560405160205260005260406000205460805260405160805167fffffffffffffffe8111615a5f576005015418615a5f576000680100000000000000056040516020526000526040600020556060516080511015614e795760605167fffffffffffffffe8111615a5f576005015460a05260a05160805167fffffffffffffffe8111615a5f57600501556080516801000000000000000560a0516020526000526040600020555b6060516801000000000000000655565b606051614eed57601260c0527f4c6f616e20646f65736e2774206578697374000000000000000000000000000060e05260c05060c0518060e001601f826000031636823750506308c379a0608052602060a052601f19601f60c0510116604401609cfd5b670de0b6b3a764000060c05260a05115614f265760c05160a0518060ff1c615a5f578082038281136000831218615a5f579050905060c0525b6060518060ff1c615a5f576020615af16000396000516362ca4b1860e05260405161010052602060e0602460fc845afa614f65573d600060003e3d6000fd5b60203d10615a5f5760e09050518060ff1c615a5f5760c05180820281191515600160ff1b8414151782158484840514171615615a5f579050905005670de0b6b3a76400008103818113615a5f57905060c052608051156151ac576020615af160003960005163b461100d61012052604051610140526040610120602461013c845afa614ff6573d600060003e3d6000fd5b60403d10615a5f576101209050805160e052602081015161010052506020615af1600039600051638f8654c5610120526020610120600461013c845afa615042573d600060003e3d6000fd5b60203d10615a5f5761012090505160e05113156151ac576020615af16000396000516386fc88d3610180526020610180600461019c845afa615089573d600060003e3d6000fd5b60203d10615a5f57610180905051610160526020615af1600039600051632eb858e76101a05260e0516101c05260206101a060246101bc845afa6150d2573d600060003e3d6000fd5b60203d10615a5f576101a090505161018052610180516101605111156151ac5760c0516060516101605161018051808203828111615a5f57905090506020615af160003960005163544fb5c16101a0526040516101c05260406101a060246101bc845afa615145573d600060003e3d6000fd5b60403d10615a5f576101a0905060208101905051808202811583838304141715615a5f57905090506020615ad1600039600051808202811583838304141715615a5f5790509050048060ff1c615a5f578082018281126000831218615a5f579050905060c0525b60c051815250565b670de0b6b3a7640000608052670de0b6b3a763ffff6040511161521957606051670de0b6b3a764000001604051670de0b6b3a76400000360605160011c670de0b6b3a7640000010204608052670de0b6b3a76400006040516040516080510102046080525b608051815250565b6040366107c0376106405160a05261523a6108006135e4565b61080080516107c05260208101516107e05250610680511561530c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610640516040526107c05160605260016080526106805160a05261529c610800614e89565b61080051131561530c57600f610820527f4e6f7420656e6f7567682072656b7400000000000000000000000000000000006108405261082050610820518061084001601f826000031636823750506308c379a06107e052602061080052601f19601f6108205101166044016107fcfd5b6107c05161080052670de0b6b3a76400006107c0516106a051808202811583838304141715615a5f5790509050046107c0526107c05115615a5f576107c0516108005103610800526106a0516040526106805160605261536d6108406151b4565b61084051610820526020615af160003960005163f3fef3a361088052610640516108a052610820516108c0526040610880604461089c6000855af16153b7573d600060003e3d6000fd5b60403d10615a5f5761088090508051610840526020810151610860525061066051610840511015615448576008610880527f536c6970706167650000000000000000000000000000000000000000000000006108a0526108805061088051806108a001601f826000031636823750506308c379a061084052602061086052601f19601f61088051011660440161085cfd5b610840516107c051808281188284100218905090506108805261088051156154d6576020615a916000396000516323b872dd6108a0526020615af16000396000516108c052306108e052610880516109005260206108a060646108bc6000855af16154b8573d600060003e3d6000fd5b60203d10615a5f576108a0518060011c615a5f576109205261092050505b610840516107c051116155805733604052610860516060526106c0516080526154fd61405b565b6107c0516108405111156158f9576020615a916000396000516323b872dd6108a0526020615af16000396000516108c052336108e0526107c05161084051036109005260206108a060646108bc6000855af161555e573d600060003e3d6000fd5b60203d10615a5f576108a0518060011c615a5f576109205261092050506158f9565b610840516107c051036108a0526106e0516156155733604052610860516060526106c0516080526155af61405b565b6020615a916000396000516323b872dd6108c052336108e05230610900526108a0516109205260206108c060646108dc6000855af16155f3573d600060003e3d6000fd5b60203d10615a5f576108c0518060011c615a5f576109405261094050506158f9565b61086051156156ab576020615ab16000396000516323b872dd6108c0526020615af16000396000516108e0526106e05161090052610860516109205260206108c060646108dc6000855af161566f573d600060003e3d6000fd5b3d61568657803b15615a5f5760016109405261569f565b60203d10615a5f576108c0518060011c615a5f57610940525b61094090505115615a5f575b6106e0516040527f4ea696bb00000000000000000000000000000000000000000000000000000000606052610640516080526108405160a0526108605160c0526107c05160e0526107005180610100528060051b806101208261072060045afa5050506157196109206141d5565b61092080516108c05260208101516108e052604081015161090052506108a0516108e05110156157a9576013610920527f6e6f7420656e6f7567682070726f6365656473000000000000000000000000006109405261092050610920518061094001601f826000031636823750506308c379a06108e052602061090052601f19601f6109205101166044016108fcfd5b6108a0516108e0511115615821576020615a916000396000516323b872dd610920526106e0516109405233610960526108a0516108e05103610980526020610920606461093c6000855af1615803573d600060003e3d6000fd5b60203d10615a5f57610920518060011c615a5f576109a0526109a050505b6020615a916000396000516323b872dd610920526106e0516109405230610960526108a051610980526020610920606461093c6000855af1615868573d600060003e3d6000fd5b60203d10615a5f57610920518060011c615a5f576109a0526109a0505061090051156158f9576020615ab16000396000516323b872dd610920526106e05161094052336109605261090051610980526020610920606461093c6000855af16158d5573d600060003e3d6000fd5b60203d10615a5f57610920518060011c615a5f576109a0526109a090505115615a5f575b68010000000000000008546107c051808201828110615a5f5790509050680100000000000000085560016106405160205260005260406000206108005181556107e051600182015550610640517f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d0610860516108a0526107c0516108c05260406108a0a261064051337f642dd4d37ddd32036b9797cec464c0045dd2118c549066ae6b0f88e32240c2d0610860516108a052610840516108c0526107c0516108e05260606108a0a361080051615a0a57610640517feec6b7095a637e006c79c1819d696e353a8f703db2c49fc0219e17a8fd04f7f260a0366108a03760a06108a0a261064051604052615a0a614dae565b6003546107e051808202811583838304141715615a5f57905090506004548015615a5f57808204905090506108a0526107c0516108a0516107c05180828118828411021890509050036003556107e051600455565b600080fda165767970657283000307000b000000000000000000000000c9332fdcb1c491dcc683bae86fe3cb70360738bc000000000000000000000000f939e0a03fb07f59a73314e73794be0e57ac1b4e0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000037417b2238aa52d0dd2d6252d989e728e8f706e400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000063000000000000000000000000000000000000000000000000003383482309faa60000000000000000000000000000000000000000000000000df29c916c5c292b0000000000000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca00000000000000000000000001e7d3bf98d3f8d8ce193236c3e0ec4b00e32daae000000000000000000000000000000000000000000000000013fbe85edc9000000000000000000000000000000000000000000000000000000d529ae9e86000000000000000000000000000037417b2238aa52d0dd2d6252d989e728e8f706e4
-----Decoded View---------------
Arg [0] : collateral_token (address): 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0
Arg [1] : monetary_policy (address): 0x1E7d3bf98d3f8D8CE193236c3e0eC4b00e32DaaE
Arg [2] : loan_discount (uint256): 90000000000000000
Arg [3] : liquidation_discount (uint256): 60000000000000000
Arg [4] : amm (address): 0x37417B2238AA52D0DD2D6252d989E728e8f706e4
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0
Arg [1] : 0000000000000000000000001e7d3bf98d3f8d8ce193236c3e0ec4b00e32daae
Arg [2] : 000000000000000000000000000000000000000000000000013fbe85edc90000
Arg [3] : 00000000000000000000000000000000000000000000000000d529ae9e860000
Arg [4] : 00000000000000000000000037417b2238aa52d0dd2d6252d989e728e8f706e4
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.994048 | 134,723,259.9051 | $133,921,387.06 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.