ETH Price: $3,325.61 (-3.69%)

Contract

0x8235c179E9e84688FBd8B12295EfC26834dAC211
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Increase_amount237447462025-11-07 3:35:111 hr ago1762486511IN
Yield Basis: veYB Token
0 ETH0.000420892.1570611
Infinite_lock_to...237432172025-11-06 22:27:236 hrs ago1762468043IN
Yield Basis: veYB Token
0 ETH0.000047980.27471927
Increase_amount237432132025-11-06 22:26:356 hrs ago1762467995IN
Yield Basis: veYB Token
0 ETH0.000062130.28481115
Infinite_lock_to...237431162025-11-06 22:07:116 hrs ago1762466831IN
Yield Basis: veYB Token
0 ETH0.000061670.35307569
Create_lock237431132025-11-06 22:06:356 hrs ago1762466795IN
Yield Basis: veYB Token
0 ETH0.000124650.31509368
Increase_amount237416332025-11-06 17:08:5911 hrs ago1762448939IN
Yield Basis: veYB Token
0 ETH0.000520942.67011407
Increase_amount237371952025-11-06 2:14:5926 hrs ago1762395299IN
Yield Basis: veYB Token
0 ETH0.00006960.35670692
Create_lock237365402025-11-06 0:02:3528 hrs ago1762387355IN
Yield Basis: veYB Token
0 ETH0.000180020.38734353
Infinite_lock_to...237361582025-11-05 22:45:3529 hrs ago1762382735IN
Yield Basis: veYB Token
0 ETH0.000041980.24033364
Create_lock237361512025-11-05 22:44:1129 hrs ago1762382651IN
Yield Basis: veYB Token
0 ETH0.000112360.28402115
Increase_amount237359662025-11-05 22:06:4730 hrs ago1762380407IN
Yield Basis: veYB Token
0 ETH0.000073520.37683024
Increase_amount237359452025-11-05 22:02:3530 hrs ago1762380155IN
Yield Basis: veYB Token
0 ETH0.000077510.39727476
Increase_amount237357882025-11-05 21:30:4731 hrs ago1762378247IN
Yield Basis: veYB Token
0 ETH0.000407982.09090461
Increase_amount237353402025-11-05 20:00:2332 hrs ago1762372823IN
Yield Basis: veYB Token
0 ETH0.000081980.42016228
Increase_amount237353232025-11-05 19:56:5932 hrs ago1762372619IN
Yield Basis: veYB Token
0 ETH0.000414072.12223312
Increase_amount237352282025-11-05 19:37:4733 hrs ago1762371467IN
Yield Basis: veYB Token
0 ETH0.000108720.5572183
Increase_amount237347522025-11-05 18:01:4734 hrs ago1762365707IN
Yield Basis: veYB Token
0 ETH0.000176530.90470489
Create_lock237343462025-11-05 16:40:3535 hrs ago1762360835IN
Yield Basis: veYB Token
0 ETH0.000436691.20842852
Safe Transfer Fr...237342832025-11-05 16:27:4736 hrs ago1762360067IN
Yield Basis: veYB Token
0 ETH0.000337661.14556576
Infinite_lock_to...237342712025-11-05 16:25:2336 hrs ago1762359923IN
Yield Basis: veYB Token
0 ETH0.000216171.23752427
Increase_amount237335052025-11-05 13:50:3538 hrs ago1762350635IN
Yield Basis: veYB Token
0 ETH0.000177340.90884317
Create_lock237329122025-11-05 11:50:3540 hrs ago1762343435IN
Yield Basis: veYB Token
0 ETH0.000174790.44183517
Create_lock237328292025-11-05 11:33:3541 hrs ago1762342415IN
Yield Basis: veYB Token
0 ETH0.000145510.36782196
Create_lock237326922025-11-05 11:06:1141 hrs ago1762340771IN
Yield Basis: veYB Token
0 ETH0.000151140.38207327
Increase_amount237326532025-11-05 10:58:2341 hrs ago1762340303IN
Yield Basis: veYB Token
0 ETH0.000077030.39481391
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x4712D2CB...59e3840F1
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Voting Escrow

Compiler Version
vyper:0.4.3

Optimization Enabled:
Yes

Other Settings:
default evmVersion, None license

Contract Source Code (Vyper Json-Input format)

File 1 of 13 : VotingEscrow.vy
# @version 0.4.3
"""
@title Voting Escrow
@author Yield Basis
@license GNU Affero General Public License v3.0
@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` (4 years).
"""

# 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 (4 years)

from ethereum.ercs import IERC20
from ethereum.ercs import IERC721

from snekmate.auth import ownable
from snekmate.tokens import erc721

from interfaces import IVotes


implements: IVotes

initializes: ownable
initializes: erc721[ownable := ownable]

exports: (
    erc721.balanceOf,
    erc721.ownerOf,
    erc721.approve,
    erc721.setApprovalForAll,
    erc721.getApproved,
    erc721.isApprovedForAll,
    erc721.name,
    erc721.symbol,
    erc721.totalSupply,
    erc721.tokenByIndex,
    erc721.tokenOfOwnerByIndex,
    erc721.tokenURI,
    ownable.transfer_ownership,
    ownable.owner
)


### ve-specific
TOKEN: public(immutable(IERC20))

struct Point:
    bias: int256
    slope: int256  # - dweight / dt
    ts: uint256

struct UntimedPoint:
    bias: uint256
    slope: uint256

struct LockedBalance:
    amount: int256
    end: uint256

flag LockActions:
    DEPOSIT_FOR
    CREATE_LOCK
    INCREASE_AMOUNT
    INCREASE_TIME

interface TransferClearanceChecker:
    def ve_transfer_allowed(user: address) -> bool: view


event Deposit:
    _from: indexed(address)
    _for: indexed(address)
    value: uint256
    locktime: indexed(uint256)
    type: LockActions
    ts: uint256

event Withdraw:
    _from: indexed(address)
    _for: indexed(address)
    value: uint256
    ts: uint256

event Supply:
    prevSupply: uint256
    supply: uint256


event SetTransferClearanceChecker:
    clearance_checker: address


WEEK: constant(uint256) = 7 * 86400  # all future times are rounded by week
MAXTIME: constant(int256) = 4 * 365 * 86400  # 4 years
UMAXTIME: constant(uint256) = 4 * 365 * 86400  # 4 years
WAD: constant(uint256) = 10**18

supply: public(uint256)

locked: public(HashMap[address, LockedBalance])

epoch: public(uint256)
point_history: public(Point[10**18])  # epoch -> unsigned point
user_point_history: public(HashMap[address, Point[10**18]])  # user -> Point[user_epoch]
user_point_epoch: public(HashMap[address, uint256])
slope_changes: public(HashMap[uint256, int256])  # time -> signed slope change

transfer_clearance_checker: public(TransferClearanceChecker)

_SUPPORTED_INTERFACES: constant(bytes4[6]) = [
    0x01FFC9A7, # The ERC-165 identifier for ERC-165.
    0x80AC58CD, # The ERC-165 identifier for ERC-721.
    0x5B5E139F, # The ERC-165 identifier for the ERC-721 metadata extension.
    0x780E9D63, # The ERC-165 identifier for the ERC-721 enumeration extension.
    0x49064906, # The ERC-165 identifier for ERC-4906.
    0xE90FB3F6  # IVotes
]

CLOCK_MODE: public(constant(String[14])) = "mode=timestamp"


@deploy
def __init__(token: IERC20, name: String[25], symbol: String[5], base_uri: String[80]):
    ownable.__init__()
    erc721.__init__(name, symbol, base_uri, "Just say no", "to EIP712")

    TOKEN = token

    self.point_history[0].ts = block.timestamp


@external
@view
def supportsInterface(interface_id: bytes4) -> bool:
    """
    @dev Returns `True` if this contract implements the
         interface defined by `interface_id`.
    @param interface_id The 4-byte interface identifier.
    @return bool The verification whether the contract
            implements the interface or not.
    """
    return interface_id in _SUPPORTED_INTERFACES


@external
@view
def delegates(account: address) -> address:
    """
    @dev Returns the delegate that `account` has chosen (it's a stub because this value cannot be changed)
    """
    return account


@external
def delegate(delegatee: address):
    """
    @dev Delegates votes from the sender to `delegatee`. This reverts because functionality is not supported
    """
    raise "Not supported"


@external
def delegateBySig(delegatee: address, nonce: uint256, expiry: uint256, v: uint8, r: bytes32, s: bytes32):
    """
    @dev Delegates votes from signer to `delegatee`. This reverts because functionality is not supported
    """
    raise "Not supported"


@external
@view
def clock() -> uint48:
    """
    EIP-6372 clock
    """
    return convert(block.timestamp, uint48)


@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: int256 = 0
    new_dslope: int256 = 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:
            if old_locked.end == max_value(uint256):
                u_old.slope = 0
                u_old.bias = old_locked.amount
            else:
                u_old.slope = old_locked.amount // MAXTIME
                u_old.bias = u_old.slope * convert(old_locked.end - block.timestamp, int256)
        if new_locked.end > block.timestamp and new_locked.amount > 0:
            if new_locked.end == max_value(uint256):
                u_new.slope = 0
                u_new.bias = new_locked.amount
            else:
                u_new.slope = new_locked.amount // MAXTIME
                u_new.bias = u_new.slope * convert(new_locked.end - block.timestamp, int256)

        # 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)
    if _epoch > 0:
        last_point = self.point_history[_epoch]
    last_checkpoint: uint256 = last_point.ts

    # Go over weeks to fill history and calculate what the current point is
    t_i: uint256 = (last_checkpoint // WEEK) * WEEK
    for i: uint256 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: int256 = 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, int256)
        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
        _epoch += 1
        if t_i == block.timestamp:
            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
        self.user_point_history[addr][user_epoch] = u_new


@external
def checkpoint():
    """
    @notice Record global data to checkpoint
    """
    self._checkpoint(empty(address), empty(LockedBalance), empty(LockedBalance))


@internal
def _deposit_for(_addr: address, _value: uint256, unlock_time: uint256, locked_balance: LockedBalance, type: LockActions):
    """
    @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
    """
    _locked: LockedBalance = locked_balance
    supply_before: uint256 = self.supply

    new_supply: uint256 = (supply_before + _value) // UMAXTIME * UMAXTIME
    rounded_value: uint256 = new_supply - supply_before
    self.supply = new_supply
    old_locked: LockedBalance = _locked
    # Adding to existing lock, or if a lock is expired - creating a new one
    _locked.amount += convert(rounded_value, int256)
    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 rounded_value != 0:
        assert extcall TOKEN.transferFrom(msg.sender, self, rounded_value)

    log Deposit(_from=msg.sender, _for=_addr, value=rounded_value, locktime=_locked.end, type=type, ts=block.timestamp)
    log Supply(prevSupply=supply_before, supply=new_supply)


