Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Voting Escrow
Compiler Version
vyper:0.3.7
Contract Source Code (Vyper language format)
# @version 0.3.7 """ @title Voting Escrow @author Curve Finance @license MIT @notice Votes have a weight depending on time, so that users are committed to the future of (whatever they are voting for) @dev Vote weight decays linearly over time. Lock time cannot be more than `MAXTIME` (set by creator). """ # Voting escrow to have time-weighted votes # Votes have a weight depending on time, so that users are committed # to the future of (whatever they are voting for). # The weight in this implementation is linear, and lock cannot be more than maxtime: # w ^ # 1 + / # | / # | / # | / # |/ # 0 +--------+------> time # maxtime struct Point: bias: int128 slope: int128 # - dweight / dt ts: uint256 blk: uint256 # block # We cannot really do block numbers per se b/c slope is per time, not per block # and per block could be fairly bad b/c Ethereum changes blocktimes. # What we can do is to extrapolate ***At functions struct LockedBalance: amount: int128 end: uint256 interface ERC20: def decimals() -> uint256: view def name() -> String[64]: view def symbol() -> String[32]: view def balanceOf(account: address) -> uint256: view def transfer(to: address, amount: uint256) -> bool: nonpayable def approve(spender: address, amount: uint256) -> bool: nonpayable def transferFrom(spender: address, to: address, amount: uint256) -> bool: nonpayable # Interface for checking whether address belongs to a whitelisted # type of a smart wallet. # When new types are added - the whole contract is changed # The check() method is modifying to be able to use caching # for individual wallet addresses interface SmartWalletChecker: def check(addr: address) -> bool: nonpayable interface BalancerMinter: def mint(gauge: address) -> uint256: nonpayable interface RewardDistributor: def depositToken(token: address, amount: uint256): nonpayable DEPOSIT_FOR_TYPE: constant(int128) = 0 CREATE_LOCK_TYPE: constant(int128) = 1 INCREASE_LOCK_AMOUNT: constant(int128) = 2 INCREASE_UNLOCK_TIME: constant(int128) = 3 event CommitOwnership: admin: address event ApplyOwnership: admin: address event EarlyUnlock: status: bool event PenaltySpeed: penalty_k: uint256 event PenaltyTreasury: penalty_treasury: address event TotalUnlock: status: bool event RewardReceiver: newReceiver: address event Deposit: provider: indexed(address) value: uint256 locktime: indexed(uint256) type: int128 ts: uint256 event Withdraw: provider: indexed(address) value: uint256 ts: uint256 event WithdrawEarly: provider: indexed(address) penalty: uint256 time_left: uint256 event Supply: prevSupply: uint256 supply: uint256 WEEK: constant(uint256) = 7 * 86400 # all future times are rounded by week MAXTIME: public(uint256) MULTIPLIER: constant(uint256) = 10**18 TOKEN: public(address) NAME: String[64] SYMBOL: String[32] DECIMALS: uint256 supply: public(uint256) locked: public(HashMap[address, LockedBalance]) epoch: public(uint256) point_history: public(Point[100000000000000000000000000000]) # epoch -> unsigned point user_point_history: public(HashMap[address, Point[1000000000]]) # user -> Point[user_epoch] user_point_epoch: public(HashMap[address, uint256]) slope_changes: public(HashMap[uint256, int128]) # time -> signed slope change # Checker for whitelisted (smart contract) wallets which are allowed to deposit # The goal is to prevent tokenizing the escrow future_smart_wallet_checker: public(address) smart_wallet_checker: public(address) admin: public(address) # unlock admins can be set only once. Zero-address means unlock is disabled admin_unlock_all: public(address) admin_early_unlock: public(address) future_admin: public(address) is_initialized: public(bool) early_unlock: public(bool) penalty_k: public(uint256) prev_penalty_k: public(uint256) penalty_upd_ts: public(uint256) PENALTY_COOLDOWN: constant(uint256) = 60 # cooldown to prevent font-run on penalty change PENALTY_MULTIPLIER: constant(uint256) = 10 penalty_treasury: public(address) balMinter: public(address) balToken: public(address) rewardReceiver: public(address) rewardReceiverChangeable: public(bool) rewardDistributor: public(address) all_unlock: public(bool) @external def initialize( _token_addr: address, _name: String[64], _symbol: String[32], _admin_addr: address, _admin_unlock_all: address, _admin_early_unlock: address, _max_time: uint256, _balToken: address, _balMinter: address, _rewardReceiver: address, _rewardReceiverChangeable: bool, _rewardDistributor: address ): """ @notice Contract constructor @param _token_addr 80/20 Token-WETH BPT token address @param _name Token name @param _symbol Token symbol @param _admin_addr Contract admin address @param _admin_unlock_all Admin to enable Unlock-All feature (zero-address to disable forever) @param _admin_early_unlock Admin to enable Eraly-Unlock feature (zero-address to disable forever) @param _max_time Locking max time @param _balToken Address of the Balancer token @param _balMinter Address of the Balancer minter @param _rewardReceiver Address of the reward receiver @param _rewardReceiverChangeable Boolean indicating whether the reward receiver is changeable @param _rewardDistributor The RewardDistributor contract address """ assert(not self.is_initialized), 'only once' self.is_initialized = True assert(_admin_addr != empty(address)), '!empty' self.admin = _admin_addr self.penalty_k = 10 self.prev_penalty_k = 10 self.penalty_upd_ts = block.timestamp self.penalty_treasury = _admin_addr self.TOKEN = _token_addr self.point_history[0].blk = block.number self.point_history[0].ts = block.timestamp _decimals: uint256 = ERC20(_token_addr).decimals() # also validates token for non-zero assert (_decimals >= 6 and _decimals <= 255), '!decimals' self.NAME = _name self.SYMBOL = _symbol self.DECIMALS = _decimals assert(_max_time >= WEEK and _max_time <= WEEK * 52 * 5), '!maxlock' self.MAXTIME = _max_time self.admin_unlock_all = _admin_unlock_all self.admin_early_unlock = _admin_early_unlock self.balToken = _balToken self.balMinter = _balMinter self.rewardReceiver = _rewardReceiver self.rewardReceiverChangeable = _rewardReceiverChangeable self.rewardDistributor = _rewardDistributor @external @view def token() -> address: return self.TOKEN @external @view def name() -> String[64]: return self.NAME @external @view def symbol() -> String[32]: return self.SYMBOL @external @view def decimals() -> uint256: return self.DECIMALS @external def commit_transfer_ownership(addr: address): """ @notice Transfer ownership of VotingEscrow contract to `addr` @param addr Address to have ownership transferred to """ assert msg.sender == self.admin # dev: admin only self.future_admin = addr log CommitOwnership(addr) @external def apply_transfer_ownership(): """ @notice Apply ownership transfer """ assert msg.sender == self.admin # dev: admin only _admin: address = self.future_admin assert _admin != empty(address) # dev: admin not set self.admin = _admin log ApplyOwnership(_admin) @external def commit_smart_wallet_checker(addr: address): """ @notice Set an external contract to check for approved smart contract wallets @param addr Address of Smart contract checker """ assert msg.sender == self.admin self.future_smart_wallet_checker = addr @external def apply_smart_wallet_checker(): """ @notice Apply setting external contract to check approved smart contract wallets """ assert msg.sender == self.admin self.smart_wallet_checker = self.future_smart_wallet_checker @internal def assert_not_contract(addr: address): """ @notice Check if the call is from a whitelisted smart contract, revert if not @param addr Address to be checked """ if addr != tx.origin: checker: address = self.smart_wallet_checker if checker != empty(address): if SmartWalletChecker(checker).check(addr): return raise "Smart contract depositors not allowed" @external def set_early_unlock(_early_unlock: bool): """ @notice Sets the availability for users to unlock their locks before lock-end with penalty @dev Only the admin_early_unlock can execute this function. @param _early_unlock A boolean indicating whether early unlock is allowed or not. """ assert msg.sender == self.admin_early_unlock, '!admin' # dev: admin_early_unlock only assert _early_unlock != self.early_unlock, 'already' self.early_unlock = _early_unlock log EarlyUnlock(_early_unlock) @external def set_early_unlock_penalty_speed(_penalty_k: uint256): """ @notice Sets penalty speed for early unlocking @dev Only the admin can execute this function. To prevent frontrunning we use PENALTY_COOLDOWN period @param _penalty_k Coefficient indicating the penalty speed for early unlock. Must be between 0 and 50, inclusive. Default 10 - means linear speed. """ assert msg.sender == self.admin_early_unlock, '!admin' # dev: admin_early_unlock only assert _penalty_k <= 50, '!k' assert block.timestamp > self.penalty_upd_ts + PENALTY_COOLDOWN, 'early' # to avoid frontrun self.prev_penalty_k = self.penalty_k self.penalty_k = _penalty_k self.penalty_upd_ts = block.timestamp log PenaltySpeed(_penalty_k) @external def set_penalty_treasury(_penalty_treasury: address): """ @notice Sets penalty treasury address @dev Only the admin_early_unlock can execute this function. @param _penalty_treasury The address to collect early penalty (default admin address) """ assert msg.sender == self.admin_early_unlock, '!admin' # dev: admin_early_unlock only assert _penalty_treasury != empty(address), '!zero' self.penalty_treasury = _penalty_treasury log PenaltyTreasury(_penalty_treasury) @external def set_all_unlock(): """ @notice Deactivates VotingEscrow and allows users to unlock their locks before lock-end. New deposits will no longer be accepted. @dev Only the admin_unlock_all can execute this function. Make sure there are no rewards for distribution in other contracts. """ assert msg.sender == self.admin_unlock_all, '!admin' # dev: admin_unlock_all only self.all_unlock = True log TotalUnlock(True) @external @view def get_last_user_slope(addr: address) -> int128: """ @notice Get the most recently recorded rate of voting power decrease for `addr` @param addr Address of the user wallet @return Value of the slope """ uepoch: uint256 = self.user_point_epoch[addr] return self.user_point_history[addr][uepoch].slope @external @view def user_point_history__ts(_addr: address, _idx: uint256) -> uint256: """ @notice Get the timestamp for checkpoint `_idx` for `_addr` @param _addr User wallet address @param _idx User epoch number @return Epoch time of the checkpoint """ return self.user_point_history[_addr][_idx].ts @external @view def locked__end(_addr: address) -> uint256: """ @notice Get timestamp when `_addr`'s lock finishes @param _addr User wallet @return Epoch time of the lock end """ return self.locked[_addr].end @internal def _checkpoint(addr: address, old_locked: LockedBalance, new_locked: LockedBalance): """ @notice Record global and per-user data to checkpoint @param addr User's wallet address. No user checkpoint if 0x0 @param old_locked Pevious locked amount / end lock time for the user @param new_locked New locked amount / end lock time for the user """ u_old: Point = empty(Point) u_new: Point = empty(Point) old_dslope: int128 = 0 new_dslope: int128 = 0 _epoch: uint256 = self.epoch if addr != empty(address): # Calculate slopes and biases # Kept at zero when they have to if old_locked.end > block.timestamp and old_locked.amount > 0: u_old.slope = old_locked.amount / convert(self.MAXTIME, int128) u_old.bias = u_old.slope * convert(old_locked.end - block.timestamp, int128) if new_locked.end > block.timestamp and new_locked.amount > 0: u_new.slope = new_locked.amount / convert(self.MAXTIME, int128) u_new.bias = u_new.slope * convert(new_locked.end - block.timestamp, int128) # Read values of scheduled changes in the slope # old_locked.end can be in the past and in the future # new_locked.end can ONLY by in the FUTURE unless everything expired: than zeros old_dslope = self.slope_changes[old_locked.end] if new_locked.end != 0: if new_locked.end == old_locked.end: new_dslope = old_dslope else: new_dslope = self.slope_changes[new_locked.end] last_point: Point = Point({bias: 0, slope: 0, ts: block.timestamp, blk: block.number}) if _epoch > 0: last_point = self.point_history[_epoch] last_checkpoint: uint256 = last_point.ts # initial_last_point is used for extrapolation to calculate block number # (approximately, for *At methods) and save them # as we cannot figure that out exactly from inside the contract initial_last_point: Point = last_point block_slope: uint256 = 0 # dblock/dt if block.timestamp > last_point.ts: block_slope = MULTIPLIER * (block.number - last_point.blk) / (block.timestamp - last_point.ts) # If last point is already recorded in this block, slope=0 # But that's ok b/c we know the block in such case # Go over weeks to fill history and calculate what the current point is t_i: uint256 = (last_checkpoint / WEEK) * WEEK for i in range(255): # Hopefully it won't happen that this won't get used in 5 years! # If it does, users will be able to withdraw but vote weight will be broken t_i += WEEK d_slope: int128 = 0 if t_i > block.timestamp: t_i = block.timestamp else: d_slope = self.slope_changes[t_i] last_point.bias -= last_point.slope * convert(t_i - last_checkpoint, int128) last_point.slope += d_slope if last_point.bias < 0: # This can happen last_point.bias = 0 if last_point.slope < 0: # This cannot happen - just in case last_point.slope = 0 last_checkpoint = t_i last_point.ts = t_i last_point.blk = initial_last_point.blk + block_slope * (t_i - initial_last_point.ts) / MULTIPLIER _epoch += 1 if t_i == block.timestamp: last_point.blk = block.number break else: self.point_history[_epoch] = last_point self.epoch = _epoch # Now point_history is filled until t=now if addr != empty(address): # If last point was in this block, the slope change has been applied already # But in such case we have 0 slope(s) last_point.slope += (u_new.slope - u_old.slope) last_point.bias += (u_new.bias - u_old.bias) if last_point.slope < 0: last_point.slope = 0 if last_point.bias < 0: last_point.bias = 0 # Record the changed point into history self.point_history[_epoch] = last_point if addr != empty(address): # Schedule the slope changes (slope is going down) # We subtract new_user_slope from [new_locked.end] # and add old_user_slope to [old_locked.end] if old_locked.end > block.timestamp: # old_dslope was <something> - u_old.slope, so we cancel that old_dslope += u_old.slope if new_locked.end == old_locked.end: old_dslope -= u_new.slope # It was a new deposit, not extension self.slope_changes[old_locked.end] = old_dslope if new_locked.end > block.timestamp: if new_locked.end > old_locked.end: new_dslope -= u_new.slope # old slope disappeared at this point self.slope_changes[new_locked.end] = new_dslope # else: we recorded it already in old_dslope # Now handle user history user_epoch: uint256 = self.user_point_epoch[addr] + 1 self.user_point_epoch[addr] = user_epoch u_new.ts = block.timestamp u_new.blk = block.number self.user_point_history[addr][user_epoch] = u_new @internal def _deposit_for(_addr: address, _value: uint256, unlock_time: uint256, locked_balance: LockedBalance, type: int128): """ @notice Deposit and lock tokens for a user @param _addr User's wallet address @param _value Amount to deposit @param unlock_time New time when to unlock the tokens, or 0 if unchanged @param locked_balance Previous locked amount / timestamp """ # block all new deposits (and extensions) in case of unlocked contract assert (not self.all_unlock), "all unlocked,no sense" _locked: LockedBalance = locked_balance supply_before: uint256 = self.supply self.supply = supply_before + _value old_locked: LockedBalance = _locked # Adding to existing lock, or if a lock is expired - creating a new one _locked.amount += convert(_value, int128) if unlock_time != 0: _locked.end = unlock_time self.locked[_addr] = _locked # Possibilities: # Both old_locked.end could be current or expired (>/< block.timestamp) # value == 0 (extend lock) or value > 0 (add to lock or extend lock) # _locked.end > block.timestamp (always) self._checkpoint(_addr, old_locked, _locked) if _value != 0: assert ERC20(self.TOKEN).transferFrom(_addr, self, _value, default_return_value=True) log Deposit(_addr, _value, _locked.end, type, block.timestamp) log Supply(supply_before, supply_before + _value) @external def checkpoint(): """ @notice Record global data to checkpoint """ self._checkpoint(empty(address), empty(LockedBalance), empty(LockedBalance)) @external @nonreentrant("lock") def deposit_for(_addr: address, _value: uint256): """ @notice Deposit `_value` tokens for `_addr` and add to the lock @dev Anyone (even a smart contract) can deposit for someone else, but cannot extend their locktime and deposit for a brand new user @param _addr User's wallet address @param _value Amount to add to user's lock """ _locked: LockedBalance = self.locked[_addr] assert _value > 0 # dev: need non-zero value assert _locked.amount > 0, "No existing lock found" assert _locked.end > block.timestamp, "Cannot add to expired lock. Withdraw" self._deposit_for(_addr, _value, 0, self.locked[_addr], DEPOSIT_FOR_TYPE) @external @nonreentrant("lock") def create_lock(_value: uint256, _unlock_time: uint256): """ @notice Deposit `_value` tokens for `msg.sender` and lock until `_unlock_time` @param _value Amount to deposit @param _unlock_time Epoch time when tokens unlock, rounded down to whole weeks """ self.assert_not_contract(msg.sender) unlock_time: uint256 = (_unlock_time / WEEK) * WEEK # Locktime is rounded down to weeks _locked: LockedBalance = self.locked[msg.sender] assert _value > 0 # dev: need non-zero value assert _locked.amount == 0, "Withdraw old tokens first" assert (unlock_time > block.timestamp), "Can only lock until time in the future" assert (unlock_time <= block.timestamp + self.MAXTIME), "Voting lock too long" self._deposit_for(msg.sender, _value, unlock_time, _locked, CREATE_LOCK_TYPE) @external @nonreentrant("lock") def increase_amount(_value: uint256): """ @notice Deposit `_value` additional tokens for `msg.sender` without modifying the unlock time @param _value Amount of tokens to deposit and add to the lock """ self.assert_not_contract(msg.sender) _locked: LockedBalance = self.locked[msg.sender] assert _value > 0 # dev: need non-zero value assert _locked.amount > 0, "No existing lock found" assert _locked.end > block.timestamp, "Cannot add to expired lock. Withdraw" self._deposit_for(msg.sender, _value, 0, _locked, INCREASE_LOCK_AMOUNT) @external @nonreentrant("lock") def increase_unlock_time(_unlock_time: uint256): """ @notice Extend the unlock time for `msg.sender` to `_unlock_time` @param _unlock_time New epoch time for unlocking """ self.assert_not_contract(msg.sender) _locked: LockedBalance = self.locked[msg.sender] unlock_time: uint256 = (_unlock_time / WEEK) * WEEK # Locktime is rounded down to weeks assert _locked.end > block.timestamp, "Lock expired" assert _locked.amount > 0, "Nothing is locked" assert unlock_time > _locked.end, "Can only increase lock duration" assert (unlock_time <= block.timestamp + self.MAXTIME), "Voting lock too long" self._deposit_for(msg.sender, 0, unlock_time, _locked, INCREASE_UNLOCK_TIME) @external @nonreentrant("lock") def withdraw(): """ @notice Withdraw all tokens for `msg.sender` @dev Only possible if the lock has expired """ _locked: LockedBalance = self.locked[msg.sender] assert block.timestamp >= _locked.end or self.all_unlock, "lock !expire or !unlock" value: uint256 = convert(_locked.amount, uint256) old_locked: LockedBalance = _locked _locked.end = 0 _locked.amount = 0 self.locked[msg.sender] = _locked supply_before: uint256 = self.supply self.supply = supply_before - value # old_locked can have either expired <= timestamp or zero end # _locked has only 0 end # Both can have >= 0 amount self._checkpoint(msg.sender, old_locked, _locked) assert ERC20(self.TOKEN).transfer(msg.sender, value, default_return_value=True) log Withdraw(msg.sender, value, block.timestamp) log Supply(supply_before, supply_before - value) @external @nonreentrant("lock") def withdraw_early(): """ @notice Withdraws locked tokens for `msg.sender` before lock-end with penalty @dev Only possible if `early_unlock` is enabled (true) By defualt there is linear formula for calculating penalty. In some cases an admin can configure penalty speed using `set_early_unlock_penalty_speed()` L - lock amount k - penalty coefficient, defined by admin (default 1) Tleft - left time to unlock Tmax - MAXLOCK time Penalty amount = L * k * (Tlast / Tmax) """ assert(self.early_unlock == True), "!early unlock" _locked: LockedBalance = self.locked[msg.sender] assert block.timestamp < _locked.end, "lock expired" value: uint256 = convert(_locked.amount, uint256) time_left: uint256 = _locked.end - block.timestamp # to avoid front-run with penalty_k penalty_k_: uint256 = 0 if block.timestamp > self.penalty_upd_ts + PENALTY_COOLDOWN: penalty_k_ = self.penalty_k else: penalty_k_ = self.prev_penalty_k penalty_ratio: uint256 = (time_left * MULTIPLIER / self.MAXTIME) * penalty_k_ penalty: uint256 = (value * penalty_ratio / MULTIPLIER) / PENALTY_MULTIPLIER if penalty > value: penalty = value user_amount: uint256 = value - penalty old_locked: LockedBalance = _locked _locked.end = 0 _locked.amount = 0 self.locked[msg.sender] = _locked supply_before: uint256 = self.supply self.supply = supply_before - value # old_locked can have either expired <= timestamp or zero end # _locked has only 0 end # Both can have >= 0 amount self._checkpoint(msg.sender, old_locked, _locked) if penalty > 0: assert ERC20(self.TOKEN).transfer(self.penalty_treasury, penalty, default_return_value=True) if user_amount > 0: assert ERC20(self.TOKEN).transfer(msg.sender, user_amount, default_return_value=True) log Withdraw(msg.sender, value, block.timestamp) log Supply(supply_before, supply_before - value) log WithdrawEarly(msg.sender, penalty, time_left) # The following ERC20/minime-compatible methods are not real balanceOf and supply! # They measure the weights for the purpose of voting, so they don't represent # real coins. @internal @view def find_block_epoch(_block: uint256, max_epoch: uint256) -> uint256: """ @notice Binary search to find epoch containing block number @param _block Block to find @param max_epoch Don't go beyond this epoch @return Epoch which contains _block """ # Binary search _min: uint256 = 0 _max: uint256 = max_epoch for i in range(128): # Will be always enough for 128-bit numbers if _min >= _max: break _mid: uint256 = (_min + _max + 1) / 2 if self.point_history[_mid].blk <= _block: _min = _mid else: _max = _mid - 1 return _min @internal @view def find_timestamp_epoch(_timestamp: uint256, max_epoch: uint256) -> uint256: """ @notice Binary search to find epoch for timestamp @param _timestamp timestamp to find @param max_epoch Don't go beyond this epoch @return Epoch which contains _timestamp """ # Binary search _min: uint256 = 0 _max: uint256 = max_epoch for i in range(128): # Will be always enough for 128-bit numbers if _min >= _max: break _mid: uint256 = (_min + _max + 1) / 2 if self.point_history[_mid].ts <= _timestamp: _min = _mid else: _max = _mid - 1 return _min @internal @view def find_block_user_epoch(_addr: address, _block: uint256, max_epoch: uint256) -> uint256: """ @notice Binary search to find epoch for block number @param _addr User for which to find user epoch for @param _block Block to find @param max_epoch Don't go beyond this epoch @return Epoch which contains _block """ # Binary search _min: uint256 = 0 _max: uint256 = max_epoch for i in range(128): # Will be always enough for 128-bit numbers if _min >= _max: break _mid: uint256 = (_min + _max + 1) / 2 if self.user_point_history[_addr][_mid].blk <= _block: _min = _mid else: _max = _mid - 1 return _min @internal @view def find_timestamp_user_epoch(_addr: address, _timestamp: uint256, max_epoch: uint256) -> uint256: """ @notice Binary search to find user epoch for timestamp @param _addr User for which to find user epoch for @param _timestamp timestamp to find @param max_epoch Don't go beyond this epoch @return Epoch which contains _timestamp """ # Binary search _min: uint256 = 0 _max: uint256 = max_epoch for i in range(128): # Will be always enough for 128-bit numbers if _min >= _max: break _mid: uint256 = (_min + _max + 1) / 2 if self.user_point_history[_addr][_mid].ts <= _timestamp: _min = _mid else: _max = _mid - 1 return _min @external @view def balanceOf(addr: address, _t: uint256 = block.timestamp) -> uint256: """ @notice Get the current voting power for `msg.sender` @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility @param addr User wallet address @param _t Epoch time to return voting power at @return User voting power """ _epoch: uint256 = 0 if _t == block.timestamp: # No need to do binary search, will always live in current epoch _epoch = self.user_point_epoch[addr] else: _epoch = self.find_timestamp_user_epoch(addr, _t, self.user_point_epoch[addr]) if _epoch == 0: return 0 else: last_point: Point = self.user_point_history[addr][_epoch] last_point.bias -= last_point.slope * convert(_t - last_point.ts, int128) if last_point.bias < 0: last_point.bias = 0 return convert(last_point.bias, uint256) @external @view def balanceOfAt(addr: address, _block: uint256) -> uint256: """ @notice Measure voting power of `addr` at block height `_block` @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime @param addr User's wallet address @param _block Block to calculate the voting power at @return Voting power """ # Copying and pasting totalSupply code because Vyper cannot pass by # reference yet assert _block <= block.number _user_epoch: uint256 = self.find_block_user_epoch(addr, _block, self.user_point_epoch[addr]) upoint: Point = self.user_point_history[addr][_user_epoch] max_epoch: uint256 = self.epoch _epoch: uint256 = self.find_block_epoch(_block, max_epoch) point_0: Point = self.point_history[_epoch] d_block: uint256 = 0 d_t: uint256 = 0 if _epoch < max_epoch: point_1: Point = self.point_history[_epoch + 1] d_block = point_1.blk - point_0.blk d_t = point_1.ts - point_0.ts else: d_block = block.number - point_0.blk d_t = block.timestamp - point_0.ts block_time: uint256 = point_0.ts if d_block != 0: block_time += d_t * (_block - point_0.blk) / d_block upoint.bias -= upoint.slope * convert(block_time - upoint.ts, int128) if upoint.bias >= 0: return convert(upoint.bias, uint256) else: return 0 @internal @view def supply_at(point: Point, t: uint256) -> uint256: """ @notice Calculate total voting power at some point in the past @param point The point (bias/slope) to start search from @param t Time to calculate the total voting power at @return Total voting power at that time """ last_point: Point = point t_i: uint256 = (last_point.ts / WEEK) * WEEK for i in range(255): t_i += WEEK d_slope: int128 = 0 if t_i > t: t_i = t else: d_slope = self.slope_changes[t_i] last_point.bias -= last_point.slope * convert(t_i - last_point.ts, int128) if t_i == t: break last_point.slope += d_slope last_point.ts = t_i if last_point.bias < 0: last_point.bias = 0 return convert(last_point.bias, uint256) @external @view def totalSupply(t: uint256 = block.timestamp) -> uint256: """ @notice Calculate total voting power @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility @return Total voting power """ _epoch: uint256 = 0 if t == block.timestamp: # No need to do binary search, will always live in current epoch _epoch = self.epoch else: _epoch = self.find_timestamp_epoch(t, self.epoch) if _epoch == 0: return 0 else: last_point: Point = self.point_history[_epoch] return self.supply_at(last_point, t) @external @view def totalSupplyAt(_block: uint256) -> uint256: """ @notice Calculate total voting power at some point in the past @param _block Block to calculate the total voting power at @return Total voting power at `_block` """ assert _block <= block.number _epoch: uint256 = self.epoch target_epoch: uint256 = self.find_block_epoch(_block, _epoch) point: Point = self.point_history[target_epoch] dt: uint256 = 0 if target_epoch < _epoch: point_next: Point = self.point_history[target_epoch + 1] if point.blk != point_next.blk: dt = (_block - point.blk) * (point_next.ts - point.ts) / (point_next.blk - point.blk) else: if point.blk != block.number: dt = (_block - point.blk) * (block.timestamp - point.ts) / (block.number - point.blk) # Now dt contains info on how far are we beyond point return self.supply_at(point, point.ts + dt) @external @nonreentrant("lock") def claimExternalRewards(): """ @notice Claims BAL rewards @dev Only possible if the TOKEN is Guage contract """ BalancerMinter(self.balMinter).mint(self.TOKEN) balBalance: uint256 = ERC20(self.balToken).balanceOf(self) if balBalance > 0: # distributes rewards using rewardDistributor into current week if self.rewardReceiver == self.rewardDistributor: assert ERC20(self.balToken).approve(self.rewardDistributor, balBalance, default_return_value=True) RewardDistributor(self.rewardDistributor).depositToken(self.balToken, balBalance) else: assert ERC20(self.balToken).transfer(self.rewardReceiver, balBalance, default_return_value=True) @external def changeRewardReceiver(newReceiver: address): """ @notice Changes the reward receiver address @param newReceiver New address to set as the reward receiver """ assert msg.sender == self.admin, '!admin' assert (self.rewardReceiverChangeable), '!available' assert newReceiver != empty(address), '!empty' self.rewardReceiver = newReceiver log RewardReceiver(newReceiver)
[{"name":"CommitOwnership","inputs":[{"name":"admin","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"ApplyOwnership","inputs":[{"name":"admin","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"EarlyUnlock","inputs":[{"name":"status","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"PenaltySpeed","inputs":[{"name":"penalty_k","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"PenaltyTreasury","inputs":[{"name":"penalty_treasury","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"TotalUnlock","inputs":[{"name":"status","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"RewardReceiver","inputs":[{"name":"newReceiver","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"Deposit","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false},{"name":"locktime","type":"uint256","indexed":true},{"name":"type","type":"int128","indexed":false},{"name":"ts","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Withdraw","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false},{"name":"ts","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"WithdrawEarly","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"penalty","type":"uint256","indexed":false},{"name":"time_left","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Supply","inputs":[{"name":"prevSupply","type":"uint256","indexed":false},{"name":"supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"function","name":"initialize","inputs":[{"name":"_token_addr","type":"address"},{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_admin_addr","type":"address"},{"name":"_admin_unlock_all","type":"address"},{"name":"_admin_early_unlock","type":"address"},{"name":"_max_time","type":"uint256"},{"name":"_balToken","type":"address"},{"name":"_balMinter","type":"address"},{"name":"_rewardReceiver","type":"address"},{"name":"_rewardReceiverChangeable","type":"bool"},{"name":"_rewardDistributor","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"token","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"commit_transfer_ownership","inputs":[{"name":"addr","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"apply_transfer_ownership","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"commit_smart_wallet_checker","inputs":[{"name":"addr","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"apply_smart_wallet_checker","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_early_unlock","inputs":[{"name":"_early_unlock","type":"bool"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_early_unlock_penalty_speed","inputs":[{"name":"_penalty_k","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_penalty_treasury","inputs":[{"name":"_penalty_treasury","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_all_unlock","inputs":[],"outputs":[]},{"stateMutability":"view","type":"function","name":"get_last_user_slope","inputs":[{"name":"addr","type":"address"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"user_point_history__ts","inputs":[{"name":"_addr","type":"address"},{"name":"_idx","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"locked__end","inputs":[{"name":"_addr","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"checkpoint","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"deposit_for","inputs":[{"name":"_addr","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"create_lock","inputs":[{"name":"_value","type":"uint256"},{"name":"_unlock_time","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"increase_amount","inputs":[{"name":"_value","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"increase_unlock_time","inputs":[{"name":"_unlock_time","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"withdraw_early","inputs":[],"outputs":[]},{"stateMutability":"view","type":"function","name":"balanceOf","inputs":[{"name":"addr","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"balanceOf","inputs":[{"name":"addr","type":"address"},{"name":"_t","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"balanceOfAt","inputs":[{"name":"addr","type":"address"},{"name":"_block","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalSupply","inputs":[{"name":"t","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalSupplyAt","inputs":[{"name":"_block","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claimExternalRewards","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"changeRewardReceiver","inputs":[{"name":"newReceiver","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"MAXTIME","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"TOKEN","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"supply","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"locked","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"amount","type":"int128"},{"name":"end","type":"uint256"}]}]},{"stateMutability":"view","type":"function","name":"epoch","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"point_history","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"bias","type":"int128"},{"name":"slope","type":"int128"},{"name":"ts","type":"uint256"},{"name":"blk","type":"uint256"}]}]},{"stateMutability":"view","type":"function","name":"user_point_history","inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"uint256"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"bias","type":"int128"},{"name":"slope","type":"int128"},{"name":"ts","type":"uint256"},{"name":"blk","type":"uint256"}]}]},{"stateMutability":"view","type":"function","name":"user_point_epoch","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"slope_changes","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"future_smart_wallet_checker","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"smart_wallet_checker","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"admin","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"admin_unlock_all","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"admin_early_unlock","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"future_admin","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"is_initialized","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"early_unlock","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"penalty_k","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"prev_penalty_k","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"penalty_upd_ts","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"penalty_treasury","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"balMinter","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"balToken","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"rewardReceiver","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"rewardReceiverChangeable","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"rewardDistributor","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"all_unlock","inputs":[],"outputs":[{"name":"","type":"bool"}]}]
Contract Creation Code
613bea61001161000039613bea610000f36003361161000c57612d19565b60003560e01c34613bd857639bf6abf3811861047c576101c43610613bd8576004358060a01c613bd8576040526024356004016040813511613bd8578035806060526020820181816080375050506044356004016020813511613bd85780358060c05260208201803560e0525050506064358060a01c613bd857610100526084358060a01c613bd8576101205260a4358060a01c613bd8576101405260e4358060a01c613bd85761016052610104358060a01c613bd85761018052610124358060a01c613bd8576101a052610144358060011c613bd8576101c052610164358060a01c613bd8576101e0526c050c783eb9b5c84000000000155415610171576009610200527f6f6e6c79206f6e636500000000000000000000000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b60016c050c783eb9b5c840000000001555610100516101f0576006610200527f21656d70747900000000000000000000000000000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b610100516c050c783eb9b5c840000000001155600a6c050c783eb9b5c840000000001755600a6c050c783eb9b5c840000000001855426c050c783eb9b5c840000000001955610100516c050c783eb9b5c840000000001a5560405160025543600f5542600e5560405163313ce567610220526020610220600461023c845afa61027e573d600060003e3d6000fd5b60203d10613bd8576102209050516102005260066102005110156102a35760006102ac565b60ff6102005111155b610316576009610220527f21646563696d616c7300000000000000000000000000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b60605180600355600081601f0160051c60028111613bd857801561034e57905b8060051b608001518160040155600101818118610336575b50505060c0518060065560e051600755506102005160085562093a8060c435101561037a576000610385565b63095f6a0060c43511155b6103ef576008610220527f216d61786c6f636b0000000000000000000000000000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b60c435600155610120516c050c783eb9b5c840000000001255610140516c050c783eb9b5c840000000001355610160516c050c783eb9b5c840000000001c55610180516c050c783eb9b5c840000000001b556101a0516c050c783eb9b5c840000000001d556101c0516c050c783eb9b5c840000000001e556101e0516c050c783eb9b5c840000000001f55005b63fc0c546a811861049b5760043610613bd85760025460405260206040f35b6306fdde0381186105205760043610613bd8576020806040528060400160035480825260208201600082601f0160051c60028111613bd85780156104f257905b80600401548160051b8401526001018181186104db575b505050508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b6395d89b4181186105785760043610613bd8576020806040528060400160065480825260208201600754815250508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b63313ce56781186105975760043610613bd85760085460405260206040f35b636b441a40811861060d5760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c8400000000011543318613bd8576040516c050c783eb9b5c8400000000014557f2f56810a6bf40af059b96d3aea4db54081f378029a518390491093a7b67032e960405160605260206060a1005b636a1c05ae811861068f5760043610613bd8576c050c783eb9b5c8400000000011543318613bd8576c050c783eb9b5c84000000000145460405260405115613bd8576040516c050c783eb9b5c8400000000011557febee2d5739011062cb4f14113f3b36bf0ffe3da5c0568f64189d1012a118910560405160605260206060a1005b6357f901e281186106d95760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c8400000000011543318613bd8576040516c050c783eb9b5c840000000000f55005b638e5b490f81186107215760043610613bd8576c050c783eb9b5c8400000000011543318613bd8576c050c783eb9b5c840000000000f546c050c783eb9b5c840000000001055005b6355a3323581186108695760243610613bd8576004358060011c613bd8576040526c050c783eb9b5c8400000000013543318156107b55760066060527f2161646d696e000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6c050c783eb9b5c840000000001654604051186108295760076060527f616c72656164790000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516c050c783eb9b5c8400000000016557f66515f71c349ef0ad8c6981cedaa58746200512e6e12754c5ac5cc701d5cf41860405160605260206060a1005b63655317ae8118610a445760243610613bd8576c050c783eb9b5c8400000000013543318156108ef5760066040527f2161646d696e000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b603260043511156109575760026040527f216b00000000000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6c050c783eb9b5c840000000001954603c8101818110613bd857905042116109d65760056040527f6561726c7900000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6c050c783eb9b5c8400000000017546c050c783eb9b5c8400000000018556004356c050c783eb9b5c840000000001755426c050c783eb9b5c8400000000019557f9c04360e3c3de1eeca25bbd4a21cdc22c4c192f4b91f91d2a0c59dcd042f8ba860043560405260206040a1005b63af3097af8118610b7c5760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000001354331815610ad85760066060527f2161646d696e000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b604051610b3c5760056060527f217a65726f00000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516c050c783eb9b5c840000000001a557ff51c492eafc918620c2d49b196e6a4e0cac71709d348224a8e7fc231ee973e5960405160605260206060a1005b6366e01ca98118610c405760043610613bd8576c050c783eb9b5c840000000001254331815610c025760066040527f2161646d696e000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b60016c050c783eb9b5c8400000000020557f7ca88488f569b55d1fb073429f75839e505182c1f6d26e5caed22e9828df430c600160405260206040a1005b637c74a1748118610cc25760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000d6040516020526000526040600020546060526c050c783eb9b5c840000000000c6040516020526000526040600020606051633b9ac9ff8111613bd85760021b810190506001810190505460805260206080f35b63da020a188118610d245760443610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000c6040516020526000526040600020602435633b9ac9ff8111613bd85760021b810190506002810190505460605260206060f35b63adc635898118610d655760243610613bd8576004358060a01c613bd857604052600a60405160205260005260406000206001810190505460605260206060f35b63c2c4c5c18118610d885760043610613bd85760a036604037610d86612e17565b005b633a46273e8118610f345760443610613bd8576004358060a01c613bd8576105e052600054600214613bd8576002600055600a6105e05160205260005260406000208054610600526001810154610620525060243515613bd8576001610600511215610e54576016610640527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b426106205111610ee9576024610640527f43616e6e6f742061646420746f2065787069726564206c6f636b2e2057697468610660527f64726177000000000000000000000000000000000000000000000000000000006106805261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b6105e0516103e05260243561040052600061042052600a6105e051602052600052604060002080546104405260018101546104605250600061048052610f2d61352a565b6003600055005b6365fc3873811861116a5760443610613bd857600054600214613bd857600260005533604052610f62612d1f565b60243562093a808104905062093a8081028162093a80820418613bd85790506105e052600a3360205260005260406000208054610600526001810154610620525060043515613bd857610600511561101a576019610640527f5769746864726177206f6c6420746f6b656e73206669727374000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b426105e051116110af576026610640527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e2074686520610660527f66757475726500000000000000000000000000000000000000000000000000006106805261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b42600154808201828110613bd857905090506105e0511115611131576014610640527f566f74696e67206c6f636b20746f6f206c6f6e670000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b336103e052600435610400526105e051610420526106005161044052610620516104605260016104805261116361352a565b6003600055005b634957677c81186112fc5760243610613bd857600054600214613bd857600260005533604052611198612d1f565b600a33602052600052604060002080546105e0526001810154610600525060043515613bd85760016105e0511215611230576016610620527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006106405261062050610620518061064001601f826000031636823750506308c379a06105e052602061060052601f19601f6106205101166044016105fcfd5b4261060051116112c5576024610620527f43616e6e6f742061646420746f2065787069726564206c6f636b2e2057697468610640527f64726177000000000000000000000000000000000000000000000000000000006106605261062050610620518061064001601f826000031636823750506308c379a06105e052602061060052601f19601f6106205101166044016105fcfd5b336103e052600435610400526000610420526105e0516104405261060051610460526002610480526112f561352a565b6003600055005b63eff7a612811861157a5760243610613bd857600054600214613bd85760026000553360405261132a612d1f565b600a33602052600052604060002080546105e0526001810154610600525060043562093a808104905062093a8081028162093a80820418613bd8579050610620524261060051116113db57600c610640527f4c6f636b206578706972656400000000000000000000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b60016105e051121561144d576011610640527f4e6f7468696e67206973206c6f636b65640000000000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b6106005161062051116114c057601f610640527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b42600154808201828110613bd85790509050610620511115611542576014610640527f566f74696e67206c6f636b20746f6f206c6f6e670000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b336103e05260006104005261062051610420526105e05161044052610600516104605260036104805261157361352a565b6003600055005b633ccfd60b81186117cf5760043610613bd857600054600214613bd8576002600055600a33602052600052604060002080546103e05260018101546104005250610400514210156115d9576c050c783eb9b5c8400000000020546115dc565b60015b611646576017610420527f6c6f636b2021657870697265206f722021756e6c6f636b0000000000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b6103e05160008112613bd857610420526103e05161044052610400516104605260006104005260006103e052600a3360205260005260406000206103e051815561040051600182015550600954610480526104805161042051808203828111613bd857905090506009553360405261044051606052610460516080526103e05160a0526104005160c0526116d8612e17565b60025463a9059cbb6104a052336104c052610420516104e05260206104a060446104bc6000855af161170f573d600060003e3d6000fd5b3d61172657803b15613bd85760016105005261173f565b60203d10613bd8576104a0518060011c613bd857610500525b61050090505115613bd857337ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568610420516104a052426104c05260406104a0a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c610480516104a0526104805161042051808203828111613bd857905090506104c05260406104a0a16003600055005b638239f0648118611c6e5760043610613bd857600054600214613bd857600260005560016c050c783eb9b5c840000000001654181561186e57600d6103e0527f216561726c7920756e6c6f636b00000000000000000000000000000000000000610400526103e0506103e0518061040001601f826000031636823750506308c379a06103a05260206103c052601f19601f6103e05101166044016103bcfd5b600a33602052600052604060002080546103e052600181015461040052506104005142106118fc57600c610420527f6c6f636b206578706972656400000000000000000000000000000000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b6103e05160008112613bd857610420526104005142808203828111613bd85790509050610440526000610460526c050c783eb9b5c840000000001954603c8101818110613bd85790504211611963576c050c783eb9b5c84000000000185461046052611977565b6c050c783eb9b5c840000000001754610460525b61044051670de0b6b3a7640000810281670de0b6b3a7640000820418613bd85790506001548015613bd8578082049050905061046051808202811583838304141715613bd85790509050610480526104205161048051808202811583838304141715613bd85790509050670de0b6b3a764000081049050600a810490506104a052610420516104a0511115611a0f57610420516104a0525b610420516104a051808203828111613bd857905090506104c0526103e0516104e052610400516105005260006104005260006103e052600a3360205260005260406000206103e051815561040051600182015550600954610520526105205161042051808203828111613bd85790509050600955336040526104e051606052610500516080526103e05160a0526104005160c052611aab612e17565b6104a05115611b355760025463a9059cbb610540526c050c783eb9b5c840000000001a54610560526104a051610580526020610540604461055c6000855af1611af9573d600060003e3d6000fd5b3d611b1057803b15613bd85760016105a052611b29565b60203d10613bd857610540518060011c613bd8576105a0525b6105a090505115613bd8575b6104c05115611bb15760025463a9059cbb6105405233610560526104c051610580526020610540604461055c6000855af1611b75573d600060003e3d6000fd5b3d611b8c57803b15613bd85760016105a052611ba5565b60203d10613bd857610540518060011c613bd8576105a0525b6105a090505115613bd8575b337ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568610420516105405242610560526040610540a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c61052051610540526105205161042051808203828111613bd85790509050610560526040610540a1337ff11a1a5a36ad286d4f77c166e8d87e5bfe87d1e74f9c46654ef21bd811c6784f6104a0516105405261044051610560526040610540a26003600055005b6370a082318118611c8b5760243610613bd8574261014052611ca5565b62fdd58e8118611e345760443610613bd857602435610140525b6004358060a01c613bd85761012052600061016052426101405118611ceb576c050c783eb9b5c840000000000d6101205160205260005260406000205461016052611d2e565b61012051604052610140516060526c050c783eb9b5c840000000000d61012051602052600052604060002054608052611d256101806139a2565b61018051610160525b61016051611d4a576000610180526020610180611e3256611e32565b6c050c783eb9b5c840000000000c61012051602052600052604060002061016051633b9ac9ff8111613bd85760021b8101905080546101805260018101546101a05260028101546101c05260038101546101e05250610180516101a051610140516101c051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd85790509050610180527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101805113611e1c576000610180525b6101805160008112613bd8576102005260206102005bf35b634ee2cd7e811861210f5760443610613bd8576004358060a01c613bd857610120524360243511613bd857610120516040526024356060526c050c783eb9b5c840000000000d61012051602052600052604060002054608052611e986101606138da565b61016051610140526c050c783eb9b5c840000000000c61012051602052600052604060002061014051633b9ac9ff8111613bd85760021b8101905080546101605260018101546101805260028101546101a05260038101546101c05250600b546101e0526024356040526101e051606052611f1461022061377a565b6102205161020052610200516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c01805461022052600181015461024052600281015461026052600381015461028052506040366102a0376101e0516102005110611fa3574361028051808203828111613bd857905090506102a0524261026051808203828111613bd857905090506102c052612025565b6102005160018101818110613bd85790506c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0180546102e052600181015461030052600281015461032052600381015461034052506103405161028051808203828111613bd857905090506102a0526103205161026051808203828111613bd857905090506102c0525b610260516102e0526102a0511561208b576102e0516102c05160243561028051808203828111613bd85790509050808202811583838304141715613bd857905090506102a0518015613bd85780820490509050808201828110613bd857905090506102e0525b61016051610180516102e0516101a051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd857905090506101605260006101605112156120f757600061030052602061030061210d5661210d565b6101605160008112613bd8576103005260206103005bf35b6318160ddd811861212c5760043610613bd857426101c052612147565b63bd85b03981186122165760243610613bd8576004356101c0525b60006101e052426101c0511861216357600b546101e052612184565b6101c051604052600b5460605261217b61020061382a565b610200516101e0525b6101e0516121a057600061020052602061020061221456612214565b6101e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c018054610200526001810154610220526002810154610240526003810154610260525060206102005160405261022051606052610240516080526102605160a0526101c05160c052612210610280613a6a565b6102805bf35b63981b24d081186124235760243610613bd8574360043511613bd857600b546101c0526004356040526101c05160605261225161020061377a565b610200516101e0526101e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c01805461020052600181015461022052600281015461024052600381015461026052506000610280526101c0516101e0511061231b574361026051146123dc5760043561026051808203828111613bd857905090504261024051808203828111613bd85790509050808202811583838304141715613bd857905090504361026051808203828111613bd857905090508015613bd85780820490509050610280526123dc565b6101e05160018101818110613bd85790506c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0180546102a05260018101546102c05260028101546102e052600381015461030052506103005161026051146123dc5760043561026051808203828111613bd857905090506102e05161024051808203828111613bd85790509050808202811583838304141715613bd857905090506103005161026051808203828111613bd857905090508015613bd85780820490509050610280525b60206102005160405261022051606052610240516080526102605160a0526102405161028051808201828110613bd8579050905060c05261241e6102a0613a6a565b6102a0f35b63db93cc7a811861265e5760043610613bd857600054600214613bd85760026000556c050c783eb9b5c840000000001b54636a627842604052600254606052602060406024605c6000855af161247e573d600060003e3d6000fd5b60203d10613bd857604050506c050c783eb9b5c840000000001c546370a0823160605230608052602060606024607c845afa6124bf573d600060003e3d6000fd5b60203d10613bd857606090505160405260405115612657576c050c783eb9b5c840000000001f546c050c783eb9b5c840000000001d54186125d4576c050c783eb9b5c840000000001c5463095ea7b36060526c050c783eb9b5c840000000001f5460805260405160a052602060606044607c6000855af1612545573d600060003e3d6000fd5b3d61255b57803b15613bd857600160c052612572565b60203d10613bd8576060518060011c613bd85760c0525b60c090505115613bd8576c050c783eb9b5c840000000001f5463338b5dea6060526c050c783eb9b5c840000000001c5460805260405160a052803b15613bd857600060606044607c6000855af16125ce573d600060003e3d6000fd5b50612657565b6c050c783eb9b5c840000000001c5463a9059cbb6060526c050c783eb9b5c840000000001d5460805260405160a052602060606044607c6000855af161261f573d600060003e3d6000fd5b3d61263557803b15613bd857600160c05261264c565b60203d10613bd8576060518060011c613bd85760c0525b60c090505115613bd8575b6003600055005b63cb8e090d81186128065760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c8400000000011543318156126f25760066060527f2161646d696e000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6c050c783eb9b5c840000000001e5461276257600a6060527f21617661696c61626c650000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516127c65760066060527f21656d707479000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516c050c783eb9b5c840000000001d557f454ccf21cdac2e344d64173597f5922657c25c5b1e6c3f733791637513d2063760405160605260206060a1005b63ee00ef3a81186128255760043610613bd85760015460405260206040f35b6382bfefc881186128445760043610613bd85760025460405260206040f35b63047fc9aa81186128635760043610613bd85760095460405260206040f35b63cbf9fe5f81186128a85760243610613bd8576004358060a01c613bd857604052600a6040516020526000526040600020805460605260018101546080525060406060f35b63900cf0cf81186128c75760043610613bd857600b5460405260206040f35b63d1febfb9811861291b5760243610613bd8576004356c01431e0fae6d7217ca9fffffff8111613bd85760021b600c01805460405260018101546060526002810154608052600381015460a0525060806040f35b6328d09d4781186129915760443610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000c6040516020526000526040600020602435633b9ac9ff8111613bd85760021b8101905080546060526001810154608052600281015460a052600381015460c0525060806060f35b63010ae75781186129d85760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000d60405160205260005260406000205460605260206060f35b63711974848118612a115760243610613bd8576c050c783eb9b5c840000000000e60043560205260005260406000205460405260206040f35b638ff36fd18118612a3c5760043610613bd8576c050c783eb9b5c840000000000f5460405260206040f35b637175d4f78118612a675760043610613bd8576c050c783eb9b5c84000000000105460405260206040f35b63f851a4408118612a925760043610613bd8576c050c783eb9b5c84000000000115460405260206040f35b63142614258118612abd5760043610613bd8576c050c783eb9b5c84000000000125460405260206040f35b6322cf35f58118612ae85760043610613bd8576c050c783eb9b5c84000000000135460405260206040f35b6317f7182a8118612b135760043610613bd8576c050c783eb9b5c84000000000145460405260206040f35b639a01873c8118612b3e5760043610613bd8576c050c783eb9b5c84000000000155460405260206040f35b63f68467278118612b695760043610613bd8576c050c783eb9b5c84000000000165460405260206040f35b63cd8c79aa8118612b945760043610613bd8576c050c783eb9b5c84000000000175460405260206040f35b63094cda238118612bbf5760043610613bd8576c050c783eb9b5c84000000000185460405260206040f35b63205ad4088118612bea5760043610613bd8576c050c783eb9b5c84000000000195460405260206040f35b635836ec3a8118612c155760043610613bd8576c050c783eb9b5c840000000001a5460405260206040f35b6373f43d6d8118612c405760043610613bd8576c050c783eb9b5c840000000001b5460405260206040f35b6338d546458118612c6b5760043610613bd8576c050c783eb9b5c840000000001c5460405260206040f35b631dac30b08118612c965760043610613bd8576c050c783eb9b5c840000000001d5460405260206040f35b63b027651a8118612cc15760043610613bd8576c050c783eb9b5c840000000001e5460405260206040f35b63acc2166a8118612cec5760043610613bd8576c050c783eb9b5c840000000001f5460405260206040f35b63b3d8f7e78118612d175760043610613bd8576c050c783eb9b5c84000000000205460405260206040f35b505b60006000fd5b3260405114612e15576c050c783eb9b5c84000000000105460605260605115612d945760605163c23697a860805260405160a052602060806024609c6000855af1612d6f573d600060003e3d6000fd5b60203d10613bd8576080518060011c613bd85760c05260c090505115612d9457612e15565b60256080527f536d61727420636f6e7472616374206465706f7369746f7273206e6f7420616c60a0527f6c6f77656400000000000000000000000000000000000000000000000000000060c0526080506080518060a001601f826000031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b565b6101403660e037600b546102205260405115612f83574260805111612e3d576000612e45565b600160605112155b15612ea65760605160015480607f1c613bd8578015613bd85780820580600f0b8118613bd85790509050610100526101005160805142808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905060e0525b4260c05111612eb6576000612ebe565b600160a05112155b15612f205760a05160015480607f1c613bd8578015613bd85780820580600f0b8118613bd85790509050610180526101805160c05142808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd85790509050610160525b6c050c783eb9b5c840000000000e6080516020526000526040600020546101e05260c05115612f835760805160c05118612f61576101e05161020052612f83565b6c050c783eb9b5c840000000000e60c051602052600052604060002054610200525b604036610240374261028052436102a0526102205115612fde57610220516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0180546102405260018101546102605260028101546102805260038101546102a052505b610280516102c052610240516102e052610260516103005261028051610320526102a051610340526000610360526102805142111561306d57436102a051808203828111613bd85790509050670de0b6b3a7640000810281670de0b6b3a7640000820418613bd85790504261028051808203828111613bd857905090508015613bd85780820490509050610360525b6102c05162093a808104905062093a8081028162093a80820418613bd857905061038052600060ff905b806103a0526103805162093a808101818110613bd85790506103805260006103c0524261038051116130ea576c050c783eb9b5c840000000000e610380516020526000526040600020546103c0526130f0565b42610380525b6102405161026051610380516102c051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd8579050905061024052610260516103c05180820180600f0b8118613bd85790509050610260527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610240511361318a576000610240525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61026051136131bb576000610260525b610380516102c052610380516102805261034051610360516103805161032051808203828111613bd85790509050808202811583838304141715613bd85790509050670de0b6b3a764000081049050808201828110613bd857905090506102a0526102205160018101818110613bd85790506102205242610380511861324957436102a0526132955661328a565b610220516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c016102405181556102605160018201556102805160028201556102a0516003820155505b600101818118613097575b505061022051600b556040511561336b5761026051610180516101005180820380600f0b8118613bd8579050905080820180600f0b8118613bd8579050905061026052610240516101605160e05180820380600f0b8118613bd8579050905080820180600f0b8118613bd85790509050610240527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610260511361333a576000610260525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610240511361336b576000610240525b610220516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c016102405181556102605160018201556102805160028201556102a0516003820155506040511561352857426080511115613425576101e0516101005180820180600f0b8118613bd857905090506101e05260805160c05118613403576101e0516101805180820380600f0b8118613bd857905090506101e0525b6101e0516c050c783eb9b5c840000000000e6080516020526000526040600020555b4260c051111561347a5760805160c051111561347a57610200516101805180820380600f0b8118613bd8579050905061020052610200516c050c783eb9b5c840000000000e60c0516020526000526040600020555b6c050c783eb9b5c840000000000d60405160205260005260406000205460018101818110613bd85790506103a0526103a0516c050c783eb9b5c840000000000d604051602052600052604060002055426101a052436101c0526c050c783eb9b5c840000000000c60405160205260005260406000206103a051633b9ac9ff8111613bd85760021b810190506101605181556101805160018201556101a05160028201556101c0516003820155505b565b6c050c783eb9b5c840000000002054156135a45760156104a0527f616c6c20756e6c6f636b65642c6e6f2073656e736500000000000000000000006104c0526104a0506104a051806104c001601f826000031636823750506308c379a061046052602061048052601f19601f6104a051011660440161047cfd5b610440516104a052610460516104c0526009546104e0526104e05161040051808201828110613bd857905090506009556104a051610500526104c051610520526104a0516104005180607f1c613bd85780820180600f0b8118613bd857905090506104a052610420511561361b57610420516104c0525b600a6103e05160205260005260406000206104a05181556104c0516001820155506103e05160405261050051606052610520516080526104a05160a0526104c05160c052613667612e17565b61040051156136eb576002546323b872dd610540526103e051610560523061058052610400516105a0526020610540606461055c6000855af16136af573d600060003e3d6000fd5b3d6136c657803b15613bd85760016105c0526136df565b60203d10613bd857610540518060011c613bd8576105c0525b6105c090505115613bd8575b6104c0516103e0517f4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d596104005161054052610480516105605242610580526060610540a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c6104e051610540526104e05161040051808201828110613bd85790509050610560526040610540a1565b600060805260605160a05260006080905b8060c05260a0516080511061379f57613820565b60805160a051808201828110613bd8579050905060018101818110613bd85790508060011c905060e05260405160e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0160038101905054111561380e5760e05160018103818111613bd857905060a052613815565b60e0516080525b60010181811861378b575b5050608051815250565b600060805260605160a05260006080905b8060c05260a0516080511061384f576138d0565b60805160a051808201828110613bd8579050905060018101818110613bd85790508060011c905060e05260405160e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c016002810190505411156138be5760e05160018103818111613bd857905060a0526138c5565b60e0516080525b60010181811861383b575b5050608051815250565b600060a05260805160c05260006080905b8060e05260c05160a051106138ff57613998565b60a05160c051808201828110613bd8579050905060018101818110613bd85790508060011c9050610100526060516c050c783eb9b5c840000000000c604051602052600052604060002061010051633b9ac9ff8111613bd85760021b81019050600381019050541115613985576101005160018103818111613bd857905060c05261398d565b6101005160a0525b6001018181186138eb575b505060a051815250565b600060a05260805160c05260006080905b8060e05260c05160a051106139c757613a60565b60a05160c051808201828110613bd8579050905060018101818110613bd85790508060011c9050610100526060516c050c783eb9b5c840000000000c604051602052600052604060002061010051633b9ac9ff8111613bd85760021b81019050600281019050541115613a4d576101005160018103818111613bd857905060c052613a55565b6101005160a0525b6001018181186139b3575b505060a051815250565b60405160e052606051610100526080516101205260a051610140526101205162093a808104905062093a8081028162093a80820418613bd857905061016052600060ff905b80610180526101605162093a808101818110613bd85790506101605260006101a05260c0516101605111613b04576c050c783eb9b5c840000000000e610160516020526000526040600020546101a052613b0c565b60c051610160525b60e051610100516101605161012051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd8579050905060e05260c0516101605118613b6757613b97565b610100516101a05180820180600f0b8118613bd85790509050610100526101605161012052600101818118613aaf575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60e05113613bc857600060e0525b60e05160008112613bd857815250565b600080fda165767970657283000307000b
Deployed Bytecode
0x6003361161000c57612d19565b60003560e01c34613bd857639bf6abf3811861047c576101c43610613bd8576004358060a01c613bd8576040526024356004016040813511613bd8578035806060526020820181816080375050506044356004016020813511613bd85780358060c05260208201803560e0525050506064358060a01c613bd857610100526084358060a01c613bd8576101205260a4358060a01c613bd8576101405260e4358060a01c613bd85761016052610104358060a01c613bd85761018052610124358060a01c613bd8576101a052610144358060011c613bd8576101c052610164358060a01c613bd8576101e0526c050c783eb9b5c84000000000155415610171576009610200527f6f6e6c79206f6e636500000000000000000000000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b60016c050c783eb9b5c840000000001555610100516101f0576006610200527f21656d70747900000000000000000000000000000000000000000000000000006102205261020050610200518061022001601f826000031636823750506308c379a06101c05260206101e052601f19601f6102005101166044016101dcfd5b610100516c050c783eb9b5c840000000001155600a6c050c783eb9b5c840000000001755600a6c050c783eb9b5c840000000001855426c050c783eb9b5c840000000001955610100516c050c783eb9b5c840000000001a5560405160025543600f5542600e5560405163313ce567610220526020610220600461023c845afa61027e573d600060003e3d6000fd5b60203d10613bd8576102209050516102005260066102005110156102a35760006102ac565b60ff6102005111155b610316576009610220527f21646563696d616c7300000000000000000000000000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b60605180600355600081601f0160051c60028111613bd857801561034e57905b8060051b608001518160040155600101818118610336575b50505060c0518060065560e051600755506102005160085562093a8060c435101561037a576000610385565b63095f6a0060c43511155b6103ef576008610220527f216d61786c6f636b0000000000000000000000000000000000000000000000006102405261022050610220518061024001601f826000031636823750506308c379a06101e052602061020052601f19601f6102205101166044016101fcfd5b60c435600155610120516c050c783eb9b5c840000000001255610140516c050c783eb9b5c840000000001355610160516c050c783eb9b5c840000000001c55610180516c050c783eb9b5c840000000001b556101a0516c050c783eb9b5c840000000001d556101c0516c050c783eb9b5c840000000001e556101e0516c050c783eb9b5c840000000001f55005b63fc0c546a811861049b5760043610613bd85760025460405260206040f35b6306fdde0381186105205760043610613bd8576020806040528060400160035480825260208201600082601f0160051c60028111613bd85780156104f257905b80600401548160051b8401526001018181186104db575b505050508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b6395d89b4181186105785760043610613bd8576020806040528060400160065480825260208201600754815250508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b63313ce56781186105975760043610613bd85760085460405260206040f35b636b441a40811861060d5760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c8400000000011543318613bd8576040516c050c783eb9b5c8400000000014557f2f56810a6bf40af059b96d3aea4db54081f378029a518390491093a7b67032e960405160605260206060a1005b636a1c05ae811861068f5760043610613bd8576c050c783eb9b5c8400000000011543318613bd8576c050c783eb9b5c84000000000145460405260405115613bd8576040516c050c783eb9b5c8400000000011557febee2d5739011062cb4f14113f3b36bf0ffe3da5c0568f64189d1012a118910560405160605260206060a1005b6357f901e281186106d95760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c8400000000011543318613bd8576040516c050c783eb9b5c840000000000f55005b638e5b490f81186107215760043610613bd8576c050c783eb9b5c8400000000011543318613bd8576c050c783eb9b5c840000000000f546c050c783eb9b5c840000000001055005b6355a3323581186108695760243610613bd8576004358060011c613bd8576040526c050c783eb9b5c8400000000013543318156107b55760066060527f2161646d696e000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6c050c783eb9b5c840000000001654604051186108295760076060527f616c72656164790000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516c050c783eb9b5c8400000000016557f66515f71c349ef0ad8c6981cedaa58746200512e6e12754c5ac5cc701d5cf41860405160605260206060a1005b63655317ae8118610a445760243610613bd8576c050c783eb9b5c8400000000013543318156108ef5760066040527f2161646d696e000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b603260043511156109575760026040527f216b00000000000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6c050c783eb9b5c840000000001954603c8101818110613bd857905042116109d65760056040527f6561726c7900000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b6c050c783eb9b5c8400000000017546c050c783eb9b5c8400000000018556004356c050c783eb9b5c840000000001755426c050c783eb9b5c8400000000019557f9c04360e3c3de1eeca25bbd4a21cdc22c4c192f4b91f91d2a0c59dcd042f8ba860043560405260206040a1005b63af3097af8118610b7c5760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000001354331815610ad85760066060527f2161646d696e000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b604051610b3c5760056060527f217a65726f00000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516c050c783eb9b5c840000000001a557ff51c492eafc918620c2d49b196e6a4e0cac71709d348224a8e7fc231ee973e5960405160605260206060a1005b6366e01ca98118610c405760043610613bd8576c050c783eb9b5c840000000001254331815610c025760066040527f2161646d696e000000000000000000000000000000000000000000000000000060605260405060405180606001601f826000031636823750506308c379a06000526020602052601f19601f6040510116604401601cfd5b60016c050c783eb9b5c8400000000020557f7ca88488f569b55d1fb073429f75839e505182c1f6d26e5caed22e9828df430c600160405260206040a1005b637c74a1748118610cc25760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000d6040516020526000526040600020546060526c050c783eb9b5c840000000000c6040516020526000526040600020606051633b9ac9ff8111613bd85760021b810190506001810190505460805260206080f35b63da020a188118610d245760443610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000c6040516020526000526040600020602435633b9ac9ff8111613bd85760021b810190506002810190505460605260206060f35b63adc635898118610d655760243610613bd8576004358060a01c613bd857604052600a60405160205260005260406000206001810190505460605260206060f35b63c2c4c5c18118610d885760043610613bd85760a036604037610d86612e17565b005b633a46273e8118610f345760443610613bd8576004358060a01c613bd8576105e052600054600214613bd8576002600055600a6105e05160205260005260406000208054610600526001810154610620525060243515613bd8576001610600511215610e54576016610640527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b426106205111610ee9576024610640527f43616e6e6f742061646420746f2065787069726564206c6f636b2e2057697468610660527f64726177000000000000000000000000000000000000000000000000000000006106805261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b6105e0516103e05260243561040052600061042052600a6105e051602052600052604060002080546104405260018101546104605250600061048052610f2d61352a565b6003600055005b6365fc3873811861116a5760443610613bd857600054600214613bd857600260005533604052610f62612d1f565b60243562093a808104905062093a8081028162093a80820418613bd85790506105e052600a3360205260005260406000208054610600526001810154610620525060043515613bd857610600511561101a576019610640527f5769746864726177206f6c6420746f6b656e73206669727374000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b426105e051116110af576026610640527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e2074686520610660527f66757475726500000000000000000000000000000000000000000000000000006106805261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b42600154808201828110613bd857905090506105e0511115611131576014610640527f566f74696e67206c6f636b20746f6f206c6f6e670000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b336103e052600435610400526105e051610420526106005161044052610620516104605260016104805261116361352a565b6003600055005b634957677c81186112fc5760243610613bd857600054600214613bd857600260005533604052611198612d1f565b600a33602052600052604060002080546105e0526001810154610600525060043515613bd85760016105e0511215611230576016610620527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006106405261062050610620518061064001601f826000031636823750506308c379a06105e052602061060052601f19601f6106205101166044016105fcfd5b4261060051116112c5576024610620527f43616e6e6f742061646420746f2065787069726564206c6f636b2e2057697468610640527f64726177000000000000000000000000000000000000000000000000000000006106605261062050610620518061064001601f826000031636823750506308c379a06105e052602061060052601f19601f6106205101166044016105fcfd5b336103e052600435610400526000610420526105e0516104405261060051610460526002610480526112f561352a565b6003600055005b63eff7a612811861157a5760243610613bd857600054600214613bd85760026000553360405261132a612d1f565b600a33602052600052604060002080546105e0526001810154610600525060043562093a808104905062093a8081028162093a80820418613bd8579050610620524261060051116113db57600c610640527f4c6f636b206578706972656400000000000000000000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b60016105e051121561144d576011610640527f4e6f7468696e67206973206c6f636b65640000000000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b6106005161062051116114c057601f610640527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b42600154808201828110613bd85790509050610620511115611542576014610640527f566f74696e67206c6f636b20746f6f206c6f6e670000000000000000000000006106605261064050610640518061066001601f826000031636823750506308c379a061060052602061062052601f19601f61064051011660440161061cfd5b336103e05260006104005261062051610420526105e05161044052610600516104605260036104805261157361352a565b6003600055005b633ccfd60b81186117cf5760043610613bd857600054600214613bd8576002600055600a33602052600052604060002080546103e05260018101546104005250610400514210156115d9576c050c783eb9b5c8400000000020546115dc565b60015b611646576017610420527f6c6f636b2021657870697265206f722021756e6c6f636b0000000000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b6103e05160008112613bd857610420526103e05161044052610400516104605260006104005260006103e052600a3360205260005260406000206103e051815561040051600182015550600954610480526104805161042051808203828111613bd857905090506009553360405261044051606052610460516080526103e05160a0526104005160c0526116d8612e17565b60025463a9059cbb6104a052336104c052610420516104e05260206104a060446104bc6000855af161170f573d600060003e3d6000fd5b3d61172657803b15613bd85760016105005261173f565b60203d10613bd8576104a0518060011c613bd857610500525b61050090505115613bd857337ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568610420516104a052426104c05260406104a0a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c610480516104a0526104805161042051808203828111613bd857905090506104c05260406104a0a16003600055005b638239f0648118611c6e5760043610613bd857600054600214613bd857600260005560016c050c783eb9b5c840000000001654181561186e57600d6103e0527f216561726c7920756e6c6f636b00000000000000000000000000000000000000610400526103e0506103e0518061040001601f826000031636823750506308c379a06103a05260206103c052601f19601f6103e05101166044016103bcfd5b600a33602052600052604060002080546103e052600181015461040052506104005142106118fc57600c610420527f6c6f636b206578706972656400000000000000000000000000000000000000006104405261042050610420518061044001601f826000031636823750506308c379a06103e052602061040052601f19601f6104205101166044016103fcfd5b6103e05160008112613bd857610420526104005142808203828111613bd85790509050610440526000610460526c050c783eb9b5c840000000001954603c8101818110613bd85790504211611963576c050c783eb9b5c84000000000185461046052611977565b6c050c783eb9b5c840000000001754610460525b61044051670de0b6b3a7640000810281670de0b6b3a7640000820418613bd85790506001548015613bd8578082049050905061046051808202811583838304141715613bd85790509050610480526104205161048051808202811583838304141715613bd85790509050670de0b6b3a764000081049050600a810490506104a052610420516104a0511115611a0f57610420516104a0525b610420516104a051808203828111613bd857905090506104c0526103e0516104e052610400516105005260006104005260006103e052600a3360205260005260406000206103e051815561040051600182015550600954610520526105205161042051808203828111613bd85790509050600955336040526104e051606052610500516080526103e05160a0526104005160c052611aab612e17565b6104a05115611b355760025463a9059cbb610540526c050c783eb9b5c840000000001a54610560526104a051610580526020610540604461055c6000855af1611af9573d600060003e3d6000fd5b3d611b1057803b15613bd85760016105a052611b29565b60203d10613bd857610540518060011c613bd8576105a0525b6105a090505115613bd8575b6104c05115611bb15760025463a9059cbb6105405233610560526104c051610580526020610540604461055c6000855af1611b75573d600060003e3d6000fd5b3d611b8c57803b15613bd85760016105a052611ba5565b60203d10613bd857610540518060011c613bd8576105a0525b6105a090505115613bd8575b337ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568610420516105405242610560526040610540a27f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c61052051610540526105205161042051808203828111613bd85790509050610560526040610540a1337ff11a1a5a36ad286d4f77c166e8d87e5bfe87d1e74f9c46654ef21bd811c6784f6104a0516105405261044051610560526040610540a26003600055005b6370a082318118611c8b5760243610613bd8574261014052611ca5565b62fdd58e8118611e345760443610613bd857602435610140525b6004358060a01c613bd85761012052600061016052426101405118611ceb576c050c783eb9b5c840000000000d6101205160205260005260406000205461016052611d2e565b61012051604052610140516060526c050c783eb9b5c840000000000d61012051602052600052604060002054608052611d256101806139a2565b61018051610160525b61016051611d4a576000610180526020610180611e3256611e32565b6c050c783eb9b5c840000000000c61012051602052600052604060002061016051633b9ac9ff8111613bd85760021b8101905080546101805260018101546101a05260028101546101c05260038101546101e05250610180516101a051610140516101c051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd85790509050610180527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101805113611e1c576000610180525b6101805160008112613bd8576102005260206102005bf35b634ee2cd7e811861210f5760443610613bd8576004358060a01c613bd857610120524360243511613bd857610120516040526024356060526c050c783eb9b5c840000000000d61012051602052600052604060002054608052611e986101606138da565b61016051610140526c050c783eb9b5c840000000000c61012051602052600052604060002061014051633b9ac9ff8111613bd85760021b8101905080546101605260018101546101805260028101546101a05260038101546101c05250600b546101e0526024356040526101e051606052611f1461022061377a565b6102205161020052610200516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c01805461022052600181015461024052600281015461026052600381015461028052506040366102a0376101e0516102005110611fa3574361028051808203828111613bd857905090506102a0524261026051808203828111613bd857905090506102c052612025565b6102005160018101818110613bd85790506c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0180546102e052600181015461030052600281015461032052600381015461034052506103405161028051808203828111613bd857905090506102a0526103205161026051808203828111613bd857905090506102c0525b610260516102e0526102a0511561208b576102e0516102c05160243561028051808203828111613bd85790509050808202811583838304141715613bd857905090506102a0518015613bd85780820490509050808201828110613bd857905090506102e0525b61016051610180516102e0516101a051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd857905090506101605260006101605112156120f757600061030052602061030061210d5661210d565b6101605160008112613bd8576103005260206103005bf35b6318160ddd811861212c5760043610613bd857426101c052612147565b63bd85b03981186122165760243610613bd8576004356101c0525b60006101e052426101c0511861216357600b546101e052612184565b6101c051604052600b5460605261217b61020061382a565b610200516101e0525b6101e0516121a057600061020052602061020061221456612214565b6101e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c018054610200526001810154610220526002810154610240526003810154610260525060206102005160405261022051606052610240516080526102605160a0526101c05160c052612210610280613a6a565b6102805bf35b63981b24d081186124235760243610613bd8574360043511613bd857600b546101c0526004356040526101c05160605261225161020061377a565b610200516101e0526101e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c01805461020052600181015461022052600281015461024052600381015461026052506000610280526101c0516101e0511061231b574361026051146123dc5760043561026051808203828111613bd857905090504261024051808203828111613bd85790509050808202811583838304141715613bd857905090504361026051808203828111613bd857905090508015613bd85780820490509050610280526123dc565b6101e05160018101818110613bd85790506c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0180546102a05260018101546102c05260028101546102e052600381015461030052506103005161026051146123dc5760043561026051808203828111613bd857905090506102e05161024051808203828111613bd85790509050808202811583838304141715613bd857905090506103005161026051808203828111613bd857905090508015613bd85780820490509050610280525b60206102005160405261022051606052610240516080526102605160a0526102405161028051808201828110613bd8579050905060c05261241e6102a0613a6a565b6102a0f35b63db93cc7a811861265e5760043610613bd857600054600214613bd85760026000556c050c783eb9b5c840000000001b54636a627842604052600254606052602060406024605c6000855af161247e573d600060003e3d6000fd5b60203d10613bd857604050506c050c783eb9b5c840000000001c546370a0823160605230608052602060606024607c845afa6124bf573d600060003e3d6000fd5b60203d10613bd857606090505160405260405115612657576c050c783eb9b5c840000000001f546c050c783eb9b5c840000000001d54186125d4576c050c783eb9b5c840000000001c5463095ea7b36060526c050c783eb9b5c840000000001f5460805260405160a052602060606044607c6000855af1612545573d600060003e3d6000fd5b3d61255b57803b15613bd857600160c052612572565b60203d10613bd8576060518060011c613bd85760c0525b60c090505115613bd8576c050c783eb9b5c840000000001f5463338b5dea6060526c050c783eb9b5c840000000001c5460805260405160a052803b15613bd857600060606044607c6000855af16125ce573d600060003e3d6000fd5b50612657565b6c050c783eb9b5c840000000001c5463a9059cbb6060526c050c783eb9b5c840000000001d5460805260405160a052602060606044607c6000855af161261f573d600060003e3d6000fd5b3d61263557803b15613bd857600160c05261264c565b60203d10613bd8576060518060011c613bd85760c0525b60c090505115613bd8575b6003600055005b63cb8e090d81186128065760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c8400000000011543318156126f25760066060527f2161646d696e000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6c050c783eb9b5c840000000001e5461276257600a6060527f21617661696c61626c650000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516127c65760066060527f21656d707479000000000000000000000000000000000000000000000000000060805260605060605180608001601f826000031636823750506308c379a06020526020604052601f19601f6060510116604401603cfd5b6040516c050c783eb9b5c840000000001d557f454ccf21cdac2e344d64173597f5922657c25c5b1e6c3f733791637513d2063760405160605260206060a1005b63ee00ef3a81186128255760043610613bd85760015460405260206040f35b6382bfefc881186128445760043610613bd85760025460405260206040f35b63047fc9aa81186128635760043610613bd85760095460405260206040f35b63cbf9fe5f81186128a85760243610613bd8576004358060a01c613bd857604052600a6040516020526000526040600020805460605260018101546080525060406060f35b63900cf0cf81186128c75760043610613bd857600b5460405260206040f35b63d1febfb9811861291b5760243610613bd8576004356c01431e0fae6d7217ca9fffffff8111613bd85760021b600c01805460405260018101546060526002810154608052600381015460a0525060806040f35b6328d09d4781186129915760443610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000c6040516020526000526040600020602435633b9ac9ff8111613bd85760021b8101905080546060526001810154608052600281015460a052600381015460c0525060806060f35b63010ae75781186129d85760243610613bd8576004358060a01c613bd8576040526c050c783eb9b5c840000000000d60405160205260005260406000205460605260206060f35b63711974848118612a115760243610613bd8576c050c783eb9b5c840000000000e60043560205260005260406000205460405260206040f35b638ff36fd18118612a3c5760043610613bd8576c050c783eb9b5c840000000000f5460405260206040f35b637175d4f78118612a675760043610613bd8576c050c783eb9b5c84000000000105460405260206040f35b63f851a4408118612a925760043610613bd8576c050c783eb9b5c84000000000115460405260206040f35b63142614258118612abd5760043610613bd8576c050c783eb9b5c84000000000125460405260206040f35b6322cf35f58118612ae85760043610613bd8576c050c783eb9b5c84000000000135460405260206040f35b6317f7182a8118612b135760043610613bd8576c050c783eb9b5c84000000000145460405260206040f35b639a01873c8118612b3e5760043610613bd8576c050c783eb9b5c84000000000155460405260206040f35b63f68467278118612b695760043610613bd8576c050c783eb9b5c84000000000165460405260206040f35b63cd8c79aa8118612b945760043610613bd8576c050c783eb9b5c84000000000175460405260206040f35b63094cda238118612bbf5760043610613bd8576c050c783eb9b5c84000000000185460405260206040f35b63205ad4088118612bea5760043610613bd8576c050c783eb9b5c84000000000195460405260206040f35b635836ec3a8118612c155760043610613bd8576c050c783eb9b5c840000000001a5460405260206040f35b6373f43d6d8118612c405760043610613bd8576c050c783eb9b5c840000000001b5460405260206040f35b6338d546458118612c6b5760043610613bd8576c050c783eb9b5c840000000001c5460405260206040f35b631dac30b08118612c965760043610613bd8576c050c783eb9b5c840000000001d5460405260206040f35b63b027651a8118612cc15760043610613bd8576c050c783eb9b5c840000000001e5460405260206040f35b63acc2166a8118612cec5760043610613bd8576c050c783eb9b5c840000000001f5460405260206040f35b63b3d8f7e78118612d175760043610613bd8576c050c783eb9b5c84000000000205460405260206040f35b505b60006000fd5b3260405114612e15576c050c783eb9b5c84000000000105460605260605115612d945760605163c23697a860805260405160a052602060806024609c6000855af1612d6f573d600060003e3d6000fd5b60203d10613bd8576080518060011c613bd85760c05260c090505115612d9457612e15565b60256080527f536d61727420636f6e7472616374206465706f7369746f7273206e6f7420616c60a0527f6c6f77656400000000000000000000000000000000000000000000000000000060c0526080506080518060a001601f826000031636823750506308c379a06040526020606052601f19601f6080510116604401605cfd5b565b6101403660e037600b546102205260405115612f83574260805111612e3d576000612e45565b600160605112155b15612ea65760605160015480607f1c613bd8578015613bd85780820580600f0b8118613bd85790509050610100526101005160805142808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905060e0525b4260c05111612eb6576000612ebe565b600160a05112155b15612f205760a05160015480607f1c613bd8578015613bd85780820580600f0b8118613bd85790509050610180526101805160c05142808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd85790509050610160525b6c050c783eb9b5c840000000000e6080516020526000526040600020546101e05260c05115612f835760805160c05118612f61576101e05161020052612f83565b6c050c783eb9b5c840000000000e60c051602052600052604060002054610200525b604036610240374261028052436102a0526102205115612fde57610220516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0180546102405260018101546102605260028101546102805260038101546102a052505b610280516102c052610240516102e052610260516103005261028051610320526102a051610340526000610360526102805142111561306d57436102a051808203828111613bd85790509050670de0b6b3a7640000810281670de0b6b3a7640000820418613bd85790504261028051808203828111613bd857905090508015613bd85780820490509050610360525b6102c05162093a808104905062093a8081028162093a80820418613bd857905061038052600060ff905b806103a0526103805162093a808101818110613bd85790506103805260006103c0524261038051116130ea576c050c783eb9b5c840000000000e610380516020526000526040600020546103c0526130f0565b42610380525b6102405161026051610380516102c051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd8579050905061024052610260516103c05180820180600f0b8118613bd85790509050610260527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610240511361318a576000610240525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61026051136131bb576000610260525b610380516102c052610380516102805261034051610360516103805161032051808203828111613bd85790509050808202811583838304141715613bd85790509050670de0b6b3a764000081049050808201828110613bd857905090506102a0526102205160018101818110613bd85790506102205242610380511861324957436102a0526132955661328a565b610220516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c016102405181556102605160018201556102805160028201556102a0516003820155505b600101818118613097575b505061022051600b556040511561336b5761026051610180516101005180820380600f0b8118613bd8579050905080820180600f0b8118613bd8579050905061026052610240516101605160e05180820380600f0b8118613bd8579050905080820180600f0b8118613bd85790509050610240527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610260511361333a576000610260525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610240511361336b576000610240525b610220516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c016102405181556102605160018201556102805160028201556102a0516003820155506040511561352857426080511115613425576101e0516101005180820180600f0b8118613bd857905090506101e05260805160c05118613403576101e0516101805180820380600f0b8118613bd857905090506101e0525b6101e0516c050c783eb9b5c840000000000e6080516020526000526040600020555b4260c051111561347a5760805160c051111561347a57610200516101805180820380600f0b8118613bd8579050905061020052610200516c050c783eb9b5c840000000000e60c0516020526000526040600020555b6c050c783eb9b5c840000000000d60405160205260005260406000205460018101818110613bd85790506103a0526103a0516c050c783eb9b5c840000000000d604051602052600052604060002055426101a052436101c0526c050c783eb9b5c840000000000c60405160205260005260406000206103a051633b9ac9ff8111613bd85760021b810190506101605181556101805160018201556101a05160028201556101c0516003820155505b565b6c050c783eb9b5c840000000002054156135a45760156104a0527f616c6c20756e6c6f636b65642c6e6f2073656e736500000000000000000000006104c0526104a0506104a051806104c001601f826000031636823750506308c379a061046052602061048052601f19601f6104a051011660440161047cfd5b610440516104a052610460516104c0526009546104e0526104e05161040051808201828110613bd857905090506009556104a051610500526104c051610520526104a0516104005180607f1c613bd85780820180600f0b8118613bd857905090506104a052610420511561361b57610420516104c0525b600a6103e05160205260005260406000206104a05181556104c0516001820155506103e05160405261050051606052610520516080526104a05160a0526104c05160c052613667612e17565b61040051156136eb576002546323b872dd610540526103e051610560523061058052610400516105a0526020610540606461055c6000855af16136af573d600060003e3d6000fd5b3d6136c657803b15613bd85760016105c0526136df565b60203d10613bd857610540518060011c613bd8576105c0525b6105c090505115613bd8575b6104c0516103e0517f4566dfc29f6f11d13a418c26a02bef7c28bae749d4de47e4e6a7cddea6730d596104005161054052610480516105605242610580526060610540a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c6104e051610540526104e05161040051808201828110613bd85790509050610560526040610540a1565b600060805260605160a05260006080905b8060c05260a0516080511061379f57613820565b60805160a051808201828110613bd8579050905060018101818110613bd85790508060011c905060e05260405160e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c0160038101905054111561380e5760e05160018103818111613bd857905060a052613815565b60e0516080525b60010181811861378b575b5050608051815250565b600060805260605160a05260006080905b8060c05260a0516080511061384f576138d0565b60805160a051808201828110613bd8579050905060018101818110613bd85790508060011c905060e05260405160e0516c01431e0fae6d7217ca9fffffff8111613bd85760021b600c016002810190505411156138be5760e05160018103818111613bd857905060a0526138c5565b60e0516080525b60010181811861383b575b5050608051815250565b600060a05260805160c05260006080905b8060e05260c05160a051106138ff57613998565b60a05160c051808201828110613bd8579050905060018101818110613bd85790508060011c9050610100526060516c050c783eb9b5c840000000000c604051602052600052604060002061010051633b9ac9ff8111613bd85760021b81019050600381019050541115613985576101005160018103818111613bd857905060c05261398d565b6101005160a0525b6001018181186138eb575b505060a051815250565b600060a05260805160c05260006080905b8060e05260c05160a051106139c757613a60565b60a05160c051808201828110613bd8579050905060018101818110613bd85790508060011c9050610100526060516c050c783eb9b5c840000000000c604051602052600052604060002061010051633b9ac9ff8111613bd85760021b81019050600281019050541115613a4d576101005160018103818111613bd857905060c052613a55565b6101005160a0525b6001018181186139b3575b505060a051815250565b60405160e052606051610100526080516101205260a051610140526101205162093a808104905062093a8081028162093a80820418613bd857905061016052600060ff905b80610180526101605162093a808101818110613bd85790506101605260006101a05260c0516101605111613b04576c050c783eb9b5c840000000000e610160516020526000526040600020546101a052613b0c565b60c051610160525b60e051610100516101605161012051808203828111613bd8579050905080607f1c613bd85780820280600f0b8118613bd8579050905080820380600f0b8118613bd8579050905060e05260c0516101605118613b6757613b97565b610100516101a05180820180600f0b8118613bd85790509050610100526101605161012052600101818118613aaf575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60e05113613bc857600060e0525b60e05160008112613bd857815250565b600080fda165767970657283000307000b
Loading...
Loading
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.