Transactions
Token Transfers
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Vyper_contract
- Optimization enabled
- false
- Compiler version
- v0.3.1
- Verified at
- 2022-04-25T11:06:09.598667Z
Constructor Arguments
00000000000000000000000013f0b2a9691bb72cae72616b39e798a824f18271000000000000000000000000b74df76cc81755cbe03f47cb38696d2a4327ed8a000000000000000000000000f5e033984d3329105253afaa945cad388fbacd6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b296bab2ed122a85977423b602ddf3527582a3da
Arg [0] (address) : 0x13f0b2a9691bb72cae72616b39e798a824f18271
Arg [1] (address) : 0xb74df76cc81755cbe03f47cb38696d2a4327ed8a
Arg [2] (address) : 0xf5e033984d3329105253afaa945cad388fbacd6e
Arg [3] (address) : 0x0000000000000000000000000000000000000000
Arg [4] (address) : 0xb296bab2ed122a85977423b602ddf3527582a3da
Contract source code
# @version 0.3.1
"""
@title Curve Factory
@license MIT
@author Curve.Fi
@notice Permissionless pool deployer and registry
"""
interface CryptoPool:
def balances(i: uint256) -> uint256: view
def initialize(
A: uint256,
gamma: uint256,
mid_fee: uint256,
out_fee: uint256,
allowed_extra_profit: uint256,
fee_gamma: uint256,
adjustment_step: uint256,
admin_fee: uint256,
ma_half_time: uint256,
initial_price: uint256,
_token: address,
_coins: address[2],
_precisions: uint256
): nonpayable
interface ERC20:
def decimals() -> uint256: view
interface LiquidityGauge:
def initialize(_lp_token: address): nonpayable
interface Token:
def initialize(_name: String[64], _symbol: String[32], _pool: address): nonpayable
event CryptoPoolDeployed:
token: address
coins: address[2]
A: uint256
gamma: uint256
mid_fee: uint256
out_fee: uint256
allowed_extra_profit: uint256
fee_gamma: uint256
adjustment_step: uint256
admin_fee: uint256
ma_half_time: uint256
initial_price: uint256
deployer: address
event LiquidityGaugeDeployed:
pool: address
token: address
gauge: address
event UpdateFeeReceiver:
_old_fee_receiver: address
_new_fee_receiver: address
event UpdatePoolImplementation:
_old_pool_implementation: address
_new_pool_implementation: address
event UpdateTokenImplementation:
_old_token_implementation: address
_new_token_implementation: address
event UpdateGaugeImplementation:
_old_gauge_implementation: address
_new_gauge_implementation: address
event TransferOwnership:
_old_owner: address
_new_owner: address
struct PoolArray:
token: address
liquidity_gauge: address
coins: address[2]
decimals: uint256
N_COINS: constant(int128) = 2
A_MULTIPLIER: constant(uint256) = 10000
# Limits
MAX_ADMIN_FEE: constant(uint256) = 10 * 10 ** 9
MIN_FEE: constant(uint256) = 5 * 10 ** 5 # 0.5 bps
MAX_FEE: constant(uint256) = 10 * 10 ** 9
MIN_GAMMA: constant(uint256) = 10 ** 10
MAX_GAMMA: constant(uint256) = 2 * 10 ** 16
MIN_A: constant(uint256) = N_COINS ** N_COINS * A_MULTIPLIER / 10
MAX_A: constant(uint256) = N_COINS ** N_COINS * A_MULTIPLIER * 100000
WETH: immutable(address)
admin: public(address)
future_admin: public(address)
# fee receiver for plain pools
fee_receiver: public(address)
pool_implementation: public(address)
token_implementation: public(address)
gauge_implementation: public(address)
# mapping of coins -> pools for trading
# a mapping key is generated for each pair of addresses via
# `bitwise_xor(convert(a, uint256), convert(b, uint256))`
markets: HashMap[uint256, address[4294967296]]
market_counts: HashMap[uint256, uint256]
pool_count: public(uint256) # actual length of pool_list
pool_data: HashMap[address, PoolArray]
pool_list: public(address[4294967296]) # master list of pools
@external
def __init__(
_fee_receiver: address,
_pool_implementation: address,
_token_implementation: address,
_gauge_implementation: address,
_weth: address
):
self.fee_receiver = _fee_receiver
self.pool_implementation = _pool_implementation
self.token_implementation = _token_implementation
self.gauge_implementation = _gauge_implementation
self.admin = msg.sender
WETH = _weth
log UpdateFeeReceiver(ZERO_ADDRESS, _fee_receiver)
log UpdatePoolImplementation(ZERO_ADDRESS, _pool_implementation)
log UpdateTokenImplementation(ZERO_ADDRESS, _token_implementation)
log UpdateGaugeImplementation(ZERO_ADDRESS, _gauge_implementation)
log TransferOwnership(ZERO_ADDRESS, msg.sender)
# <--- Pool Deployers --->
@external
def deploy_pool(
_name: String[32],
_symbol: String[10],
_coins: address[2],
A: uint256,
gamma: uint256,
mid_fee: uint256,
out_fee: uint256,
allowed_extra_profit: uint256,
fee_gamma: uint256,
adjustment_step: uint256,
admin_fee: uint256,
ma_half_time: uint256,
initial_price: uint256
) -> address:
"""
@notice Deploy a new pool
@param _name Name of the new plain pool
@param _symbol Symbol for the new plain pool - will be concatenated with factory symbol
Other parameters need some description
@return Address of the deployed pool
"""
# Validate parameters
assert A > MIN_A-1
assert A < MAX_A+1
assert gamma > MIN_GAMMA-1
assert gamma < MAX_GAMMA+1
assert mid_fee > MIN_FEE-1
assert mid_fee < MAX_FEE-1
assert out_fee >= mid_fee
assert out_fee < MAX_FEE-1
assert admin_fee < 10**18+1
assert allowed_extra_profit < 10**16+1
assert fee_gamma < 10**18+1
assert fee_gamma > 0
assert adjustment_step < 10**18+1
assert adjustment_step > 0
assert ma_half_time < 7 * 86400
assert ma_half_time > 0
assert initial_price > 10**6
assert initial_price < 10**30
assert _coins[0] != _coins[1], "Duplicate coins"
decimals: uint256[2] = empty(uint256[2])
for i in range(2):
d: uint256 = ERC20(_coins[i]).decimals()
assert d < 19, "Max 18 decimals for coins"
decimals[i] = d
precisions: uint256 = (18 - decimals[0]) + shift(18 - decimals[1], 8)
name: String[64] = concat("Curve.fi Factory Crypto Pool: ", _name)
symbol: String[32] = concat(_symbol, "-f")
token: address = create_forwarder_to(self.token_implementation)
pool: address = create_forwarder_to(self.pool_implementation)
Token(token).initialize(name, symbol, pool)
CryptoPool(pool).initialize(
A, gamma, mid_fee, out_fee, allowed_extra_profit, fee_gamma,
adjustment_step, admin_fee, ma_half_time, initial_price,
token, _coins, precisions)
length: uint256 = self.pool_count
self.pool_list[length] = pool
self.pool_count = length + 1
self.pool_data[pool].token = token
self.pool_data[pool].decimals = shift(decimals[0], 8) + decimals[1]
self.pool_data[pool].coins = _coins
key: uint256 = bitwise_xor(convert(_coins[0], uint256), convert(_coins[1], uint256))
length = self.market_counts[key]
self.markets[key][length] = pool
self.market_counts[key] = length + 1
log CryptoPoolDeployed(
token, _coins,
A, gamma, mid_fee, out_fee, allowed_extra_profit, fee_gamma,
adjustment_step, admin_fee, ma_half_time, initial_price,
msg.sender)
return pool
@external
def deploy_gauge(_pool: address) -> address:
"""
@notice Deploy a liquidity gauge for a factory pool
@param _pool Factory pool address to deploy a gauge for
@return Address of the deployed gauge
"""
assert self.pool_data[_pool].coins[0] != ZERO_ADDRESS, "Unknown pool"
assert self.pool_data[_pool].liquidity_gauge == ZERO_ADDRESS, "Gauge already deployed"
gauge: address = create_forwarder_to(self.gauge_implementation)
token: address = self.pool_data[_pool].token
LiquidityGauge(gauge).initialize(token)
self.pool_data[_pool].liquidity_gauge = gauge
log LiquidityGaugeDeployed(_pool, token, gauge)
return gauge
# <--- Admin / Guarded Functionality --->
@external
def set_fee_receiver(_fee_receiver: address):
"""
@notice Set fee receiver
@param _fee_receiver Address that fees are sent to
"""
assert msg.sender == self.admin # dev: admin only
log UpdateFeeReceiver(self.fee_receiver, _fee_receiver)
self.fee_receiver = _fee_receiver
@external
def set_pool_implementation(_pool_implementation: address):
"""
@notice Set pool implementation
@dev Set to ZERO_ADDRESS to prevent deployment of new pools
@param _pool_implementation Address of the new pool implementation
"""
assert msg.sender == self.admin # dev: admin only
log UpdatePoolImplementation(self.pool_implementation, _pool_implementation)
self.pool_implementation = _pool_implementation
@external
def set_token_implementation(_token_implementation: address):
"""
@notice Set token implementation
@dev Set to ZERO_ADDRESS to prevent deployment of new pools
@param _token_implementation Address of the new token implementation
"""
assert msg.sender == self.admin # dev: admin only
log UpdateTokenImplementation(self.token_implementation, _token_implementation)
self.token_implementation = _token_implementation
@external
def set_gauge_implementation(_gauge_implementation: address):
"""
@notice Set gauge implementation
@dev Set to ZERO_ADDRESS to prevent deployment of new gauges
@param _gauge_implementation Address of the new token implementation
"""
assert msg.sender == self.admin # dev: admin-only function
log UpdateGaugeImplementation(self.gauge_implementation, _gauge_implementation)
self.gauge_implementation = _gauge_implementation
@external
def commit_transfer_ownership(_addr: address):
"""
@notice Transfer ownership of this contract to `addr`
@param _addr Address of the new owner
"""
assert msg.sender == self.admin # dev: admin only
self.future_admin = _addr
@external
def accept_transfer_ownership():
"""
@notice Accept a pending ownership transfer
@dev Only callable by the new owner
"""
assert msg.sender == self.future_admin # dev: future admin only
log TransferOwnership(self.admin, msg.sender)
self.admin = msg.sender
# <--- Factory Getters --->
@view
@external
def find_pool_for_coins(_from: address, _to: address, i: uint256 = 0) -> address:
"""
@notice Find an available pool for exchanging two coins
@param _from Address of coin to be sent
@param _to Address of coin to be received
@param i Index value. When multiple pools are available
this value is used to return the n'th address.
@return Pool address
"""
key: uint256 = bitwise_xor(convert(_from, uint256), convert(_to, uint256))
return self.markets[key][i]
# <--- Pool Getters --->
@view
@external
def get_coins(_pool: address) -> address[2]:
"""
@notice Get the coins within a pool
@param _pool Pool address
@return List of coin addresses
"""
return self.pool_data[_pool].coins
@view
@external
def get_decimals(_pool: address) -> uint256[2]:
"""
@notice Get decimal places for each coin within a pool
@param _pool Pool address
@return uint256 list of decimals
"""
decimals: uint256 = self.pool_data[_pool].decimals
return [shift(decimals, -8), decimals % 256]
@view
@external
def get_balances(_pool: address) -> uint256[2]:
"""
@notice Get balances for each coin within a pool
@dev For pools using lending, these are the wrapped coin balances
@param _pool Pool address
@return uint256 list of balances
"""
return [CryptoPool(_pool).balances(0), CryptoPool(_pool).balances(1)]
@view
@external
def get_coin_indices(
_pool: address,
_from: address,
_to: address
) -> (uint256, uint256):
"""
@notice Convert coin addresses to indices for use with pool methods
@param _pool Pool address
@param _from Coin address to be used as `i` within a pool
@param _to Coin address to be used as `j` within a pool
@return uint256 `i`, uint256 `j`
"""
coins: address[2] = self.pool_data[_pool].coins
if _from == coins[0] and _to == coins[1]:
return 0, 1
elif _from == coins[1] and _to == coins[0]:
return 1, 0
else:
raise "Coins not found"
@view
@external
def get_gauge(_pool: address) -> address:
"""
@notice Get the address of the liquidity gauge contract for a factory pool
@dev Returns `ZERO_ADDRESS` if a gauge has not been deployed
@param _pool Pool address
@return Implementation contract address
"""
return self.pool_data[_pool].liquidity_gauge
@view
@external
def get_eth_index(_pool: address) -> uint256:
"""
@notice Get the index of WETH for a pool
@dev Returns MAX_UINT256 if WETH is not a coin in the pool
"""
for i in range(2):
if self.pool_data[_pool].coins[i] == WETH:
return i
return MAX_UINT256
@view
@external
def get_token(_pool: address) -> address:
"""
@notice Get the address of the LP token of a pool
"""
return self.pool_data[_pool].token
Contract ABI
[{"type":"event","name":"CryptoPoolDeployed","inputs":[{"type":"address","name":"token","indexed":false},{"type":"address[2]","name":"coins","indexed":false},{"type":"uint256","name":"A","indexed":false},{"type":"uint256","name":"gamma","indexed":false},{"type":"uint256","name":"mid_fee","indexed":false},{"type":"uint256","name":"out_fee","indexed":false},{"type":"uint256","name":"allowed_extra_profit","indexed":false},{"type":"uint256","name":"fee_gamma","indexed":false},{"type":"uint256","name":"adjustment_step","indexed":false},{"type":"uint256","name":"admin_fee","indexed":false},{"type":"uint256","name":"ma_half_time","indexed":false},{"type":"uint256","name":"initial_price","indexed":false},{"type":"address","name":"deployer","indexed":false}],"anonymous":false},{"type":"event","name":"LiquidityGaugeDeployed","inputs":[{"type":"address","name":"pool","indexed":false},{"type":"address","name":"token","indexed":false},{"type":"address","name":"gauge","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateFeeReceiver","inputs":[{"type":"address","name":"_old_fee_receiver","indexed":false},{"type":"address","name":"_new_fee_receiver","indexed":false}],"anonymous":false},{"type":"event","name":"UpdatePoolImplementation","inputs":[{"type":"address","name":"_old_pool_implementation","indexed":false},{"type":"address","name":"_new_pool_implementation","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateTokenImplementation","inputs":[{"type":"address","name":"_old_token_implementation","indexed":false},{"type":"address","name":"_new_token_implementation","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateGaugeImplementation","inputs":[{"type":"address","name":"_old_gauge_implementation","indexed":false},{"type":"address","name":"_new_gauge_implementation","indexed":false}],"anonymous":false},{"type":"event","name":"TransferOwnership","inputs":[{"type":"address","name":"_old_owner","indexed":false},{"type":"address","name":"_new_owner","indexed":false}],"anonymous":false},{"type":"constructor","stateMutability":"nonpayable","outputs":[],"inputs":[{"type":"address","name":"_fee_receiver"},{"type":"address","name":"_pool_implementation"},{"type":"address","name":"_token_implementation"},{"type":"address","name":"_gauge_implementation"},{"type":"address","name":"_weth"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_pool","inputs":[{"type":"string","name":"_name"},{"type":"string","name":"_symbol"},{"type":"address[2]","name":"_coins"},{"type":"uint256","name":"A"},{"type":"uint256","name":"gamma"},{"type":"uint256","name":"mid_fee"},{"type":"uint256","name":"out_fee"},{"type":"uint256","name":"allowed_extra_profit"},{"type":"uint256","name":"fee_gamma"},{"type":"uint256","name":"adjustment_step"},{"type":"uint256","name":"admin_fee"},{"type":"uint256","name":"ma_half_time"},{"type":"uint256","name":"initial_price"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":""}],"name":"deploy_gauge","inputs":[{"type":"address","name":"_pool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_fee_receiver","inputs":[{"type":"address","name":"_fee_receiver"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_pool_implementation","inputs":[{"type":"address","name":"_pool_implementation"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_token_implementation","inputs":[{"type":"address","name":"_token_implementation"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_gauge_implementation","inputs":[{"type":"address","name":"_gauge_implementation"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"commit_transfer_ownership","inputs":[{"type":"address","name":"_addr"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"accept_transfer_ownership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"find_pool_for_coins","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"find_pool_for_coins","inputs":[{"type":"address","name":"_from"},{"type":"address","name":"_to"},{"type":"uint256","name":"i"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[2]","name":""}],"name":"get_coins","inputs":[{"type":"address","name":"_pool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[2]","name":""}],"name":"get_decimals","inputs":[{"type":"address","name":"_pool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[2]","name":""}],"name":"get_balances","inputs":[{"type":"address","name":"_pool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""},{"type":"uint256","name":""}],"name":"get_coin_indices","inputs":[{"type":"address","name":"_pool"},{"type":"address","name":"_from"},{"type":"address","name":"_to"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"get_gauge","inputs":[{"type":"address","name":"_pool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"get_eth_index","inputs":[{"type":"address","name":"_pool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"get_token","inputs":[{"type":"address","name":"_pool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"admin","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"future_admin","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"fee_receiver","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"pool_implementation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"token_implementation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"gauge_implementation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":""}],"name":"pool_count","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":""}],"name":"pool_list","inputs":[{"type":"uint256","name":"arg0"}]}]
Contract Creation Code
0x602061130e6080396080518060a01c6113095760e0526020602061130e016080396080518060a01c61130957610100526020604061130e016080396080518060a01c61130957610120526020606061130e016080396080518060a01c61130957610140526020608061130e016080396080518060a01c611309576101605260e0516002556101005160035561012051600455610140516005553360005561016051610180527f2861448678f0be67f11bfb5481b3e3b4cfeb3acc6126ad60a05f95bfc653066660006101a05260e0516101c05260406101a0a17f0617fd31aa5ab95ec80eefc1eb61a2c477aa419d1d761b4e46f5f077e47852aa60006101a052610100516101c05260406101a0a17f1cc4f8e20b0cd3e5109eb156cadcfd3a5496ac0794c6085ca02afd7d710dd56660006101a052610120516101c05260406101a0a17f1fd705f9c77053962a503f2f2f57f0862b4c3af687c25615c13817a86946c35960006101a052610140516101c05260406101a0a17f5c486528ec3e3f0ea91181cff8116f02bfa350e03b8b6f12e00765adbb5af85c60006101a052336101c05260406101a0a16112e156600436101561000d57611128565b60046000601c376000513461112e5763c955fa04811861080057600435600401602081351161112e57808035602001808260e037505050602435600401600a81351161112e578080356020018082610120375050506044358060a01c61112e57610160526064358060a01c61112e5761018052610f9f608435111561112e5763ee6b2801608435101561112e576402540be3ff60a435111561112e5766470de4df82000160a435101561112e576207a11f60c435111561112e576402540be3ff60c435101561112e5760c43560e4351061112e576402540be3ff60e435101561112e57670de0b6b3a764000161016435101561112e57662386f26fc1000161010435101561112e57670de0b6b3a764000161012435101561112e57600061012435111561112e57670de0b6b3a764000161014435101561112e57600061014435111561112e5762093a8061018435101561112e57600061018435111561112e57620f42406101a435111561112e576c0c9f2c9cd04674edea400000006101a435101561112e576101805161016051141561021857600f6101a0527f4475706c696361746520636f696e7300000000000000000000000000000000006101c0526101a0506101a051806101c001818260206001820306601f82010390500336823750506308c379a0610160526020610180526101a05160206001820306601f820103905060440161017cfd5b6040366101a0376101e060006002818352015b63313ce567610220526020610220600461023c6101606101e051600281101561112e5760200201515afa610264573d600060003e3d6000fd5b601f3d111561112e576102205161020052601361020051106102f7576019610220527f4d617820313820646563696d616c7320666f7220636f696e73000000000000006102405261022050610220518061024001818260206001820306601f82010390500336823750506308c379a06101e0526020610200526102205160206001820306601f82010390506044016101fcfd5b610200516101a06101e051600281101561112e576020020152815160010180835281141561022b57505060126101a05180821061112e578082039050905060126101c05180821061112e578082039050905060081b818183011061112e57808201905090506101e0526000601e610260527f43757276652e666920466163746f72792043727970746f20506f6f6c3a20000061028052610260601e806020846102a00101826020850160045afa50508051820191505060e06020806020846102a00101826020850160045afa505080518201915050806102a0526102a09050805160200180610200828460045afa905050506000610120600a806020846102e00101826020850160045afa50508051820191505060026102a0527f2d660000000000000000000000000000000000000000000000000000000000006102c0526102a06002806020846102e00101826020850160045afa505080518201915050806102e0526102e09050805160200180610260828460045afa905050507f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006102c05260045460601b6102d3527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006102e75260366102c06000f06102a0527f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006102e05260035460601b6102f3527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006103075260366102e06000f06102c05263077f224a6102e0526103008060608082528083018061020080516020018083828460045afa905050508051806020830101818260206001820306601f8201039050033682375050805160200160206001820306601f820103905090509050810190506020820191508082528083018061026080516020018083828460045afa905050508051806020830101818260206001820306601f8201039050033682375050805160200160206001820306601f820103905090509050810190506020820191506102c05182525050506102a0513b1561112e57600060006101046102fc60006102a0515af161062a573d600060003e3d6000fd5b63a39e95c56102e0526101406084610300376102a05161044052610160516104605261018051610480526101e0516104a0526102c0513b1561112e57600060006101c46102fc60006102c0515af1610687573d600060003e3d6000fd5b6008546102e0526102c05160016102e05164010000000081101561112e5702600a01556102e0516001818183011061112e57808201905090506008556102a05160096102c05160a0526080526040608020556101a05160081b6101c051818183011061112e5780820190509050600460096102c05160a05260805260406080200155600260096102c05160a052608052604060802001610160518155610180516001820155506101805161016051186103005260076103005160a0526080526040608020546102e0526102c05160016102e05164010000000081101561112e570260066103005160a052608052604060802001556102e0516001818183011061112e578082019050905060076103005160a0526080526040608020557f0394cb40d7dbe28dad1d4ee890bdd35bbb0d89e17924a80a542535e83d54ba146102a0516103205261016051610340526101805161036052610140608461038037336104c0526101c0610320a16102c051610320526020610320f35b6396bebb348118610a4b576004358060a01c61112e5760e05260006002600960e05160a0526080526040608020015414156108a957600c610100527f556e6b6e6f776e20706f6f6c00000000000000000000000000000000000000006101205261010050610100518061012001818260206001820306601f82010390500336823750506308c379a060c052602060e0526101005160206001820306601f820103905060440160dcfd5b6001600960e05160a0526080526040608020015415610936576016610100527f476175676520616c7265616479206465706c6f796564000000000000000000006101205261010050610100518061012001818260206001820306601f82010390500336823750506308c379a060c052602060e0526101005160206001820306601f820103905060440160dcfd5b7f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006101205260055460601b610133527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006101475260366101206000f061010052600960e05160a0526080526040608020546101205263c4d66de8610140526101205161016052610100513b1561112e5760006000602461015c6000610100515af16109e6573d600060003e3d6000fd5b610100516001600960e05160a052608052604060802001557f1d6247eae69b5feb96b30be78552f35de45f61fdb6d6d7e1b08aae159b6226af60e05161014052610120516101605261010051610180526060610140a161010051610140526020610140f35b63e41ab7718118610aaa576004358060a01c61112e5760e052600054331861112e577f2861448678f0be67f11bfb5481b3e3b4cfeb3acc6126ad60a05f95bfc65306666002546101005260e051610120526040610100a160e051600255005b639ed796d08118610b09576004358060a01c61112e5760e052600054331861112e577f0617fd31aa5ab95ec80eefc1eb61a2c477aa419d1d761b4e46f5f077e47852aa6003546101005260e051610120526040610100a160e051600355005b63653023c28118610b68576004358060a01c61112e5760e052600054331861112e577f1cc4f8e20b0cd3e5109eb156cadcfd3a5496ac0794c6085ca02afd7d710dd5666004546101005260e051610120526040610100a160e051600455005b638f03182c8118610bc7576004358060a01c61112e5760e052600054331861112e577f1fd705f9c77053962a503f2f2f57f0862b4c3af687c25615c13817a86946c3596005546101005260e051610120526040610100a160e051600555005b636b441a408118610bf1576004358060a01c61112e5760e052600054331861112e5760e051600155005b63e5ea47b88118610c3c57600154331861112e577f5c486528ec3e3f0ea91181cff8116f02bfa350e03b8b6f12e00765adbb5af85c60005460e0523361010052604060e0a133600055005b63a87df06c8118610c5257600061012052610c65565b636982eb0b8118610cc057604435610120525b6004358060a01c61112e5760e0526024358060a01c61112e57610100526101005160e051186101405260016101205164010000000081101561112e570260066101405160a05260805260406080200154610160526020610160f35b639ac90d3d8118610d03576004358060a01c61112e5760e0526002600960e05160a052608052604060802001805461010052600181015461012052506040610100f35b6352b515558118610d58576004358060a01c61112e5760e0526004600960e05160a05260805260406080200154610100526101005160081c610120526101005161010080820690509050610140526040610120f35b6392e3cc2d8118610df4576004358060a01c61112e5760e052634903b0d1610100526000610120526020610100602461011c60e0515afa610d9e573d600060003e3d6000fd5b601f3d111561112e576101005161018052634903b0d1610140526001610160526020610140602461015c60e0515afa610ddc573d600060003e3d6000fd5b601f3d111561112e57610140516101a0526040610180f35b63eb85226d8118610f3f576004358060a01c61112e5760e0526024358060a01c61112e57610100526044358060a01c61112e57610120526002600960e05160a05260805260406080200180546101405260018101546101605250610140516101005118610e6957610160516101205114610e6c565b60005b610f2757610160516101005118610e8b57610140516101205114610e8e565b60005b610f0d57600f610180527f436f696e73206e6f7420666f756e6400000000000000000000000000000000006101a0526101805061018051806101a001818260206001820306601f82010390500336823750506308c379a0610140526020610160526101805160206001820306601f820103905060440161015cfd610f3d565b60016101805260006101a0526040610180610f3d56610f3d565b60006101805260016101a0526040610180610f3d565bf35b63daf297b98118610f77576004358060a01c61112e5760e0526001600960e05160a05260805260406080200154610100526020610100f35b63ccb156058118611025576004358060a01c61112e5760e05261010060006002818352015b602060203803608039608051600161010051600281101561112e57026002600960e05160a052608052604060802001015418610fe75750505061010051610120526020610120611023565b8151600101808352811415610f9c5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101005260206101005bf35b63977d9122811861105a576004358060a01c61112e5760e052600960e05160a052608052604060802054610100526020610100f35b63f851a44081186110715760005460e052602060e0f35b6317f7182a81186110885760015460e052602060e0f35b63cab4d3db811861109f5760025460e052602060e0f35b632489a2c381186110b65760035460e052602060e0f35b6335214d8181186110cd5760045460e052602060e0f35b638df2420781186110e45760055460e052602060e0f35b63956aae3a81186110fb5760085460e052602060e0f35b633a1d5d8e811861112657600160043564010000000081101561112e5702600a015460e052602060e0f35b505b60006000fd5b600080fd5b6101ae6112e1036101ae6101a0396101ae6112e10361018051816101a00152806020016101a0f35b600080fd00000000000000000000000013f0b2a9691bb72cae72616b39e798a824f18271000000000000000000000000b74df76cc81755cbe03f47cb38696d2a4327ed8a000000000000000000000000f5e033984d3329105253afaa945cad388fbacd6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b296bab2ed122a85977423b602ddf3527582a3da
Deployed ByteCode
0x600436101561000d57611128565b60046000601c376000513461112e5763c955fa04811861080057600435600401602081351161112e57808035602001808260e037505050602435600401600a81351161112e578080356020018082610120375050506044358060a01c61112e57610160526064358060a01c61112e5761018052610f9f608435111561112e5763ee6b2801608435101561112e576402540be3ff60a435111561112e5766470de4df82000160a435101561112e576207a11f60c435111561112e576402540be3ff60c435101561112e5760c43560e4351061112e576402540be3ff60e435101561112e57670de0b6b3a764000161016435101561112e57662386f26fc1000161010435101561112e57670de0b6b3a764000161012435101561112e57600061012435111561112e57670de0b6b3a764000161014435101561112e57600061014435111561112e5762093a8061018435101561112e57600061018435111561112e57620f42406101a435111561112e576c0c9f2c9cd04674edea400000006101a435101561112e576101805161016051141561021857600f6101a0527f4475706c696361746520636f696e7300000000000000000000000000000000006101c0526101a0506101a051806101c001818260206001820306601f82010390500336823750506308c379a0610160526020610180526101a05160206001820306601f820103905060440161017cfd5b6040366101a0376101e060006002818352015b63313ce567610220526020610220600461023c6101606101e051600281101561112e5760200201515afa610264573d600060003e3d6000fd5b601f3d111561112e576102205161020052601361020051106102f7576019610220527f4d617820313820646563696d616c7320666f7220636f696e73000000000000006102405261022050610220518061024001818260206001820306601f82010390500336823750506308c379a06101e0526020610200526102205160206001820306601f82010390506044016101fcfd5b610200516101a06101e051600281101561112e576020020152815160010180835281141561022b57505060126101a05180821061112e578082039050905060126101c05180821061112e578082039050905060081b818183011061112e57808201905090506101e0526000601e610260527f43757276652e666920466163746f72792043727970746f20506f6f6c3a20000061028052610260601e806020846102a00101826020850160045afa50508051820191505060e06020806020846102a00101826020850160045afa505080518201915050806102a0526102a09050805160200180610200828460045afa905050506000610120600a806020846102e00101826020850160045afa50508051820191505060026102a0527f2d660000000000000000000000000000000000000000000000000000000000006102c0526102a06002806020846102e00101826020850160045afa505080518201915050806102e0526102e09050805160200180610260828460045afa905050507f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006102c05260045460601b6102d3527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006102e75260366102c06000f06102a0527f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006102e05260035460601b6102f3527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006103075260366102e06000f06102c05263077f224a6102e0526103008060608082528083018061020080516020018083828460045afa905050508051806020830101818260206001820306601f8201039050033682375050805160200160206001820306601f820103905090509050810190506020820191508082528083018061026080516020018083828460045afa905050508051806020830101818260206001820306601f8201039050033682375050805160200160206001820306601f820103905090509050810190506020820191506102c05182525050506102a0513b1561112e57600060006101046102fc60006102a0515af161062a573d600060003e3d6000fd5b63a39e95c56102e0526101406084610300376102a05161044052610160516104605261018051610480526101e0516104a0526102c0513b1561112e57600060006101c46102fc60006102c0515af1610687573d600060003e3d6000fd5b6008546102e0526102c05160016102e05164010000000081101561112e5702600a01556102e0516001818183011061112e57808201905090506008556102a05160096102c05160a0526080526040608020556101a05160081b6101c051818183011061112e5780820190509050600460096102c05160a05260805260406080200155600260096102c05160a052608052604060802001610160518155610180516001820155506101805161016051186103005260076103005160a0526080526040608020546102e0526102c05160016102e05164010000000081101561112e570260066103005160a052608052604060802001556102e0516001818183011061112e578082019050905060076103005160a0526080526040608020557f0394cb40d7dbe28dad1d4ee890bdd35bbb0d89e17924a80a542535e83d54ba146102a0516103205261016051610340526101805161036052610140608461038037336104c0526101c0610320a16102c051610320526020610320f35b6396bebb348118610a4b576004358060a01c61112e5760e05260006002600960e05160a0526080526040608020015414156108a957600c610100527f556e6b6e6f776e20706f6f6c00000000000000000000000000000000000000006101205261010050610100518061012001818260206001820306601f82010390500336823750506308c379a060c052602060e0526101005160206001820306601f820103905060440160dcfd5b6001600960e05160a0526080526040608020015415610936576016610100527f476175676520616c7265616479206465706c6f796564000000000000000000006101205261010050610100518061012001818260206001820306601f82010390500336823750506308c379a060c052602060e0526101005160206001820306601f820103905060440160dcfd5b7f602d3d8160093d39f3363d3d373d3d3d363d73000000000000000000000000006101205260055460601b610133527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006101475260366101206000f061010052600960e05160a0526080526040608020546101205263c4d66de8610140526101205161016052610100513b1561112e5760006000602461015c6000610100515af16109e6573d600060003e3d6000fd5b610100516001600960e05160a052608052604060802001557f1d6247eae69b5feb96b30be78552f35de45f61fdb6d6d7e1b08aae159b6226af60e05161014052610120516101605261010051610180526060610140a161010051610140526020610140f35b63e41ab7718118610aaa576004358060a01c61112e5760e052600054331861112e577f2861448678f0be67f11bfb5481b3e3b4cfeb3acc6126ad60a05f95bfc65306666002546101005260e051610120526040610100a160e051600255005b639ed796d08118610b09576004358060a01c61112e5760e052600054331861112e577f0617fd31aa5ab95ec80eefc1eb61a2c477aa419d1d761b4e46f5f077e47852aa6003546101005260e051610120526040610100a160e051600355005b63653023c28118610b68576004358060a01c61112e5760e052600054331861112e577f1cc4f8e20b0cd3e5109eb156cadcfd3a5496ac0794c6085ca02afd7d710dd5666004546101005260e051610120526040610100a160e051600455005b638f03182c8118610bc7576004358060a01c61112e5760e052600054331861112e577f1fd705f9c77053962a503f2f2f57f0862b4c3af687c25615c13817a86946c3596005546101005260e051610120526040610100a160e051600555005b636b441a408118610bf1576004358060a01c61112e5760e052600054331861112e5760e051600155005b63e5ea47b88118610c3c57600154331861112e577f5c486528ec3e3f0ea91181cff8116f02bfa350e03b8b6f12e00765adbb5af85c60005460e0523361010052604060e0a133600055005b63a87df06c8118610c5257600061012052610c65565b636982eb0b8118610cc057604435610120525b6004358060a01c61112e5760e0526024358060a01c61112e57610100526101005160e051186101405260016101205164010000000081101561112e570260066101405160a05260805260406080200154610160526020610160f35b639ac90d3d8118610d03576004358060a01c61112e5760e0526002600960e05160a052608052604060802001805461010052600181015461012052506040610100f35b6352b515558118610d58576004358060a01c61112e5760e0526004600960e05160a05260805260406080200154610100526101005160081c610120526101005161010080820690509050610140526040610120f35b6392e3cc2d8118610df4576004358060a01c61112e5760e052634903b0d1610100526000610120526020610100602461011c60e0515afa610d9e573d600060003e3d6000fd5b601f3d111561112e576101005161018052634903b0d1610140526001610160526020610140602461015c60e0515afa610ddc573d600060003e3d6000fd5b601f3d111561112e57610140516101a0526040610180f35b63eb85226d8118610f3f576004358060a01c61112e5760e0526024358060a01c61112e57610100526044358060a01c61112e57610120526002600960e05160a05260805260406080200180546101405260018101546101605250610140516101005118610e6957610160516101205114610e6c565b60005b610f2757610160516101005118610e8b57610140516101205114610e8e565b60005b610f0d57600f610180527f436f696e73206e6f7420666f756e6400000000000000000000000000000000006101a0526101805061018051806101a001818260206001820306601f82010390500336823750506308c379a0610140526020610160526101805160206001820306601f820103905060440161015cfd610f3d565b60016101805260006101a0526040610180610f3d56610f3d565b60006101805260016101a0526040610180610f3d565bf35b63daf297b98118610f77576004358060a01c61112e5760e0526001600960e05160a05260805260406080200154610100526020610100f35b63ccb156058118611025576004358060a01c61112e5760e05261010060006002818352015b602060203803608039608051600161010051600281101561112e57026002600960e05160a052608052604060802001015418610fe75750505061010051610120526020610120611023565b8151600101808352811415610f9c5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101005260206101005bf35b63977d9122811861105a576004358060a01c61112e5760e052600960e05160a052608052604060802054610100526020610100f35b63f851a44081186110715760005460e052602060e0f35b6317f7182a81186110885760015460e052602060e0f35b63cab4d3db811861109f5760025460e052602060e0f35b632489a2c381186110b65760035460e052602060e0f35b6335214d8181186110cd5760045460e052602060e0f35b638df2420781186110e45760055460e052602060e0f35b63956aae3a81186110fb5760085460e052602060e0f35b633a1d5d8e811861112657600160043564010000000081101561112e5702600a015460e052602060e0f35b505b60006000fd5b600080fd000000000000000000000000b296bab2ed122a85977423b602ddf3527582a3da