@external
@nonreentrant
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
    """
    unlock_time: uint256 = (_unlock_time // WEEK) * WEEK  # Locktime is rounded down to weeks
    _locked: LockedBalance = self.locked[msg.sender]

    assert _value >= UMAXTIME, "Min 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 + UMAXTIME, "Voting lock can be 4 years max"

    self._deposit_for(msg.sender, _value, unlock_time, _locked, LockActions.CREATE_LOCK)
    erc721._mint(msg.sender, convert(msg.sender, uint256))


@external
@nonreentrant
def increase_amount(_value: uint256, _for: address = msg.sender):
    """
    @notice Deposit `_value` additional tokens for `_for` which is `msg.sender` by default
            without modifying the unlock time
    @param _value Amount of tokens to deposit and add to the lock
    @param _for Lock to increase for
    """
    _locked: LockedBalance = self.locked[_for]

    assert _value >= UMAXTIME  # 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(_for, _value, 0, _locked, LockActions.INCREASE_AMOUNT)


@external
@nonreentrant
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
    """
    _locked: LockedBalance = self.locked[msg.sender]
    unlock_time: uint256 = (_unlock_time // WEEK) * WEEK  # Locktime is rounded down to weeks

    assert _locked.amount > 0, "Nothing is locked"
    assert _locked.end > block.timestamp, "Lock expired"
    assert unlock_time > _locked.end, "Can only increase lock duration"
    assert unlock_time <= block.timestamp + UMAXTIME, "Voting lock can be 4 years max"

    self._deposit_for(msg.sender, 0, unlock_time, _locked, LockActions.INCREASE_TIME)


@external
@nonreentrant
def infinite_lock_toggle():
    """
    @notice Make ever-extending lock or cancel it
    """
    _locked: LockedBalance = self.locked[msg.sender]
    assert _locked.end > block.timestamp, "Lock expired"
    assert _locked.amount > 0, "Nothing is locked"
    unlock_time: uint256 = 0

    if _locked.end == max_value(uint256):
        checker: TransferClearanceChecker = self.transfer_clearance_checker
        if checker.address != empty(address):
            # The check is whether the source (owner) has 0 votes.
            # Destination address can STILL have votes, that's fine
            assert staticcall checker.ve_transfer_allowed(msg.sender), "Not allowed"
        unlock_time = ((block.timestamp + UMAXTIME) // WEEK) * WEEK
    else:
        unlock_time = max_value(uint256)

    self._deposit_for(msg.sender, 0, unlock_time, _locked, LockActions.INCREASE_TIME)


@external
@nonreentrant
def withdraw(_for: address = msg.sender):
    """
    @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, "The lock didn't expire"
    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
    new_supply: uint256 = supply_before - value
    self.supply = new_supply

    # 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)

    erc721._burn(convert(msg.sender, uint256))

    assert extcall TOKEN.transfer(_for, value)

    log Withdraw(_from=msg.sender, _for=_for, value=value, ts=block.timestamp)
    log Supply(prevSupply=supply_before, supply=new_supply)


@external
@view
def getVotes(account: address) -> uint256:
    """
    @dev Returns the current amount of votes that `account` has.
    """
    _epoch: uint256 = self.user_point_epoch[account]
    if _epoch == 0:
        return 0
    else:
        last_point: Point = self.user_point_history[account][_epoch]
        last_point.bias -= last_point.slope * convert(block.timestamp - last_point.ts, int256)
        if last_point.bias < 0:
            last_point.bias = 0
        return convert(last_point.bias, uint256)


@external
@view
def getPastVotes(account: address, timepoint: uint256) -> uint256:
    """
    @dev Returns the amount of votes that `account` had at a specific moment in the past
    """
    # Binary search
    _min: uint256 = 0
    _max: uint256 = self.user_point_epoch[account]

    if timepoint < self.user_point_history[account][0].ts:
        return 0

    for i: uint256 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[account][_mid].ts <= timepoint:
            _min = _mid
        else:
            _max = _mid - 1

    upoint: Point = self.user_point_history[account][_min]
    upoint.bias -= upoint.slope * convert(timepoint - upoint.ts, int256)

    if upoint.bias >= 0:
        return convert(upoint.bias, uint256)
    else:
        return 0


@internal
@view
def total_supply_at(timepoint: uint256) -> uint256:
    _epoch: uint256 = self.epoch
    if _epoch == 0:
        return 0
    else:
        if timepoint < self.point_history[0].ts:
            return 0

        # Past total supply binary search
        _min: uint256 = 0
        for i: uint256 in range(128):  # Will be always enough for 128-bit numbers
            if _min >= _epoch:
                break
            _mid: uint256 = (_min + _epoch + 1) // 2
            if self.point_history[_mid].ts <= timepoint:
                _min = _mid
            else:
                _epoch = _mid - 1

        point: Point = self.point_history[_min]

        if _min == _epoch:
            # Future total supply search -> iterate over all slope changes
            t_i: uint256 = point.ts  # Already rounded to whole weeks
            for i: uint256 in range(255):
                t_i += WEEK
                d_slope: int256 = 0
                if t_i > timepoint:
                    t_i = timepoint
                else:
                    d_slope = self.slope_changes[t_i]
                point.bias -= point.slope * convert(t_i - point.ts, int256)
                if t_i == timepoint:
                    break
                point.slope += d_slope
                point.ts = t_i

            if point.bias < 0:
                point.bias = 0

        else:
            point.bias -= point.slope * convert(timepoint - point.ts, int256)

        return convert(point.bias, uint256)


@external
@view
def totalVotes() -> uint256:
    """
    @notice Returns current total supply of votes
    """
    return self.total_supply_at(block.timestamp)


@external
@view
def getPastTotalSupply(timepoint: uint256) -> uint256:
    """
    @dev Returns the total supply of votes available at a specific moment in the past.

    @notice This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
    Votes that have not been delegated are still part of total supply, even though they would not participate in a
    vote.
    Unlike the original method, this one ALSO works with the future
    """
    return self.total_supply_at(timepoint)


@internal
@view
def _ve_transfer_allowed(owner: address, to: address) -> bool:
    checker: TransferClearanceChecker = self.transfer_clearance_checker
    if checker.address != empty(address):
        # The check is whether the source (owner) has 0 votes.
        # Destination address can STILL have votes, that's fine
        assert staticcall checker.ve_transfer_allowed(owner), "Not allowed"
    assert owner != to

    sender_max: bool = False
    receiver_max: bool = False
    max_time: uint256 = (block.timestamp + UMAXTIME) // WEEK * WEEK

    owner_time: uint256 = self.locked[owner].end
    if owner_time == max_value(uint256) or owner_time // WEEK * WEEK == max_time:
        sender_max = True
    to_time: uint256 = self.locked[to].end
    if to_time == max_value(uint256) or to_time // WEEK * WEEK == max_time:
        receiver_max = True

    # the end slope should be the same, that's why the last condition is needed
    return sender_max and receiver_max and (owner_time // WEEK * WEEK == to_time // WEEK * WEEK)


@internal
def _merge_positions(owner: address, to: address):
    """
    @dev Merge veLocked positions of `owner` with `to`, giving it to `to`.
    """
    locked: LockedBalance = self.locked[owner]
    self.locked[owner] = empty(LockedBalance)
    new_locked: LockedBalance = self.locked[to]
    new_locked.amount += locked.amount
    self.locked[to].amount = new_locked.amount

    user_epoch: uint256 = self.user_point_epoch[owner] + 1
    self.user_point_epoch[owner] = user_epoch
    self.user_point_history[owner][user_epoch] = Point(bias=0, slope=0, ts=block.timestamp)

    user_epoch = self.user_point_epoch[to] + 1
    self.user_point_epoch[to] = user_epoch
    slope: int256 = 0
    bias: int256 = 0
    if new_locked.end == max_value(uint256):
        bias = new_locked.amount
    else:
        slope = new_locked.amount // MAXTIME
        bias = slope * convert(new_locked.end - block.timestamp, int256)
    self.user_point_history[to][user_epoch] = Point(
        bias=bias,
        slope=slope,
        ts=block.timestamp
    )

    # Total should not change because we transfer between users

    self._checkpoint(empty(address), empty(LockedBalance), empty(LockedBalance))


@external
def set_transfer_clearance_checker(transfer_clearance_checker: TransferClearanceChecker):
    """
    @notice Set checker for when the transfer os the ve-token is allowed (usually when all votes are removed)
    """
    ownable._check_owner()
    self.transfer_clearance_checker = transfer_clearance_checker
    log SetTransferClearanceChecker(clearance_checker=transfer_clearance_checker.address)


@external
def transferFrom(owner: address, to: address, token_id: uint256):
    """
    @notice Transfer ve-NFT
    """
    assert erc721._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved"
    assert token_id == convert(owner, uint256), "Wrong token ID"
    assert self._ve_transfer_allowed(owner, to), "Need max veLock"
    self._merge_positions(owner, to)
    erc721._burn(token_id)


@external
def safeTransferFrom(owner: address, to: address, token_id: uint256, data: Bytes[1_024] = b""):
    """
    @notice Transfer ve-NFT and use a callback. Keep in mind that NFT gets destructed before the callback is hit
    """
    assert erc721._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved"
    assert token_id == convert(owner, uint256), "Wrong token ID"
    assert self._ve_transfer_allowed(owner, to), "Need max veLock"
    self._merge_positions(owner, to)
    erc721._burn(token_id)
    assert erc721._check_on_erc721_received(owner, to, token_id, data), "erc721: transfer to non-IERC721Receiver implementer"


@external
@view
def get_last_user_slope(addr: address) -> int256:
    """
    @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 get_last_user_point(addr: address) -> UntimedPoint:
    """
    @notice Get the most recently recorded point of voting power decrease for `addr`
    @param addr Address of the user wallet
    """
    uepoch: uint256 = self.user_point_epoch[addr]
    return UntimedPoint(
        bias=convert(self.user_point_history[addr][uepoch].bias, uint256),
        slope=convert(self.user_point_history[addr][uepoch].slope, uint256)
    )


@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

File 2 of 13 : ownable.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title Owner-Based Access Control Functions
@custom:contract-name ownable
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions can be used to implement a basic access
        control mechanism, where there is an account (an owner)
        that can be granted exclusive access to specific functions.
        By default, the owner account will be the one that deploys
        the contract. This can later be changed with `transfer_ownership`.
        An exemplary integration can be found in the ERC-20 implementation here:
        https://github.com/pcaversaccio/snekmate/blob/main/src/snekmate/tokens/erc20.vy.
        The implementation is inspired by OpenZeppelin's implementation here:
        https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol.
"""


# @dev Returns the address of the current owner.
# @notice If you declare a variable as `public`,
# Vyper automatically generates an `external`
# getter function for the variable.
owner: public(address)


# @dev Emitted when the ownership is transferred
# from `previous_owner` to `new_owner`.
event OwnershipTransferred:
    previous_owner: indexed(address)
    new_owner: indexed(address)


@deploy
@payable
def __init__():
    """
    @dev To omit the opcodes for checking the `msg.value`
         in the creation-time EVM bytecode, the constructor
         is declared as `payable`.
    @notice The `owner` role will be assigned to
            the `msg.sender`.
    """
    self._transfer_ownership(msg.sender)


@external
def transfer_ownership(new_owner: address):
    """
    @dev Transfers the ownership of the contract
         to a new account `new_owner`.
    @notice Note that this function can only be
            called by the current `owner`. Also,
            the `new_owner` cannot be the zero address.
    @param new_owner The 20-byte address of the new owner.
    """
    self._check_owner()
    assert new_owner != empty(address), "ownable: new owner is the zero address"
    self._transfer_ownership(new_owner)


@external
def renounce_ownership():
    """
    @dev Leaves the contract without an owner.
    @notice Renouncing ownership will leave the
            contract without an owner, thereby
            removing any functionality that is
            only available to the owner.
    """
    self._check_owner()
    self._transfer_ownership(empty(address))


@internal
def _check_owner():
    """
    @dev Throws if the sender is not the owner.
    """
    assert msg.sender == self.owner, "ownable: caller is not the owner"


@internal
def _transfer_ownership(new_owner: address):
    """
    @dev Transfers the ownership of the contract
         to a new account `new_owner`.
    @notice This is an `internal` function without
            access restriction.
    @param new_owner The 20-byte address of the new owner.
    """
    old_owner: address = self.owner
    self.owner = new_owner
    log OwnershipTransferred(previous_owner=old_owner, new_owner=new_owner)

File 3 of 13 : Vyper_contract.vy
# pragma version ~=0.4.3
"""
@title EIP-721 Optional Metadata Interface Definition
@custom:contract-name IERC721Metadata
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice The metadata extension is optional for an ERC-721
        smart contract. This allows a smart contract to
        be interrogated for its name and for details about
        the asset(s) which a non-fungible token (NFT)
        represents. For more details, please refer to:
        https://eips.ethereum.org/EIPS/eip-721#specification.

        Note that Vyper interfaces that implement functions
        with return values that require an upper bound (e.g.
        `Bytes`, `DynArray`, or `String`), the upper bound
        defined in the interface represents the lower bound
        of the implementation:
        https://github.com/vyperlang/vyper/pull/3205.

        On how to use interfaces in Vyper, please visit:
        https://vyper.readthedocs.io/en/latest/interfaces.html#interfaces.
"""


# @dev We import and implement the `IERC165` interface,
# which is a built-in interface of the Vyper compiler.
from ethereum.ercs import IERC165
implements: IERC165


# @dev We import the `IERC721` interface, which is a built-in
# interface of the Vyper compiler, to highlight the association
# of the custom `IERC721Metadata` interface with the built-in
# `IERC721` interface.
# @notice The interface `IERC721Metadata` must be used in conjunction
# with the built-in interface `IERC721` to be EIP-721 compatible.
# If you want to use this interface as a stand-alone interface,
# you must add `implements: IERC721` to this interface and implement
# all required events and functions accordingly.
from ethereum.ercs import IERC721


@external
@view
def supportsInterface(interfaceId: bytes4) -> bool:
    """
    @dev Returns `True` if this contract implements the
         interface defined by `interfaceId`.
    @notice For more details on how these identifiers are
            created, please refer to:
            https://eips.ethereum.org/EIPS/eip-165.
    @param interfaceId The 4-byte interface identifier.
    @return bool The verification whether the contract
            implements the interface or not.
    """
    ...


@external
@view
def name() -> String[25]:
    """
    @dev Returns the token collection name.
    @return String The maximum 25-character
            user-readable string name of the
            token collection.
    """
    ...


@external
@view
def symbol() -> String[5]:
    """
    @dev Returns the token collection symbol.
    @return String The maximum 5-character
            user-readable string symbol of the
            token collection.
    """
    ...


@external
@view
def tokenURI(_tokenId: uint256) -> String[512]:
    """
    @dev Returns the Uniform Resource Identifier (URI)
         for `_tokenId` token.
    @notice Throws if `_tokenId` is not a valid ERC-721 token.
    @param _tokenId The 32-byte identifier of the token.
    @return String The maximum 512-character user-readable
            string token URI of the `_tokenId` token.
    """
    ...

File 4 of 13 : Vyper_contract.vy
# pragma version ~=0.4.3
"""
@title EIP-721 Optional Enumeration Interface Definition
@custom:contract-name IERC721Enumerable
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice The enumeration extension is optional for an ERC-721
        smart contract. This allows a contract to publish its
        full list of ERC-721 tokens and make them discoverable.
        For more details, please refer to:
        https://eips.ethereum.org/EIPS/eip-721#specification.

        On how to use interfaces in Vyper, please visit:
        https://vyper.readthedocs.io/en/latest/interfaces.html#interfaces.
"""


# @dev We import and implement the `IERC165` interface,
# which is a built-in interface of the Vyper compiler.
from ethereum.ercs import IERC165
implements: IERC165


# @dev We import the `IERC721` interface, which is a built-in
# interface of the Vyper compiler, to highlight the association
# of the custom `IERC721Enumerable` interface with the built-in
# `IERC721` interface.
# @notice The interface `IERC721Enumerable` must be used in conjunction
# with the built-in interface `IERC721` to be EIP-721 compatible.
# If you want to use this interface as a stand-alone interface,
# you must add `implements: IERC721` to this interface and implement
# all required events and functions accordingly.
from ethereum.ercs import IERC721


@external
@view
def supportsInterface(interfaceId: bytes4) -> bool:
    """
    @dev Returns `True` if this contract implements the
         interface defined by `interfaceId`.
    @notice For more details on how these identifiers are
            created, please refer to:
            https://eips.ethereum.org/EIPS/eip-165.
    @param interfaceId The 4-byte interface identifier.
    @return bool The verification whether the contract
            implements the interface or not.
    """
    ...


@external
@view
def totalSupply() -> uint256:
    """
    @dev Returns the amount of tokens in existence.
    @return uint256 The 32-byte token supply.
    """
    ...


@external
@view
def tokenByIndex(_index: uint256) -> uint256:
    """
    @dev Returns a token ID at a given `_index` of
         all the tokens stored by the contract.
    @notice Use along with `totalSupply` to enumerate
            all tokens.
    @param _index The 32-byte counter (must be less
           than `totalSupply()`).
    @return uint256 The 32-byte token ID at index
            `_index`.
    """
    ...


@external
@view
def tokenOfOwnerByIndex(_owner: address, _index: uint256) -> uint256:
    """
    @dev Returns a token ID owned by `_owner` at a
         given `_index` of its token list.
    @notice Use along with `balanceOf` to enumerate
            all of `_owner`'s tokens.
    @param _owner The 20-byte owner address.
    @param _index The 32-byte counter (must be less
           than `balanceOf(_owner)`).
    @return uint256 The 32-byte token ID owned by
            `_owner` at index `_index`.
    """
    ...

File 5 of 13 : Vyper_contract.vy
# pragma version ~=0.4.3
"""
@title EIP-4494 Interface Definition
@custom:contract-name IERC721Permit
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice The `permit` function implements approvals via
        EIP-712 secp256k1 signatures for ERC-721 tokens:
        https://eips.ethereum.org/EIPS/eip-4494. The
        `permit` function allows users to modify the
        permission of who can manage a `tokenId` using
        a signed message (via secp256k1 signatures),
        instead of through `msg.sender`. By not relying
        on `approve`, the token holder's account does not
        need to send a transaction and therefore does not
        need to hold ether, enabling important use cases
        such as meta-transactions.

        IMPORTANT: Due to sake of consistency, we follow EIP-2612's
        pattern (see https://eips.ethereum.org/EIPS/eip-2612) and
        implement the `permit` function via the secp256k1 signature
        parameters `v`, `r`, and `s` and do not support EIP-2098
        signatures (64-byte length, see https://eips.ethereum.org/EIPS/eip-2098).
        The ERC-165 identifier for this interface is `0x589C5CE2`.

        On how to use interfaces in Vyper, please visit:
        https://vyper.readthedocs.io/en/latest/interfaces.html#interfaces.
"""


# @dev We import and implement the `IERC165` interface,
# which is a built-in interface of the Vyper compiler.
from ethereum.ercs import IERC165
implements: IERC165


@external
@view
def supportsInterface(interfaceId: bytes4) -> bool:
    """
    @dev Returns `True` if this contract implements the
         interface defined by `interfaceId`.
    @notice For more details on how these identifiers are
            created, please refer to:
            https://eips.ethereum.org/EIPS/eip-165.
    @param interfaceId The 4-byte interface identifier.
    @return bool The verification whether the contract
            implements the interface or not.
    """
    ...


@external
def permit(spender: address, tokenId: uint256, deadline: uint256, v: uint8, r: bytes32, s: bytes32):
    """
    @dev Sets permission to `spender` to transfer `tokenId`
         token to another account, given `owner`'s signed
         approval.
    @notice Note that `spender` cannot be the zero address.
            Also, `deadline` must be a block timestamp in
            the future. `v`, `r`, and `s` must be a valid
            secp256k1 signature from `owner` over the
            EIP-712-formatted function arguments. Eventually,
            the signature must use `tokenId`'s current nonce.
    @param spender The 20-byte spender address.
    @param tokenId The 32-byte identifier of the token.
    @param deadline The 32-byte block timestamp up
           which the `spender` is allowed to spend `tokenId`.
    @param v The secp256k1 1-byte signature parameter `v`.
    @param r The secp256k1 32-byte signature parameter `r`.
    @param s The secp256k1 32-byte signature parameter `s`.
    """
    ...


@external
@view
def nonces(tokenId: uint256) -> uint256:
    """
    @dev Returns the current on-chain tracked nonce of `tokenId`.
    @param tokenId The 32-byte identifier of the token.
    @return uint256 The 32-byte `tokenId` nonce.
    """
    ...


@external
@view
def DOMAIN_SEPARATOR() -> bytes32:
    """
    @dev Returns the domain separator for the current chain.
    @return bytes32 The 32-byte domain separator.
    """
    ...

File 6 of 13 : Vyper_contract.vy
# pragma version ~=0.4.3
"""
@title EIP-4906 Interface Definition
@custom:contract-name IERC4906
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice The ERC-4906 standard is an extension of EIP-721.
        It adds a `MetadataUpdate` event to EIP-721 tokens.
        The ERC-165 identifier for this interface is `0x49064906`.
        For more details, please refer to:
        https://eips.ethereum.org/EIPS/eip-4906.

        On how to use interfaces in Vyper, please visit:
        https://vyper.readthedocs.io/en/latest/interfaces.html#interfaces.
"""


# @dev We import and implement the `IERC165` interface,
# which is a built-in interface of the Vyper compiler.
from ethereum.ercs import IERC165
implements: IERC165


# @dev We import the `IERC721` interface, which is a built-in
# interface of the Vyper compiler, to highlight the association
# of the custom `IERC4906` interface with the built-in `IERC721`
# interface.
# @notice The interface `IERC4906` must be used in conjunction
# with the built-in interface `IERC721` to be EIP-721 compatible.
# If you want to use this interface as a stand-alone interface,
# you must add `implements: IERC721` to this interface and implement
# all required events and functions accordingly.
from ethereum.ercs import IERC721


# @dev Emitted when the metadata of a token is changed.
# Thus, third-party platforms, such as NFT marketplaces,
# can update the images and associated attributes of the
# NFT in a timely manner.
event MetadataUpdate:
    _tokenId: uint256


# @dev Emitted when the metadata of a range of tokens is
# changed. Thus, third-party platforms, such as NFT marketplaces,
# can update the images and associated attributes of the
# NFTs in a timely manner.
event BatchMetadataUpdate:
    _fromTokenId: uint256
    _toTokenId: uint256


@external
@view
def supportsInterface(interfaceId: bytes4) -> bool:
    """
    @dev Returns `True` if this contract implements the
         interface defined by `interfaceId`.
    @notice For more details on how these identifiers are
            created, please refer to:
            https://eips.ethereum.org/EIPS/eip-165.
    @param interfaceId The 4-byte interface identifier.
    @return bool The verification whether the contract
            implements the interface or not.
    """
    ...

File 7 of 13 : Vyper_contract.vy
# pragma version ~=0.4.3
"""
@title EIP-5267 Interface Definition
@custom:contract-name IERC5267
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice The ERC-5267 standard complements the EIP-712 standard
        by standardising how contracts should publish the fields
        and values that describe their domain. This enables
        applications to retrieve this description and generate
        appropriate domain separators in a general way, and thus
        integrate EIP-712 signatures securely and scalably. For
        more details, please refer to:
        https://eips.ethereum.org/EIPS/eip-5267.

        Note that Vyper interfaces that implement functions
        with return values that require an upper bound (e.g.
        `Bytes`, `DynArray`, or `String`), the upper bound
        defined in the interface represents the lower bound
        of the implementation:
        https://github.com/vyperlang/vyper/pull/3205.

        On how to use interfaces in Vyper, please visit:
        https://vyper.readthedocs.io/en/latest/interfaces.html#interfaces.
"""


# @dev May be emitted to signal that the domain could
# have changed.
event EIP712DomainChanged:
    pass


@external
@view
def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 32]):
    """
    @dev Returns the fields and values that describe the domain
         separator used by this contract for EIP-712 signatures.
    @notice The bits in the 1-byte bit map are read from the least
            significant to the most significant, and fields are indexed
            in the order that is specified by EIP-712, identical to the
            order in which they are listed in the function type.
    @return bytes1 The 1-byte bit map where bit `i` is set to `1`
            if and only if domain field `i` is present (`0 ≤ i ≤ 4`).
    @return String The maximum 50-character user-readable string name
            of the signing domain, i.e. the name of the dApp or protocol.
    @return String The maximum 20-character current main version of
            the signing domain. Signatures from different versions are
            not compatible.
    @return uint256 The 32-byte EIP-155 chain ID.
    @return address The 20-byte address of the verifying contract.
    @return bytes32 The 32-byte disambiguation salt for the protocol.
    @return DynArray The 32-byte array of EIP-712 extensions.
    """
    ...

File 8 of 13 : Vyper_contract.vy
# pragma version ~=0.4.3
"""
@title EIP-721 Token Receiver Interface Definition
@custom:contract-name IERC721Receiver
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice The interface definition for any contract
        that wants to support safe transfers from
        ERC-721 asset contracts. For more details,
        please refer to:
        https://eips.ethereum.org/EIPS/eip-721#specification.

        On how to use interfaces in Vyper, please visit:
        https://vyper.readthedocs.io/en/latest/interfaces.html#interfaces.
"""


@external
def onERC721Received(_operator: address, _from: address, _tokenId: uint256, _data: Bytes[1_024]) -> bytes4:
    """
    @dev Whenever a `_tokenId` token is transferred to
         this contract via `safeTransferFrom` by
         `_operator` from `_from`, this function is called.
    @notice It must return its function selector to
            confirm the token transfer. If any other value
            is returned or the interface is not implemented
            by the recipient, the transfer will be reverted.
    @param _operator The 20-byte address which called
           the `safeTransferFrom` function.
    @param _from The 20-byte address which previously
           owned the token.
    @param _tokenId The 32-byte identifier of the token.
    @param _data The maximum 1,024-byte additional data
           with no specified format.
    @return bytes4 The 4-byte function selector of `onERC721Received`.
    """
    ...

File 9 of 13 : ecdsa.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title Elliptic Curve Digital Signature Algorithm (ECDSA) Secp256k1-Based Functions
@custom:contract-name ecdsa
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions can be used to verify that a message was signed by
        the holder of the private key of a given address. All cryptographic
        calculations are based on the Ethereum-native secp256k1 elliptic curve
        (see https://en.bitcoin.it/wiki/Secp256k1). For verification functions
        based on the NIST P-256 elliptic curve (also known as secp256r1), see
        the {p256} contract. The implementation is inspired by OpenZeppelin's
        implementation here:
        https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol.
@custom:security Signatures must not be used as unique identifiers since the
                 `ecrecover` EVM precompile allows for malleable (non-unique)
                 signatures (see EIP-2: https://eips.ethereum.org/EIPS/eip-2)
                 or signatures can be malleablised using EIP-2098:
                 https://eips.ethereum.org/EIPS/eip-2098.
"""


# @dev The malleability threshold used as part of the ECDSA
# verification function.
_MALLEABILITY_THRESHOLD: constant(uint256) = (
    57_896_044_618_658_097_711_785_492_504_343_953_926_418_782_139_537_452_191_302_581_570_759_080_747_168
)


@deploy
@payable
def __init__():
    """
    @dev To omit the opcodes for checking the `msg.value`
         in the creation-time EVM bytecode, the constructor
         is declared as `payable`.
    """
    pass


@internal
@pure
def _recover_sig(hash: bytes32, signature: Bytes[65]) -> address:
    """
    @dev Recovers the signer address from a message digest `hash`
         and the signature `signature`.
    @notice WARNING: This function is vulnerable to a kind of
            signature malleability due to accepting EIP-2098
            compact signatures in addition to the traditional
            65-byte signature format. The potentially affected
            contracts are those that implement signature reuse
            or replay protection by marking the signature itself
            as used rather than the signed message or a nonce
            included in it. A user may take a signature that has
            already been submitted, submit it again in a different
            form, and bypass this protection. Also, see OpenZeppelin's
            security advisory for more information:
            https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h.
    @param hash The 32-byte message digest that was signed.
    @param signature The secp256k1 64/65-byte signature of `hash`.
    @return address The recovered 20-byte signer address.
    """
    sig_length: uint256 = len(signature)
    # 65-byte case: `(r,s,v)` standard signature.
    if sig_length == 65:
        r: uint256 = extract32(signature, empty(uint256), output_type=uint256)
        s: uint256 = extract32(signature, 32, output_type=uint256)
        v: uint256 = convert(slice(signature, 64, 1), uint256)
        return self._try_recover_vrs(hash, v, r, s)
    # 64-byte case: `(r,vs)` signature; see: https://eips.ethereum.org/EIPS/eip-2098.
    elif sig_length == 64:
        r: uint256 = extract32(signature, empty(uint256), output_type=uint256)
        vs: uint256 = extract32(signature, 32, output_type=uint256)
        return self._try_recover_r_vs(hash, r, vs)

    return empty(address)


@internal
@pure
def _recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address:
    """
    @dev Recovers the signer address from a message digest `hash`
         and the secp256k1 signature parameters `v`, `r`, and `s`.
    @param hash The 32-byte message digest that was signed.
    @param v The secp256k1 1-byte signature parameter `v`.
    @param r The secp256k1 32-byte signature parameter `r`.
    @param s The secp256k1 32-byte signature parameter `s`.
    @return address The recovered 20-byte signer address.
    """
    return self._try_recover_vrs(hash, v, r, s)


@internal
@pure
def _try_recover_r_vs(hash: bytes32, r: uint256, vs: uint256) -> address:
    """
    @dev Recovers the signer address from a message digest `hash`
         and the secp256k1 short signature fields `r` and `vs`.
    @notice See https://eips.ethereum.org/EIPS/eip-2098 for the
            compact signature representation.
    @param hash The 32-byte message digest that was signed.
    @param r The secp256k1 32-byte signature parameter `r`.
    @param vs The secp256k1 32-byte short signature field of `v` and `s`.
    @return address The recovered 20-byte signer address.
    """
    s: uint256 = vs & convert(max_value(int256), uint256)
    # We do not check for an overflow here, as the shift operation
    # `vs >> 255` results in `0` or `1`.
    v: uint256 = unsafe_add(vs >> 255, 27)
    return self._try_recover_vrs(hash, v, r, s)


@internal
@pure
def _try_recover_vrs(hash: bytes32, v: uint256, r: uint256, s: uint256) -> address:
    """
    @dev Recovers the signer address from a message digest `hash`
         and the secp256k1 signature parameters `v`, `r`, and `s`.
    @notice All client implementations of the precompile `ecrecover`
            check if the value of `v` is `27` or `28`. The references
            for the different client implementations can be found here:
            https://github.com/ethereum/yellowpaper/pull/860. Thus,
            the signature check on the value of `v` is neglected.
    @param hash The 32-byte message digest that was signed.
    @param v The secp256k1 1-byte signature parameter `v`.
    @param r The secp256k1 32-byte signature parameter `r`.
    @param s The secp256k1 32-byte signature parameter `s`.
    @return address The recovered 20-byte signer address.
    """
    assert s <= _MALLEABILITY_THRESHOLD, "ecdsa: invalid signature `s` value"

    signer: address = ecrecover(hash, v, r, s)
    assert signer != empty(address), "ecdsa: invalid signature"

    return signer

File 10 of 13 : message_hash_utils.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title Signature Message Hash Utility Functions
@custom:contract-name message_hash_utils
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions can be used to generate message hashes that conform
        to the EIP-191 (https://eips.ethereum.org/EIPS/eip-191) as well as
        EIP-712 (https://eips.ethereum.org/EIPS/eip-712) specifications. The
        implementation is inspired by OpenZeppelin's implementation here:
        https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MessageHashUtils.sol.
"""


@deploy
@payable
def __init__():
    """
    @dev To omit the opcodes for checking the `msg.value`
         in the creation-time EVM bytecode, the constructor
         is declared as `payable`.
    """
    pass


@internal
@pure
def _to_eth_signed_message_hash(hash: bytes32) -> bytes32:
    """
    @dev Returns an Ethereum signed message from a 32-byte
         message digest `hash`.
    @notice This function returns a 32-byte hash that
            corresponds to the one signed with the JSON-RPC method:
            https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign.
            This method is part of EIP-191:
            https://eips.ethereum.org/EIPS/eip-191.
    @param hash The 32-byte message digest.
    @return bytes32 The 32-byte Ethereum signed message.
    """
    return keccak256(concat(b"\x19Ethereum Signed Message:\n32", hash))


@internal
@view
def _to_data_with_intended_validator_hash_self(data: Bytes[1_024]) -> bytes32:
    """
    @dev Returns an Ethereum signed data with this contract
         as the intended validator and a maximum 1,024-byte
         payload `data`.
    @notice This function structures the data according to
            the version `0x00` of EIP-191:
            https://eips.ethereum.org/EIPS/eip-191#version-0x00.
    @param data The maximum 1,024-byte data to be signed.
    @return bytes32 The 32-byte Ethereum signed data.
    """
    return self._to_data_with_intended_validator_hash(self, data)


@internal
@pure
def _to_data_with_intended_validator_hash(validator: address, data: Bytes[1_024]) -> bytes32:
    """
    @dev Returns an Ethereum signed data with `validator` as
         the intended validator and a maximum 1,024-byte payload
         `data`.
    @notice This function structures the data according to
            the version `0x00` of EIP-191:
            https://eips.ethereum.org/EIPS/eip-191#version-0x00.
    @param validator The 20-byte intended validator address.
    @param data The maximum 1,024-byte data to be signed.
    @return bytes32 The 32-byte Ethereum signed data.
    """
    return keccak256(concat(x"1900", convert(validator, bytes20), data))


@internal
@pure
def _to_typed_data_hash(domain_separator: bytes32, struct_hash: bytes32) -> bytes32:
    """
    @dev Returns an Ethereum signed typed data from a 32-byte
         `domain_separator` and a 32-byte `struct_hash`.
    @notice This function returns a 32-byte hash that
            corresponds to the one signed with the JSON-RPC method:
            https://eips.ethereum.org/EIPS/eip-712#specification-of-the-eth_signtypeddata-json-rpc.
            This method is part of EIP-712:
            https://eips.ethereum.org/EIPS/eip-712.
    @param domain_separator The 32-byte domain separator that is
           used as part of the EIP-712 encoding scheme.
    @param struct_hash The 32-byte struct hash that is used as
           part of the EIP-712 encoding scheme. See the definition:
           https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
    @return bytes32 The 32-byte Ethereum signed typed data.
    """
    return keccak256(concat(x"1901", domain_separator, struct_hash))

File 11 of 13 : eip712_domain_separator.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title EIP-712 Domain Separator
@custom:contract-name eip712_domain_separator
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions are part of EIP-712: https://eips.ethereum.org/EIPS/eip-712.
        These functions implement the version of encoding known
        as "v4" as implemented by the JSON-RPC method:
        https://docs.metamask.io/guide/signing-data.html#sign-typed-data-v4.
        In addition, this contract also implements EIP-5267:
        https://eips.ethereum.org/EIPS/eip-5267.
        The implementation is inspired by OpenZeppelin's implementation here:
        https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol.
"""


# @dev We import and implement the `IERC5267` interface,
# which is written using standard Vyper syntax.
from .interfaces import IERC5267
implements: IERC5267


# @dev We import the `message_hash_utils` module.
# @notice Please note that the `message_hash_utils`
# module is stateless and therefore does not require
# the `uses` keyword for usage.
from . import message_hash_utils


# @dev The 32-byte type hash for the EIP-712 domain separator.
_TYPE_HASH: constant(bytes32) = keccak256(
    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
)


# @dev Caches the domain separator as an `immutable`
# value, but also stores the corresponding chain ID
# to invalidate the cached domain separator if the
# chain ID changes.
_CACHED_DOMAIN_SEPARATOR: immutable(bytes32)
_CACHED_CHAIN_ID: immutable(uint256)


# @dev Caches `self` to `immutable` storage to avoid
# potential issues if a vanilla contract is used in
# a `delegatecall` context.
_CACHED_SELF: immutable(address)


# @dev `immutable` variables to store the (hashed)
# name and (hashed) version during contract creation.
_NAME: immutable(String[50])
_HASHED_NAME: immutable(bytes32)
_VERSION: immutable(String[20])
_HASHED_VERSION: immutable(bytes32)


@deploy
@payable
def __init__(name_: String[50], version_: String[20]):
    """
    @dev Initialises the domain separator and the parameter caches.
         To omit the opcodes for checking the `msg.value` in the
         creation-time EVM bytecode, the constructor is declared as
         `payable`.
    @notice The definition of the domain separator can be found here:
            https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator.
            Since the Vyper design requires strings of fixed size,
            we arbitrarily set the maximum length for `name` to 50
            characters and `version` to 20 characters.
    @param name_ The maximum 50-character user-readable string name
           of the signing domain, i.e. the name of the dApp or protocol.
    @param version_ The maximum 20-character current main version of
           the signing domain. Signatures from different versions are
           not compatible.
    """
    _NAME = name_
    _VERSION = version_
    _HASHED_NAME = keccak256(name_)
    _HASHED_VERSION = keccak256(version_)
    _CACHED_DOMAIN_SEPARATOR = self._build_domain_separator()
    _CACHED_CHAIN_ID = chain.id
    _CACHED_SELF = self


@external
@view
def eip712Domain() -> (bytes1, String[50], String[20], uint256, address, bytes32, DynArray[uint256, 32]):
    """
    @dev Returns the fields and values that describe the domain
         separator used by this contract for EIP-712 signatures.
    @notice The bits in the 1-byte bit map are read from the least
            significant to the most significant, and fields are indexed
            in the order that is specified by EIP-712, identical to the
            order in which they are listed in the function type.
    @return bytes1 The 1-byte bit map where bit `i` is set to `1`
            if and only if domain field `i` is present (`0 ≤ i ≤ 4`).
    @return String The maximum 50-character user-readable string name
            of the signing domain, i.e. the name of the dApp or protocol.
    @return String The maximum 20-character current main version of
            the signing domain. Signatures from different versions are
            not compatible.
    @return uint256 The 32-byte EIP-155 chain ID.
    @return address The 20-byte address of the verifying contract.
    @return bytes32 The 32-byte disambiguation salt for the protocol.
    @return DynArray The 32-byte array of EIP-712 extensions.
    """
    # Note that `0x0f` equals `01111`.
    return (0x0f, _NAME, _VERSION, chain.id, self, empty(bytes32), empty(DynArray[uint256, 32]))


@internal
@view
def _domain_separator_v4() -> bytes32:
    """
    @dev Returns the domain separator for the current chain.
    @return bytes32 The 32-byte domain separator.
    """
    if self == _CACHED_SELF and chain.id == _CACHED_CHAIN_ID:
        return _CACHED_DOMAIN_SEPARATOR

    return self._build_domain_separator()


@internal
@view
def _build_domain_separator() -> bytes32:
    """
    @dev Builds the domain separator for the current chain.
    @return bytes32 The 32-byte domain separator.
    """
    return keccak256(abi_encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, chain.id, self))


@internal
@view
def _hash_typed_data_v4(struct_hash: bytes32) -> bytes32:
    """
    @dev Returns the hash of the fully encoded EIP-712
         message for this domain.
    @notice The definition of the hashed struct can be found here:
            https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
    @param struct_hash The 32-byte hashed struct.
    @return bytes32 The 32-byte fully encoded EIP712
            message hash for this domain.
    """
    return message_hash_utils._to_typed_data_hash(self._domain_separator_v4(), struct_hash)

File 12 of 13 : erc721.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title Modern and Gas-Efficient ERC-721 + EIP-4494 Implementation
@custom:contract-name erc721
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions implement the ERC-721
        standard interface:
        - https://eips.ethereum.org/EIPS/eip-721.
        In addition, the following functions have
        been added for convenience:
        - `name` (`external` `view` function),
        - `symbol` (`external` `view` function),
        - `tokenURI` (`external` `view` function),
        - `totalSupply` (`external` `view` function),
        - `tokenByIndex` (`external` `view` function),
        - `tokenOfOwnerByIndex` (`external` `view` function),
        - `burn` (`external` function),
        - `is_minter` (`external` `view` function),
        - `safe_mint` (`external` function),
        - `set_minter` (`external` function),
        - `permit` (`external` function),
        - `nonces` (`external` `view` function),
        - `DOMAIN_SEPARATOR` (`external` `view` function),
        - `eip712Domain` (`external` `view` function),
        - `owner` (`external` `view` function),
        - `transfer_ownership` (`external` function),
        - `renounce_ownership` (`external` function),
        - `_check_on_erc721_received` (`internal` function),
        - `_before_token_transfer` (`internal` function),
        - `_after_token_transfer` (`internal` function).
        The `permit` function implements approvals via
        EIP-712 secp256k1 signatures for ERC-721 tokens:
        https://eips.ethereum.org/EIPS/eip-4494.
        In addition, this contract also implements the EIP-5267
        function `eip712Domain`:
        https://eips.ethereum.org/EIPS/eip-5267.
        Eventually, this contract also implements the EIP-4906
        metadata update extension:
        https://eips.ethereum.org/EIPS/eip-4906.
        The implementation is inspired by OpenZeppelin's
        implementation here:
        https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol,
        as well as by ApeAcademy's implementation here:
        https://github.com/ApeAcademy/ERC721/blob/main/%7B%7Bcookiecutter.project_name%7D%7D/contracts/NFT.vy.
"""


# @dev We import and implement the `IERC165` interface,
# which is a built-in interface of the Vyper compiler.
from ethereum.ercs import IERC165
implements: IERC165


# @dev We import and implement the `IERC721` interface,
# which is a built-in interface of the Vyper compiler.
from ethereum.ercs import IERC721
implements: IERC721


# @dev We import and implement the `IERC721Metadata`
# interface, which is written using standard Vyper
# syntax.
from .interfaces import IERC721Metadata
implements: IERC721Metadata


# @dev We import and implement the `IERC721Enumerable`
# interface, which is written using standard Vyper
# syntax.
from .interfaces import IERC721Enumerable
implements: IERC721Enumerable


# @dev We import and implement the `IERC721Permit`
# interface, which is written using standard Vyper
# syntax.
from .interfaces import IERC721Permit
implements: IERC721Permit


# @dev We import and implement the `IERC4906` interface,
# which is written using standard Vyper syntax.
from .interfaces import IERC4906
implements: IERC4906


# @dev We import and implement the `IERC5267` interface,
# which is written using standard Vyper syntax.
from ..utils.interfaces import IERC5267
implements: IERC5267


# @dev We import the `IERC721Receiver` interface, which
# is written using standard Vyper syntax.
from .interfaces import IERC721Receiver


# @dev We import and use the `ownable` module.
from ..auth import ownable
uses: ownable


# @dev We import the `ecdsa` module.
# @notice Please note that the `ecdsa` module
# is stateless and therefore does not require
# the `uses` keyword for usage.
from ..utils import ecdsa


# @dev We import and initialise the `eip712_domain_separator` module.
from ..utils import eip712_domain_separator
initializes: eip712_domain_separator


# @dev We export (i.e. the runtime bytecode exposes these
# functions externally, allowing them to be called using
# the ABI encoding specification) the `external` getter
# function `owner` from the `ownable` module as well as the
# function `eip712Domain` from the `eip712_domain_separator`
# module.
# @notice Please note that you must always also export (if
# required by the contract logic) `public` declared `constant`,
# `immutable`, and state variables, for which Vyper automatically
# generates an `external` getter function for the variable.
exports: (
    # @notice This ERC-721 implementation includes the `transfer_ownership`
    # and `renounce_ownership` functions, which incorporate
    # the additional built-in `is_minter` role logic and are
    # therefore not exported from the `ownable` module.
    ownable.owner,
    eip712_domain_separator.eip712Domain,
)


# @dev Stores the ERC-165 interface identifier for each
# imported interface. The ERC-165 interface identifier
# is defined as the XOR of all function selectors in the
# interface.
# @notice If you are not using the full feature set of
# this contract, please ensure you exclude the unused
# ERC-165 interface identifiers in the main contract.
_SUPPORTED_INTERFACES: constant(bytes4[6]) = [
    0x01FFC9A7, # The ERC-165 identifier for ERC-165.
    0x80AC58CD, # The ERC-165 identifier for ERC-721.
    0x5B5E139F, # The ERC-165 identifier for the ERC-721 metadata extension.
    0x780E9D63, # The ERC-165 identifier for the ERC-721 enumeration extension.
    0x589C5CE2, # The ERC-165 identifier for ERC-4494.
    0x49064906, # The ERC-165 identifier for ERC-4906.
]


# @dev The 32-byte type hash of the `permit` function.
_PERMIT_TYPE_HASH: constant(bytes32) = keccak256(
    "Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)"
)


# @dev Returns the token collection name.
# @notice If you declare a variable as `public`,
# Vyper automatically generates an `external`
# getter function for the variable. Furthermore,
# to preserve consistency with the interface for
# the optional metadata functions of the ERC-721
# standard, we use lower case letters for the
# `immutable` variables `name` and `symbol`.
name: public(immutable(String[25]))


# @dev Returns the token collection symbol.
# @notice See comment on lower case letters
# above at `name`.
symbol: public(immutable(String[5]))


# @dev Stores the base URI for computing `tokenURI`.
_BASE_URI: immutable(String[80])


# @dev Mapping from owner to operator approvals.
isApprovedForAll: public(HashMap[address, HashMap[address, bool]])


# @dev Returns `True` if an `address` has been
# granted the minter role.
is_minter: public(HashMap[address, bool])


# @dev Returns the current on-chain tracked nonce
# of `token_id`.
nonces: public(HashMap[uint256, uint256])


# @dev Mapping from owner address to token count.
_balances: HashMap[address, uint256]


# @dev Mapping from token ID to owner address.
_owners: HashMap[uint256, address]


# @dev Mapping from token ID to approved address.
_token_approvals: HashMap[uint256, address]


# @dev Mapping from owner to list of owned token IDs.
_owned_tokens: HashMap[address, HashMap[uint256, uint256]]


# @dev Mapping from token ID to index of the owner
# tokens list.
_owned_tokens_index: HashMap[uint256, uint256]


# @dev Array with all token IDs used for enumeration.
_all_tokens: DynArray[uint256, max_value(uint64)]


# @dev Mapping from token ID to position in the
# `_all_tokens` array.
_all_tokens_index: HashMap[uint256, uint256]


# @dev Mapping from token ID to token URI.
# @notice Since the Vyper design requires
# strings of fixed size, we arbitrarily set
# the maximum length for `_token_uris` to 432
# characters. Since we have set the maximum
# length for `_BASE_URI` to 80 characters,
# which implies a maximum character length
# for `tokenURI` of 512.
_token_uris: HashMap[uint256, String[432]]


# @dev An `uint256` counter variable that sets
# the token ID for each `safe_mint` call and
# then increments.
_counter: uint256


# @dev Emitted when the status of a `minter`
# address is changed.
event RoleMinterChanged:
    minter: indexed(address)
    status: bool


@deploy
@payable
def __init__(
    name_: String[25], symbol_: String[5], base_uri_: String[80], name_eip712_: String[50], version_eip712_: String[20]
):
    """
    @dev To omit the opcodes for checking the `msg.value`
         in the creation-time EVM bytecode, the constructor
         is declared as `payable`.
    @notice At initialisation time, the `owner` role will be
            assigned to the `msg.sender` since we `uses` the
            `ownable` module, which implements the aforementioned
            logic at contract creation time.
    @param name_ The maximum 25-character user-readable string
           name of the token collection.
    @param symbol_ The maximum 5-character user-readable string
           symbol of the token collection.
    @param base_uri_ The maximum 80-character user-readable
           string base URI for computing `tokenURI`.
    @param name_eip712_ The maximum 50-character user-readable
           string name of the signing domain, i.e. the name
           of the dApp or protocol.
    @param version_eip712_ The maximum 20-character current
           main version of the signing domain. Signatures
           from different versions are not compatible.
    """
    self._counter = empty(uint256)

    name = name_
    symbol = symbol_
    _BASE_URI = base_uri_

    self.is_minter[msg.sender] = True
    log RoleMinterChanged(minter=msg.sender, status=True)

    eip712_domain_separator.__init__(name_eip712_, version_eip712_)


@external
@view
def supportsInterface(interface_id: bytes4) -> bool:
    """
    @dev Returns `True` if this contract implements the
         interface defined by `interface_id`.
    @param interface_id The 4-byte interface identifier.
    @return bool The verification whether the contract
            implements the interface or not.
    """
    return interface_id in _SUPPORTED_INTERFACES


@external
@view
def balanceOf(owner: address) -> uint256:
    """
    @dev Returns the amount of tokens owned by `owner`.
    @notice Note that `owner` cannot be the zero address.
    @param owner The 20-byte owner address.
    @return uint256 The 32-byte token amount owned
            by `owner`.
    """
    return self._balance_of(owner)


@external
@view
def ownerOf(token_id: uint256) -> address:
    """
    @dev Returns the owner of the `token_id` token.
    @notice Note that `token_id` must exist.
    @param token_id The 32-byte identifier of the token.
    @return address The 20-byte owner address.
    """
    return self._owner_of(token_id)


@external
@payable
def approve(to: address, token_id: uint256):
    """
    @dev Gives permission to `to` to transfer
         `token_id` token to another account.
         The approval is cleared when the token
         is transferred.
    @notice Only a single account can be approved
            at a time, so approving the zero address
            clears previous approvals. Also, the
            caller must own the token or be an
            approved operator, and `token_id` must
            exist.

            IMPORTANT: The function is declared as
            `payable` to comply with the EIP-721
            standard definition:
            https://eips.ethereum.org/EIPS/eip-721.
    @param to The 20-byte spender address.
    @param token_id The 32-byte identifier of the token.
    """
    owner: address = self._owner_of(token_id)
    assert to != owner, "erc721: approval to current owner"
    assert (
        msg.sender == owner or self.isApprovedForAll[owner][msg.sender]
    ), "erc721: approve caller is not token owner or approved for all"
    self._approve(to, token_id)


@external
@view
def getApproved(token_id: uint256) -> address:
    """
    @dev Returns the account approved for `token_id`
         token.
    @notice Note that `token_id` must exist.
    @param token_id The 32-byte identifier of the token.
    @return address The 20-byte approved address.
    """
    return self._get_approved(token_id)


@external
def setApprovalForAll(operator: address, approved: bool):
    """
    @dev Approves or removes `operator` as an operator
         for the caller. Operators can call `transferFrom`
         or `safeTransferFrom` for any token owned by
         the caller.
    @notice Note that the `operator` cannot be the caller.
    @param operator The 20-byte operator address.
    @param approved The Boolean variable that sets the
           approval status.
    """
    self._set_approval_for_all(msg.sender, operator, approved)


@external
@payable
def transferFrom(owner: address, to: address, token_id: uint256):
    """
    @dev Transfers `token_id` token from `owner` to `to`.
    @notice WARNING: Note that the caller is responsible
            to confirm that the recipient is capable of
            receiving an ERC-721 token or else they may
            be permanently lost. Usage of `safeTransferFrom`
            prevents loss, though the caller must understand
            this adds an external call which potentially
            creates a reentrancy vulnerability.

            Note that `owner` and `to` cannot be the zero
            address. Also, `token_id` token must exist and
            must be owned by `owner`. Eventually, if the caller
            is not `owner`, it must be approved to move this
            token by either `approve` or `setApprovalForAll`.

            IMPORTANT: The function is declared as `payable`
            to comply with the EIP-721 standard definition:
            https://eips.ethereum.org/EIPS/eip-721.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param token_id The 32-byte identifier of the token.
    """
    assert self._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved"
    self._transfer(owner, to, token_id)


@external
@payable
def safeTransferFrom(owner: address, to: address, token_id: uint256, data: Bytes[1_024] = b""):
    """
    @dev Safely transfers `token_id` token from `owner`
         to `to`.
    @notice Note that `owner` and `to` cannot be the zero
            address. Also, `token_id` token must exist and
            must be owned by `owner`. Furthermore, if the caller
            is not `owner`, it must be approved to move this
            token by either `approve` or `setApprovalForAll`.
            Eventually, if `to` refers to a smart contract,
            it must implement {IERC721Receiver-onERC721Received},
            which is called upon a safe transfer.

            The Vyper compiler processes this function `safeTransferFrom`
            as two separate function selectors, since a default
            parameter `b""` is set in the function declaration.
            Anyone can invoke this function using only `owner`,
            `to`, and `token_id` as arguments, and is therefore
            compatible with the function overloading of `safeTransferFrom`
            in the standard ERC-721 interface. You can find more
            information here:
            - https://github.com/vyperlang/vyper/issues/903,
            - https://github.com/vyperlang/vyper/pull/987.

            IMPORTANT: The function is declared as `payable`
            to comply with the EIP-721 standard definition:
            https://eips.ethereum.org/EIPS/eip-721.

            WARNING: This function can potentially allow a reentrancy
            attack when transferring tokens to an untrusted contract,
            when invoking {IERC721Receiver-onERC721Received} on the
            receiver. We ensure that we consistently follow the checks-
            effects-interactions (CEI) pattern to avoid being vulnerable
            to this type of attack.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param token_id The 32-byte identifier of the token.
    @param data The maximum 1,024-byte additional data
           with no specified format that is sent
           to `to`.
    """
    assert self._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved"
    self._safe_transfer(owner, to, token_id, data)


@external
@view
def tokenURI(token_id: uint256) -> String[512]:
    """
    @dev Returns the Uniform Resource Identifier (URI)
         for `token_id` token.
    @notice Throws if `token_id` is not a valid ERC-721 token.
    @param token_id The 32-byte identifier of the token.
    @return String The maximum 512-character user-readable
            string token URI of the `token_id` token.
    """
    self._require_minted(token_id)
    token_uri: String[432] = self._token_uris[token_id]

    base_uri_length: uint256 = len(_BASE_URI)
    # If there is no base URI, return the token URI.
    if base_uri_length == empty(uint256):
        return token_uri
    # If both are set, concatenate the base URI
    # and token URI.
    elif len(token_uri) != empty(uint256):
        return concat(_BASE_URI, token_uri)
    # If there is no token URI but a base URI,
    # concatenate the base URI and token ID.
    elif base_uri_length != empty(uint256):
        return concat(_BASE_URI, uint2str(token_id))

    return ""


@external
@view
def totalSupply() -> uint256:
    """
    @dev Returns the amount of tokens in existence.
    @return uint256 The 32-byte token supply.
    """
    return self._total_supply()


@external
@view
def tokenByIndex(index: uint256) -> uint256:
    """
    @dev Returns a token ID at a given `index` of
         all the tokens stored by the contract.
    @notice Use along with `totalSupply` to enumerate
            all tokens.
    @param index The 32-byte counter (must be less
           than `totalSupply`).
    @return uint256 The 32-byte token ID at index
            `index`.
    """
    assert index < self._total_supply(), "erc721: global index out of bounds"
    return self._all_tokens[index]


@external
@view
def tokenOfOwnerByIndex(owner: address, index: uint256) -> uint256:
    """
    @dev Returns a token ID owned by `owner` at a
         given `index` of its token list.
    @notice Use along with `balanceOf` to enumerate
            all of `owner`'s tokens.
    @param owner The 20-byte owner address.
    @param index The 32-byte counter (must be less
           than `balanceOf(owner)`).
    @return uint256 The 32-byte token ID owned by
            `owner` at index `index`.
    """
    assert index < self._balance_of(owner), "erc721: owner index out of bounds"
    return self._owned_tokens[owner][index]


@external
def burn(token_id: uint256):
    """
    @dev Burns the `token_id` token.
    @notice Note that the caller must own `token_id`
            or be an approved operator.
    @param token_id The 32-byte identifier of the token.
    """
    assert self._is_approved_or_owner(msg.sender, token_id), "erc721: caller is not token owner or approved"
    self._burn(token_id)


@external
def safe_mint(owner: address, uri: String[432]):
    """
    @dev Safely mints `token_id` and transfers it to `owner`.
    @notice Only authorised minters can access this function.
            Note that `owner` cannot be the zero address.
            Also, new tokens will be automatically assigned
            an incremental ID.
    @param owner The 20-byte owner address.
    @param uri The maximum 432-character user-readable
           string URI for computing `tokenURI`.
    """
    assert self.is_minter[msg.sender], "erc721: access is denied"
    # New tokens will be automatically assigned an incremental ID.
    # The first token ID will be zero.
    token_id: uint256 = self._counter
    self._counter = token_id + 1
    # Theoretically, the following line could overflow
    # if all 2**256 token IDs were minted. However,
    # since we have bounded the dynamic array `_all_tokens`
    # by the maximum value of `uint64` and the `_counter`
    # increments above are checked for an overflow, this is
    # no longer even theoretically possible.
    self._safe_mint(owner, token_id, b"")
    self._set_token_uri(token_id, uri)


@external
def set_minter(minter: address, status: bool):
    """
    @dev Adds or removes an address `minter` to/from the
         list of allowed minters. Note that only the
         `owner` can add or remove `minter` addresses.
         Also, the `minter` cannot be the zero address.
         Eventually, the `owner` cannot remove himself
         from the list of allowed minters.
    @param minter The 20-byte minter address.
    @param status The Boolean variable that sets the status.
    """
    ownable._check_owner()
    assert minter != empty(address), "erc721: minter is the zero address"
    # We ensured in the previous step `ownable._check_owner`
    # that `msg.sender` is the `owner`.
    assert minter != msg.sender, "erc721: minter is owner address"
    self.is_minter[minter] = status
    log RoleMinterChanged(minter=minter, status=status)


@external
def permit(spender: address, token_id: uint256, deadline: uint256, v: uint8, r: bytes32, s: bytes32):
    """
    @dev Sets permission to `spender` to transfer `token_id`
         token to another account, given `owner`'s signed
         approval.
    @notice Note that `spender` cannot be the zero address.
            Also, `deadline` must be a block timestamp in
            the future. `v`, `r`, and `s` must be a valid
            secp256k1 signature from `owner` over the
            EIP-712-formatted function arguments. Eventually,
            the signature must use `token_id`'s current nonce.
    @param spender The 20-byte spender address.
    @param token_id The 32-byte identifier of the token.
    @param deadline The 32-byte block timestamp up
           which the `spender` is allowed to spend `token_id`.
    @param v The secp256k1 1-byte signature parameter `v`.
    @param r The secp256k1 32-byte signature parameter `r`.
    @param s The secp256k1 32-byte signature parameter `s`.
    """
    assert block.timestamp <= deadline, "erc721: expired deadline"

    current_nonce: uint256 = self.nonces[token_id]
    self.nonces[token_id] = unsafe_add(current_nonce, 1)

    struct_hash: bytes32 = keccak256(abi_encode(_PERMIT_TYPE_HASH, spender, token_id, current_nonce, deadline))
    hash: bytes32 = eip712_domain_separator._hash_typed_data_v4(struct_hash)

    signer: address = ecdsa._recover_vrs(hash, convert(v, uint256), convert(r, uint256), convert(s, uint256))
    assert signer == self._owner_of(token_id), "erc721: invalid signature"

    self._approve(spender, token_id)


@external
@view
def DOMAIN_SEPARATOR() -> bytes32:
    """
    @dev Returns the domain separator for the current chain.
    @return bytes32 The 32-byte domain separator.
    """
    return eip712_domain_separator._domain_separator_v4()


@external
def transfer_ownership(new_owner: address):
    """
    @dev Transfers the ownership of the contract
         to a new account `new_owner`.
    @notice Note that this function can only be
            called by the current `owner`. Also,
            the `new_owner` cannot be the zero address.

            WARNING: The ownership transfer also removes
            the previous owner's minter role and assigns
            the minter role to `new_owner` accordingly.
    @param new_owner The 20-byte address of the new owner.
    """
    ownable._check_owner()
    assert new_owner != empty(address), "erc721: new owner is the zero address"

    self.is_minter[msg.sender] = False
    log RoleMinterChanged(minter=msg.sender, status=False)

    ownable._transfer_ownership(new_owner)
    self.is_minter[new_owner] = True
    log RoleMinterChanged(minter=new_owner, status=True)


@external
def renounce_ownership():
    """
    @dev Leaves the contract without an owner.
    @notice Renouncing ownership will leave the
            contract without an owner, thereby
            removing any functionality that is
            only available to the owner. Note
            that the `owner` is also removed from
            the list of allowed minters.

            WARNING: All other existing `minter`
            addresses will still be able to create
            new tokens. Consider removing all non-owner
            minter addresses first via `set_minter`
            before calling `renounce_ownership`.
    """
    ownable._check_owner()
    self.is_minter[msg.sender] = False
    log RoleMinterChanged(minter=msg.sender, status=False)
    ownable._transfer_ownership(empty(address))


@internal
@view
def _balance_of(owner: address) -> uint256:
    """
    @dev An `internal` helper function that returns the
         amount of tokens owned by `owner`.
    @notice Note that `owner` cannot be the zero address.
    @param owner The 20-byte owner address.
    @return uint256 The 32-byte token amount owned
            by `owner`.
    """
    assert owner != empty(address), "erc721: the zero address is not a valid owner"
    return self._balances[owner]


@internal
@view
def _owner_of(token_id: uint256) -> address:
    """
    @dev An `internal` helper function that returns the
         owner of the `token_id` token.
    @notice Note that `token_id` must exist.
    @param token_id The 32-byte identifier of the token.
    @return address The 20-byte owner address.
    """
    owner: address = self._owners[token_id]
    assert owner != empty(address), "erc721: invalid token ID"
    return owner


@internal
@view
def _require_minted(token_id: uint256):
    """
    @dev Reverts if the `token_id` has not yet been minted.
    @param token_id The 32-byte identifier of the token.
    """
    assert self._exists(token_id), "erc721: invalid token ID"


@internal
@view
def _exists(token_id: uint256) -> bool:
    """
    @dev Returns whether `token_id` exists.
    @notice Tokens can be managed by their owner or approved
            accounts via `approve` or `setApprovalForAll`.
            Tokens start existing when they are minted (`_mint`),
            and stop existing when they are burned (`_burn`).
    @param token_id The 32-byte identifier of the token.
    @return bool The verification whether `token_id` exists
            or not.
    """
    return self._owners[token_id] != empty(address)


@internal
def _approve(to: address, token_id: uint256):
    """
    @dev Approves `to` to operate on `token_id`.
    @param to The 20-byte spender address.
    @param token_id The 32-byte identifier of the token.
    """
    self._token_approvals[token_id] = to
    log IERC721.Approval(owner=self._owner_of(token_id), approved=to, token_id=token_id)


@internal
@view
def _get_approved(token_id: uint256) -> address:
    """
    @dev An `internal` helper function that returns the
         account approved for `token_id` token.
    @notice Note that `token_id` must exist.
    @param token_id The 32-byte identifier of the token.
    @return address The 20-byte approved address.
    """
    self._require_minted(token_id)
    return self._token_approvals[token_id]


@internal
def _set_approval_for_all(owner: address, operator: address, approved: bool):
    """
    @dev Approves `operator` to operate on all of `owner` tokens.
    @param owner The 20-byte owner address.
    @param operator The 20-byte operator address.
    @param approved The Boolean variable that sets the
           approval status.
    """
    assert owner != operator, "erc721: approve to caller"
    self.isApprovedForAll[owner][operator] = approved
    log IERC721.ApprovalForAll(owner=owner, operator=operator, approved=approved)


@internal
def _is_approved_or_owner(spender: address, token_id: uint256) -> bool:
    """
    @dev Returns whether `spender` is allowed to manage
         `token_id`.
    @notice Note that `token_id` must exist.
    @param spender The 20-byte spender address.
    @param token_id The 32-byte identifier of the token.
    """
    owner: address = self._owner_of(token_id)
    return ((spender == owner) or (self.isApprovedForAll[owner][spender]) or (self._get_approved(token_id) == spender))


@internal
def _safe_mint(owner: address, token_id: uint256, data: Bytes[1_024]):
    """
    @dev Safely mints `token_id` and transfers it to `owner`.
    @notice Note that `token_id` must not exist. Also, if `owner`
            refers to a smart contract, it must implement
            {IERC721Receiver-onERC721Received}, which is called
            upon a safe transfer.

            WARNING: This `internal` function without access
            restriction can potentially allow a reentrancy
            attack when transferring tokens to an untrusted
            contract, when invoking {IERC721Receiver-onERC721Received}
            on the receiver. We ensure that we consistently
            follow the checks-effects-interactions (CEI) pattern
            to avoid being vulnerable to this type of attack.
    @param owner The 20-byte owner address.
    @param token_id The 32-byte identifier of the token.
    @param data The maximum 1,024-byte additional data
           with no specified format that is sent
           to `owner`.
    """
    self._mint(owner, token_id)
    assert self._check_on_erc721_received(
        empty(address), owner, token_id, data
    ), "erc721: transfer to non-IERC721Receiver implementer"


@internal
def _mint(owner: address, token_id: uint256):
    """
    @dev Mints `token_id` and transfers it to `owner`.
    @notice Note that `token_id` must not exist and
            `owner` cannot be the zero address.

            WARNING: Usage of this method is discouraged,
            use `_safe_mint` whenever possible.
    @param owner The 20-byte owner address.
    @param token_id The 32-byte identifier of the token.
    """
    assert owner != empty(address), "erc721: mint to the zero address"
    assert not self._exists(token_id), "erc721: token already minted"

    self._before_token_transfer(empty(address), owner, token_id)
    # Checks that the `token_id` was not minted by the
    # `_before_token_transfer` hook.
    assert not self._exists(token_id), "erc721: token already minted"

    # Theoretically, the following line could overflow
    # if all 2**256 token IDs were minted to the same owner.
    # However, since we have bounded the dynamic array
    # `_all_tokens` by the maximum value of `uint64`,
    # this is no longer even theoretically possible.
    self._balances[owner] = unsafe_add(self._balances[owner], 1)
    self._owners[token_id] = owner
    log IERC721.Transfer(sender=empty(address), receiver=owner, token_id=token_id)

    self._after_token_transfer(empty(address), owner, token_id)


@internal
def _safe_transfer(owner: address, to: address, token_id: uint256, data: Bytes[1_024]):
    """
    @dev Safely transfers `token_id` token from
         `owner` to `to`, checking first that contract
         recipients are aware of the ERC-721 protocol
         to prevent tokens from being forever locked.
    @notice This `internal` function is equivalent to
            `safeTransferFrom`, and can be used to e.g.
            implement alternative mechanisms to perform
            token transfers, such as signature-based.

            Note that `owner` and `to` cannot be the zero
            address. Also, `token_id` token must exist and
            must be owned by `owner`. Eventually, if `to`
            refers to a smart contract, it must implement
            {IERC721Receiver-onERC721Received}, which is
            called upon a safe transfer.

            WARNING: This `internal` function can potentially
            allow a reentrancy attack when transferring tokens
            to an untrusted contract, when invoking {IERC721Receiver-onERC721Received}
            on the receiver. We ensure that we consistently
            follow the checks-effects-interactions (CEI) pattern
            to avoid being vulnerable to this type of attack.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param token_id The 32-byte identifier of the token.
    @param data The maximum 1,024-byte additional data
           with no specified format that is sent
           to `to`.
    """
    self._transfer(owner, to, token_id)
    assert self._check_on_erc721_received(
        owner, to, token_id, data
    ), "erc721: transfer to non-IERC721Receiver implementer"


@internal
def _transfer(owner: address, to: address, token_id: uint256):
    """
    @dev Transfers `token_id` from `owner` to `to`.
         As opposed to `transferFrom`, this imposes
         no restrictions on `msg.sender`.
    @notice Note that `to` cannot be the zero address.
            Also, `token_id` token must be owned by
            `owner`.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param token_id The 32-byte identifier of the token.
    """
    assert self._owner_of(token_id) == owner, "erc721: transfer from incorrect owner"
    assert to != empty(address), "erc721: transfer to the zero address"

    self._before_token_transfer(owner, to, token_id)
    # Checks that the `token_id` was not transferred by the
    # `_before_token_transfer` hook.
    assert self._owner_of(token_id) == owner, "erc721: transfer from incorrect owner"

    self._token_approvals[token_id] = empty(address)
    # See comment why an overflow is not possible in the
    # following two lines above at `_mint`.
    self._balances[owner] = unsafe_sub(self._balances[owner], 1)
    self._balances[to] = unsafe_add(self._balances[to], 1)
    self._owners[token_id] = to
    log IERC721.Transfer(sender=owner, receiver=to, token_id=token_id)

    self._after_token_transfer(owner, to, token_id)


@internal
def _set_token_uri(token_id: uint256, token_uri: String[432]):
    """
    @dev Sets `token_uri` as the token URI of `token_id`.
    @notice Note that `token_id` must exist.
    @param token_id The 32-byte identifier of the token.
    @param token_uri The maximum 432-character user-readable
           string URI for computing `tokenURI`.
    """
    assert self._exists(token_id), "erc721: URI set of nonexistent token"
    self._token_uris[token_id] = token_uri
    log IERC4906.MetadataUpdate(_tokenId=token_id)


@internal
@view
def _total_supply() -> uint256:
    """
    @dev An `internal` helper function that returns the amount
         of tokens in existence.
    @return uint256 The 32-byte token supply.
    """
    return len(self._all_tokens)


@internal
def _burn(token_id: uint256):
    """
    @dev Destroys `token_id`.
    @notice The approval is cleared when the token is burned.
            This is an `internal` function that does not check
            if the sender is authorised to operate on the token.
            Note that `token_id` must exist.
    @param token_id The 32-byte identifier of the token.
    """
    owner: address = self._owner_of(token_id)

    self._before_token_transfer(owner, empty(address), token_id)
    # Updates ownership in case the `token_id` was
    # transferred by the `_before_token_transfer` hook.
    owner = self._owner_of(token_id)

    self._token_approvals[token_id] = empty(address)
    # Overflow is not possible, as in this case more tokens would
    # have to be burned/transferred than the owner originally
    # received through minting and transfer.
    self._balances[owner] = unsafe_sub(self._balances[owner], 1)
    self._owners[token_id] = empty(address)
    log IERC721.Transfer(sender=owner, receiver=empty(address), token_id=token_id)

    self._after_token_transfer(owner, empty(address), token_id)

    # Checks whether a token-specific URI has been set for the token
    # and deletes the token URI from the storage mapping.
    if len(self._token_uris[token_id]) != empty(uint256):
        self._token_uris[token_id] = ""


@internal
def _check_on_erc721_received(owner: address, to: address, token_id: uint256, data: Bytes[1_024]) -> bool:
    """
    @dev An `internal` function that invokes {IERC721Receiver-onERC721Received}
         on a target address. The call is not executed
         if the target address is not a contract.
    @param owner The 20-byte address which previously
           owned the token.
    @param to The 20-byte address receiver address.
    @param token_id The 32-byte identifier of the token.
    @param data The maximum 1,024-byte additional data
           with no specified format.
    @return bool The verification whether the call correctly
            returned the expected magic value.
    """
    # Contract case.
    if to.is_contract:
        return_value: bytes4 = extcall IERC721Receiver(to).onERC721Received(msg.sender, owner, token_id, data)
        assert return_value == method_id(
            "onERC721Received(address,address,uint256,bytes)", output_type=bytes4
        ), "erc721: transfer to non-IERC721Receiver implementer"
        return True

    # EOA case.
    return True


@internal
def _before_token_transfer(owner: address, to: address, token_id: uint256):
    """
    @dev Hook that is called before any token transfer.
         This includes minting and burning.
    @notice The calling conditions are:
            - when `owner` and `to` are both non-zero,
              `owner`'s tokens will be transferred to `to`,
            - when `owner` is zero, the tokens will
              be minted for `to`,
            - when `to` is zero, `owner`'s tokens will
              be burned,
            - `owner` and `to` are never both zero.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param token_id The 32-byte identifier of the token.
    """
    if owner == empty(address):
        self._add_token_to_all_tokens_enumeration(token_id)
    elif owner != to:
        self._remove_token_from_owner_enumeration(owner, token_id)

    if to == empty(address):
        self._remove_token_from_all_tokens_enumeration(token_id)
    elif to != owner:
        self._add_token_to_owner_enumeration(to, token_id)


@internal
def _after_token_transfer(owner: address, to: address, token_id: uint256):
    """
    @dev Hook that is called after any token transfer.
         This includes minting and burning.
    @notice The calling conditions are:
            - when `owner` and `to` are both non-zero,
              `owner`'s tokens were transferred to `to`,
            - when `owner` is zero, the tokens were
              be minted for `to`,
            - when `to` is zero, `owner`'s tokens will
              be burned,
            - `owner` and `to` are never both zero.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param token_id The 32-byte identifier of the token.
    """
    pass


@internal
def _add_token_to_owner_enumeration(to: address, token_id: uint256):
    """
    @dev This is an `internal` function that adds a token
         to the ownership-tracking data structures.
    @param to The 20-byte receiver address.
    @param token_id The 32-byte identifier of the token.
    """
    length: uint256 = self._balance_of(to)
    self._owned_tokens[to][length] = token_id
    self._owned_tokens_index[token_id] = length


@internal
def _add_token_to_all_tokens_enumeration(token_id: uint256):
    """
    @dev This is an `internal` function that adds a token
         to the token tracking data structures.
    @param token_id The 32-byte identifier of the token.
    """
    self._all_tokens_index[token_id] = len(self._all_tokens)
    self._all_tokens.append(token_id)


@internal
def _remove_token_from_owner_enumeration(owner: address, token_id: uint256):
    """
    @dev This is an `internal` function that removes a token
         from the ownership-tracking data structures.
    @notice Note that while the token is not assigned a new
            owner, the `_owned_tokens_index` mapping is NOT
            updated: this allows for gas optimisations e.g.
            when performing a transfer operation (avoiding
            double writes). This function has O(1) time
            complexity, but alters the order of the
            `_owned_tokens` array.
    @param owner The 20-byte owner address.
    @param token_id The 32-byte identifier of the token.
    """
    # To prevent a gap in `owner`'s tokens array,
    # we store the last token in the index of the
    # token to delete, and then delete the last slot.
    last_token_index: uint256 = self._balance_of(owner) - 1
    token_index: uint256 = self._owned_tokens_index[token_id]

    # When the token to delete is the last token,
    # the swap operation is unnecessary.
    if token_index != last_token_index:
        last_token_id: uint256 = self._owned_tokens[owner][last_token_index]
        # Moves the last token to the slot of the to-delete token.
        self._owned_tokens[owner][token_index] = last_token_id
        # Updates the moved token's index.
        self._owned_tokens_index[last_token_id] = token_index

    # This also deletes the contents at the
    # last position of the array.
    self._owned_tokens_index[token_id] = empty(uint256)
    self._owned_tokens[owner][last_token_index] = empty(uint256)


@internal
def _remove_token_from_all_tokens_enumeration(token_id: uint256):
    """
    @dev This is an `internal` function that removes a token
         from the token tracking data structures.
    @notice This function has O(1) time complexity, but
            alters the order of the `_all_tokens` array.
    @param token_id The 32-byte identifier of the token.
    """
    # To prevent a gap in the tokens array,
    # we store the last token in the index
    # of the token to delete, and then delete
    # the last slot.
    last_token_index: uint256 = len(self._all_tokens) - 1
    token_index: uint256 = self._all_tokens_index[token_id]

    # When the token to delete is the last token,
    # the swap operation is unnecessary. However,
    # since this occurs so rarely (when the last
    # minted token is burned) that we still do the
    # swap here to avoid the gas cost of adding
    # an `if` statement (like in `_remove_token_from_owner_enumeration`).
    last_token_id: uint256 = self._all_tokens[last_token_index]

    # Moves the last token to the slot of the to-delete token.
    self._all_tokens[token_index] = last_token_id
    # Updates the moved token's index.
    self._all_tokens_index[last_token_id] = token_index

    # This also deletes the contents at the
    # last position of the array.
    self._all_tokens_index[token_id] = empty(uint256)
    self._all_tokens.pop()

File 13 of 13 : Vyper_contract.vy
# @version 0.4.3
"""
OpenZeppelin's IVotes interface:
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/governance/utils/IVotes.sol
"""

# @dev Emitted when an account changes their delegate.
event DelegateChanged:
    delegator: indexed(address)
    fromDelegate: indexed(address)
    toDelegate: indexed(address)

# @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units.
event DelegateVotesChanged:
    delegate: indexed(address)
    previousVotes: uint256
    newVotes: uint256


@external
@view
def getVotes(account: address) -> uint256:
    """
    @dev Returns the current amount of votes that `account` has.
    """
    ...


@external
@view
def getPastVotes(account: address, timepoint: uint256) -> uint256:
    """
    @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
    configured to use block numbers, this will return the value at the end of the corresponding block.
    """
    ...


@external
@view
def getPastTotalSupply(timepoint: uint256) -> uint256:
    """
    @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
    configured to use block numbers, this will return the value at the end of the corresponding block.

    @notice This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
    Votes that have not been delegated are still part of total supply, even though they would not participate in a
    vote.
    """
    ...


@external
@view
def delegates(account: address) -> address:
    """
    @dev Returns the delegate that `account` has chosen.
    """
    ...


@external
def delegate(delegatee: address):
    """
    @dev Delegates votes from the sender to `delegatee`.
    """
    ...


@external
def delegateBySig(delegatee: address, nonce: uint256, expiry: uint256, v: uint8, r: bytes32, s: bytes32):
    """
    @dev Delegates votes from signer to `delegatee`.
    """
    ...

Settings
{
  "outputSelection": {
    "contracts/dao/VotingEscrow.vy": [
      "evm.bytecode",
      "evm.deployedBytecode",
      "abi"
    ]
  },
  "search_paths": [
    ".venv/lib/pypy3.11/site-packages",
    "."
  ]
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_for","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":true,"name":"locktime","type":"uint256"},{"indexed":false,"name":"type","type":"uint256"},{"indexed":false,"name":"ts","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_for","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"ts","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"prevSupply","type":"uint256"},{"indexed":false,"name":"supply","type":"uint256"}],"name":"Supply","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"clearance_checker","type":"address"}],"name":"SetTransferClearanceChecker","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previous_owner","type":"address"},{"indexed":true,"name":"new_owner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"minter","type":"address"},{"indexed":false,"name":"status","type":"bool"}],"name":"RoleMinterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"approved","type":"address"},{"indexed":true,"name":"token_id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"operator","type":"address"},{"indexed":false,"name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"receiver","type":"address"},{"indexed":true,"name":"token_id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"token_id","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"to","type":"address"},{"name":"token_id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"name":"operator","type":"address"},{"name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"token_id","type":"uint256"}],"name":"getApproved","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"name":"isApprovedForAll","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"owner","type":"address"},{"name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"token_id","type":"uint256"}],"name":"tokenURI","outputs":[{"name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"new_owner","type":"address"}],"name":"transfer_ownership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"interface_id","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"account","type":"address"}],"name":"delegates","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"delegatee","type":"address"},{"name":"nonce","type":"uint256"},{"name":"expiry","type":"uint256"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clock","outputs":[{"name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_value","type":"uint256"},{"name":"_unlock_time","type":"uint256"}],"name":"create_lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_value","type":"uint256"}],"name":"increase_amount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_value","type":"uint256"},{"name":"_for","type":"address"}],"name":"increase_amount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_unlock_time","type":"uint256"}],"name":"increase_unlock_time","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"infinite_lock_toggle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_for","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"account","type":"address"}],"name":"getVotes","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"account","type":"address"},{"name":"timepoint","type":"uint256"}],"name":"getPastVotes","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalVotes","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"timepoint","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"transfer_clearance_checker","type":"address"}],"name":"set_transfer_clearance_checker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"owner","type":"address"},{"name":"to","type":"address"},{"name":"token_id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"owner","type":"address"},{"name":"to","type":"address"},{"name":"token_id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"owner","type":"address"},{"name":"to","type":"address"},{"name":"token_id","type":"uint256"},{"name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"addr","type":"address"}],"name":"get_last_user_slope","outputs":[{"name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"addr","type":"address"}],"name":"get_last_user_point","outputs":[{"components":[{"name":"bias","type":"uint256"},{"name":"slope","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_addr","type":"address"}],"name":"locked__end","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supply","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"locked","outputs":[{"components":[{"name":"amount","type":"int256"},{"name":"end","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"point_history","outputs":[{"components":[{"name":"bias","type":"int256"},{"name":"slope","type":"int256"},{"name":"ts","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"uint256"}],"name":"user_point_history","outputs":[{"components":[{"name":"bias","type":"int256"},{"name":"slope","type":"int256"},{"name":"ts","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"user_point_epoch","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"slope_changes","outputs":[{"name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transfer_clearance_checker","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CLOCK_MODE","outputs":[{"name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"token","type":"address"},{"name":"name","type":"string"},{"name":"symbol","type":"string"},{"name":"base_uri","type":"string"}],"outputs":[],"stateMutability":"nonpayable","type":"constructor"}]

0x6143c051503461033b5760206144f85f395f518060a01c61033b576103805260206145185f395f516020816144f8015f395f516019811161033b57506039816144f8016103a0395060206145385f395f516020816144f8015f395f516005811161033b57506025816144f8016103e0395060206145585f395f516020816144f8015f395f516050811161033b57506070816144f80161042039506100a161018d565b60396103a06101c05e60256103e06102005e60706104206102405e600b6104a0527f4a75737420736179206e6f0000000000000000000000000000000000000000006104c0526104a0602b816102c05e5060096104e0527f746f204549503731320000000000000000000000000000000000000000000000610500526104e06029816103205e50610130610273565b610380516143c05242680100000000000000115561418061033f610000396143e0610000f35b5f546060526040515f556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f6080a3565b33604052610199610156565b565b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f606052614240516080526142a05160a0524660c0523060e05260a06040526040805160208201209050815250565b602061010051015f81601f0160051c6003811161033b57801561022957905b8060051b61010001518160051b6060016141800152600101818118610209575b5050506101605161426052610180516142805261010051610120206142405261016051610180206142a05261025f6101a061019b565b6101a05161418052466141a052306141c052565b5f6801000000000000000b556101c0516142c0526101e0516142e05261020051614300526102205161432052602061024051015f81601f0160051c6004811161033b5780156102df57905b8060051b61024001518160051b6101c00161418001526001018181186102be575b50505060016002336020525f5260405f2055337fbb6e183664bd7425a9e444072cb0f1c7f7c4d5486a36d7d24d0b0735687c2ef46001610360526020610360a260526102c06101005e60346103206101605e6103396101ea565b565b5f80fd5f3560e01c60026028820660011b61413001601e395f51565b6370a0823181186100555760243610341761412c576004358060a01c61412c5761016052602061016051604052610050610180612615565b610180f35b63adc6358981186126115760243610341761412c576004358060a01c61412c576040526801000000000000000d6040516020525f5260405f206001810190505460605260206060f35b636352211e81186100cb5760243610341761412c5760206004356040526100c66101406126c5565b610140f35b63587cde1e81186126115760243610341761412c576004358060a01c61412c5760405260206040f35b63095ea7b381186102c357604336111561412c576004358060a01c61412c576101a0526024356040526101286101e06126c5565b6101e0516101c0526101c0516101a051186101da576020806102605260216101e0527f6572633732313a20617070726f76616c20746f2063757272656e74206f776e65610200527f7200000000000000000000000000000000000000000000000000000000000000610220526101e08161026001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610240528060040161025cfd5b6101c05133186101eb576001610209565b60016101c0516020525f5260405f2080336020525f5260405f209050545b6102aa5760208061026052603d6101e0527f6572633732313a20617070726f76652063616c6c6572206973206e6f7420746f610200527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000610220526101e08161026001605d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610240528060040161025cfd5b6101a05161014052602435610160526102c1612757565b005b6306fdde03811861030d573461412c576020806040528060400160396142c082398051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b6365fc387381186126115760443610341761412c575f5c60011461412c5760015f5d60243562093a808104905062093a8081028162093a8082041861412c579050610520526801000000000000000d336020525f5260405f2080546105405260018101546105605250630784ce0060043510156103fc576020806105e0526009610580527f4d696e2076616c756500000000000000000000000000000000000000000000006105a052610580816105e001602982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b610540511561047d576020806105e0526019610580527f5769746864726177206f6c6420746f6b656e73206669727374000000000000006105a052610580816105e001603982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b42610520511161052457602080610600526026610580527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e20746865206105a0527f66757475726500000000000000000000000000000000000000000000000000006105c0526105808161060001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105e052806004016105fcfd5b42630784ce00810181811061412c5790506105205111156105b7576020806105e052601e610580527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006105a052610580816105e001603e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b336102e05260043561030052610520516103205260406105406103405e6002610380526105e2613027565b336102605233610280526105f4613495565b5f5f5d005b63a22cb46581186126115760443610341761412c576004358060a01c61412c57610160526024358060011c61412c576101805233604052604061016060605e6106406127b1565b005b63081812fc81186106705760243610341761412c5760206004356101605261066b610180612926565b610180f35b634957677c811861068f5760243610341761412c5733610520526107f3565b637c74a17481186126115760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f2054606052680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c5702810190506001810190505460805260206080f35b63e985e9c581186126115760443610341761412c576004358060a01c61412c576040526024358060a01c61412c5760605260016040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b6395d89b4181186107ae573461412c5760208060405280604001602561430082398051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b63c2c4c5c181186107ce573461412c5760a0366040376107cc612a05565b005b635e56b23981186126115760443610341761412c576024358060a01c61412c57610520525b5f5c60011461412c5760015f5d6801000000000000000d610520516020525f5260405f2080546105405260018101546105605250630784ce006004351061412c5760016105405112156108b8576020806105e0526016610580527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006105a052610580816105e001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b42610560511161095f57602080610600526024610580527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686105a0527f64726177000000000000000000000000000000000000000000000000000000006105c0526105808161060001604482825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105e052806004016105fcfd5b610520516102e052600435610300525f6103205260406105406103405e60046103805261098a613027565b5f5f5d005b6318160ddd81186109af573461412c5760206109ab604061294a565b6040f35b63c87b56dd81186126115760243610341761412c576004356060526109d261289a565b6801000000000000000a6004356020525f5260405f2060208154015f81601f0160051c600f811161412c578015610a1d57905b808401548160051b6101600152600101818118610a05575b5050505060206143406103403961034051610a79576020806103605280610360016020610160510180610160835e508051806020830101601f825f03163682375050601f19601f82516020010116905081019050610360610c24565b6101605115610b03576020806105a0525f60206143405f395f5181610380018161436082395080820191505061016051816103800181610180825e5080820191505080610360526103609050816105a00160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506105a0610c24565b6103405115610bec576020806104c0525f60206143405f395f5181610400018161436082395080820191505060043580610b4b57603061036152600161036052610360610b8a565b5f604f905b82610b685780816103ae0352806103ae039250610b86565b600a8306603001816103ae0352600a83049250600101818118610b50575b5050805b905080516020820183610400018282825e505080830192505050806103e0526103e09050816104c00160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506104c0610c24565b6020806103805280610380015f81528051806020830101601f825f03163682375050601f19601f825160200101169050810190506103805bf35b634f6ccce781186126115760243610341761412c57610c45604061294a565b60405160043510610ce55760208060e05260226060527f6572633732313a20676c6f62616c20696e646578206f7574206f6620626f756e6080527f647300000000000000000000000000000000000000000000000000000000000060a05260608160e001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b60043560095481101561412c57600a015460405260206040f35b632f745c598118610e085760443610341761412c576004358060a01c61412c576101605261016051604052610d35610180612615565b6101805160243510610dde576020806102205260216101a0527f6572633732313a206f776e657220696e646578206f7574206f6620626f756e646101c0527f73000000000000000000000000000000000000000000000000000000000000006101e0526101a08161022001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610200528060040161021cfd5b6007610160516020525f5260405f20806024356020525f5260405f20905054610180526020610180f35b63d1febfb981186126115760243610341761412c576003600435670de0b6b3a764000081101561412c57026801000000000000000f018054604052600181015460605260028101546080525060606040f35b63f0350c0481186126115760243610341761412c576004358060a01c61412c5761010052610e86612952565b61010051610f2b576020806101a0526026610120527f6f776e61626c653a206e6577206f776e657220697320746865207a65726f2061610140527f646472657373000000000000000000000000000000000000000000000000000061016052610120816101a001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61010051604052610f3a6129ce565b005b638da5cb5b8118612611573461412c575f5460405260206040f35b6301ffc9a781186110935760243610341761412c576004358060201b61412c576040526040517f01ffc9a7000000000000000000000000000000000000000000000000000000008118610fab576001611088565b7f80ac58cd000000000000000000000000000000000000000000000000000000008118610fd9576001611088565b7f5b5e139f000000000000000000000000000000000000000000000000000000008118611007576001611088565b7f780e9d63000000000000000000000000000000000000000000000000000000008118611035576001611088565b7f49064906000000000000000000000000000000000000000000000000000000008118611063576001611088565b7fe90fb3f6000000000000000000000000000000000000000000000000000000008118155b905060805260206080f35b63010ae75781186126115760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f205460605260206060f35b635c19a95c811861116a5760243610341761412c576004358060a01c61412c5760405260208060c052600d6060527f4e6f7420737570706f727465640000000000000000000000000000000000000060805260608160c001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b6391ddadf4811861118c573461412c57428060301c61412c5760405260206040f35b638e539e8c81186126115760243610341761412c5760206004356040526111b46101606137e5565b610160f35b63c3cda52081186126115760c43610341761412c576004358060a01c61412c576040526064358060081c61412c5760605260208060e052600d6080527f4e6f7420737570706f727465640000000000000000000000000000000000000060a05260808160e001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b63eff7a61281186126115760243610341761412c575f5c60011461412c5760015f5d6801000000000000000d336020525f5260405f208054610520526001810154610540525060043562093a808104905062093a8081028162093a8082041861412c579050610560526001610520511215611348576020806105e0526011610580527f4e6f7468696e67206973206c6f636b65640000000000000000000000000000006105a052610580816105e001603182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b4261054051116113ca576020806105e052600c610580527f4c6f636b206578706972656400000000000000000000000000000000000000006105a052610580816105e001602c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b61054051610560511161144f576020806105e052601f610580527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006105a052610580816105e001603f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b42630784ce00810181811061412c5790506105605111156114e2576020806105e052601e610580527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006105a052610580816105e001603e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b336102e0525f61030052610560516103205260406105206103405e60086103805261150b613027565b5f5f5d005b63b25ec64581186117dd573461412c575f5c60011461412c5760015f5d6801000000000000000d336020525f5260405f20805461052052600181015461054052504261054051116115d3576020806105c052600c610560527f4c6f636b2065787069726564000000000000000000000000000000000000000061058052610560816105c001602c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105a052806004016105bcfd5b6001610520511215611657576020806105c0526011610560527f4e6f7468696e67206973206c6f636b656400000000000000000000000000000061058052610560816105c001603182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105a052806004016105bcfd5b5f61056052610540511961178957680129a2241af62c0012546105805261058051156117535761058051635f1a104c6105a052336105c05260206105a060246105bc845afa6116a8573d5f5f3e3d5ffd5b3d602081183d6020100218806105a0016105c01161412c576105a0518060011c61412c576105e052506105e09050516117535760208061066052600b610600527f4e6f7420616c6c6f776564000000000000000000000000000000000000000000610620526106008161066001602b82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610640528060040161065cfd5b42630784ce00810181811061412c57905062093a808104905062093a8081028162093a8082041861412c579050610560526117af565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610560525b336102e0525f61030052610560516103205260406105206103405e6008610380526117d8613027565b5f5f5d005b6323b872dd81186126115760643610341761412c576004358060a01c61412c57610400526024358060a01c61412c576104205233610180526044356101a052611827610440613a97565b610440516118cc576020806104e052602d610460527f6572633732313a2063616c6c6572206973206e6f7420746f6b656e206f776e65610480527f72206f7220617070726f766564000000000000000000000000000000000000006104a052610460816104e001604d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104c052806004016104dcfd5b610400516044351815611951576020806104a052600e610440527f57726f6e6720746f6b656e20494400000000000000000000000000000000000061046052610440816104a001602e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610480528060040161049cfd5b604061040060405e611964610440613b13565b610440516119e4576020806104c052600f610460527f4e656564206d61782076654c6f636b000000000000000000000000000000000061048052610460816104c001602f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104a052806004016104bcfd5b60406104006102e05e6119f5613d5e565b60443561026052611a046136cd565b005b633ccfd60b8118612611573461412c57336102e052611a45565b6351cff8d98118611c7e5760243610341761412c576004358060a01c61412c576102e0525b5f5c60011461412c5760015f5d6801000000000000000d336020525f5260405f208054610300526001810154610320525061032051421015611af9576020806103a0526016610340527f546865206c6f636b206469646e2774206578706972650000000000000000000061036052610340816103a001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b610300515f811261412c576103405260406103006103605e5f610320525f610300526801000000000000000d336020525f5260405f20610300518155610320516001820155506801000000000000000c546103a0526103a0516103405180820382811161412c57905090506103c0526103c0516801000000000000000c5533604052604061036060605e604061030060a05e611b93612a05565b3361026052611ba06136cd565b60206143c05f395f5163a9059cbb6103e0526102e05161040052610340516104205260206103e060446103fc5f855af1611bdc573d5f5f3e3d5ffd5b3d602081183d6020100218806103e0016104001161412c576103e0518060011c61412c5761044052506104409050511561412c576102e051337ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567610340516103e052426104005260406103e0a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c60406103a06103e05e60406103e0a15f5f5d005b634bf5d7e98118612611573461412c57602080608052600e6040527f6d6f64653d74696d657374616d70000000000000000000000000000000000000606052604081608001602e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b639ab24eb08118611e235760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f2054606052606051611d44575f60805260206080611e21565b680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c5702810190508054608052600181015460a052600281015460c0525060805160a0514260c05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c57905090506080527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60805113611e0f575f6080525b6080515f811261412c5760e052602060e05bf35b6372e3af5081186126115760243610341761412c576004358060a01c61412c5761010052611e4f612952565b61010051680129a2241af62c0012557fa7fad85ba00d983deab3d92e1bbba81938da68cddbcb5d4f018ef3b1e66534fa61010051610120526020610120a1005b633a46b1a881186126115760443610341761412c576004358060a01c61412c576040525f606052680129a2241af62c00106040516020525f5260405f2054608052680129a2241af62c000f6040516020525f5260405f20600281019050546024351015611f03575f60a052602060a061207a565b5f6080905b8060a0526080516060511015611fac5760605160805180820182811061412c57905090506001810181811061412c5790508060011c905060c052602435680129a2241af62c000f6040516020525f5260405f20600360c051670de0b6b3a764000081101561412c570281019050600281019050541115611f9a5760c0516001810381811161412c579050608052611fa1565b60c0516060525b600101818118611f08575b5050680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c570281019050805460a052600181015460c052600281015460e0525060a05160c05160243560e05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905060a0525f60a0511215612066575f61010052602061010061207a565b60a0515f811261412c576101005260206101005bf35b630d15fd7781186120a2573461412c5760204260405261209d6101606137e5565b610160f35b63cbf9fe5f81186120ef5760243610341761412c576004358060a01c61412c576040526801000000000000000d6040516020525f5260405f20805460605260018101546080525060406060f35b6328d09d4781186126115760443610341761412c576004358060a01c61412c57604052680129a2241af62c000f6040516020525f5260405f206003602435670de0b6b3a764000081101561412c57028101905080546060526001810154608052600281015460a0525060606060f35b6342842e0e81186126115760643610341761412c575f610a00526121b2565b63b88d4fde81186124935760843610341761412c576064356004018035610400811161412c575060208135018082610a003750505b6004358060a01c61412c576109c0526024358060a01c61412c576109e05233610180526044356101a0526121e7610e40613a97565b610e405161228c57602080610ee052602d610e60527f6572633732313a2063616c6c6572206973206e6f7420746f6b656e206f776e65610e80527f72206f7220617070726f76656400000000000000000000000000000000000000610ea052610e6081610ee001604d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610ec05280600401610edcfd5b6109c051604435181561231157602080610ea052600e610e40527f57726f6e6720746f6b656e204944000000000000000000000000000000000000610e6052610e4081610ea001602e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610e805280600401610e9cfd5b60406109c060405e612324610e40613b13565b610e40516123a457602080610ec052600f610e60527f4e656564206d61782076654c6f636b0000000000000000000000000000000000610e8052610e6081610ec001602f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610ea05280600401610ebcfd5b60406109c06102e05e6123b5613d5e565b604435610260526123c46136cd565b60406109c060405e6044356080526020610a00510180610a0060a05e506123ec610e40613f9f565b610e405161249157602080610ee0526033610e60527f6572633732313a207472616e7366657220746f206e6f6e2d4945524337323152610e80527f6563656976657220696d706c656d656e74657200000000000000000000000000610ea052610e6081610ee001605382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610ec05280600401610edcfd5b005b63a7afdcae81186126115760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f2054606052680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c570281019050545f811261412c57608052680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c570281019050600181019050545f811261412c5760a05260406080f35b6382bfefc88118612611573461412c5760206143c060403960206040f35b63047fc9aa8118612611573461412c576801000000000000000c5460405260206040f35b63900cf0cf8118612611573461412c576801000000000000000e5460405260206040f35b637119748481186126115760243610341761412c57680129a2241af62c00116004356020525f5260405f205460405260206040f35b63cada36828118612611573461412c57680129a2241af62c00125460405260206040f35b5f5ffd5b6040516126b15760208060e052602d6060527f6572633732313a20746865207a65726f2061646472657373206973206e6f74206080527f612076616c6964206f776e65720000000000000000000000000000000000000060a05260608160e001604d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b60046040516020525f5260405f2054815250565b60056040516020525f5260405f205460605260605161274f5760208060e05260186080527f6572633732313a20696e76616c696420746f6b656e204944000000000000000060a05260808160e001603882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b606051815250565b610140516006610160516020525f5260405f20556101605161014051610160516040526127856101806126c5565b610180517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f6101a0a4565b6060516040511861282f5760208061010052601960a0527f6572633732313a20617070726f766520746f2063616c6c65720000000000000060c05260a08161010001603982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060e0528060040160fcfd5b60805160016040516020525f5260405f20806060516020525f5260405f209050556060516040517f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160805160a052602060a0a3565b60056040516020525f5260405f20541515815250565b6060516040526128aa6080612884565b6080516129245760208061010052601860a0527f6572633732313a20696e76616c696420746f6b656e204944000000000000000060c05260a08161010001603882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060e0528060040160fcfd5b565b6101605160605261293561289a565b6006610160516020525f5260405f2054815250565b600954815250565b5f543318156129cc5760208060a05260206040527f6f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260605260408160a001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060805280600401609cfd5b565b5f546060526040515f556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f6080a3565b6101003660e0376801000000000000000e546101e05260405115612b8c574260805111612a32575f612a3a565b600160605112155b15612aab5760805119612a57575f6101005260605160e052612aab565b606051630784ce008105905061010052610100516080514280820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c579050905060e0525b4260c05111612aba575f612ac2565b600160a05112155b15612b355760c05119612ae0575f6101605260a05161014052612b35565b60a051630784ce0081059050610160526101605160c0514280820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c5790509050610140525b680129a2241af62c00116080516020525f5260405f20546101a05260c05115612b8c5760805160c05118612b70576101a0516101c052612b8c565b680129a2241af62c001160c0516020525f5260405f20546101c0525b6040366102003742610240526101e05115612bdd5760036101e051670de0b6b3a764000081101561412c57026801000000000000000f01805461020052600181015461022052600281015461024052505b61024051610260526102605162093a808104905062093a8081028162093a8082041861412c579050610280525f60ff905b806102a0526102805162093a80810181811061412c579050610280525f6102c052426102805111612c5a57680129a2241af62c0011610280516020525f5260405f20546102c052612c60565b42610280525b6102005161022051610280516102605180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905061020052610220516102c0518082018281125f83121861412c5790509050610220527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102005113612d0c575f610200525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102205113612d3c575f610220525b610280516102605261028051610240526101e0516001810181811061412c5790506101e05242610280511815612db25760036101e051670de0b6b3a764000081101561412c57026801000000000000000f0161020051815561022051600182015561024051600282015550600101818118612c0e575b50506101e0516801000000000000000e5560405115612e92576102205161016051610100518082038281135f83121861412c57905090508082018281125f83121861412c579050905061022052610200516101405160e0518082038281135f83121861412c57905090508082018281125f83121861412c5790509050610200527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102205113612e62575f610220525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102005113612e92575f610200525b60036101e051670de0b6b3a764000081101561412c57026801000000000000000f01610200518155610220516001820155610240516002820155506040511561302557426080511115612f43576101a051610100518082018281125f83121861412c57905090506101a05260805160c05118612f27576101a051610160518082038281135f83121861412c57905090506101a0525b6101a051680129a2241af62c00116080516020525f5260405f20555b4260c0511115612f925760805160c05114612f92576101c051610160518082038281135f83121861412c57905090506101c0526101c051680129a2241af62c001160c0516020525f5260405f20555b680129a2241af62c00106040516020525f5260405f20546001810181811061412c5790506102a0526102a051680129a2241af62c00106040516020525f5260405f20554261018052680129a2241af62c000f6040516020525f5260405f2060036102a051670de0b6b3a764000081101561412c570281019050610140518155610160516001820155610180516002820155505b565b60406103406103a05e6801000000000000000c546103e0526103e0516103005180820182811061412c5790509050630784ce0081049050630784ce00810281630784ce0082041861412c57905061040052610400516103e05180820382811161412c579050905061042052610400516801000000000000000c5560406103a06104405e6103a051610420518060ff1c61412c578082018281125f83121861412c57905090506103a05261032051156130e257610320516103c0525b6801000000000000000d6102e0516020525f5260405f206103a05181556103c0516001820155506102e051604052604061044060605e60406103a060a05e613128612a05565b61042051156131a45760206143c05f395f516323b872dd61048052336104a052306104c052610420516104e0526020610480606461049c5f855af161316f573d5f5f3e3d5ffd5b3d602081183d602010021880610480016104a01161412c57610480518060011c61412c5761050052506105009050511561412c575b6103c0516102e051337f5f971bd00bf3ffbca8a6d72cdd4fd92cfd4f62636161921d1e5a64f0b64ccb6d6104205161048052610380516104a052426104c0526060610480a47f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c60406103e06104805e6040610480a1565b600954680100000000000000096040516020525f5260405f205560095467fffffffffffffffe811161412c5760405181600a01556001810160095550565b6101605160405261326b6101c0612615565b6101c0516001810381811161412c5790506101a0526008610180516020525f5260405f20546101c0526101a0516101c051146132fe576007610160516020525f5260405f20806101a0516020525f5260405f209050546101e0526101e0516007610160516020525f5260405f20806101c0516020525f5260405f209050556101c05160086101e0516020525f5260405f20555b5f6008610180516020525f5260405f20555f6007610160516020525f5260405f20806101a0516020525f5260405f20905055565b6009546001810381811161412c579050606052680100000000000000096040516020525f5260405f205460805260605160095481101561412c57600a015460a05260a05160805160095481101561412c57600a01556080516801000000000000000960a0516020525f5260405f20555f680100000000000000096040516020525f5260405f20556001600954801561412c57038060095550565b610160516040526133de6101c0612615565b6101c0516101a052610180516007610160516020525f5260405f20806101a0516020525f5260405f209050556101a0516008610180516020525f5260405f2055565b61020051613437576102405160405261345c61321b565b61022051610200511461345c576102005161016052610240516101805261345c613259565b610220516134735761024051604052613491613332565b6102005161022051146134915760406102206101605e6134916133cc565b565b565b61026051613515576020806103005260206102a0527f6572633732313a206d696e7420746f20746865207a65726f20616464726573736102c0526102a08161030001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06102e052806004016102fcfd5b610280516040526135276102a0612884565b6102a051156135a85760208061032052601c6102c0527f6572633732313a20746f6b656e20616c7265616479206d696e746564000000006102e0526102c08161032001603c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610300528060040161031cfd5b5f6102005260406102606102205e6135be613420565b610280516040526135d06102a0612884565b6102a051156136515760208061032052601c6102c0527f6572633732313a20746f6b656e20616c7265616479206d696e746564000000006102e0526102c08161032001603c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610300528060040161031cfd5b60016004610260516020525f5260405f2054016004610260516020525f5260405f2055610260516005610280516020525f5260405f205561028051610260515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f6102a0a45f604052604061026060605e6136cb613493565b565b610260516040526136df6102a06126c5565b6102a0516102805261028051610200525f610220526102605161024052613704613420565b610260516040526137166102a06126c5565b6102a051610280525f6006610260516020525f5260405f205560016004610280516020525f5260405f2054036004610280516020525f5260405f20555f6005610260516020525f5260405f2055610260515f610280517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f6102a0a4610280516040525f606052610260516080526137ac613493565b6801000000000000000a610260516020525f5260405f2054156137e3575f6801000000000000000a610260516020525f5260405f20555b565b6801000000000000000e54606052606051613803575f815250613a95565b68010000000000000011546040511015613820575f815250613a95565b5f6080525f6080905b8060a05260605160805110156138be5760805160605180820182811061412c57905090506001810181811061412c5790508060011c905060c052604051600360c051670de0b6b3a764000081101561412c57026801000000000000000f016002810190505411156138ac5760c0516001810381811161412c5790506060526138b3565b60c0516080525b600101818118613829575b50506003608051670de0b6b3a764000081101561412c57026801000000000000000f01805460a052600181015460c052600281015460e0525060605160805118613a2d5760e051610100525f60ff905b80610120526101005162093a80810181811061412c579050610100525f61014052604051610100511161395c57680129a2241af62c0011610100516020525f5260405f205461014052613964565b604051610100525b60a05160c0516101005160e05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905060a0526040516101005118156139f95760c051610140518082018281125f83121861412c579050905060c0526101005160e05260010181811861390e575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60a05113613a87575f60a052613a87565b60a05160c05160405160e05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905060a0525b60a0515f811261412c578152505b565b6101a051604052613aa96101e06126c5565b6101e0516101c0526101c0516101805118613ac5576001613b0e565b60016101c0516020525f5260405f2080610180516020525f5260405f20905054613b0b57610180516101a05161016052613b006101e0612926565b6101e0511815613b0e565b60015b815250565b680129a2241af62c00125460805260805115613bf757608051635f1a104c60a05260405160c052602060a0602460bc845afa613b51573d5f5f3e3d5ffd5b3d602081183d60201002188060a00160c01161412c5760a0518060011c61412c5760e0525060e0905051613bf75760208061016052600b610100527f4e6f7420616c6c6f776564000000000000000000000000000000000000000000610120526101008161016001602b82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610140528060040161015cfd5b6060516040511461412c5760403660a03742630784ce00810181811061412c57905062093a808104905062093a8081028162093a8082041861412c57905060e0526801000000000000000d6040516020525f5260405f2060018101905054610100526101005119613c69576001613c8f565b60e0516101005162093a808104905062093a8081028162093a8082041861412c57905018155b15613c9a57600160a0525b6801000000000000000d6060516020525f5260405f2060018101905054610120526101205119613ccb576001613cf1565b60e0516101205162093a808104905062093a8081028162093a8082041861412c57905018155b15613cfc57600160c0525b60a051613d09575f613d59565b60c051613d16575f613d59565b6101205162093a808104905062093a8081028162093a8082041861412c5790506101005162093a808104905062093a8081028162093a8082041861412c57905018155b815250565b6801000000000000000d6102e0516020525f5260405f20805461032052600181015461034052506801000000000000000d6102e0516020525f5260405f205f81555f6001820155506801000000000000000d610300516020525f5260405f208054610360526001810154610380525061036051610320518082018281125f83121861412c579050905061036052610360516801000000000000000d610300516020525f5260405f2055680129a2241af62c00106102e0516020525f5260405f20546001810181811061412c5790506103a0526103a051680129a2241af62c00106102e0516020525f5260405f2055680129a2241af62c000f6102e0516020525f5260405f2060036103a051670de0b6b3a764000081101561412c5702810190505f81555f600182015542600282015550680129a2241af62c0010610300516020525f5260405f20546001810181811061412c5790506103a0526103a051680129a2241af62c0010610300516020525f5260405f20556040366103c0376103805119613ef057610360516103e052613f47565b61036051630784ce00810590506103c0526103c051610380514280820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090506103e0525b680129a2241af62c000f610300516020525f5260405f2060036103a051670de0b6b3a764000081101561412c5702810190506103e05181556103c05160018201554260028201555060a036604037613f9d612a05565b565b6060513b156141245760605163150b7a026104e05260803361050052604051610520526080516105405280610560528061050001602060a051018060a0835e508051806020830101601f825f03163682375050601f19601f8251602001011690508101505060206104e06104a46104fc5f855af161401f573d5f5f3e3d5ffd5b3d602081183d6020100218806104e0016105001161412c576104e0518060201b61412c576109a052506109a09050516104c0527f150b7a02000000000000000000000000000000000000000000000000000000006104c051181561411a576020806105605260336104e0527f6572633732313a207472616e7366657220746f206e6f6e2d4945524337323152610500527f6563656976657220696d706c656d656e74657200000000000000000000000000610520526104e08161056001605382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610540528060040161055cfd5b600181525061412a565b60018152505b565b5f80fd25520018257026110e5a098f217d0c261e8f0cff125b261106422611009e26111cf32611261100f42611070c261125942611076426111a0610d615102611207c11b91a2025ed0f3c25b805f9215e0f57855820d9bd45f862a3703e900ef32fd6148faa34ece7c6b6bd0e312da27c5c52082d41194180811850190260a165767970657283000403003900000000000000000000000001791f726b4103694969820be083196cc7c045ff000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000019566f74696e67457363726f773a205969656c6420426173697300000000000000000000000000000000000000000000000000000000000000000000000000000476655942000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x5f3560e01c60026028820660011b61413001601e395f51565b6370a0823181186100555760243610341761412c576004358060a01c61412c5761016052602061016051604052610050610180612615565b610180f35b63adc6358981186126115760243610341761412c576004358060a01c61412c576040526801000000000000000d6040516020525f5260405f206001810190505460605260206060f35b636352211e81186100cb5760243610341761412c5760206004356040526100c66101406126c5565b610140f35b63587cde1e81186126115760243610341761412c576004358060a01c61412c5760405260206040f35b63095ea7b381186102c357604336111561412c576004358060a01c61412c576101a0526024356040526101286101e06126c5565b6101e0516101c0526101c0516101a051186101da576020806102605260216101e0527f6572633732313a20617070726f76616c20746f2063757272656e74206f776e65610200527f7200000000000000000000000000000000000000000000000000000000000000610220526101e08161026001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610240528060040161025cfd5b6101c05133186101eb576001610209565b60016101c0516020525f5260405f2080336020525f5260405f209050545b6102aa5760208061026052603d6101e0527f6572633732313a20617070726f76652063616c6c6572206973206e6f7420746f610200527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000610220526101e08161026001605d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610240528060040161025cfd5b6101a05161014052602435610160526102c1612757565b005b6306fdde03811861030d573461412c576020806040528060400160396142c082398051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b6365fc387381186126115760443610341761412c575f5c60011461412c5760015f5d60243562093a808104905062093a8081028162093a8082041861412c579050610520526801000000000000000d336020525f5260405f2080546105405260018101546105605250630784ce0060043510156103fc576020806105e0526009610580527f4d696e2076616c756500000000000000000000000000000000000000000000006105a052610580816105e001602982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b610540511561047d576020806105e0526019610580527f5769746864726177206f6c6420746f6b656e73206669727374000000000000006105a052610580816105e001603982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b42610520511161052457602080610600526026610580527f43616e206f6e6c79206c6f636b20756e74696c2074696d6520696e20746865206105a0527f66757475726500000000000000000000000000000000000000000000000000006105c0526105808161060001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105e052806004016105fcfd5b42630784ce00810181811061412c5790506105205111156105b7576020806105e052601e610580527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006105a052610580816105e001603e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b336102e05260043561030052610520516103205260406105406103405e6002610380526105e2613027565b336102605233610280526105f4613495565b5f5f5d005b63a22cb46581186126115760443610341761412c576004358060a01c61412c57610160526024358060011c61412c576101805233604052604061016060605e6106406127b1565b005b63081812fc81186106705760243610341761412c5760206004356101605261066b610180612926565b610180f35b634957677c811861068f5760243610341761412c5733610520526107f3565b637c74a17481186126115760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f2054606052680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c5702810190506001810190505460805260206080f35b63e985e9c581186126115760443610341761412c576004358060a01c61412c576040526024358060a01c61412c5760605260016040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b6395d89b4181186107ae573461412c5760208060405280604001602561430082398051806020830101601f825f03163682375050601f19601f825160200101169050810190506040f35b63c2c4c5c181186107ce573461412c5760a0366040376107cc612a05565b005b635e56b23981186126115760443610341761412c576024358060a01c61412c57610520525b5f5c60011461412c5760015f5d6801000000000000000d610520516020525f5260405f2080546105405260018101546105605250630784ce006004351061412c5760016105405112156108b8576020806105e0526016610580527f4e6f206578697374696e67206c6f636b20666f756e64000000000000000000006105a052610580816105e001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b42610560511161095f57602080610600526024610580527f43616e6e6f742061646420746f2065787069726564206c6f636b2e20576974686105a0527f64726177000000000000000000000000000000000000000000000000000000006105c0526105808161060001604482825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105e052806004016105fcfd5b610520516102e052600435610300525f6103205260406105406103405e60046103805261098a613027565b5f5f5d005b6318160ddd81186109af573461412c5760206109ab604061294a565b6040f35b63c87b56dd81186126115760243610341761412c576004356060526109d261289a565b6801000000000000000a6004356020525f5260405f2060208154015f81601f0160051c600f811161412c578015610a1d57905b808401548160051b6101600152600101818118610a05575b5050505060206143406103403961034051610a79576020806103605280610360016020610160510180610160835e508051806020830101601f825f03163682375050601f19601f82516020010116905081019050610360610c24565b6101605115610b03576020806105a0525f60206143405f395f5181610380018161436082395080820191505061016051816103800181610180825e5080820191505080610360526103609050816105a00160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506105a0610c24565b6103405115610bec576020806104c0525f60206143405f395f5181610400018161436082395080820191505060043580610b4b57603061036152600161036052610360610b8a565b5f604f905b82610b685780816103ae0352806103ae039250610b86565b600a8306603001816103ae0352600a83049250600101818118610b50575b5050805b905080516020820183610400018282825e505080830192505050806103e0526103e09050816104c00160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506104c0610c24565b6020806103805280610380015f81528051806020830101601f825f03163682375050601f19601f825160200101169050810190506103805bf35b634f6ccce781186126115760243610341761412c57610c45604061294a565b60405160043510610ce55760208060e05260226060527f6572633732313a20676c6f62616c20696e646578206f7574206f6620626f756e6080527f647300000000000000000000000000000000000000000000000000000000000060a05260608160e001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b60043560095481101561412c57600a015460405260206040f35b632f745c598118610e085760443610341761412c576004358060a01c61412c576101605261016051604052610d35610180612615565b6101805160243510610dde576020806102205260216101a0527f6572633732313a206f776e657220696e646578206f7574206f6620626f756e646101c0527f73000000000000000000000000000000000000000000000000000000000000006101e0526101a08161022001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610200528060040161021cfd5b6007610160516020525f5260405f20806024356020525f5260405f20905054610180526020610180f35b63d1febfb981186126115760243610341761412c576003600435670de0b6b3a764000081101561412c57026801000000000000000f018054604052600181015460605260028101546080525060606040f35b63f0350c0481186126115760243610341761412c576004358060a01c61412c5761010052610e86612952565b61010051610f2b576020806101a0526026610120527f6f776e61626c653a206e6577206f776e657220697320746865207a65726f2061610140527f646472657373000000000000000000000000000000000000000000000000000061016052610120816101a001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61010051604052610f3a6129ce565b005b638da5cb5b8118612611573461412c575f5460405260206040f35b6301ffc9a781186110935760243610341761412c576004358060201b61412c576040526040517f01ffc9a7000000000000000000000000000000000000000000000000000000008118610fab576001611088565b7f80ac58cd000000000000000000000000000000000000000000000000000000008118610fd9576001611088565b7f5b5e139f000000000000000000000000000000000000000000000000000000008118611007576001611088565b7f780e9d63000000000000000000000000000000000000000000000000000000008118611035576001611088565b7f49064906000000000000000000000000000000000000000000000000000000008118611063576001611088565b7fe90fb3f6000000000000000000000000000000000000000000000000000000008118155b905060805260206080f35b63010ae75781186126115760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f205460605260206060f35b635c19a95c811861116a5760243610341761412c576004358060a01c61412c5760405260208060c052600d6060527f4e6f7420737570706f727465640000000000000000000000000000000000000060805260608160c001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b6391ddadf4811861118c573461412c57428060301c61412c5760405260206040f35b638e539e8c81186126115760243610341761412c5760206004356040526111b46101606137e5565b610160f35b63c3cda52081186126115760c43610341761412c576004358060a01c61412c576040526064358060081c61412c5760605260208060e052600d6080527f4e6f7420737570706f727465640000000000000000000000000000000000000060a05260808160e001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b63eff7a61281186126115760243610341761412c575f5c60011461412c5760015f5d6801000000000000000d336020525f5260405f208054610520526001810154610540525060043562093a808104905062093a8081028162093a8082041861412c579050610560526001610520511215611348576020806105e0526011610580527f4e6f7468696e67206973206c6f636b65640000000000000000000000000000006105a052610580816105e001603182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b4261054051116113ca576020806105e052600c610580527f4c6f636b206578706972656400000000000000000000000000000000000000006105a052610580816105e001602c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b61054051610560511161144f576020806105e052601f610580527f43616e206f6e6c7920696e637265617365206c6f636b206475726174696f6e006105a052610580816105e001603f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b42630784ce00810181811061412c5790506105605111156114e2576020806105e052601e610580527f566f74696e67206c6f636b2063616e2062652034207965617273206d617800006105a052610580816105e001603e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b336102e0525f61030052610560516103205260406105206103405e60086103805261150b613027565b5f5f5d005b63b25ec64581186117dd573461412c575f5c60011461412c5760015f5d6801000000000000000d336020525f5260405f20805461052052600181015461054052504261054051116115d3576020806105c052600c610560527f4c6f636b2065787069726564000000000000000000000000000000000000000061058052610560816105c001602c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105a052806004016105bcfd5b6001610520511215611657576020806105c0526011610560527f4e6f7468696e67206973206c6f636b656400000000000000000000000000000061058052610560816105c001603182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105a052806004016105bcfd5b5f61056052610540511961178957680129a2241af62c0012546105805261058051156117535761058051635f1a104c6105a052336105c05260206105a060246105bc845afa6116a8573d5f5f3e3d5ffd5b3d602081183d6020100218806105a0016105c01161412c576105a0518060011c61412c576105e052506105e09050516117535760208061066052600b610600527f4e6f7420616c6c6f776564000000000000000000000000000000000000000000610620526106008161066001602b82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610640528060040161065cfd5b42630784ce00810181811061412c57905062093a808104905062093a8081028162093a8082041861412c579050610560526117af565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610560525b336102e0525f61030052610560516103205260406105206103405e6008610380526117d8613027565b5f5f5d005b6323b872dd81186126115760643610341761412c576004358060a01c61412c57610400526024358060a01c61412c576104205233610180526044356101a052611827610440613a97565b610440516118cc576020806104e052602d610460527f6572633732313a2063616c6c6572206973206e6f7420746f6b656e206f776e65610480527f72206f7220617070726f766564000000000000000000000000000000000000006104a052610460816104e001604d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104c052806004016104dcfd5b610400516044351815611951576020806104a052600e610440527f57726f6e6720746f6b656e20494400000000000000000000000000000000000061046052610440816104a001602e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610480528060040161049cfd5b604061040060405e611964610440613b13565b610440516119e4576020806104c052600f610460527f4e656564206d61782076654c6f636b000000000000000000000000000000000061048052610460816104c001602f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104a052806004016104bcfd5b60406104006102e05e6119f5613d5e565b60443561026052611a046136cd565b005b633ccfd60b8118612611573461412c57336102e052611a45565b6351cff8d98118611c7e5760243610341761412c576004358060a01c61412c576102e0525b5f5c60011461412c5760015f5d6801000000000000000d336020525f5260405f208054610300526001810154610320525061032051421015611af9576020806103a0526016610340527f546865206c6f636b206469646e2774206578706972650000000000000000000061036052610340816103a001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b610300515f811261412c576103405260406103006103605e5f610320525f610300526801000000000000000d336020525f5260405f20610300518155610320516001820155506801000000000000000c546103a0526103a0516103405180820382811161412c57905090506103c0526103c0516801000000000000000c5533604052604061036060605e604061030060a05e611b93612a05565b3361026052611ba06136cd565b60206143c05f395f5163a9059cbb6103e0526102e05161040052610340516104205260206103e060446103fc5f855af1611bdc573d5f5f3e3d5ffd5b3d602081183d6020100218806103e0016104001161412c576103e0518060011c61412c5761044052506104409050511561412c576102e051337ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567610340516103e052426104005260406103e0a37f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c60406103a06103e05e60406103e0a15f5f5d005b634bf5d7e98118612611573461412c57602080608052600e6040527f6d6f64653d74696d657374616d70000000000000000000000000000000000000606052604081608001602e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b639ab24eb08118611e235760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f2054606052606051611d44575f60805260206080611e21565b680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c5702810190508054608052600181015460a052600281015460c0525060805160a0514260c05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c57905090506080527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60805113611e0f575f6080525b6080515f811261412c5760e052602060e05bf35b6372e3af5081186126115760243610341761412c576004358060a01c61412c5761010052611e4f612952565b61010051680129a2241af62c0012557fa7fad85ba00d983deab3d92e1bbba81938da68cddbcb5d4f018ef3b1e66534fa61010051610120526020610120a1005b633a46b1a881186126115760443610341761412c576004358060a01c61412c576040525f606052680129a2241af62c00106040516020525f5260405f2054608052680129a2241af62c000f6040516020525f5260405f20600281019050546024351015611f03575f60a052602060a061207a565b5f6080905b8060a0526080516060511015611fac5760605160805180820182811061412c57905090506001810181811061412c5790508060011c905060c052602435680129a2241af62c000f6040516020525f5260405f20600360c051670de0b6b3a764000081101561412c570281019050600281019050541115611f9a5760c0516001810381811161412c579050608052611fa1565b60c0516060525b600101818118611f08575b5050680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c570281019050805460a052600181015460c052600281015460e0525060a05160c05160243560e05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905060a0525f60a0511215612066575f61010052602061010061207a565b60a0515f811261412c576101005260206101005bf35b630d15fd7781186120a2573461412c5760204260405261209d6101606137e5565b610160f35b63cbf9fe5f81186120ef5760243610341761412c576004358060a01c61412c576040526801000000000000000d6040516020525f5260405f20805460605260018101546080525060406060f35b6328d09d4781186126115760443610341761412c576004358060a01c61412c57604052680129a2241af62c000f6040516020525f5260405f206003602435670de0b6b3a764000081101561412c57028101905080546060526001810154608052600281015460a0525060606060f35b6342842e0e81186126115760643610341761412c575f610a00526121b2565b63b88d4fde81186124935760843610341761412c576064356004018035610400811161412c575060208135018082610a003750505b6004358060a01c61412c576109c0526024358060a01c61412c576109e05233610180526044356101a0526121e7610e40613a97565b610e405161228c57602080610ee052602d610e60527f6572633732313a2063616c6c6572206973206e6f7420746f6b656e206f776e65610e80527f72206f7220617070726f76656400000000000000000000000000000000000000610ea052610e6081610ee001604d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610ec05280600401610edcfd5b6109c051604435181561231157602080610ea052600e610e40527f57726f6e6720746f6b656e204944000000000000000000000000000000000000610e6052610e4081610ea001602e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610e805280600401610e9cfd5b60406109c060405e612324610e40613b13565b610e40516123a457602080610ec052600f610e60527f4e656564206d61782076654c6f636b0000000000000000000000000000000000610e8052610e6081610ec001602f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610ea05280600401610ebcfd5b60406109c06102e05e6123b5613d5e565b604435610260526123c46136cd565b60406109c060405e6044356080526020610a00510180610a0060a05e506123ec610e40613f9f565b610e405161249157602080610ee0526033610e60527f6572633732313a207472616e7366657220746f206e6f6e2d4945524337323152610e80527f6563656976657220696d706c656d656e74657200000000000000000000000000610ea052610e6081610ee001605382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610ec05280600401610edcfd5b005b63a7afdcae81186126115760243610341761412c576004358060a01c61412c57604052680129a2241af62c00106040516020525f5260405f2054606052680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c570281019050545f811261412c57608052680129a2241af62c000f6040516020525f5260405f206003606051670de0b6b3a764000081101561412c570281019050600181019050545f811261412c5760a05260406080f35b6382bfefc88118612611573461412c5760206143c060403960206040f35b63047fc9aa8118612611573461412c576801000000000000000c5460405260206040f35b63900cf0cf8118612611573461412c576801000000000000000e5460405260206040f35b637119748481186126115760243610341761412c57680129a2241af62c00116004356020525f5260405f205460405260206040f35b63cada36828118612611573461412c57680129a2241af62c00125460405260206040f35b5f5ffd5b6040516126b15760208060e052602d6060527f6572633732313a20746865207a65726f2061646472657373206973206e6f74206080527f612076616c6964206f776e65720000000000000000000000000000000000000060a05260608160e001604d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b60046040516020525f5260405f2054815250565b60056040516020525f5260405f205460605260605161274f5760208060e05260186080527f6572633732313a20696e76616c696420746f6b656e204944000000000000000060a05260808160e001603882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060c0528060040160dcfd5b606051815250565b610140516006610160516020525f5260405f20556101605161014051610160516040526127856101806126c5565b610180517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f6101a0a4565b6060516040511861282f5760208061010052601960a0527f6572633732313a20617070726f766520746f2063616c6c65720000000000000060c05260a08161010001603982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060e0528060040160fcfd5b60805160016040516020525f5260405f20806060516020525f5260405f209050556060516040517f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160805160a052602060a0a3565b60056040516020525f5260405f20541515815250565b6060516040526128aa6080612884565b6080516129245760208061010052601860a0527f6572633732313a20696e76616c696420746f6b656e204944000000000000000060c05260a08161010001603882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060e0528060040160fcfd5b565b6101605160605261293561289a565b6006610160516020525f5260405f2054815250565b600954815250565b5f543318156129cc5760208060a05260206040527f6f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260605260408160a001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060805280600401609cfd5b565b5f546060526040515f556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f6080a3565b6101003660e0376801000000000000000e546101e05260405115612b8c574260805111612a32575f612a3a565b600160605112155b15612aab5760805119612a57575f6101005260605160e052612aab565b606051630784ce008105905061010052610100516080514280820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c579050905060e0525b4260c05111612aba575f612ac2565b600160a05112155b15612b355760c05119612ae0575f6101605260a05161014052612b35565b60a051630784ce0081059050610160526101605160c0514280820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c5790509050610140525b680129a2241af62c00116080516020525f5260405f20546101a05260c05115612b8c5760805160c05118612b70576101a0516101c052612b8c565b680129a2241af62c001160c0516020525f5260405f20546101c0525b6040366102003742610240526101e05115612bdd5760036101e051670de0b6b3a764000081101561412c57026801000000000000000f01805461020052600181015461022052600281015461024052505b61024051610260526102605162093a808104905062093a8081028162093a8082041861412c579050610280525f60ff905b806102a0526102805162093a80810181811061412c579050610280525f6102c052426102805111612c5a57680129a2241af62c0011610280516020525f5260405f20546102c052612c60565b42610280525b6102005161022051610280516102605180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905061020052610220516102c0518082018281125f83121861412c5790509050610220527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102005113612d0c575f610200525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102205113612d3c575f610220525b610280516102605261028051610240526101e0516001810181811061412c5790506101e05242610280511815612db25760036101e051670de0b6b3a764000081101561412c57026801000000000000000f0161020051815561022051600182015561024051600282015550600101818118612c0e575b50506101e0516801000000000000000e5560405115612e92576102205161016051610100518082038281135f83121861412c57905090508082018281125f83121861412c579050905061022052610200516101405160e0518082038281135f83121861412c57905090508082018281125f83121861412c5790509050610200527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102205113612e62575f610220525b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102005113612e92575f610200525b60036101e051670de0b6b3a764000081101561412c57026801000000000000000f01610200518155610220516001820155610240516002820155506040511561302557426080511115612f43576101a051610100518082018281125f83121861412c57905090506101a05260805160c05118612f27576101a051610160518082038281135f83121861412c57905090506101a0525b6101a051680129a2241af62c00116080516020525f5260405f20555b4260c0511115612f925760805160c05114612f92576101c051610160518082038281135f83121861412c57905090506101c0526101c051680129a2241af62c001160c0516020525f5260405f20555b680129a2241af62c00106040516020525f5260405f20546001810181811061412c5790506102a0526102a051680129a2241af62c00106040516020525f5260405f20554261018052680129a2241af62c000f6040516020525f5260405f2060036102a051670de0b6b3a764000081101561412c570281019050610140518155610160516001820155610180516002820155505b565b60406103406103a05e6801000000000000000c546103e0526103e0516103005180820182811061412c5790509050630784ce0081049050630784ce00810281630784ce0082041861412c57905061040052610400516103e05180820382811161412c579050905061042052610400516801000000000000000c5560406103a06104405e6103a051610420518060ff1c61412c578082018281125f83121861412c57905090506103a05261032051156130e257610320516103c0525b6801000000000000000d6102e0516020525f5260405f206103a05181556103c0516001820155506102e051604052604061044060605e60406103a060a05e613128612a05565b61042051156131a45760206143c05f395f516323b872dd61048052336104a052306104c052610420516104e0526020610480606461049c5f855af161316f573d5f5f3e3d5ffd5b3d602081183d602010021880610480016104a01161412c57610480518060011c61412c5761050052506105009050511561412c575b6103c0516102e051337f5f971bd00bf3ffbca8a6d72cdd4fd92cfd4f62636161921d1e5a64f0b64ccb6d6104205161048052610380516104a052426104c0526060610480a47f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c60406103e06104805e6040610480a1565b600954680100000000000000096040516020525f5260405f205560095467fffffffffffffffe811161412c5760405181600a01556001810160095550565b6101605160405261326b6101c0612615565b6101c0516001810381811161412c5790506101a0526008610180516020525f5260405f20546101c0526101a0516101c051146132fe576007610160516020525f5260405f20806101a0516020525f5260405f209050546101e0526101e0516007610160516020525f5260405f20806101c0516020525f5260405f209050556101c05160086101e0516020525f5260405f20555b5f6008610180516020525f5260405f20555f6007610160516020525f5260405f20806101a0516020525f5260405f20905055565b6009546001810381811161412c579050606052680100000000000000096040516020525f5260405f205460805260605160095481101561412c57600a015460a05260a05160805160095481101561412c57600a01556080516801000000000000000960a0516020525f5260405f20555f680100000000000000096040516020525f5260405f20556001600954801561412c57038060095550565b610160516040526133de6101c0612615565b6101c0516101a052610180516007610160516020525f5260405f20806101a0516020525f5260405f209050556101a0516008610180516020525f5260405f2055565b61020051613437576102405160405261345c61321b565b61022051610200511461345c576102005161016052610240516101805261345c613259565b610220516134735761024051604052613491613332565b6102005161022051146134915760406102206101605e6134916133cc565b565b565b61026051613515576020806103005260206102a0527f6572633732313a206d696e7420746f20746865207a65726f20616464726573736102c0526102a08161030001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06102e052806004016102fcfd5b610280516040526135276102a0612884565b6102a051156135a85760208061032052601c6102c0527f6572633732313a20746f6b656e20616c7265616479206d696e746564000000006102e0526102c08161032001603c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610300528060040161031cfd5b5f6102005260406102606102205e6135be613420565b610280516040526135d06102a0612884565b6102a051156136515760208061032052601c6102c0527f6572633732313a20746f6b656e20616c7265616479206d696e746564000000006102e0526102c08161032001603c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610300528060040161031cfd5b60016004610260516020525f5260405f2054016004610260516020525f5260405f2055610260516005610280516020525f5260405f205561028051610260515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f6102a0a45f604052604061026060605e6136cb613493565b565b610260516040526136df6102a06126c5565b6102a0516102805261028051610200525f610220526102605161024052613704613420565b610260516040526137166102a06126c5565b6102a051610280525f6006610260516020525f5260405f205560016004610280516020525f5260405f2054036004610280516020525f5260405f20555f6005610260516020525f5260405f2055610260515f610280517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f6102a0a4610280516040525f606052610260516080526137ac613493565b6801000000000000000a610260516020525f5260405f2054156137e3575f6801000000000000000a610260516020525f5260405f20555b565b6801000000000000000e54606052606051613803575f815250613a95565b68010000000000000011546040511015613820575f815250613a95565b5f6080525f6080905b8060a05260605160805110156138be5760805160605180820182811061412c57905090506001810181811061412c5790508060011c905060c052604051600360c051670de0b6b3a764000081101561412c57026801000000000000000f016002810190505411156138ac5760c0516001810381811161412c5790506060526138b3565b60c0516080525b600101818118613829575b50506003608051670de0b6b3a764000081101561412c57026801000000000000000f01805460a052600181015460c052600281015460e0525060605160805118613a2d5760e051610100525f60ff905b80610120526101005162093a80810181811061412c579050610100525f61014052604051610100511161395c57680129a2241af62c0011610100516020525f5260405f205461014052613964565b604051610100525b60a05160c0516101005160e05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905060a0526040516101005118156139f95760c051610140518082018281125f83121861412c579050905060c0526101005160e05260010181811861390e575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60a05113613a87575f60a052613a87565b60a05160c05160405160e05180820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090508082038281135f83121861412c579050905060a0525b60a0515f811261412c578152505b565b6101a051604052613aa96101e06126c5565b6101e0516101c0526101c0516101805118613ac5576001613b0e565b60016101c0516020525f5260405f2080610180516020525f5260405f20905054613b0b57610180516101a05161016052613b006101e0612926565b6101e0511815613b0e565b60015b815250565b680129a2241af62c00125460805260805115613bf757608051635f1a104c60a05260405160c052602060a0602460bc845afa613b51573d5f5f3e3d5ffd5b3d602081183d60201002188060a00160c01161412c5760a0518060011c61412c5760e0525060e0905051613bf75760208061016052600b610100527f4e6f7420616c6c6f776564000000000000000000000000000000000000000000610120526101008161016001602b82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610140528060040161015cfd5b6060516040511461412c5760403660a03742630784ce00810181811061412c57905062093a808104905062093a8081028162093a8082041861412c57905060e0526801000000000000000d6040516020525f5260405f2060018101905054610100526101005119613c69576001613c8f565b60e0516101005162093a808104905062093a8081028162093a8082041861412c57905018155b15613c9a57600160a0525b6801000000000000000d6060516020525f5260405f2060018101905054610120526101205119613ccb576001613cf1565b60e0516101205162093a808104905062093a8081028162093a8082041861412c57905018155b15613cfc57600160c0525b60a051613d09575f613d59565b60c051613d16575f613d59565b6101205162093a808104905062093a8081028162093a8082041861412c5790506101005162093a808104905062093a8081028162093a8082041861412c57905018155b815250565b6801000000000000000d6102e0516020525f5260405f20805461032052600181015461034052506801000000000000000d6102e0516020525f5260405f205f81555f6001820155506801000000000000000d610300516020525f5260405f208054610360526001810154610380525061036051610320518082018281125f83121861412c579050905061036052610360516801000000000000000d610300516020525f5260405f2055680129a2241af62c00106102e0516020525f5260405f20546001810181811061412c5790506103a0526103a051680129a2241af62c00106102e0516020525f5260405f2055680129a2241af62c000f6102e0516020525f5260405f2060036103a051670de0b6b3a764000081101561412c5702810190505f81555f600182015542600282015550680129a2241af62c0010610300516020525f5260405f20546001810181811061412c5790506103a0526103a051680129a2241af62c0010610300516020525f5260405f20556040366103c0376103805119613ef057610360516103e052613f47565b61036051630784ce00810590506103c0526103c051610380514280820382811161412c57905090508060ff1c61412c5780820281191515600160ff1b841415178215848484051417161561412c57905090506103e0525b680129a2241af62c000f610300516020525f5260405f2060036103a051670de0b6b3a764000081101561412c5702810190506103e05181556103c05160018201554260028201555060a036604037613f9d612a05565b565b6060513b156141245760605163150b7a026104e05260803361050052604051610520526080516105405280610560528061050001602060a051018060a0835e508051806020830101601f825f03163682375050601f19601f8251602001011690508101505060206104e06104a46104fc5f855af161401f573d5f5f3e3d5ffd5b3d602081183d6020100218806104e0016105001161412c576104e0518060201b61412c576109a052506109a09050516104c0527f150b7a02000000000000000000000000000000000000000000000000000000006104c051181561411a576020806105605260336104e0527f6572633732313a207472616e7366657220746f206e6f6e2d4945524337323152610500527f6563656976657220696d706c656d656e74657200000000000000000000000000610520526104e08161056001605382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610540528060040161055cfd5b600181525061412a565b60018152505b565b5f80fd25520018257026110e5a098f217d0c261e8f0cff125b261106422611009e26111cf32611261100f42611070c261125942611076426111a0610d615102611207c11b91a2025ed0f3c25b805f9215e0f57a0532e09ee38adcd4089b204812691c51a32b3eb375436a86ae088d9b036f8b300000000000000000000000000000000000000000000000000000000000000010000000000000000000000008235c179e9e84688fbd8b12295efc26834dac211000000000000000000000000000000000000000000000000000000000000000b4a75737420736179206e6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009b29f4eab2afb955a939e5bb4e080257fdc8071103f99888124cf4197dffda0d0000000000000000000000000000000000000000000000000000000000000009746f2045495037313200000000000000000000000000000000000000000000004ca7bd70c5e2b6c43a1f5331172941165e5965688189aa73516af0c22165f1100000000000000000000000000000000000000000000000000000000000000019566f74696e67457363726f773a205969656c642042617369730000000000000000000000000000000000000000000000000000000000000000000000000000047665594200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001791f726b4103694969820be083196cc7c045ff

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

Yield protocol on top of Curve Finance.

Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.