ETH Price: $1,972.84 (+0.15%)
 

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
Approve244717182026-02-16 20:17:235 days ago1771273043IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000001920.0418539
Claim244717162026-02-16 20:16:595 days ago1771273019IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000205191
Claim244694362026-02-16 12:39:235 days ago1771245563IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000017640.09381427
Claim244676062026-02-16 6:31:356 days ago1771223495IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000006730.03327337
Approve244202102026-02-09 15:49:3512 days ago1770652175IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.00005551.20729143
Redeem243922382026-02-05 17:52:1116 days ago1770313931IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.001963164.12647821
Claim243922352026-02-05 17:51:3516 days ago1770313895IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000941454.23524597
Redeem243919012026-02-05 16:44:3516 days ago1770309875IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.002470145.02819763
Approve243918922026-02-05 16:42:4716 days ago1770309767IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000242155.26699686
Approve243837602026-02-04 13:22:3517 days ago1770211355IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000009080.37885017
Approve243683762026-02-02 9:48:1119 days ago1770025691IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000019430.81011905
Approve243168672026-01-26 5:19:3527 days ago1769404775IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000001960.08220199
Approve243162762026-01-26 3:21:1127 days ago1769397671IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000012840.53582169
Approve243148762026-01-25 22:40:2327 days ago1769380823IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000005990.24972929
Approve242629802026-01-18 16:57:1134 days ago1768755431IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000000870.03644348
Approve242246822026-01-13 8:43:5940 days ago1768293839IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000001220.05121079
Approve242246802026-01-13 8:43:3540 days ago1768293815IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000001250.05227153
Approve242233472026-01-13 4:15:4740 days ago1768277747IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000001690.03692968
Approve241950562026-01-09 5:33:1144 days ago1767936791IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000001610.06729048
Deposit241815282026-01-07 8:12:3546 days ago1767773555IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000065160.12923572
Approve241790282026-01-06 23:49:4746 days ago1767743387IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000002070.04506124
Claim241790212026-01-06 23:48:2346 days ago1767743303IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000010740.04190138
Approve241779662026-01-06 20:16:4746 days ago1767730607IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000001180.04959299
Claim241729842026-01-06 3:36:4747 days ago1767670607IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000023930.1
Approve241209622025-12-29 21:23:3554 days ago1767043415IN
Yield Basis: g(yb-tBTC) Token
0 ETH0.000004720.10269798
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x613d1651234340122025-09-24 16:12:59150 days ago1758730379  Contract Creation0 ETH
Loading...
Loading
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 0x7e4383Bd...8C5CB6659
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Liquidity Gauge

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 10 : LiquidityGauge.vy
# @version 0.4.3
"""
@title Liquidity Gauge
@author Yield Basis
@license GNU Affero General Public License v3.0
@notice Liquidity Gauge to measure who deposited LP tokens for how long
"""
from ethereum.ercs import IERC20
from snekmate.utils import math
import erc4626


initializes: erc4626


exports: (
    erc4626.erc20.totalSupply,
    erc4626.erc20.balanceOf,
    erc4626.erc20.approve,
    erc4626.erc20.allowance,
    erc4626.decimals,
    erc4626.totalAssets,
    erc4626.convertToShares,
    erc4626.convertToAssets,
    erc4626.maxDeposit,
    erc4626.previewDeposit,
    erc4626.maxMint,
    erc4626.previewMint,
    erc4626.maxWithdraw,
    erc4626.previewWithdraw,
    erc4626.maxRedeem,
    erc4626.previewRedeem,
    erc4626.asset,
    erc4626.ownable.transfer_ownership,
    erc4626.ownable.owner,
    erc4626.MIN_SHARES
)


interface GaugeController:
    def emit() -> uint256: nonpayable
    def preview_emissions(gauge: address, at_time: uint256) -> uint256: view
    def TOKEN() -> IERC20: view

interface Factory:
    def gauge_controller() -> GaugeController: view
    def admin() -> address: view
    def emergency_admin() -> address: view

interface IERC20Slice:
    def symbol() -> String[29]: view

interface LT:
    def is_killed() -> bool: view
    def checkpoint_staker_rebase(): nonpayable


event AddReward:
    token: indexed(address)
    distributor: address
    id: uint256

event ChangeRewardDistributor:
    token: indexed(address)
    distributor: address

event DepositRewards:
    token: indexed(address)
    distributor: address
    amount: uint256
    finish_time: uint256


struct Reward:
    distributor: address
    finish_time: uint256
    total: uint256

struct Integral:
    v: uint256
    t: uint256

struct RewardIntegrals:
    integral_inv_supply: Integral
    reward_rate_integral: Integral
    user_rewards_integral: Integral


VERSION: public(constant(String[8])) = "v1.0.0"

MAX_REWARDS: constant(uint256) = 8
MIN_SHARES_DECIMALS: constant(uint8) = 12
GC: public(immutable(GaugeController))
YB: public(immutable(IERC20))
LP_TOKEN: public(immutable(IERC20))
FACTORY: public(immutable(Factory))


reward_count: public(uint256)
reward_tokens: public(IERC20[MAX_REWARDS])
rewards: public(HashMap[IERC20, Reward])
processed_rewards: public(HashMap[IERC20, uint256])

integral_inv_supply: public(Integral)
integral_inv_supply_4_token: public(HashMap[IERC20, uint256])

reward_rate_integral: public(HashMap[IERC20, Integral])
reward_rate_integral_4_user: public(HashMap[address, HashMap[IERC20, uint256]])

user_rewards_integral: public(HashMap[address, HashMap[IERC20, Integral]])
claimed_rewards: public(HashMap[address, HashMap[IERC20, uint256]])


@deploy
def __init__(lp_token: IERC20):
    erc4626.__init__("YB Gauge: ..", "g(..)", lp_token, MIN_SHARES_DECIMALS, "Just say no", "to EIP712")
    LP_TOKEN = lp_token
    GC = staticcall Factory(msg.sender).gauge_controller()
    YB = staticcall GC.TOKEN()
    FACTORY = Factory(msg.sender)
    erc4626.ownable.owner = staticcall Factory(msg.sender).admin()
    self.rewards[YB].distributor = GC.address
    self.reward_tokens[0] = YB
    self.reward_count = 1
    log AddReward(token=YB.address, distributor=GC.address, id=0)


@external
@view
def symbol() -> String[32]:
    return concat('g(', staticcall IERC20Slice(LP_TOKEN.address).symbol(), ')')


@external
@view
def name() -> String[39]:
    return concat('YB Gauge: ', staticcall IERC20Slice(LP_TOKEN.address).symbol())


@external
@view
def get_adjustment() -> uint256:
    """
    @notice Get a measure of how many Liquidity Tokens are staked: sqrt(staked / totalSupply)
    @return Result from 0.0 (0) to 1.0 (1e18)
    """
    staked: uint256 = staticcall LP_TOKEN.balanceOf(self)
    supply: uint256 = staticcall LP_TOKEN.totalSupply()
    return isqrt(unsafe_div(staked * 10**36, supply))


@internal
@view
def _checkpoint(reward: IERC20, d_reward: uint256, user: address) -> RewardIntegrals:
    r: RewardIntegrals = empty(RewardIntegrals)

    r.integral_inv_supply = self.integral_inv_supply
    if block.timestamp > r.integral_inv_supply.t:
        r.integral_inv_supply.v += unsafe_div(10**36 * (block.timestamp - r.integral_inv_supply.t), erc4626.erc20.totalSupply)
        r.integral_inv_supply.t = block.timestamp

    if reward.address != empty(address):
        r.reward_rate_integral = self.reward_rate_integral[reward]
        if block.timestamp > r.reward_rate_integral.t:
            r.reward_rate_integral.v += (r.integral_inv_supply.v - self.integral_inv_supply_4_token[reward]) * d_reward //\
               (block.timestamp - r.reward_rate_integral.t)
            r.reward_rate_integral.t = block.timestamp

    if user != empty(address):
        r.user_rewards_integral = self.user_rewards_integral[user][reward]
        if block.timestamp > r.user_rewards_integral.t:
            r.user_rewards_integral.v += math._mul_div(
                r.reward_rate_integral.v - self.reward_rate_integral_4_user[user][reward],
                erc4626.erc20.balanceOf[user],
                10**36,
                False)
            r.user_rewards_integral.t = block.timestamp

    return r


@internal
@view
def _get_vested_rewards(token: IERC20) -> uint256:
    assert self.rewards[token].distributor != empty(address), "No reward"

    last_reward_time: uint256 = self.reward_rate_integral[token].t
    used_rewards: uint256 = self.processed_rewards[token]
    finish_time: uint256 = self.rewards[token].finish_time
    total: uint256 = self.rewards[token].total
    if finish_time > last_reward_time:
        new_used: uint256 = (total - used_rewards) * (block.timestamp - last_reward_time) //\
            (finish_time - last_reward_time) + used_rewards
        return min(new_used, total) - used_rewards
    else:
        return 0


@internal
def _vest_rewards(reward: IERC20, pre: bool) -> uint256:
    d_reward: uint256 = 0
    if reward == YB:
        if pre:
            d_reward = staticcall GC.preview_emissions(self, block.timestamp)
        else:
            d_reward = extcall GC.emit()
    else:
        d_reward = self._get_vested_rewards(reward)
        self.processed_rewards[reward] += d_reward
    return d_reward


@internal
def _checkpoint_user(user: address):
    n: uint256 = self.reward_count
    for i: uint256 in range(MAX_REWARDS):
        if i == n:
            break
        reward: IERC20 = self.reward_tokens[i]
        d_reward: uint256 = self._vest_rewards(reward, True)
        r: RewardIntegrals = self._checkpoint(reward, d_reward, user)
        if i == 0:
            self.integral_inv_supply = r.integral_inv_supply
        self.integral_inv_supply_4_token[reward] = r.integral_inv_supply.v
        self.reward_rate_integral[reward] = r.reward_rate_integral
        self.reward_rate_integral_4_user[user][reward] = r.reward_rate_integral.v
        self.user_rewards_integral[user][reward] = r.user_rewards_integral


@external
@nonreentrant
def claim(reward: IERC20 = YB, user: address = msg.sender) -> uint256:
    """
    @notice Claim rewards (YB or external) earned by the user
    @param reward Reward token (YB by default)
    @param user User to claim for
    """
    d_reward: uint256 = self._vest_rewards(reward, False)
    r: RewardIntegrals = self._checkpoint(reward, d_reward, user)

    self.integral_inv_supply = r.integral_inv_supply
    self.integral_inv_supply_4_token[reward] = r.integral_inv_supply.v
    self.reward_rate_integral[reward] = r.reward_rate_integral
    self.reward_rate_integral_4_user[user][reward] = r.reward_rate_integral.v
    self.user_rewards_integral[user][reward] = r.user_rewards_integral

    d_reward = r.user_rewards_integral.v - self.claimed_rewards[user][reward]
    self.claimed_rewards[user][reward] = r.user_rewards_integral.v

    assert extcall reward.transfer(user, d_reward, default_return_value=True)
    return d_reward


@external
@view
def preview_claim(reward: IERC20, user: address) -> uint256:
    """
    @notice Calculate amount of rewards which user can claim
    @param reward Reward token address
    @param user Recipient address
    """
    d_reward: uint256 = 0
    if reward == YB:
        d_reward = staticcall GC.preview_emissions(self, block.timestamp)
    else:
        d_reward = self._get_vested_rewards(reward)

    r: RewardIntegrals = self._checkpoint(reward, d_reward, user)
    return r.user_rewards_integral.v - self.claimed_rewards[user][reward]


@external
@nonreentrant
def add_reward(token: IERC20, distributor: address):
    """
    @notice Add a non-YB reward token. This does not deposit it, just creates a possibility to do it
    @param token Token address to add as an extra reward
    @param distributor Address of distributor of the reward
    """
    assert token != YB, "YB"
    assert token != LP_TOKEN, "LP_TOKEN"
    assert distributor != empty(address)
    assert self.rewards[token].distributor == empty(address), "Already added"
    erc4626.ownable._check_owner()
    self.rewards[token].distributor = distributor
    reward_id: uint256 = self.reward_count
    self.reward_tokens[reward_id] = token
    self.reward_count = reward_id + 1
    log AddReward(token=token.address, distributor=distributor, id=reward_id)


@external
def change_reward_distributor(token: IERC20, distributor: address):
    """
    @notice Change the distributor of a custom (non-YB) reward
    @param token Reward token address
    @param distributor New distributor of the reward
    """
    assert token != YB, "YB"
    assert distributor != empty(address)
    assert self.rewards[token].distributor != empty(address), "Not added"
    erc4626.ownable._check_owner()
    self.rewards[token].distributor = distributor
    log ChangeRewardDistributor(token=token.address, distributor=distributor)


@external
@nonreentrant
def deposit_reward(token: IERC20, amount: uint256, finish_time: uint256):
    """
    @notice Deposit a custom (non-YB) reward token if it was added with add_reward
    @param token Reward token address
    @param amount Amount of token to deposit
    @param finish_time Timestamp when distribution should finish. Do not change the reward rate if set to 0
    """
    assert token != YB, "YB"
    assert amount > 0, "No rewards"
    r: Reward = self.rewards[token]

    if msg.sender != r.distributor:
        erc4626.ownable._check_owner()

    d_reward: uint256 = self._vest_rewards(token, False)
    ri: RewardIntegrals = self._checkpoint(token, d_reward, empty(address))
    self.integral_inv_supply = ri.integral_inv_supply
    self.integral_inv_supply_4_token[token] = ri.integral_inv_supply.v
    self.reward_rate_integral[token] = ri.reward_rate_integral

    unused_rewards: uint256 = r.total - self.processed_rewards[token]

    if finish_time > 0 or unused_rewards == 0:
        # Change rate to meet new finish time
        assert finish_time > block.timestamp, "Finishes in the past"
        r.finish_time = finish_time
    else:
        # Keep the reward rate
        assert r.finish_time > block.timestamp, "Rate unknown"
        r.finish_time = block.timestamp + (r.finish_time - block.timestamp) * (unused_rewards + amount) // unused_rewards
    r.total += amount

    self.rewards[token] = r
    assert extcall token.transferFrom(msg.sender, self, amount, default_return_value=True)
    log DepositRewards(token=token.address, distributor=msg.sender, amount=amount, finish_time=r.finish_time)


@external
@nonreentrant
def deposit(assets: uint256, receiver: address) -> uint256:
    """
    @notice Deposit liquidity token to earn rewards
    @param assets Amount of LT token to deposit
    @param receiver Who should get the gauge tokens
    """
    extcall LT(LP_TOKEN.address).checkpoint_staker_rebase()
    assert assets <= erc4626._max_deposit(receiver), "erc4626: deposit more than maximum"
    shares: uint256 = erc4626._preview_deposit(assets)
    self._checkpoint_user(receiver)
    erc4626._deposit(msg.sender, receiver, assets, shares)
    erc4626._check_min_shares()
    extcall GC.emit()
    return shares


@external
@nonreentrant
def mint(shares: uint256, receiver: address) -> uint256:
    """
    @notice Deposit liquidity token to earn rewards given amount of gauge shares to receive
    @param shares Gauge shares to receive
    @param receiver Receiver of the gauge shares
    """
    extcall LT(LP_TOKEN.address).checkpoint_staker_rebase()
    assert shares <= erc4626._max_mint(receiver), "erc4626: mint more than maximum"
    assets: uint256 = erc4626._preview_mint(shares)
    self._checkpoint_user(receiver)
    erc4626._deposit(msg.sender, receiver, assets, shares)
    erc4626._check_min_shares()
    extcall GC.emit()
    return assets


@external
@nonreentrant
def withdraw(assets: uint256, receiver: address, owner: address) -> uint256:
    """
    @notice Withdraw gauge shares given the amount of LT tokens to receive
    @param assets Amount of LT tokens to receive
    @param receiver Receiver of LT tokens
    @param owner Who had the gauge tokens before the tx
    """
    extcall LT(LP_TOKEN.address).checkpoint_staker_rebase()
    assert assets <= erc4626._max_withdraw(owner), "erc4626: withdraw more than maximum"
    shares: uint256 = erc4626._preview_withdraw(assets)
    self._checkpoint_user(owner)
    erc4626._withdraw(msg.sender, receiver, owner, assets, shares)
    erc4626._check_min_shares()
    extcall GC.emit()
    return shares


@external
@nonreentrant
def redeem(shares: uint256, receiver: address, owner: address) -> uint256:
    """
    @notice Withdraw gauge shares given the amount of gauge shares
    @param shares Amount of gauge shares to withdraw
    @param receiver Receiver of LT tokens
    @param owner Who had the gauge tokens before the tx
    """
    extcall LT(LP_TOKEN.address).checkpoint_staker_rebase()
    assert shares <= erc4626._max_redeem(owner), "erc4626: redeem more than maximum"

    # Handle killing so that eadmin can withdraw anyone's shares to their own wallet
    sender: address = msg.sender
    if staticcall LT(LP_TOKEN.address).is_killed():
        if msg.sender == staticcall FACTORY.emergency_admin():
            # Only emergency admin is allowed to withdraw for others, but then only transfer to themselves
            assert receiver == owner, "receiver"
            sender = owner  # Tell _withdraw() to bypass checks who can do it

    assets: uint256 = erc4626._preview_redeem(shares)
    self._checkpoint_user(owner)
    erc4626._withdraw(sender, receiver, owner, assets, shares)
    erc4626._check_min_shares()
    extcall GC.emit()
    return assets


@external
@nonreentrant
def transfer(to: address, amount: uint256) -> bool:
    """
    @notice ERC20 transfer of gauge shares
    """
    self._checkpoint_user(msg.sender)
    self._checkpoint_user(to)
    erc4626.erc20._transfer(msg.sender, to, amount)
    extcall GC.emit()
    return True


@external
@nonreentrant
def transferFrom(owner: address, to: address, amount: uint256) -> bool:
    """
    @notice ERC20 transferFrom of gauge shares
    """
    self._checkpoint_user(owner)
    self._checkpoint_user(to)
    erc4626.erc20._spend_allowance(owner, msg.sender, amount)
    erc4626.erc20._transfer(owner, to, amount)
    extcall GC.emit()
    return True

File 2 of 10 : math.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title Standard Mathematical Utility Functions
@custom:contract-name math
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@custom:coauthor bout3fiddy
@notice These functions implement standard mathematical utility
        functions that are missing in the Vyper language. If a
        function is inspired by an existing implementation, it
        is properly referenced in the function docstring. The
        following functions have been added for convenience:
        - `_uint256_average` (`internal` `pure` function),
        - `_int256_average` (`internal` `pure` function),
        - `_ceil_div` (`internal` `pure` function),
        - `_signum` (`internal` `pure` function),
        - `_mul_div` (`internal` `pure` function),
        - `_log2` (`internal` `pure` function),
        - `_log10` (`internal` `pure` function),
        - `_log256` (`internal` `pure` function),
        - `_wad_ln` (`internal` `pure` function),
        - `_wad_exp` (`internal` `pure` function),
        - `_cbrt` (`internal` `pure` function),
        - `_wad_cbrt` (`internal` `pure` function).
"""


@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 _uint256_average(x: uint256, y: uint256) -> uint256:
    """
    @dev Returns the average of two 32-byte unsigned integers.
    @notice Note that the result is rounded towards zero. For
            more details on finding the average of two unsigned
            integers without an overflow, please refer to:
            https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223.
    @param x The first 32-byte unsigned integer of the data set.
    @param y The second 32-byte unsigned integer of the data set.
    @return uint256 The 32-byte average (rounded towards zero) of
            `x` and `y`.
    """
    return unsafe_add(x & y, (x ^ y) >> 1)


@internal
@pure
def _int256_average(x: int256, y: int256) -> int256:
    """
    @dev Returns the average of two 32-byte signed integers.
    @notice Note that the result is rounded towards infinity.
            For more details on finding the average of two signed
            integers without an overflow, please refer to:
            https://patents.google.com/patent/US6007232A/en.
    @param x The first 32-byte signed integer of the data set.
    @param y The second 32-byte signed integer of the data set.
    @return int256 The 32-byte average (rounded towards infinity)
            of `x` and `y`.
    """
    return unsafe_add(unsafe_add(x >> 1, y >> 1), x & y & 1)


@internal
@pure
def _ceil_div(x: uint256, y: uint256) -> uint256:
    """
    @dev Calculates "ceil(x / y)" for any strictly positive `y`.
    @notice The implementation is inspired by OpenZeppelin's
            implementation here:
            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.
    @param x The 32-byte numerator.
    @param y The 32-byte denominator.
    @return uint256 The 32-byte rounded up result of "x/y".
    """
    assert y != empty(uint256), "math: ceil_div division by zero"
    # Due to a known compiler bug (https://github.com/vyperlang/vyper/issues/3480),
    # we use `0` instead of `empty(uint256)` as return value.
    return 0 if (x == empty(uint256)) else unsafe_add(unsafe_div(x - 1, y), 1)


@internal
@pure
def _signum(x: int256) -> int256:
    """
    @dev Returns the indication of the sign of a 32-byte signed integer.
    @notice The function returns `-1` if `x < 0`, `0` if `x == 0`, and `1`
            if `x > 0`. For more details on finding the sign of a signed
            integer, please refer to:
            https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign.
    @param x The 32-byte signed integer variable.
    @return int256 The 32-byte sign indication (`1`, `0`, or `-1`) of `x`.
    """
    return unsafe_sub(convert((x > empty(int256)), int256), convert((x < empty(int256)), int256))


@internal
@pure
def _mul_div(x: uint256, y: uint256, denominator: uint256, roundup: bool) -> uint256:
    """
    @dev Calculates "(x * y) / denominator" in 512-bit precision,
         following the selected rounding direction.
    @notice The implementation is inspired by Remco Bloemen's
            implementation under the MIT license here:
            https://xn--2-umb.com/21/muldiv.
            Furthermore, the rounding direction design pattern is
            inspired by OpenZeppelin's implementation here:
            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.
    @param x The 32-byte multiplicand.
    @param y The 32-byte multiplier.
    @param denominator The 32-byte divisor.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return uint256 The 32-byte calculation result.
    """
    # Handle division by zero.
    assert denominator != empty(uint256), "math: mul_div division by zero"

    # 512-bit multiplication "[prod1 prod0] = x * y".
    # Compute the product "mod 2**256" and "mod 2**256 - 1".
    # Then use the Chinese Remainder theorem to reconstruct
    # the 512-bit result. The result is stored in two 256-bit
    # variables, where: "product = prod1 * 2**256 + prod0".
    mm: uint256 = uint256_mulmod(x, y, max_value(uint256))
    # The least significant 256 bits of the product.
    prod0: uint256 = unsafe_mul(x, y)
    # The most significant 256 bits of the product.
    prod1: uint256 = empty(uint256)

    if mm < prod0:
        prod1 = unsafe_sub(unsafe_sub(mm, prod0), 1)
    else:
        prod1 = unsafe_sub(mm, prod0)

    # Handling of non-overflow cases, 256 by 256 division.
    if prod1 == empty(uint256):
        if roundup and uint256_mulmod(x, y, denominator) != empty(uint256):
            # Calculate "ceil((x * y) / denominator)". The following
            # line cannot overflow because we have the previous check
            # "(x * y) % denominator != 0", which accordingly rules out
            # the possibility of "x * y = 2**256 - 1" and `denominator == 1`.
            return unsafe_add(unsafe_div(prod0, denominator), 1)

        return unsafe_div(prod0, denominator)

    # Ensure that the result is less than "2**256". Also,
    # prevents that `denominator == 0`.
    assert denominator > prod1, "math: mul_div overflow"

    #######################
    # 512 by 256 Division #
    #######################

    # Make division exact by subtracting the remainder
    # from "[prod1 prod0]". First, compute remainder using
    # the `uint256_mulmod` operation.
    remainder: uint256 = uint256_mulmod(x, y, denominator)

    # Second, subtract the 256-bit number from the 512-bit
    # number.
    if remainder > prod0:
        prod1 = unsafe_sub(prod1, 1)
    prod0 = unsafe_sub(prod0, remainder)

    # Factor powers of two out of the denominator and calculate
    # the largest power of two divisor of denominator. Always `>= 1`,
    # unless the denominator is zero (which is prevented above),
    # in which case `twos` is zero. For more details, please refer to:
    # https://cs.stackexchange.com/q/138556.
    twos: uint256 = unsafe_sub(empty(uint256), denominator) & denominator
    # Divide denominator by `twos`.
    denominator_div: uint256 = unsafe_div(denominator, twos)
    # Divide "[prod1 prod0]" by `twos`.
    prod0 = unsafe_div(prod0, twos)
    # Flip `twos` such that it is "2**256 / twos". If `twos` is zero,
    # it becomes one.
    twos = unsafe_add(unsafe_div(unsafe_sub(empty(uint256), twos), twos), 1)

    # Shift bits from `prod1` to `prod0`.
    prod0 |= unsafe_mul(prod1, twos)

    # Invert the denominator "mod 2**256". Since the denominator is
    # now an odd number, it has an inverse modulo "2**256", so we have:
    # "denominator * inverse = 1 mod 2**256". Calculate the inverse by
    # starting with a seed that is correct for four bits. That is,
    # "denominator * inverse = 1 mod 2**4".
    inverse: uint256 = unsafe_mul(3, denominator_div) ^ 2

    # Use Newton-Raphson iteration to improve accuracy. Thanks to Hensel's
    # lifting lemma, this also works in modular arithmetic by doubling the
    # correct bits in each step.
    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**8".
    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**16".
    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**32".
    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**64".
    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**128".
    inverse = unsafe_mul(inverse, unsafe_sub(2, unsafe_mul(denominator_div, inverse))) # Inverse "mod 2**256".

    # Since the division is now exact, we can divide by multiplying
    # with the modular inverse of the denominator. This returns the
    # correct result modulo "2**256". Since the preconditions guarantee
    # that the result is less than "2**256", this is the final result.
    # We do not need to calculate the high bits of the result and
    # `prod1` is no longer necessary.
    result: uint256 = unsafe_mul(prod0, inverse)

    if roundup and uint256_mulmod(x, y, denominator) != empty(uint256):
        # Calculate "ceil((x * y) / denominator)". The following
        # line uses intentionally checked arithmetic to prevent
        # a theoretically possible overflow.
        result += 1

    return result


@internal
@pure
def _log2(x: uint256, roundup: bool) -> uint256:
    """
    @dev Returns the log in base 2 of `x`, following the selected
         rounding direction.
    @notice Note that it returns `0` if given `0`. The implementation
            is inspired by OpenZeppelin's implementation here:
            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.
    @param x The 32-byte variable.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return uint256 The 32-byte calculation result.
    """
    # For the special case `x == 0`, we already return `0` here in order
    # not to iterate through the remaining code.
    if x == empty(uint256):
        return empty(uint256)

    value: uint256 = x
    result: uint256 = empty(uint256)

    # The following lines cannot overflow because we have the well-known
    # decay behaviour of `log2(max_value(uint256)) < max_value(uint256)`.
    if x >> 128 != empty(uint256):
        x >>= 128
        result = 128
    if x >> 64 != empty(uint256):
        x >>= 64
        result = unsafe_add(result, 64)
    if x >> 32 != empty(uint256):
        x >>= 32
        result = unsafe_add(result, 32)
    if x >> 16 != empty(uint256):
        x >>= 16
        result = unsafe_add(result, 16)
    if x >> 8 != empty(uint256):
        x >>= 8
        result = unsafe_add(result, 8)
    if x >> 4 != empty(uint256):
        x >>= 4
        result = unsafe_add(result, 4)
    if x >> 2 != empty(uint256):
        x >>= 2
        result = unsafe_add(result, 2)
    if x >> 1 != empty(uint256):
        result = unsafe_add(result, 1)

    if roundup and (1 << result) < value:
        result = unsafe_add(result, 1)

    return result


@internal
@pure
def _log10(x: uint256, roundup: bool) -> uint256:
    """
    @dev Returns the log in base 10 of `x`, following the selected
         rounding direction.
    @notice Note that it returns `0` if given `0`. The implementation
            is inspired by OpenZeppelin's implementation here:
            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.
    @param x The 32-byte variable.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return uint256 The 32-byte calculation result.
    """
    # For the special case `x == 0`, we already return `0` here in order
    # not to iterate through the remaining code.
    if x == empty(uint256):
        return empty(uint256)

    value: uint256 = x
    result: uint256 = empty(uint256)

    # The following lines cannot overflow because we have the well-known
    # decay behaviour of `log10(max_value(uint256)) < max_value(uint256)`.
    if x >= 10 ** 64:
        x = unsafe_div(x, 10 ** 64)
        result = 64
    if x >= 10 ** 32:
        x = unsafe_div(x, 10 ** 32)
        result = unsafe_add(result, 32)
    if x >= 10 ** 16:
        x = unsafe_div(x, 10 ** 16)
        result = unsafe_add(result, 16)
    if x >= 10 ** 8:
        x = unsafe_div(x, 10 ** 8)
        result = unsafe_add(result, 8)
    if x >= 10 ** 4:
        x = unsafe_div(x, 10 ** 4)
        result = unsafe_add(result, 4)
    if x >= 10 ** 2:
        x = unsafe_div(x, 10 ** 2)
        result = unsafe_add(result, 2)
    if x >= 10:
        result = unsafe_add(result, 1)

    if roundup and (10 ** result) < value:
        result = unsafe_add(result, 1)

    return result


@internal
@pure
def _log256(x: uint256, roundup: bool) -> uint256:
    """
    @dev Returns the log in base 256 of `x`, following the selected
         rounding direction.
    @notice Note that it returns `0` if given `0`. Also, adding one to the
            rounded down result gives the number of pairs of hex symbols
            needed to represent `x` as a hex string. The implementation is
            inspired by OpenZeppelin's implementation here:
            https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol.
    @param x The 32-byte variable.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return uint256 The 32-byte calculation result.
    """
    # For the special case `x == 0`, we already return `0` here in order
    # not to iterate through the remaining code.
    if x == empty(uint256):
        return empty(uint256)

    value: uint256 = x
    result: uint256 = empty(uint256)

    # The following lines cannot overflow because we have the well-known
    # decay behaviour of `log256(max_value(uint256)) < max_value(uint256)`.
    if x >> 128 != empty(uint256):
        x >>= 128
        result = 16
    if x >> 64 != empty(uint256):
        x >>= 64
        result = unsafe_add(result, 8)
    if x >> 32 != empty(uint256):
        x >>= 32
        result = unsafe_add(result, 4)
    if x >> 16 != empty(uint256):
        x >>= 16
        result = unsafe_add(result, 2)
    if x >> 8 != empty(uint256):
        result = unsafe_add(result, 1)

    if roundup and (1 << (result << 3)) < value:
        result = unsafe_add(result, 1)

    return result


@internal
@pure
def _wad_ln(x: int256) -> int256:
    """
    @dev Calculates the natural logarithm of a signed integer with a
         precision of 1e18.
    @notice Note that it returns `0` if given `0`. Furthermore, this function
            consumes about 1,400 to 1,650 gas units depending on the value
            of `x`. The implementation is inspired by Remco Bloemen's
            implementation under the MIT license here:
            https://xn--2-umb.com/22/exp-ln.
    @param x The 32-byte variable.
    @return int256 The 32-byte calculation result.
    """
    assert x >= empty(int256), "math: wad_ln undefined"

    # For the special case `x == 0`, we already return `0` here in order
    # not to iterate through the remaining code.
    if x == empty(int256):
        return empty(int256)

    # We want to convert `x` from "10**18" fixed point to "2**96"
    # fixed point. We do this by multiplying by "2**96 / 10**18".
    # But since "ln(x * C) = ln(x) + ln(C)" holds, we can just do
    # nothing here and add "ln(2**96 / 10**18)" at the end.

    # Reduce the range of `x` to "(1, 2) * 2**96".
    # Also remember that "ln(2**k * x) = k * ln(2) + ln(x)" holds.
    k: int256 = unsafe_sub(convert(self._log2(convert(x, uint256), False), int256), 96)
    # Note that to circumvent Vyper's safecast feature for the potentially
    # negative expression `x <<= uint256(159 - k)`, we first convert the
    # expression `x <<= uint256(159 - k)` to `bytes32` and subsequently
    # to `uint256`. Remember that the EVM default behaviour is to use two's
    # complement representation to handle signed integers.
    x = convert(convert(convert(x << convert(unsafe_sub(159, k), uint256), bytes32), uint256) >> 159, int256)

    # Evaluate using a "(8, 8)"-term rational approximation. Since `p` is monic,
    # we will multiply by a scaling factor later.
    p: int256 = unsafe_add(
        unsafe_mul(unsafe_add(x, 3_273_285_459_638_523_848_632_254_066_296), x) >> 96,
        24_828_157_081_833_163_892_658_089_445_524,
    )
    p = unsafe_add(unsafe_mul(p, x) >> 96, 43_456_485_725_739_037_958_740_375_743_393)
    p = unsafe_sub(unsafe_mul(p, x) >> 96, 11_111_509_109_440_967_052_023_855_526_967)
    p = unsafe_sub(unsafe_mul(p, x) >> 96, 45_023_709_667_254_063_763_336_534_515_857)
    p = unsafe_sub(unsafe_mul(p, x) >> 96, 14_706_773_417_378_608_786_704_636_184_526)
    p = unsafe_sub(unsafe_mul(p, x), 795_164_235_651_350_426_258_249_787_498 << 96)

    # We leave `p` in the "2**192" base so that we do not have to scale it up
    # again for the division. Note that `q` is monic by convention.
    q: int256 = unsafe_add(
        unsafe_mul(unsafe_add(x, 5_573_035_233_440_673_466_300_451_813_936), x) >> 96,
        71_694_874_799_317_883_764_090_561_454_958,
    )
    q = unsafe_add(unsafe_mul(q, x) >> 96, 283_447_036_172_924_575_727_196_451_306_956)
    q = unsafe_add(unsafe_mul(q, x) >> 96, 401_686_690_394_027_663_651_624_208_769_553)
    q = unsafe_add(unsafe_mul(q, x) >> 96, 204_048_457_590_392_012_362_485_061_816_622)
    q = unsafe_add(unsafe_mul(q, x) >> 96, 31_853_899_698_501_571_402_653_359_427_138)
    q = unsafe_add(unsafe_mul(q, x) >> 96, 909_429_971_244_387_300_277_376_558_375)

    # It is known that the polynomial `q` has no zeros in the domain.
    # No scaling is required, as `p` is already "2**96" too large. Also,
    # `r` is in the range "(0, 0.125) * 2**96" after the division.
    r: int256 = unsafe_div(p, q)

    # To finalise the calculation, we have to proceed with the following steps:
    #   - multiply by the scaling factor "s = 5.549...",
    #   - add "ln(2**96 / 10**18)",
    #   - add "k * ln(2)", and
    #   - multiply by "10**18 / 2**96 = 5**18 >> 78".
    # In order to perform the most gas-efficient calculation, we carry out all
    # these steps in one expression.
    return (
        unsafe_add(
            unsafe_add(
                unsafe_mul(r, 1_677_202_110_996_718_588_342_820_967_067_443_963_516_166),
                unsafe_mul(
                    k, 16_597_577_552_685_614_221_487_285_958_193_947_469_193_820_559_219_878_177_908_093_499_208_371
                ),
            ),
            600_920_179_829_731_861_736_702_779_321_621_459_595_472_258_049_074_101_567_377_883_020_018_308,
        )
        >> 174
    )


@internal
@pure
def _wad_exp(x: int256) -> int256:
    """
    @dev Calculates the natural exponential function of a signed integer with
         a precision of 1e18.
    @notice Note that this function consumes about 810 gas units. The implementation
            is inspired by Remco Bloemen's implementation under the MIT license here:
            https://xn--2-umb.com/22/exp-ln.
    @param x The 32-byte variable.
    @return int256 The 32-byte calculation result.
    """
    # If the result is `< 1`, we return zero. This happens when we have the following:
    # "x <= (log(1e-18) * 1e18) ~ -4.15e19".
    if x <= -41_446_531_673_892_822_313:
        return empty(int256)

    # When the result is "> (2**255 - 1) / 1e18" we cannot represent it as a signed integer.
    # This happens when "x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135".
    assert x < 135_305_999_368_893_231_589, "math: wad_exp overflow"

    # `x` is now in the range "(-42, 136) * 1e18". Convert to "(-42, 136) * 2**96" for higher
    # intermediate precision and a binary base. This base conversion is a multiplication with
    # "1e18 / 2**96 = 5**18 / 2**78".
    x = unsafe_div(x << 78, 5 ** 18)

    # Reduce the range of `x` to "(-½ ln 2, ½ ln 2) * 2**96" by factoring out powers of two
    # so that "exp(x) = exp(x') * 2**k", where `k` is a signer integer. Solving this gives
    # "k = round(x / log(2))" and "x' = x - k * log(2)". Thus, `k` is in the range "[-61, 195]".
    k: int256 = unsafe_add(unsafe_div(x << 96, 54_916_777_467_707_473_351_141_471_128), 2 ** 95) >> 96
    x = unsafe_sub(x, unsafe_mul(k, 54_916_777_467_707_473_351_141_471_128))

    # Evaluate using a "(6, 7)"-term rational approximation. Since `p` is monic,
    # we will multiply by a scaling factor later.
    y: int256 = unsafe_add(
        unsafe_mul(unsafe_add(x, 1_346_386_616_545_796_478_920_950_773_328), x) >> 96,
        57_155_421_227_552_351_082_224_309_758_442,
    )
    p: int256 = unsafe_add(
        unsafe_mul(
            unsafe_add(
                unsafe_mul(unsafe_sub(unsafe_add(y, x), 94_201_549_194_550_492_254_356_042_504_812), y) >> 96,
                28_719_021_644_029_726_153_956_944_680_412_240,
            ),
            x,
        ),
        4_385_272_521_454_847_904_659_076_985_693_276 << 96,
    )

    # We leave `p` in the "2**192" base so that we do not have to scale it up
    # again for the division.
    q: int256 = unsafe_add(
        unsafe_mul(unsafe_sub(x, 2_855_989_394_907_223_263_936_484_059_900), x) >> 96,
        50_020_603_652_535_783_019_961_831_881_945,
    )
    q = unsafe_sub(unsafe_mul(q, x) >> 96, 533_845_033_583_426_703_283_633_433_725_380)
    q = unsafe_add(unsafe_mul(q, x) >> 96, 3_604_857_256_930_695_427_073_651_918_091_429)
    q = unsafe_sub(unsafe_mul(q, x) >> 96, 14_423_608_567_350_463_180_887_372_962_807_573)
    q = unsafe_add(unsafe_mul(q, x) >> 96, 26_449_188_498_355_588_339_934_803_723_976_023)

    # The polynomial `q` has no zeros in the range because all its roots are complex.
    # No scaling is required, as `p` is already "2**96" too large. Also,
    # `r` is in the range "(0.09, 0.25) * 2**96" after the division.
    r: int256 = unsafe_div(p, q)

    # To finalise the calculation, we have to multiply `r` by:
    #   - the scale factor "s = ~6.031367120",
    #   - the factor "2**k" from the range reduction, and
    #   - the factor "1e18 / 2**96" for the base conversion.
    # We do this all at once, with an intermediate result in "2**213" base,
    # so that the final right shift always gives a positive value.

    # Note that to circumvent Vyper's safecast feature for the potentially
    # negative parameter value `r`, we first convert `r` to `bytes32` and
    # subsequently to `uint256`. Remember that the EVM default behaviour is
    # to use two's complement representation to handle signed integers.
    return convert(
        unsafe_mul(
            convert(convert(r, bytes32), uint256), 3_822_833_074_963_236_453_042_738_258_902_158_003_155_416_615_667
        )
        >> convert(unsafe_sub(195, k), uint256),
        int256,
    )


@internal
@pure
def _cbrt(x: uint256, roundup: bool) -> uint256:
    """
    @dev Calculates the cube root of an unsigned integer.
    @notice Note that this function consumes about 1,600 to 1,800 gas units
            depending on the value of `x` and `roundup`. The implementation is
            inspired by Curve Finance's implementation under the MIT license here:
            https://github.com/curvefi/tricrypto-ng/blob/main/contracts/main/CurveCryptoMathOptimized3.vy.
    @param x The 32-byte variable from which the cube root is calculated.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return The 32-byte cube root of `x`.
    """
    # For the special case `x == 0`, we already return `0` here in order
    # not to iterate through the remaining code.
    if x == empty(uint256):
        return empty(uint256)

    y: uint256 = unsafe_div(self._wad_cbrt(x), 10 ** 12)

    if roundup and unsafe_mul(unsafe_mul(y, y), y) != x:
        y = unsafe_add(y, 1)

    return y


@internal
@pure
def _wad_cbrt(x: uint256) -> uint256:
    """
    @dev Calculates the cube root of an unsigned integer with a precision
         of 1e18.
    @notice Note that this function consumes about 1,500 to 1,700 gas units
            depending on the value of `x`. The implementation is inspired
            by Curve Finance's implementation under the MIT license here:
            https://github.com/curvefi/tricrypto-ng/blob/main/contracts/main/CurveCryptoMathOptimized3.vy.
    @param x The 32-byte variable from which the cube root is calculated.
    @return The 32-byte cubic root of `x` with a precision of 1e18.
    """
    # For the special case `x == 0`, we already return `0` here in order
    # not to iterate through the remaining code.
    if x == empty(uint256):
        return empty(uint256)

    # Since this cube root is for numbers with base 1e18, we have to scale
    # the input by 1e36 to increase the precision. This leads to an overflow
    # for very large numbers. So we conditionally sacrifice precision.
    value: uint256 = empty(uint256)
    if x >= unsafe_mul(unsafe_div(max_value(uint256), 10 ** 36), 10 ** 18):
        value = x
    elif x >= unsafe_div(max_value(uint256), 10 ** 36):
        value = unsafe_mul(x, 10 ** 18)
    else:
        value = unsafe_mul(x, 10 ** 36)

    # Compute the binary logarithm of `value`.
    log2x: uint256 = self._log2(value, False)

    # If we divide log2x by 3, the remainder is "log2x % 3". So if we simply
    # multiply "2**(log2x/3)" and discard the remainder to calculate our guess,
    # the Newton-Raphson method takes more iterations to converge to a solution
    # because it lacks this precision. A few more calculations now in order to
    # do fewer calculations later:
    #   - "pow = log2(x) // 3" (the operator `//` means integer division),
    #   - "remainder = log2(x) % 3",
    #   - "initial_guess = 2**pow * cbrt(2)**remainder".
    # Now substituting "2 = 1.26 ≈ 1,260 / 1,000", we get:
    #   - "initial_guess = 2**pow * 1,260**remainder // 1,000**remainder".
    remainder: uint256 = log2x % 3
    y: uint256 = unsafe_div(
        unsafe_mul(pow_mod256(2, unsafe_div(log2x, 3)), pow_mod256(1_260, remainder)), pow_mod256(1_000, remainder)
    )

    # Since we have chosen good initial values for the cube roots, 7 Newton-Raphson
    # iterations are just sufficient. 6 iterations would lead to non-convergences,
    # and 8 would be one iteration too many. Without initial values, the iteration
    # number can be up to 20 or more. The iterations are unrolled. This reduces the
    # gas cost, but requires more bytecode.
    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)
    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)
    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)
    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)
    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)
    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)
    y = unsafe_div(unsafe_add(unsafe_mul(2, y), unsafe_div(value, unsafe_mul(y, y))), 3)

    # Since we scaled up, we have to scale down accordingly.
    if x >= unsafe_mul(unsafe_div(max_value(uint256), 10 ** 36), 10 ** 18):
        return unsafe_mul(y, 10 ** 12)
    elif x >= unsafe_div(max_value(uint256), 10 ** 36):
        return unsafe_mul(y, 10 ** 6)

    return y

File 3 of 10 : Vyper_contract.vy
# pragma version ~=0.4.3
"""
@title EIP-2612 Interface Definition
@custom:contract-name IERC20Permit
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice The `permit` function implements approvals via
        EIP-712 secp256k1 signatures:
        https://eips.ethereum.org/EIPS/eip-2612.
        The `permit` function allows users to modify
        the allowance mapping 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.

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


@external
def permit(owner: address, spender: address, amount: uint256, deadline: uint256, v: uint8, r: bytes32, s: bytes32):
    """
    @dev Sets `amount` as the allowance of `spender`
         over `owner`'s tokens, 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 `owner`'s current nonce.
    @param owner The 20-byte owner address.
    @param spender The 20-byte spender address.
    @param amount The 32-byte token amount that is
           allowed to be spent by the `spender`.
    @param deadline The 32-byte block timestamp up
           which the `spender` is allowed to spend `amount`.
    @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(owner: address) -> uint256:
    """
    @dev Returns the current on-chain tracked nonce of `owner`.
    @param owner The 20-byte owner address.
    @return uint256 The 32-byte owner nonce.
    """
    ...


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

File 4 of 10 : 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 5 of 10 : 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 6 of 10 : 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 7 of 10 : 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 8 of 10 : 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 9 of 10 : erc20.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title Modern and Gas-Efficient ERC-20 + EIP-2612 Implementation
@custom:contract-name erc20
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
@notice These functions implement the ERC-20
        standard interface:
        - https://eips.ethereum.org/EIPS/eip-20.
        In addition, the following functions have
        been added for convenience:
        - `name` (`external` `view` function),
        - `symbol` (`external` `view` function),
        - `decimals` (`external` `view` function),
        - `burn` (`external` function),
        - `burn_from` (`external` function),
        - `is_minter` (`external` `view` function),
        - `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),
        - `_before_token_transfer` (`internal` function),
        - `_after_token_transfer` (`internal` function).
        The `permit` function implements approvals via
        EIP-712 secp256k1 signatures:
        https://eips.ethereum.org/EIPS/eip-2612.
        In addition, this contract also implements the EIP-5267
        function `eip712Domain`:
        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/token/ERC20/ERC20.sol,
        as well as by ApeAcademy's implementation here:
        https://github.com/ApeAcademy/ERC20/blob/main/%7B%7Bcookiecutter.project_name%7D%7D/contracts/Token.vy.
@custom:security This ERC-20 implementation allows the commonly known
                 address poisoning attack, where `transferFrom` instructions
                 are executed from arbitrary addresses with an `amount` of `0`.
                 However, this poisoning attack is not an on-chain vulnerability.
                 All assets are safe. It is an off-chain log interpretation issue.
                 The main reason why we do not disallow address poisonig is that
                 we do not want to potentially break any DeFi composability.
                 This issue has been extensively discussed here:
                 https://github.com/pcaversaccio/snekmate/issues/51,
                 as well as in the OpenZeppelin repository:
                 https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3931.
"""


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


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


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


# @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 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-20 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 The 32-byte type hash of the `permit` function.
_PERMIT_TYPE_HASH: constant(bytes32) = keccak256(
    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
)


# @dev Returns the name of the token.
# @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-20
# standard, we use lower case letters for the
# `immutable` variables `name`, `symbol`, and
# `decimals`.
name: public(immutable(String[25]))


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


# @dev Returns the decimal places of the token.
# @notice See comment on lower case letters
# above at `name`.
decimals: public(immutable(uint8))


# @dev Returns the amount of tokens owned by an `address`.
balanceOf: public(HashMap[address, uint256])


# @dev Returns the remaining number of tokens that a
# `spender` will be allowed to spend on behalf of
# `owner` through `transferFrom`. This is zero by
# default. This value changes when `approve` or
# `transferFrom` are called.
allowance: public(HashMap[address, HashMap[address, uint256]])


# @dev Returns the amount of tokens in existence.
totalSupply: public(uint256)


# @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 `address`.
nonces: public(HashMap[address, 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], decimals_: uint8, 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.
    @param symbol_ The maximum 5-character user-readable
           string symbol of the token.
    @param decimals_ The 1-byte decimal places of the token.
    @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.
    """
    name = name_
    symbol = symbol_
    decimals = decimals_

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

    eip712_domain_separator.__init__(name_eip712_, version_eip712_)


@external
def transfer(to: address, amount: uint256) -> bool:
    """
    @dev Moves `amount` tokens from the caller's
         account to `to`.
    @notice Note that `to` cannot be the zero address.
            Also, the caller must have a balance of at
            least `amount`.
    @param to The 20-byte receiver address.
    @param amount The 32-byte token amount to be transferred.
    @return bool The verification whether the transfer succeeded
            or failed. Note that the function reverts instead
            of returning `False` on a failure.
    """
    self._transfer(msg.sender, to, amount)
    return True


@external
def approve(spender: address, amount: uint256) -> bool:
    """
    @dev Sets `amount` as the allowance of `spender`
         over the caller's tokens.
    @notice WARNING: Note that if `amount` is the maximum
            `uint256`, the allowance is not updated on
            `transferFrom`. This is semantically equivalent
            to an infinite approval. Also, `spender` cannot
            be the zero address.

            IMPORTANT: Beware that changing an allowance
            with this method brings the risk that someone
            may use both the old and the new allowance by
            unfortunate transaction ordering. One possible
            solution to mitigate this race condition is to
            first reduce the spender's allowance to `0` and
            set the desired amount afterwards:
            https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729.
    @param spender The 20-byte spender address.
    @param amount The 32-byte token amount that is
           allowed to be spent by the `spender`.
    @return bool The verification whether the approval operation
            succeeded or failed. Note that the function reverts
            instead of returning `False` on a failure.
    """
    self._approve(msg.sender, spender, amount)
    return True


@external
def transferFrom(owner: address, to: address, amount: uint256) -> bool:
    """
    @dev Moves `amount` tokens from `owner`
         to `to` using the allowance mechanism.
         The `amount` is then deducted from the
         caller's allowance.
    @notice Note that `owner` and `to` cannot
            be the zero address. Also, `owner`
            must have a balance of at least `amount`.
            Eventually, the caller must have allowance
            for `owner`'s tokens of at least `amount`.

            WARNING: The function does not update the
            allowance if the current allowance is the
            maximum `uint256`.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param amount The 32-byte token amount to be transferred.
    @return bool The verification whether the transfer succeeded
            or failed. Note that the function reverts instead
            of returning `False` on a failure.
    """
    self._spend_allowance(owner, msg.sender, amount)
    self._transfer(owner, to, amount)
    return True


@external
def burn(amount: uint256):
    """
    @dev Destroys `amount` tokens from the caller.
    @param amount The 32-byte token amount to be destroyed.
    """
    self._burn(msg.sender, amount)


@external
def burn_from(owner: address, amount: uint256):
    """
    @dev Destroys `amount` tokens from `owner`,
         deducting from the caller's allowance.
    @notice Note that `owner` cannot be the
            zero address. Also, the caller must
            have an allowance for `owner`'s tokens
            of at least `amount`.
    @param owner The 20-byte owner address.
    @param amount The 32-byte token amount to be destroyed.
    """
    self._spend_allowance(owner, msg.sender, amount)
    self._burn(owner, amount)


@external
def mint(owner: address, amount: uint256):
    """
    @dev Creates `amount` tokens and assigns them to `owner`.
    @notice Only authorised minters can access this function.
            Note that `owner` cannot be the zero address.
    @param owner The 20-byte owner address.
    @param amount The 32-byte token amount to be created.
    """
    assert self.is_minter[msg.sender], "erc20: access is denied"
    self._mint(owner, amount)


@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), "erc20: minter is the zero address"
    # We ensured in the previous step `ownable._check_owner`
    # that `msg.sender` is the `owner`.
    assert minter != msg.sender, "erc20: minter is owner address"
    self.is_minter[minter] = status
    log RoleMinterChanged(minter=minter, status=status)


@external
def permit(owner: address, spender: address, amount: uint256, deadline: uint256, v: uint8, r: bytes32, s: bytes32):
    """
    @dev Sets `amount` as the allowance of `spender`
         over `owner`'s tokens, 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 `owner`'s current nonce.
    @param owner The 20-byte owner address.
    @param spender The 20-byte spender address.
    @param amount The 32-byte token amount that is
           allowed to be spent by the `spender`.
    @param deadline The 32-byte block timestamp up
           which the `spender` is allowed to spend `amount`.
    @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, "erc20: expired deadline"

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

    struct_hash: bytes32 = keccak256(abi_encode(_PERMIT_TYPE_HASH, owner, spender, amount, 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 == owner, "erc20: invalid signature"

    self._approve(owner, spender, amount)


@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), "erc20: 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
def _transfer(owner: address, to: address, amount: uint256):
    """
    @dev Moves `amount` tokens from the owner's
         account to `to`.
    @notice Note that `owner` and `to` cannot be
            the zero address. Also, `owner` must
            have a balance of at least `amount`.
    @param owner The 20-byte owner address.
    @param to The 20-byte receiver address.
    @param amount The 32-byte token amount to be transferred.
    """
    assert owner != empty(address), "erc20: transfer from the zero address"
    assert to != empty(address), "erc20: transfer to the zero address"

    self._before_token_transfer(owner, to, amount)

    owner_balanceOf: uint256 = self.balanceOf[owner]
    assert owner_balanceOf >= amount, "erc20: transfer amount exceeds balance"
    self.balanceOf[owner] = unsafe_sub(owner_balanceOf, amount)
    self.balanceOf[to] = unsafe_add(self.balanceOf[to], amount)
    log IERC20.Transfer(sender=owner, receiver=to, value=amount)

    self._after_token_transfer(owner, to, amount)


@internal
def _mint(owner: address, amount: uint256):
    """
    @dev Creates `amount` tokens and assigns
         them to `owner`, increasing the
         total supply.
    @notice This is an `internal` function without
            access restriction. Note that `owner`
            cannot be the zero address.
    @param owner The 20-byte owner address.
    @param amount The 32-byte token amount to be created.
    """
    assert owner != empty(address), "erc20: mint to the zero address"

    self._before_token_transfer(empty(address), owner, amount)

    self.totalSupply += amount
    self.balanceOf[owner] = unsafe_add(self.balanceOf[owner], amount)
    log IERC20.Transfer(sender=empty(address), receiver=owner, value=amount)

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


@internal
def _burn(owner: address, amount: uint256):
    """
    @dev Destroys `amount` tokens from `owner`,
         reducing the total supply.
    @notice Note that `owner` cannot be the
            zero address. Also, `owner` must
            have at least `amount` tokens.
    @param owner The 20-byte owner address.
    @param amount The 32-byte token amount to be destroyed.
    """
    assert owner != empty(address), "erc20: burn from the zero address"

    self._before_token_transfer(owner, empty(address), amount)

    account_balance: uint256 = self.balanceOf[owner]
    assert account_balance >= amount, "erc20: burn amount exceeds balance"
    self.balanceOf[owner] = unsafe_sub(account_balance, amount)
    self.totalSupply = unsafe_sub(self.totalSupply, amount)
    log IERC20.Transfer(sender=owner, receiver=empty(address), value=amount)

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


@internal
def _approve(owner: address, spender: address, amount: uint256):
    """
    @dev Sets `amount` as the allowance of `spender`
         over the `owner`'s tokens.
    @notice Note that `owner` and `spender` cannot
            be the zero address.
    @param owner The 20-byte owner address.
    @param spender The 20-byte spender address.
    @param amount The 32-byte token amount that is
           allowed to be spent by the `spender`.
    """
    assert owner != empty(address), "erc20: approve from the zero address"
    assert spender != empty(address), "erc20: approve to the zero address"

    self.allowance[owner][spender] = amount
    log IERC20.Approval(owner=owner, spender=spender, value=amount)


@internal
def _spend_allowance(owner: address, spender: address, amount: uint256):
    """
    @dev Updates `owner`'s allowance for `spender`
         based on spent `amount`.
    @notice WARNING: Note that it does not update the
            allowance `amount` in case of infinite
            allowance. Also, it reverts if not enough
            allowance is available.
    @param owner The 20-byte owner address.
    @param spender The 20-byte spender address.
    @param amount The 32-byte token amount that is
           allowed to be spent by the `spender`.
    """
    current_allowance: uint256 = self.allowance[owner][spender]
    if current_allowance < max_value(uint256):
        # The following line allows the commonly known address
        # poisoning attack, where `transferFrom` instructions
        # are executed from arbitrary addresses with an `amount`
        # of `0`. However, this poisoning attack is not an on-chain
        # vulnerability. All assets are safe. It is an off-chain
        # log interpretation issue.
        assert current_allowance >= amount, "erc20: insufficient allowance"
        self._approve(owner, spender, unsafe_sub(current_allowance, amount))


@internal
def _before_token_transfer(owner: address, to: address, amount: uint256):
    """
    @dev Hook that is called before any transfer of tokens.
         This includes minting and burning.
    @notice The calling conditions are:
            - when `owner` and `to` are both non-zero,
              `amount` of `owner`'s tokens will be
              transferred to `to`,
            - when `owner` is zero, `amount` tokens will
              be minted for `to`,
            - when `to` is zero, `amount` of `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 amount The 32-byte token amount to be transferred.
    """
    pass


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

File 10 of 10 : erc4626.vy
# pragma version ~=0.4.3
# pragma nonreentrancy off
"""
@title ERC4626
@author Yield Basis
@license GNU Affero General Public License v3.0
@notice Library implementing ERC4626 standard derived from snekmate implenmentation.
        Unlike snekmate, however, it does not use offset and instead has a limit on minimal deposit allowed
"""


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


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


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


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


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


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


# @dev We import and initialise the `ownable` module.
# @notice The `ownable` module is merely used to initialise
# the `erc20` module, but none of the associated functions
# are exported.
from snekmate.auth import ownable
initializes: ownable


# @dev We import and initialise the `erc20` module.
from snekmate.tokens import erc20
initializes: erc20[ownable := ownable]


# @dev We export (i.e. the runtime bytecode exposes these
# functions externally, allowing them to be called using
# the ABI encoding specification) the required `external`
# functions from the `erc20` module to implement a compliant
# ERC-20 + EIP-2612 token.
# @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: (
    erc20.totalSupply,
    erc20.balanceOf,
    erc20.transfer,
    erc20.transferFrom,
    erc20.approve,
    erc20.allowance,
    erc20.name,
    erc20.symbol,
    erc20.decimals,
    erc20.permit,
    erc20.nonces,
    erc20.DOMAIN_SEPARATOR,
    erc20.eip712Domain,
)


# @dev Returns the address of the underlying token
# used for the vault for accounting, depositing,
# and withdrawing. To preserve consistency with the
# ERC-4626 interface, we use lower case letters for
# the `immutable` variable `asset`.
# @notice Vyper returns the `address` type for interface
# types by default. Furthermore, if you declare a
# variable as `public`, Vyper automatically generates
# an `external` getter function for the variable.
asset: public(immutable(address))


# @dev Stores the ERC-20 interface object of the underlying
# token used for the vault for accounting, depositing,
# and withdrawing.
_ASSET: immutable(IERC20)


# @ dev Minimal amount of shares allowed to exist (unless it is zero).
# The objective is to prevent inflation attacks on integrations

MIN_SHARES: public(immutable(uint256))



@deploy
@payable
def __init__(
    name_: String[25],
    symbol_: String[5],
    asset_: IERC20,
    min_shares_decimals_: uint8,
    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`.
    @param name_ The maximum 25-character user-readable
           string name of the token.
    @param symbol_ The maximum 5-character user-readable
           string symbol of the token.
    @param asset_ The ERC-20 compatible (i.e. ERC-777 is also viable)
           underlying asset contract.
    @param min_shares_decimals_ 1-byte vaulue to determine MIN_SHARES = 10 ** min_shares_decimals_
    @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.
    """
    _ASSET = asset_
    asset = _ASSET.address

    success: bool = empty(bool)
    decoded_decimals: uint8 = empty(uint8)
    # Attempt to fetch the underlying's decimals. A return
    # value of `False` indicates that the attempt failed in
    # some way.
    success, decoded_decimals = self._try_get_underlying_decimals(asset_)
    decoded_decimals = decoded_decimals if success else 18

    MIN_SHARES = 10 ** convert(min_shares_decimals_, uint256)

    # Please note that the `ownable` module is merely used to
    # initialise the `erc20` module, but none of the associated
    # functions are exported.
    ownable.__init__()
    # The following line uses intentionally checked arithmetic
    # to prevent a theoretically possible overflow.
    erc20.__init__(name_, symbol_, decoded_decimals, name_eip712_, version_eip712_)


@external
@view
def totalAssets() -> uint256:
    """
    @dev Returns the total amount of the underlying asset
         that is managed by the vault.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#totalassets.
    @return uint256 The 32-byte total managed assets.
    """
    return self._total_assets()


@external
@view
def convertToShares(assets: uint256) -> uint256:
    """
    @dev Returns the amount of shares that the vault would
         exchange for the amount of assets provided, in an
         ideal scenario where all the conditions are met.
    @notice Note that the conversion must round down to `0`.
            For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#converttoshares.
    @param assets The 32-byte assets amount.
    @return uint256 The converted 32-byte shares amount.
    """
    return self._convert_to_shares(assets, False)


@external
@view
def convertToAssets(shares: uint256) -> uint256:
    """
    @dev Returns the amount of assets that the vault would
         exchange for the amount of shares provided, in an
         ideal scenario where all the conditions are met.
    @notice Note that the conversion must round down to `0`.
            For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#converttoassets.
    @param shares The 32-byte shares amount.
    @return uint256 The converted 32-byte assets amount.
    """
    return self._convert_to_assets(shares, False)


@external
@view
def maxDeposit(receiver: address) -> uint256:
    """
    @dev Returns the maximum amount of the underlying asset
         that can be deposited into the vault for the `receiver`,
         through a `deposit` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxdeposit.
    @param receiver The 20-byte receiver address.
    @return uint256 The 32-byte maximum deposit amount.
    """
    return self._max_deposit(receiver)


@external
@view
def previewDeposit(assets: uint256) -> uint256:
    """
    @dev Allows an on-chain or off-chain user to simulate the
         effects of their deposit at the current block, given
         current on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewdeposit.
    @param assets The 32-byte assets amount.
    @return uint256 The simulated 32-byte returning shares amount.
    """
    return self._preview_deposit(assets)


@external
def deposit(assets: uint256, receiver: address) -> uint256:
    """
    @dev Mints `shares` vault shares to `receiver` by depositing
         exactly `assets` of underlying tokens.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#deposit.
    @param assets The 32-byte assets amount.
    @param receiver The 20-byte receiver address.
    @return uint256 The 32-byte shares amount to be created.
    """
    assert assets <= self._max_deposit(receiver), "erc4626: deposit more than maximum"
    shares: uint256 = self._preview_deposit(assets)
    self._deposit(msg.sender, receiver, assets, shares)
    self._check_min_shares()
    return shares


@external
@view
def maxMint(receiver: address) -> uint256:
    """
    @dev Returns the maximum amount of shares that can be minted
         from the vault for the `receiver`, through a `mint` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxmint.
    @param receiver The 20-byte receiver address.
    @return uint256 The 32-byte maximum mint amount.
    """
    return self._max_mint(receiver)


@external
@view
def previewMint(shares: uint256) -> uint256:
    """
    @dev Allows an on-chain or off-chain user to simulate the
         effects of their `mint` at the current block, given
         current on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewmint.
    @param shares The 32-byte shares amount.
    @return uint256 The simulated 32-byte required assets amount.
    """
    return self._preview_mint(shares)


@external
def mint(shares: uint256, receiver: address) -> uint256:
    """
    @dev Mints exactly `shares` vault shares to `receiver` by
         depositing `assets` of underlying tokens.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#mint.
    @param shares The 32-byte shares amount to be created.
    @param receiver The 20-byte receiver address.
    @return uint256 The deposited 32-byte assets amount.
    """
    assert shares <= self._max_mint(receiver), "erc4626: mint more than maximum"
    assets: uint256 = self._preview_mint(shares)
    self._deposit(msg.sender, receiver, assets, shares)
    self._check_min_shares()
    return assets


@external
@view
def maxWithdraw(owner: address) -> uint256:
    """
    @dev Returns the maximum amount of the underlying asset that
         can be withdrawn from the owner balance in the vault,
         through a `withdraw` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxwithdraw.
    @param owner The 20-byte owner address.
    @return uint256 The 32-byte maximum withdraw amount.
    """
    return self._max_withdraw(owner)


@external
@view
def previewWithdraw(assets: uint256) -> uint256:
    """
    @dev Allows an on-chain or off-chain user to simulate the
         effects of their withdrawal at the current block, given
         current on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewwithdraw.
    @param assets The 32-byte assets amount.
    @return uint256 The simulated 32-byte burned shares amount.
    """
    return self._preview_withdraw(assets)


@external
def withdraw(assets: uint256, receiver: address, owner: address) -> uint256:
    """
    @dev Burns `shares` from `owner` and sends exactly `assets` of
         underlying tokens to `receiver`.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#withdraw.
    @param assets The 32-byte assets amount to be withdrawn.
    @param receiver The 20-byte receiver address.
    @param owner The 20-byte owner address.
    @return uint256 The burned 32-byte shares amount.
    """
    assert assets <= self._max_withdraw(owner), "erc4626: withdraw more than maximum"
    shares: uint256 = self._preview_withdraw(assets)
    self._withdraw(msg.sender, receiver, owner, assets, shares)
    self._check_min_shares()
    return shares


@external
@view
def maxRedeem(owner: address) -> uint256:
    """
    @dev Maximum amount of vault shares that can be redeemed from
         the `owner` balance in the vault, through a `redeem` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxredeem.
    @param owner The 20-byte owner address.
    @return uint256 The 32-byte maximum redeemable shares amount.
    """
    return self._max_redeem(owner)


@external
@view
def previewRedeem(shares: uint256) -> uint256:
    """
    @dev Allows an on-chain or off-chain user to simulate the effects
         of their redeemption at the current block, given current
         on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewredeem.
    @param shares The 32-byte shares amount to be redeemed.
    @return uint256 The simulated 32-byte returning assets amount.
    """
    return self._preview_redeem(shares)


@external
def redeem(shares: uint256, receiver: address, owner: address) -> uint256:
    """
    @dev Burns exactly `shares` from `owner` and sends `assets` of
         underlying tokens to `receiver`.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#redeem.
    @param shares The 32-byte redeemed shares amount.
    @param receiver The 20-byte receiver address.
    @param owner The 20-byte owner address.
    @return uint256 The returned 32-byte assets amount.
    """
    assert shares <= self._max_redeem(owner), "erc4626: redeem more than maximum"
    assets: uint256 = self._preview_redeem(shares)
    self._withdraw(msg.sender, receiver, owner, assets, shares)
    self._check_min_shares()
    return assets


@internal
@view
def _try_get_underlying_decimals(underlying: IERC20) -> (bool, uint8):
    """
    @dev Attempts to fetch the underlying's decimals. A return
         value of `False` indicates that the attempt failed in
         some way.
    @param underlying The ERC-20 compatible (i.e. ERC-777 is also viable)
           underlying asset contract.
    @return bool The verification whether the call succeeded or
            failed.
    @return uint8 The fetched underlying's decimals.
    """
    success: bool = empty(bool)
    return_data: Bytes[32] = b""
    # The following low-level call does not revert, but instead
    # returns `False` if the callable contract does not implement
    # the `decimals` function. Since we perform a length check of
    # 32 bytes for the return data in the return expression at the
    # end, we also return `False` for EOA wallets instead of reverting
    # (remember that the EVM always considers a call to an EOA as
    # successful with return data `0x`). Furthermore, it is important
    # to note that an external call via `raw_call` does not perform an
    # external code size check on the target address.
    success, return_data = raw_call(
        underlying.address, method_id("decimals()"), max_outsize=32, is_static_call=True, revert_on_failure=False
    )
    if success and len(return_data) == 32 and convert(return_data, uint256) <= convert(max_value(uint8), uint256):
        return (True, convert(return_data, uint8))
    return (False, empty(uint8))


@internal
def _check_min_shares():
    supply: uint256 = erc20.totalSupply
    assert supply >= MIN_SHARES or supply == 0, "erc4626: leave MIN_SHARES"


@internal
@view
def _total_assets() -> uint256:
    """
    @dev An `internal` helper function that returns the total amount
         of the underlying asset that is managed by the vault.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#totalassets.
    @return uint256 The 32-byte total managed assets.
    """
    return staticcall _ASSET.balanceOf(self)


@internal
@view
def _convert_to_shares(assets: uint256, roundup: bool) -> uint256:
    """
    @dev An `internal` conversion function (from assets to shares)
         with support for rounding direction.
    @param assets The 32-byte assets amount.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return uint256 The converted 32-byte shares amount.
    """
    supply: uint256 = erc20.totalSupply
    if supply == 0:
        return assets + self._total_assets()
    else:
        return math._mul_div(
            assets, supply + 1, self._total_assets() + 1, roundup
        )


@internal
@view
def _convert_to_assets(shares: uint256, roundup: bool) -> uint256:
    """
    @dev An `internal` conversion function (from shares to assets)
         with support for rounding direction.
    @param shares The 32-byte shares amount.
    @param roundup The Boolean variable that specifies whether
           to round up or not. The default `False` is round down.
    @return uint256 The converted 32-byte assets amount.
    """
    supply: uint256 = erc20.totalSupply
    if supply == 0:
        return shares - self._total_assets()
    else:
        return math._mul_div(
            shares, self._total_assets() + 1, supply + 1, roundup
        )


@internal
@pure
def _max_deposit(receiver: address) -> uint256:
    """
    @dev An `internal` helper function that returns the maximum
         amount of the underlying asset that can be deposited into
         the vault for the `receiver`, through a `deposit` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxdeposit.
    @param receiver The 20-byte receiver address.
    @return uint256 The 32-byte maximum deposit amount.
    """
    return max_value(uint256)


@internal
@view
def _preview_deposit(assets: uint256) -> uint256:
    """
    @dev An `internal` helper function that allows an on-chain or
         off-chain user to simulate the effects of their deposit at
         the current block, given current on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewdeposit.
    @param assets The 32-byte assets amount.
    @return uint256 The simulated 32-byte returning shares amount.
    """
    return self._convert_to_shares(assets, False)


@internal
@pure
def _max_mint(receiver: address) -> uint256:
    """
    @dev An `internal` helper function that returns the maximum
         amount of shares that can be minted from the vault for
         the `receiver`, through a `mint` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxmint.
    @param receiver The 20-byte receiver address.
    @return uint256 The 32-byte maximum mint amount.
    """
    return max_value(uint256)


@internal
@view
def _preview_mint(shares: uint256) -> uint256:
    """
    @dev An `internal` helper function that allows an on-chain or
         off-chain user to simulate the effects of their `mint` at
         the current block, given current on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewmint.
    @param shares The 32-byte shares amount.
    @return uint256 The simulated 32-byte required assets amount.
    """
    return self._convert_to_assets(shares, True)


@internal
@view
def _max_withdraw(owner: address) -> uint256:
    """
    @dev An `internal` helper function that returns the maximum
         amount of the underlying asset that can be withdrawn from
         the owner balance in the vault, through a `withdraw` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxwithdraw.
    @param owner The 20-byte owner address.
    @return uint256 The 32-byte maximum withdraw amount.
    """
    return self._convert_to_assets(erc20.balanceOf[owner], False)


@internal
@view
def _preview_withdraw(assets: uint256) -> uint256:
    """
    @dev An `internal` helper function that allows an on-chain or
         off-chain user to simulate the effects of their withdrawal
         at the current block, given current on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewwithdraw.
    @param assets The 32-byte assets amount.
    @return uint256 The simulated 32-byte burned shares amount.
    """
    return self._convert_to_shares(assets, True)


@internal
@view
def _max_redeem(owner: address) -> uint256:
    """
    @dev An `internal` helper function that returns the maximum
         amount of vault shares that can be redeemed from the `owner`
         balance in the vault, through a `redeem` call.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#maxredeem.
    @param owner The 20-byte owner address.
    @return uint256 The 32-byte maximum redeemable shares amount.
    """
    return erc20.balanceOf[owner]


@internal
@view
def _preview_redeem(shares: uint256) -> uint256:
    """
    @dev An `internal` helper function that allows an on-chain or
         off-chain user to simulate the effects of their redeemption
         at the current block, given current on-chain conditions.
    @notice For the to be fulfilled conditions, please refer to:
            https://eips.ethereum.org/EIPS/eip-4626#previewredeem.
    @param shares The 32-byte shares amount to be redeemed.
    @return uint256 The simulated 32-byte returning assets amount.
    """
    return self._convert_to_assets(shares, False)


@internal
def _deposit(sender: address, receiver: address, assets: uint256, shares: uint256):
    """
    @dev An `internal` function handling the `deposit` and `mint`
         common workflow.
    @param sender The 20-byte sender address.
    @param receiver The 20-byte receiver address.
    @param assets The 32-byte assets amount.
    @param shares The 32-byte shares amount.
    """
    # If `asset` is an ERC-777, `transferFrom` can trigger a reentrancy
    # before the transfer happens through the `tokensToSend` hook. On the
    # other hand, the `tokenReceived` hook, that is triggered after the
    # transfer, calls the vault which is assumed not to be malicious.
    # Thus, we need to do the transfer before we mint so that any reentrancy
    # would happen before the assets are transferred and before the shares
    # are minted, which is a valid state.

    # To deal with (potentially) non-compliant ERC-20 tokens that do have
    # no return value, we use the kwarg `default_return_value` for external
    # calls. This function was introduced in Vyper version `0.3.4`. For more
    # details see:
    # - https://github.com/vyperlang/vyper/pull/2839,
    # - https://github.com/vyperlang/vyper/issues/2812,
    # - https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca.

    # It is important to note that an external call via interface casting
    # always performs an external code size check on the target address unless
    # you add the kwarg `skip_contract_check=True`. If the check fails (i.e.
    # the target address is an EOA), the call reverts.
    assert extcall _ASSET.transferFrom(
        sender, self, assets, default_return_value=True
    ), "erc4626: transferFrom operation did not succeed"
    erc20._mint(receiver, shares)
    log IERC4626.Deposit(sender=sender, owner=receiver, assets=assets, shares=shares)


@internal
def _withdraw(sender: address, receiver: address, owner: address, assets: uint256, shares: uint256):
    """
    @dev An `internal` function handling the `withdraw` and `redeem`
         common workflow.
    @param sender The 20-byte sender address.
    @param receiver The 20-byte receiver address.
    @param owner The 20-byte owner address.
    @param assets The 32-byte assets amount.
    @param shares The 32-byte shares amount.
    """
    if sender != owner:
        erc20._spend_allowance(owner, sender, shares)

    # If `asset` is an ERC-777, `transfer` can trigger a reentrancy
    # after the transfer happens through the `tokensReceived` hook.
    # On the other hand, the `tokensToSend` hook, that is triggered
    # before the transfer, calls the vault which is assumed not to
    # be malicious. Thus, we need to do the transfer after the burn
    # so that any reentrancy would happen after the shares are burned
    # and after the assets are transferred, which is a valid state.
    erc20._burn(owner, shares)

    # To deal with (potentially) non-compliant ERC-20 tokens that do have
    # no return value, we use the kwarg `default_return_value` for external
    # calls. This function was introduced in Vyper version `0.3.4`. For more
    # details see:
    # - https://github.com/vyperlang/vyper/pull/2839,
    # - https://github.com/vyperlang/vyper/issues/2812,
    # - https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca.

    # It is important to note that an external call via interface casting
    # always performs an external code size check on the target address unless
    # you add the kwarg `skip_contract_check=True`. If the check fails (i.e.
    # the target address is an EOA), the call reverts.
    assert extcall _ASSET.transfer(
        receiver, assets, default_return_value=True
    ), "erc4626: transfer operation did not succeed"
    log IERC4626.Withdraw(sender=sender, receiver=receiver, owner=owner, assets=assets, shares=shares)

Settings
{
  "outputSelection": {
    "contracts/dao/LiquidityGauge.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":"token","type":"address"},{"indexed":false,"name":"distributor","type":"address"},{"indexed":false,"name":"id","type":"uint256"}],"name":"AddReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"distributor","type":"address"}],"name":"ChangeRewardDistributor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"distributor","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"finish_time","type":"uint256"}],"name":"DepositRewards","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":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"receiver","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"owner","type":"address"},{"indexed":false,"name":"assets","type":"uint256"},{"indexed":false,"name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"receiver","type":"address"},{"indexed":true,"name":"owner","type":"address"},{"indexed":false,"name":"assets","type":"uint256"},{"indexed":false,"name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"spender","type":"address"},{"name":"amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"receiver","type":"address"}],"name":"maxDeposit","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"receiver","type":"address"}],"name":"maxMint","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"name":"","type":"address"}],"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":"MIN_SHARES","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"get_adjustment","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"reward","type":"address"}],"name":"claim","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"reward","type":"address"},{"name":"user","type":"address"}],"name":"claim","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"reward","type":"address"},{"name":"user","type":"address"}],"name":"preview_claim","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"token","type":"address"},{"name":"distributor","type":"address"}],"name":"add_reward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"token","type":"address"},{"name":"distributor","type":"address"}],"name":"change_reward_distributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"},{"name":"finish_time","type":"uint256"}],"name":"deposit_reward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"}],"name":"deposit","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"}],"name":"mint","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"},{"name":"owner","type":"address"}],"name":"withdraw","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"},{"name":"owner","type":"address"}],"name":"redeem","outputs":[{"name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"owner","type":"address"},{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GC","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YB","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LP_TOKEN","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reward_count","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"uint256"}],"name":"reward_tokens","outputs":[{"name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"rewards","outputs":[{"components":[{"name":"distributor","type":"address"},{"name":"finish_time","type":"uint256"},{"name":"total","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"processed_rewards","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"integral_inv_supply","outputs":[{"components":[{"name":"v","type":"uint256"},{"name":"t","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"integral_inv_supply_4_token","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"}],"name":"reward_rate_integral","outputs":[{"components":[{"name":"v","type":"uint256"},{"name":"t","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"name":"reward_rate_integral_4_user","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"name":"user_rewards_integral","outputs":[{"components":[{"name":"v","type":"uint256"},{"name":"t","type":"uint256"}],"name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"name":"claimed_rewards","outputs":[{"name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"lp_token","type":"address"}],"outputs":[],"stateMutability":"nonpayable","type":"constructor"}]

0x613d165150346105ad5760206140605f395f518060a01c6105ad5761054052600c610560527f59422047617567653a202e2e000000000000000000000000000000000000000061058052610560602c816103205e5060056105a0527f67282e2e290000000000000000000000000000000000000000000000000000006105c0526105a06025816103605e50610540516103a052600c6103c052600b6105e0527f4a75737420736179206e6f000000000000000000000000000000000000000000610600526105e0602b816103e05e506009610620527f746f204549503731320000000000000000000000000000000000000000000000610640526106206029816104405e5061010c6104fd565b61054051613cf6523363d8b9a018610560526020610560600461057c845afa610137573d5f5f3e3d5ffd5b3d602081183d60201002188061056001610580116105ad57610560518060a01c6105ad576105a052506105a0905051613cb652613cb6516382bfefc8610560526020610560600461057c845afa610190573d5f5f3e3d5ffd5b3d602081183d60201002188061056001610580116105ad57610560518060a01c6105ad576105a052506105a0905051613cd65233613d16523363f851a440610560526020610560600461057c845afa6101eb573d5f5f3e3d5ffd5b3d602081183d60201002188061056001610580116105ad57610560518060a01c6105ad576105a052506105a09050515f55613cb651600f613cd6516020525f5260405f2055613cd6516007556001600655613cd6517fbaa8134d057f38ffff73248ae9edf1012783d074fbae40443077bf53fc57b9ec613cb651610560525f610580526040610560a2613a766105b161000039613d36610000f35b6040366060376040515a600460c0527f313ce5670000000000000000000000000000000000000000000000000000000060e05260c050602061012060c05160e08585fa90509050610140523d602081183d6020100218610100526101006040816101605e5061014051606052604061016060805e606051610307575f610329565b6020608051186103275760ff60a05160805160200360031b1c1115610329565b5f5b15610352576001815260a05160805160200360031b1c8060081c6105ad5760208201525061035d565b5f81525f6020820152505b565b5f546060526040515f556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f6080a3565b336040526103a261035f565b565b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f606052613b3651608052613b965160a0524660c0523060e05260a06040526040805160208201209050815250565b602061010051015f81601f0160051c600381116105ad57801561043257905b8060051b61010001518160051b606001613a760152600101818118610412575b50505061016051613b565261018051613b76526101005161012020613b36526101605161018020613b96526104686101a06103a4565b6101a051613a765246613a965230613ab652565b6101c051613bb6526101e051613bd65261020051613bf65261022051613c165261024051613c365260016004336020525f5260405f2055337fbb6e183664bd7425a9e444072cb0f1c7f7c4d5486a36d7d24d0b0735687c2ef46001610300526020610300a260526102606101005e60346102c06101605e6104fb6103f3565b565b6103a051613c7652613c7651613c5652604036610480376103a0516040526105266104c0610286565b6104c06040816105005e5060406105006104805e610480516105505760126104c0526104c0610554565b6104a05b516104a0526103c051604d81116105ad5780600a0a9050613c9652610577610396565b60396103206101c05e60256103606102005e6104a0516102405260526103e06102605e60346104406102c05e6105ab61047c565b565b5f80fd5f3560e01c6002602b820660011b613a2001601e395f51565b6318160ddd81186100345734613a1c5760035460405260206040f35b63a9059cbb811861224357604436103417613a1c576004358060a01c613a1c57610540525f5c600114613a1c5760015f5d3361032052610072612ec4565b6105405161032052610082612ec4565b3360a0526105405160c05260243560e05261009b61378a565b6020613cb65f395f51633bdab8bf610560526020610560600461057c5f855af16100c7573d5f5f3e3d5ffd5b60203d10613a1c57610560505060016105605260206105605f5f5df35b6370a08231811861224357602436103417613a1c576004358060a01c613a1c5760405260016040516020525f5260405f205460605260206060f35b63095ea7b3811861016957604436103417613a1c576004358060a01c613a1c576101a052336040526101a05160605260243560805261015c612247565b60016101c05260206101c0f35b630700037d811861224357602436103417613a1c576004358060a01c613a1c57604052600f6040516020525f5260405f2080546060526001810154608052600281015460a0525060606060f35b63dd62ed3e811861020e57604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260026040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b63402d267d811861224357602436103417613a1c576004358060a01c613a1c576060526020606051604052610243608061287c565b6080f35b63313ce56781186102655734613a1c576020613c3660403960206040f35b631e83409a811861224357602436103417613a1c576004358060a01c613a1c57610320523361034052611225565b6301e1d11481186102b35734613a1c5760206102af60806123dc565b6080f35b63d905777e81186102ec57602436103417613a1c576004358060a01c613a1c5760605260206060516040526102e8608061295a565b6080f35b63ad598e81811861224357604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260176040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b63c6e6f592811861037757602436103417613a1c5760206004356101e0525f61020052610372610300612748565b610300f35b63b3d7f6b981186103a557602436103417613a1c576020600435610300526103a06103406128e9565b610340f35b63ba087652811861224357606436103417613a1c576024358060a01c613a1c57610540526044358060a01c613a1c57610560525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261058052803b15613a1c575f610580600461059c5f855af1610417573d5f5f3e3d5ffd5b506105605160405261042a61058061295a565b6105805160043511156104d4576020806106205260216105a0527f657263343632363a2072656465656d206d6f7265207468616e206d6178696d756105c0527f6d000000000000000000000000000000000000000000000000000000000000006105e0526105a08161062001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610600528060040161061cfd5b33610580526020613cf65f395f51639c868ac06105a05260206105a060046105bc845afa610504573d5f5f3e3d5ffd5b3d602081183d6020100218806105a0016105c011613a1c576105a0518060011c613a1c576105e052506105e090505115610627576020613d165f395f5163680c7783610600526020610600600461061c845afa610563573d5f5f3e3d5ffd5b3d602081183d6020100218806106000161062011613a1c57610600518060a01c613a1c5761064052506106409050513318610627576105605161054051181561061e576020806106c0526008610660527f726563656976657200000000000000000000000000000000000000000000000061068052610660816106c001602882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06106a052806004016106bcfd5b61056051610580525b600435610300526106396105c061296e565b6105c0516105a0526105605161032052610651612ec4565b610580516102e052610540516103005261056051610320526105a05161034052600435610360526106806135e5565b610688613277565b6020613cb65f395f51633bdab8bf6105c05260206105c060046105dc5f855af16106b4573d5f5f3e3d5ffd5b60203d10613a1c576105c0505060206105a05f5f5df35b6307a2d13a811861224357602436103417613a1c5760206004356101e0525f610200526106f96103006127e2565b610300f35b63ef8b30f7811861224357602436103417613a1c576020600435610300526107276103406128a2565b610340f35b63c63d75b6811861076557602436103417613a1c576004358060a01c613a1c57606052602060605160405261076160806128c3565b6080f35b6354c49fe9811861224357602436103417613a1c576004356008811015613a1c576007015460405260206040f35b63ce96cb7781186107d157602436103417613a1c576004358060a01c613a1c5761034052602061034051610300526107cc61036061290b565b610360f35b634e71d92d81186122435734613a1c576020613cd6610320393361034052611225565b630a28a477811861082257602436103417613a1c5760206004356103005261081d610340612938565b610340f35b63692e099e811861224357604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260166040516020525f5260405f20806060516020525f5260405f2090508054608052600181015460a0525060406080f35b634cdad506811861224357602436103417613a1c576020600435610300526108ad61034061296e565b610340f35b6338d52e0f81186108d05734613a1c576020613c5660403960206040f35b633ea9f06f8118610a705734613a1c576020613cf65f395f516370a0823160605230608052602060606024607c845afa61090c573d5f5f3e3d5ffd5b60203d10613a1c5760609050516040526020613cf65f395f516318160ddd608052602060806004609c845afa610944573d5f5f3e3d5ffd5b60203d10613a1c5760809050516060526060516040516ec097ce7bc90715b34b9f10000000008102816ec097ce7bc90715b34b9f1000000000820418613a1c579050048060b57101000000000000000000000000000000000082106109b0578160801c91508060401b90505b690100000000000000000082106109ce578160401c91508060201b90505b6501000000000082106109e8578160201c91508060101b90505b63010000008210610a00578160101c91508060081b90505b620100008201810260121c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808304808281188284100218905090509050905060805260206080f35b63f986ca50811861224357604436103417613a1c576004358060a01c613a1c57610320526024358060a01c613a1c57610340525f610360526020613cd65f395f516103205118610b06576020613cb65f395f5163e3a8d98a61038052306103a052426103c0526020610380604461039c845afa610aef573d5f5f3e3d5ffd5b60203d10613a1c5761038090505161036052610b21565b61032051604052610b18610380612a42565b61038051610360525b610320516101e05261036051610200526103405161022052610b44610440612cc5565b61044060c0816103805e50610400516017610340516020525f5260405f2080610320516020525f5260405f20905054808203828111613a1c5790509050610440526020610440f35b63f0350c04811861224357602436103417613a1c576004358060a01c613a1c5761010052610bb861298f565b61010051610c5d576020806101a0526026610120527f6f776e61626c653a206e6577206f776e657220697320746865207a65726f2061610140527f646472657373000000000000000000000000000000000000000000000000000061016052610120816101a001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61010051604052610c6c612a0b565b005b638da5cb5b81186122435734613a1c575f5460405260206040f35b631fcd308081186122435734613a1c576020613c9660403960206040f35b6395d89b418118610e1a5734613a1c576020806101e0525f60026040527f67280000000000000000000000000000000000000000000000000000000000006060526040805160208201836101a001815181525050808301925050506020613cf65f395f516395d89b41608052606060806004609c845afa610d2a573d5f5f3e3d5ffd5b3d606081183d60601002188060800160a011613a1c57608060805160800110613a1c576080516080018051826080018251602001830111613a1c57601d8111613a1c5750603d816101005e50506101009050805160208201836101a001815181525050808301925050506001610140527f290000000000000000000000000000000000000000000000000000000000000061016052610140805160208201836101a0018151815250508083019250505080610180526101809050816101e001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506101e0f35b63e8de0d4d811861108957604436103417613a1c576004358060a01c613a1c57610100526024358060a01c613a1c57610120525f5c600114613a1c5760015f5d6020613cd65f395f516101005118610ee4576020806101a0526002610140527f594200000000000000000000000000000000000000000000000000000000000061016052610140816101a001602282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b6020613cf65f395f516101005118610f6e576020806101a0526008610140527f4c505f544f4b454e00000000000000000000000000000000000000000000000061016052610140816101a001602882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b6101205115613a1c57600f610100516020525f5260405f205415611004576020806101a052600d610140527f416c72656164792061646465640000000000000000000000000000000000000061016052610140816101a001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61100c61298f565b61012051600f610100516020525f5260405f20556006546101405261010051610140516008811015613a1c57600701556101405160018101818110613a1c579050600655610100517fbaa8134d057f38ffff73248ae9edf1012783d074fbae40443077bf53fc57b9ec60406101206101605e6040610160a25f5f5d005b63d7a03b17811861224357602436103417613a1c576004358060a01c613a1c5760405260106040516020525f5260405f205460605260206060f35b6306fdde0381186122435734613a1c576020806101c0525f600a6040527f59422047617567653a200000000000000000000000000000000000000000000060605260408051602082018361016001815181525050808301925050506020613cf65f395f516395d89b41608052606060806004609c845afa611147573d5f5f3e3d5ffd5b3d606081183d60601002188060800160a011613a1c57608060805160800110613a1c576080516080018051826080018251602001830111613a1c57601d8111613a1c5750603d816101005e5050610100905080516020820183610160018151815250508083019250505080610140526101409050816101c001604782825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506101c0f35b6321c0b342811861224357604436103417613a1c576004358060a01c613a1c57610320526024358060a01c613a1c57610340525b5f5c600114613a1c5760015f5d61032051610120525f6101405261124a610380612bcd565b6103805161036052610320516101e05261036051610200526103405161022052611275610440612cc5565b61044060c0816103805e50610380516011556103a051601255610380516013610320516020525f5260405f20556014610320516020525f5260405f206103c05181556103e0516001820155506103c0516015610340516020525f5260405f2080610320516020525f5260405f209050556016610340516020525f5260405f2080610320516020525f5260405f20905061040051815561042051600182015550610400516017610340516020525f5260405f2080610320516020525f5260405f20905054808203828111613a1c579050905061036052610400516017610340516020525f5260405f2080610320516020525f5260405f209050556103205163a9059cbb6104405260406103406104605e6020610440604461045c5f855af161139e573d5f5f3e3d5ffd5b3d6113b557803b15613a1c5760016104a0526113df565b3d602081183d6020100218806104400161046011613a1c57610440518060011c613a1c576104a052505b6104a090505115613a1c5760206103605f5f5df35b63215d0bbf811861159757604436103417613a1c576004358060a01c613a1c57610100526024358060a01c613a1c57610120526020613cd65f395f5161010051186114b1576020806101a0526002610140527f594200000000000000000000000000000000000000000000000000000000000061016052610140816101a001602282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b6101205115613a1c57600f610100516020525f5260405f2054611546576020806101a0526009610140527f4e6f74206164646564000000000000000000000000000000000000000000000061016052610140816101a001602982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61154e61298f565b61012051600f610100516020525f5260405f2055610100517fd6161cfaa8ff15169d3b9c3c69f7dcd627a1c5ca6a3534afdd8054d2961c610261012051610140526020610140a2005b6323b872dd811861224357606436103417613a1c576004358060a01c613a1c57610540526024358060a01c613a1c57610560525f5c600114613a1c5760015f5d61054051610320526115e7612ec4565b61056051610320526115f7612ec4565b610540516101a052336101c0526044356101e052611613613312565b604061054060a05e60443560e05261162961378a565b6020613cb65f395f51633bdab8bf610580526020610580600461059c5f855af1611655573d5f5f3e3d5ffd5b60203d10613a1c57610580505060016105805260206105805f5f5df35b635f8275fc811861224357606436103417613a1c576004358060a01c613a1c57610320525f5c600114613a1c5760015f5d6020613cd65f395f51610320511861172d576020806103a0526002610340527f594200000000000000000000000000000000000000000000000000000000000061036052610340816103a001602282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b6024356117ac576020806103a052600a610340527f4e6f20726577617264730000000000000000000000000000000000000000000061036052610340816103a001602a82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b600f610320516020525f5260405f20805461034052600181015461036052600281015461038052506103405133146117e6576117e661298f565b61032051610120525f610140526117fe6103c0612bcd565b6103c0516103a052610320516101e0526103a051610200525f61022052611826610480612cc5565b61048060c0816103c05e506103c0516011556103e0516012556103c0516013610320516020525f5260405f20556014610320516020525f5260405f2061040051815561042051600182015550610380516010610320516020525f5260405f2054808203828111613a1c579050905061048052604435156118a75760016118ad565b61048051155b611998574261036051116119335760208061050052600c6104a0527f5261746520756e6b6e6f776e00000000000000000000000000000000000000006104c0526104a08161050001602c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104e052806004016104fcfd5b426103605142808203828111613a1c579050905061048051602435808201828110613a1c5790509050808202811583838304141715613a1c5790509050610480518015613a1c5780820490509050808201828110613a1c579050905061036052611a21565b4260443511611a19576020806105005260146104a0527f46696e697368657320696e2074686520706173740000000000000000000000006104c0526104a08161050001603482825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104e052806004016104fcfd5b604435610360525b61038051602435808201828110613a1c579050905061038052600f610320516020525f5260405f2061034051815561036051600182015561038051600282015550610320516323b872dd6104a052336104c052306104e0526024356105005260206104a060646104bc5f855af1611a9a573d5f5f3e3d5ffd5b3d611ab157803b15613a1c57600161052052611adb565b3d602081183d6020100218806104a0016104c011613a1c576104a0518060011c613a1c5761052052505b61052090505115613a1c57610320517f1ecc08cf4f4c06326e836da1a250282d8c384890b0d027466c2923183d9da0bd336104a0526024356104c052610360516104e05260606104a0a25f5f5d005b636e553f658118611ce357604436103417613a1c576024358060a01c613a1c57610540525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261056052803b15613a1c575f610560600461057c5f855af1611b8d573d5f5f3e3d5ffd5b5061054051604052611ba061056061287c565b610560516004351115611c4a57602080610600526022610580527f657263343632363a206465706f736974206d6f7265207468616e206d6178696d6105a0527f756d0000000000000000000000000000000000000000000000000000000000006105c0526105808161060001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105e052806004016105fcfd5b60043561030052611c5c6105806128a2565b61058051610560526105405161032052611c74612ec4565b336101a052610540516101c0526004356101e0526105605161020052611c986130fe565b611ca0613277565b6020613cb65f395f51633bdab8bf610580526020610580600461059c5f855af1611ccc573d5f5f3e3d5ffd5b60203d10613a1c57610580505060206105605f5f5df35b631de8b63181186122435734613a1c576020613cd660403960206040f35b6394bf804d811861224357604436103417613a1c576024358060a01c613a1c57610540525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261056052803b15613a1c575f610560600461057c5f855af1611d64573d5f5f3e3d5ffd5b5061054051604052611d776105606128c3565b610560516004351115611dfc576020806105e052601f610580527f657263343632363a206d696e74206d6f7265207468616e206d6178696d756d006105a052610580816105e001603f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b60043561030052611e0e6105806128e9565b61058051610560526105405161032052611e26612ec4565b336101a05260406105406101c05e60043561020052611e436130fe565b611e4b613277565b6020613cb65f395f51633bdab8bf610580526020610580600461059c5f855af1611e77573d5f5f3e3d5ffd5b60203d10613a1c57610580505060206105605f5f5df35b63b460af94811861224357606436103417613a1c576024358060a01c613a1c57610540526044358060a01c613a1c57610560525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261058052803b15613a1c575f610580600461059c5f855af1611f00573d5f5f3e3d5ffd5b506105605161030052611f1461058061290b565b610580516004351115611fbe576020806106205260236105a0527f657263343632363a207769746864726177206d6f7265207468616e206d6178696105c0527f6d756d00000000000000000000000000000000000000000000000000000000006105e0526105a08161062001604382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610600528060040161061cfd5b60043561030052611fd06105a0612938565b6105a051610580526105605161032052611fe8612ec4565b336102e05260406105406103005e60043561034052610580516103605261200d6135e5565b612015613277565b6020613cb65f395f51633bdab8bf6105a05260206105a060046105bc5f855af1612041573d5f5f3e3d5ffd5b60203d10613a1c576105a0505060206105805f5f5df35b63ffa1ad7481186122435734613a1c5760208060805260066040527f76312e302e300000000000000000000000000000000000000000000000000000606052604081608001602682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b6309dba08381186120eb5734613a1c576020613cb660403960206040f35b63c493dfeb811861224357602436103417613a1c576004358060a01c613a1c5760405260136040516020525f5260405f205460605260206060f35b63bfd9041b81186121445734613a1c576020613cf660403960206040f35b63963c94b981186122435734613a1c5760065460405260206040f35b632dd3100081146003361116156122435734613a1c576020613d1660403960206040f35b639d263dfc81186122435734613a1c5760115460405260125460605260406040f35b637d58777b811861224357602436103417613a1c576004358060a01c613a1c5760405260146040516020525f5260405f20805460605260018101546080525060406060f35b637e1e9cea811861224357604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260156040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b5f5ffd5b6040516122e75760208061012052602460a0527f65726332303a20617070726f76652066726f6d20746865207a65726f2061646460c0527f726573730000000000000000000000000000000000000000000000000000000060e05260a08161012001604482825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610100528060040161011cfd5b6060516123875760208061012052602260a0527f65726332303a20617070726f766520746f20746865207a65726f20616464726560c0527f737300000000000000000000000000000000000000000000000000000000000060e05260a08161012001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610100528060040161011cfd5b60805160026040516020525f5260405f20806060516020525f5260405f209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560805160a052602060a0a3565b6020613c765f395f516370a0823160405230606052602060406024605c845afa612408573d5f5f3e3d5ffd5b60203d10613a1c576040905051815250565b6080516124965760208061012052601e60c0527f6d6174683a206d756c5f646976206469766973696f6e206279207a65726f000060e05260c08161012001603e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610100528060040161011cfd5b6040516060517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183099050905060c0526060516040510260e0525f6101005260e05160c051106124f15760e05160c0510361010052612500565b600160e05160c0510303610100525b610100516125575760a051612515575f612531565b6040516060516080518015613a1c578082840990509050905015155b1561254857600160805160e0510401815250612746565b60805160e05104815250612746565b61010051608051116125db57602080610180526016610120527f6d6174683a206d756c5f646976206f766572666c6f7700000000000000000000610140526101208161018001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b6040516060516080518015613a1c57808284099050905090506101205260e0516101205111156126115760016101005103610100525b6101205160e0510360e0526080516080515f0316610140526101405160805104610160526101405160e0510460e052600161014051610140515f0304016101405261014051610100510260e0511760e05260026101605160030218610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805160e051026101a05260a051612707575f612723565b6040516060516080518015613a1c578082840990509050905015155b1561273e576101a05160018101818110613a1c5790506101a0525b6101a0518152505b565b6003546102205261022051612780576101e0516127666102406123dc565b61024051808201828110613a1c57905090508152506127e0565b6101e051610280526102205160018101818110613a1c5790506102a0526127a86102406123dc565b6102405160018101818110613a1c5790506102c052610200516102e052608061028060405e6127d861026061241a565b610260518152505b565b600354610220526102205161281a576101e0516128006102406123dc565b61024051808203828111613a1c579050905081525061287a565b6101e0516102805261282d6102406123dc565b6102405160018101818110613a1c5790506102a0526102205160018101818110613a1c5790506102c052610200516102e052608061028060405e61287261026061241a565b610260518152505b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815250565b610300516101e0525f610200526128ba610320612748565b61032051815250565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815250565b610300516101e0526001610200526129026103206127e2565b61032051815250565b6001610300516020525f5260405f20546101e0525f6102005261292f6103206127e2565b61032051815250565b610300516101e052600161020052612951610320612748565b61032051815250565b60016040516020525f5260405f2054815250565b610300516101e0525f610200526129866103206127e2565b61032051815250565b5f54331815612a095760208060a05260206040527f6f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260605260408160a001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060805280600401609cfd5b565b5f546060526040515f556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f6080a3565b600f6040516020525f5260405f2054612ac65760208060c05260096060527f4e6f20726577617264000000000000000000000000000000000000000000000060805260608160c001602982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b60146040516020525f5260405f206001810190505460605260106040516020525f5260405f2054608052600f6040516020525f5260405f206001810190505460a052600f6040516020525f5260405f206002810190505460c05260605160a05111612b34575f815250612bcb565b60c051608051808203828111613a1c579050905042606051808203828111613a1c5790509050808202811583838304141715613a1c579050905060a051606051808203828111613a1c57905090508015613a1c5780820490509050608051808201828110613a1c579050905060e05260e05160c05180828118828410021890509050608051808203828111613a1c57905090508152505b565b5f610160526020613cd65f395f516101205118612c7b5761014051612c2f576020613cb65f395f51633bdab8bf610180526020610180600461019c5f855af1612c18573d5f5f3e3d5ffd5b60203d10613a1c5761018090505161016052612cbc565b6020613cb65f395f5163e3a8d98a61018052306101a052426101c0526020610180604461019c845afa612c64573d5f5f3e3d5ffd5b60203d10613a1c5761018090505161016052612cbc565b61012051604052612c8d610180612a42565b61018051610160526010610120516020525f5260405f20805461016051808201828110613a1c57905090508155505b61016051815250565b60c03661024037601154610240526012546102605261026051421115612d4457610240516003544261026051808203828111613a1c57905090506ec097ce7bc90715b34b9f10000000008102816ec097ce7bc90715b34b9f1000000000820418613a1c57905004808201828110613a1c57905090506102405242610260525b6101e05115612ded5760146101e0516020525f5260405f2080546102805260018101546102a052506102a051421115612ded57610280516102405160136101e0516020525f5260405f2054808203828111613a1c579050905061020051808202811583838304141715613a1c5790509050426102a051808203828111613a1c57905090508015613a1c5780820490509050808201828110613a1c579050905061028052426102a0525b6102205115612eba576016610220516020525f5260405f20806101e0516020525f5260405f20905080546102c05260018101546102e052506102e051421115612eba576102c051610280516015610220516020525f5260405f20806101e0516020525f5260405f20905054808203828111613a1c57905090506040526001610220516020525f5260405f20546060526ec097ce7bc90715b34b9f10000000006080525f60a052612e9e61030061241a565b61030051808201828110613a1c57905090506102c052426102e0525b60c0610240825e50565b600654610340525f6008905b806103605261034051610360511815612fe857610360516008811015613a1c5760070154610380526103805161012052600161014052612f116103c0612bcd565b6103c0516103a05260406103806101e05e6103205161022052612f35610480612cc5565b61048060c0816103c05e5061036051612f57576103c0516011556103e0516012555b6103c0516013610380516020525f5260405f20556014610380516020525f5260405f2061040051815561042051600182015550610400516015610320516020525f5260405f2080610380516020525f5260405f209050556016610320516020525f5260405f2080610380516020525f5260405f20905061044051815561046051600182015550600101818118612ed0575b5050565b565b565b60a05161306d5760208061014052601f60e0527f65726332303a206d696e7420746f20746865207a65726f2061646472657373006101005260e08161014001603f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610120528060040161013cfd5b5f604052604060a060605e613080612fec565b60035460c051808201828110613a1c579050905060035560c051600160a0516020525f5260405f205401600160a0516020525f5260405f205560a0515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60c05160e052602060e0a35f604052604060a060605e6130fc612fee565b565b6020613c765f395f516323b872dd610220526101a0516102405230610260526101e051610280526020610220606461023c5f855af161313f573d5f5f3e3d5ffd5b3d61315657803b15613a1c5760016102a052613180565b3d602081183d6020100218806102200161024011613a1c57610220518060011c613a1c576102a052505b6102a09050516132275760208061034052602f6102c0527f657263343632363a207472616e7366657246726f6d206f7065726174696f6e206102e0527f646964206e6f7420737563636565640000000000000000000000000000000000610300526102c08161034001604f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610320528060040161033cfd5b6101c05160a0526102005160c05261323d612ff0565b6101c0516101a0517fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760406101e06102205e6040610220a3565b6003546040526020613c965f395f516040511015613298576040511561329b565b60015b6133105760208060c05260196060527f657263343632363a206c65617665204d494e5f5348415245530000000000000060805260608160c001603982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b565b60026101a0516020525f5260405f20806101c0516020525f5260405f20905054610200527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102005114613402576101e0516102005110156133e65760208061028052601d610220527f65726332303a20696e73756666696369656e7420616c6c6f77616e6365000000610240526102208161028001603d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610260528060040161027cfd5b60406101a060405e6101e0516102005103608052613402612247565b565b60a0516134a65760208061016052602160e0527f65726332303a206275726e2066726f6d20746865207a65726f20616464726573610100527f73000000000000000000000000000000000000000000000000000000000000006101205260e08161016001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610140528060040161015cfd5b60a0516040525f60605260c0516080526134be612fec565b600160a0516020525f5260405f205460e05260c05160e051101561357957602080610180526022610100527f65726332303a206275726e20616d6f756e7420657863656564732062616c616e610120527f6365000000000000000000000000000000000000000000000000000000000000610140526101008161018001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b60c05160e05103600160a0516020525f5260405f205560c051600354036003555f60a0517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60c051610100526020610100a360a0516040525f60605260c0516080526135e3612fee565b565b610320516102e0511461361257610320516101a0526102e0516101c052610360516101e052613612613312565b6103205160a0526103605160c052613628613404565b6020613c765f395f5163a9059cbb61038052610300516103a052610340516103c0526020610380604461039c5f855af1613664573d5f5f3e3d5ffd5b3d61367b57803b15613a1c5760016103e0526136a5565b3d602081183d602010021880610380016103a011613a1c57610380518060011c613a1c576103e052505b6103e090505161374c5760208061048052602b610400527f657263343632363a207472616e73666572206f7065726174696f6e2064696420610420527f6e6f742073756363656564000000000000000000000000000000000000000000610440526104008161048001604b82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610460528060040161047cfd5b61032051610300516102e0517ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60406103406103805e6040610380a4565b60a05161382e57602080610180526025610100527f65726332303a207472616e736665722066726f6d20746865207a65726f206164610120527f6472657373000000000000000000000000000000000000000000000000000000610140526101008161018001604582825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b60c0516138d257602080610180526023610100527f65726332303a207472616e7366657220746f20746865207a65726f2061646472610120527f6573730000000000000000000000000000000000000000000000000000000000610140526101008161018001604382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b606060a060405e6138e1612fec565b600160a0516020525f5260405f20546101005260e05161010051101561399e576020806101a0526026610120527f65726332303a207472616e7366657220616d6f756e7420657863656564732062610140527f616c616e6365000000000000000000000000000000000000000000000000000061016052610120816101a001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b60e0516101005103600160a0516020525f5260405f205560e051600160c0516020525f5260405f205401600160c0516020525f5260405f205560c05160a0517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60e051610120526020610120a3606060a060405e613a1a612fee565b565b5f80fd07f422430c891d012126001800e410c420580247224321a6224320cd22432184088406cb01b613f4011f0293216021eb0344224308b2072c22430ca7224322431e8e22430c6e0b8c16721b2a2243224311f1079306fe8558203a85b2c63fc34bac2c754983aefe5f65ec0ebbbcf744af5dc75ec59bb47043e9193a768118561902c0a16576797065728300040300390000000000000000000000002b513ebe7070cff91cf699a0bfe5075020c732ff

Deployed Bytecode

0x5f3560e01c6002602b820660011b613a2001601e395f51565b6318160ddd81186100345734613a1c5760035460405260206040f35b63a9059cbb811861224357604436103417613a1c576004358060a01c613a1c57610540525f5c600114613a1c5760015f5d3361032052610072612ec4565b6105405161032052610082612ec4565b3360a0526105405160c05260243560e05261009b61378a565b6020613cb65f395f51633bdab8bf610560526020610560600461057c5f855af16100c7573d5f5f3e3d5ffd5b60203d10613a1c57610560505060016105605260206105605f5f5df35b6370a08231811861224357602436103417613a1c576004358060a01c613a1c5760405260016040516020525f5260405f205460605260206060f35b63095ea7b3811861016957604436103417613a1c576004358060a01c613a1c576101a052336040526101a05160605260243560805261015c612247565b60016101c05260206101c0f35b630700037d811861224357602436103417613a1c576004358060a01c613a1c57604052600f6040516020525f5260405f2080546060526001810154608052600281015460a0525060606060f35b63dd62ed3e811861020e57604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260026040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b63402d267d811861224357602436103417613a1c576004358060a01c613a1c576060526020606051604052610243608061287c565b6080f35b63313ce56781186102655734613a1c576020613c3660403960206040f35b631e83409a811861224357602436103417613a1c576004358060a01c613a1c57610320523361034052611225565b6301e1d11481186102b35734613a1c5760206102af60806123dc565b6080f35b63d905777e81186102ec57602436103417613a1c576004358060a01c613a1c5760605260206060516040526102e8608061295a565b6080f35b63ad598e81811861224357604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260176040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b63c6e6f592811861037757602436103417613a1c5760206004356101e0525f61020052610372610300612748565b610300f35b63b3d7f6b981186103a557602436103417613a1c576020600435610300526103a06103406128e9565b610340f35b63ba087652811861224357606436103417613a1c576024358060a01c613a1c57610540526044358060a01c613a1c57610560525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261058052803b15613a1c575f610580600461059c5f855af1610417573d5f5f3e3d5ffd5b506105605160405261042a61058061295a565b6105805160043511156104d4576020806106205260216105a0527f657263343632363a2072656465656d206d6f7265207468616e206d6178696d756105c0527f6d000000000000000000000000000000000000000000000000000000000000006105e0526105a08161062001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610600528060040161061cfd5b33610580526020613cf65f395f51639c868ac06105a05260206105a060046105bc845afa610504573d5f5f3e3d5ffd5b3d602081183d6020100218806105a0016105c011613a1c576105a0518060011c613a1c576105e052506105e090505115610627576020613d165f395f5163680c7783610600526020610600600461061c845afa610563573d5f5f3e3d5ffd5b3d602081183d6020100218806106000161062011613a1c57610600518060a01c613a1c5761064052506106409050513318610627576105605161054051181561061e576020806106c0526008610660527f726563656976657200000000000000000000000000000000000000000000000061068052610660816106c001602882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06106a052806004016106bcfd5b61056051610580525b600435610300526106396105c061296e565b6105c0516105a0526105605161032052610651612ec4565b610580516102e052610540516103005261056051610320526105a05161034052600435610360526106806135e5565b610688613277565b6020613cb65f395f51633bdab8bf6105c05260206105c060046105dc5f855af16106b4573d5f5f3e3d5ffd5b60203d10613a1c576105c0505060206105a05f5f5df35b6307a2d13a811861224357602436103417613a1c5760206004356101e0525f610200526106f96103006127e2565b610300f35b63ef8b30f7811861224357602436103417613a1c576020600435610300526107276103406128a2565b610340f35b63c63d75b6811861076557602436103417613a1c576004358060a01c613a1c57606052602060605160405261076160806128c3565b6080f35b6354c49fe9811861224357602436103417613a1c576004356008811015613a1c576007015460405260206040f35b63ce96cb7781186107d157602436103417613a1c576004358060a01c613a1c5761034052602061034051610300526107cc61036061290b565b610360f35b634e71d92d81186122435734613a1c576020613cd6610320393361034052611225565b630a28a477811861082257602436103417613a1c5760206004356103005261081d610340612938565b610340f35b63692e099e811861224357604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260166040516020525f5260405f20806060516020525f5260405f2090508054608052600181015460a0525060406080f35b634cdad506811861224357602436103417613a1c576020600435610300526108ad61034061296e565b610340f35b6338d52e0f81186108d05734613a1c576020613c5660403960206040f35b633ea9f06f8118610a705734613a1c576020613cf65f395f516370a0823160605230608052602060606024607c845afa61090c573d5f5f3e3d5ffd5b60203d10613a1c5760609050516040526020613cf65f395f516318160ddd608052602060806004609c845afa610944573d5f5f3e3d5ffd5b60203d10613a1c5760809050516060526060516040516ec097ce7bc90715b34b9f10000000008102816ec097ce7bc90715b34b9f1000000000820418613a1c579050048060b57101000000000000000000000000000000000082106109b0578160801c91508060401b90505b690100000000000000000082106109ce578160401c91508060201b90505b6501000000000082106109e8578160201c91508060101b90505b63010000008210610a00578160101c91508060081b90505b620100008201810260121c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808184040160011c9050808304808281188284100218905090509050905060805260206080f35b63f986ca50811861224357604436103417613a1c576004358060a01c613a1c57610320526024358060a01c613a1c57610340525f610360526020613cd65f395f516103205118610b06576020613cb65f395f5163e3a8d98a61038052306103a052426103c0526020610380604461039c845afa610aef573d5f5f3e3d5ffd5b60203d10613a1c5761038090505161036052610b21565b61032051604052610b18610380612a42565b61038051610360525b610320516101e05261036051610200526103405161022052610b44610440612cc5565b61044060c0816103805e50610400516017610340516020525f5260405f2080610320516020525f5260405f20905054808203828111613a1c5790509050610440526020610440f35b63f0350c04811861224357602436103417613a1c576004358060a01c613a1c5761010052610bb861298f565b61010051610c5d576020806101a0526026610120527f6f776e61626c653a206e6577206f776e657220697320746865207a65726f2061610140527f646472657373000000000000000000000000000000000000000000000000000061016052610120816101a001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61010051604052610c6c612a0b565b005b638da5cb5b81186122435734613a1c575f5460405260206040f35b631fcd308081186122435734613a1c576020613c9660403960206040f35b6395d89b418118610e1a5734613a1c576020806101e0525f60026040527f67280000000000000000000000000000000000000000000000000000000000006060526040805160208201836101a001815181525050808301925050506020613cf65f395f516395d89b41608052606060806004609c845afa610d2a573d5f5f3e3d5ffd5b3d606081183d60601002188060800160a011613a1c57608060805160800110613a1c576080516080018051826080018251602001830111613a1c57601d8111613a1c5750603d816101005e50506101009050805160208201836101a001815181525050808301925050506001610140527f290000000000000000000000000000000000000000000000000000000000000061016052610140805160208201836101a0018151815250508083019250505080610180526101809050816101e001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506101e0f35b63e8de0d4d811861108957604436103417613a1c576004358060a01c613a1c57610100526024358060a01c613a1c57610120525f5c600114613a1c5760015f5d6020613cd65f395f516101005118610ee4576020806101a0526002610140527f594200000000000000000000000000000000000000000000000000000000000061016052610140816101a001602282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b6020613cf65f395f516101005118610f6e576020806101a0526008610140527f4c505f544f4b454e00000000000000000000000000000000000000000000000061016052610140816101a001602882825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b6101205115613a1c57600f610100516020525f5260405f205415611004576020806101a052600d610140527f416c72656164792061646465640000000000000000000000000000000000000061016052610140816101a001602d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61100c61298f565b61012051600f610100516020525f5260405f20556006546101405261010051610140516008811015613a1c57600701556101405160018101818110613a1c579050600655610100517fbaa8134d057f38ffff73248ae9edf1012783d074fbae40443077bf53fc57b9ec60406101206101605e6040610160a25f5f5d005b63d7a03b17811861224357602436103417613a1c576004358060a01c613a1c5760405260106040516020525f5260405f205460605260206060f35b6306fdde0381186122435734613a1c576020806101c0525f600a6040527f59422047617567653a200000000000000000000000000000000000000000000060605260408051602082018361016001815181525050808301925050506020613cf65f395f516395d89b41608052606060806004609c845afa611147573d5f5f3e3d5ffd5b3d606081183d60601002188060800160a011613a1c57608060805160800110613a1c576080516080018051826080018251602001830111613a1c57601d8111613a1c5750603d816101005e5050610100905080516020820183610160018151815250508083019250505080610140526101409050816101c001604782825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506101c0f35b6321c0b342811861224357604436103417613a1c576004358060a01c613a1c57610320526024358060a01c613a1c57610340525b5f5c600114613a1c5760015f5d61032051610120525f6101405261124a610380612bcd565b6103805161036052610320516101e05261036051610200526103405161022052611275610440612cc5565b61044060c0816103805e50610380516011556103a051601255610380516013610320516020525f5260405f20556014610320516020525f5260405f206103c05181556103e0516001820155506103c0516015610340516020525f5260405f2080610320516020525f5260405f209050556016610340516020525f5260405f2080610320516020525f5260405f20905061040051815561042051600182015550610400516017610340516020525f5260405f2080610320516020525f5260405f20905054808203828111613a1c579050905061036052610400516017610340516020525f5260405f2080610320516020525f5260405f209050556103205163a9059cbb6104405260406103406104605e6020610440604461045c5f855af161139e573d5f5f3e3d5ffd5b3d6113b557803b15613a1c5760016104a0526113df565b3d602081183d6020100218806104400161046011613a1c57610440518060011c613a1c576104a052505b6104a090505115613a1c5760206103605f5f5df35b63215d0bbf811861159757604436103417613a1c576004358060a01c613a1c57610100526024358060a01c613a1c57610120526020613cd65f395f5161010051186114b1576020806101a0526002610140527f594200000000000000000000000000000000000000000000000000000000000061016052610140816101a001602282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b6101205115613a1c57600f610100516020525f5260405f2054611546576020806101a0526009610140527f4e6f74206164646564000000000000000000000000000000000000000000000061016052610140816101a001602982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b61154e61298f565b61012051600f610100516020525f5260405f2055610100517fd6161cfaa8ff15169d3b9c3c69f7dcd627a1c5ca6a3534afdd8054d2961c610261012051610140526020610140a2005b6323b872dd811861224357606436103417613a1c576004358060a01c613a1c57610540526024358060a01c613a1c57610560525f5c600114613a1c5760015f5d61054051610320526115e7612ec4565b61056051610320526115f7612ec4565b610540516101a052336101c0526044356101e052611613613312565b604061054060a05e60443560e05261162961378a565b6020613cb65f395f51633bdab8bf610580526020610580600461059c5f855af1611655573d5f5f3e3d5ffd5b60203d10613a1c57610580505060016105805260206105805f5f5df35b635f8275fc811861224357606436103417613a1c576004358060a01c613a1c57610320525f5c600114613a1c5760015f5d6020613cd65f395f51610320511861172d576020806103a0526002610340527f594200000000000000000000000000000000000000000000000000000000000061036052610340816103a001602282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b6024356117ac576020806103a052600a610340527f4e6f20726577617264730000000000000000000000000000000000000000000061036052610340816103a001602a82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610380528060040161039cfd5b600f610320516020525f5260405f20805461034052600181015461036052600281015461038052506103405133146117e6576117e661298f565b61032051610120525f610140526117fe6103c0612bcd565b6103c0516103a052610320516101e0526103a051610200525f61022052611826610480612cc5565b61048060c0816103c05e506103c0516011556103e0516012556103c0516013610320516020525f5260405f20556014610320516020525f5260405f2061040051815561042051600182015550610380516010610320516020525f5260405f2054808203828111613a1c579050905061048052604435156118a75760016118ad565b61048051155b611998574261036051116119335760208061050052600c6104a0527f5261746520756e6b6e6f776e00000000000000000000000000000000000000006104c0526104a08161050001602c82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104e052806004016104fcfd5b426103605142808203828111613a1c579050905061048051602435808201828110613a1c5790509050808202811583838304141715613a1c5790509050610480518015613a1c5780820490509050808201828110613a1c579050905061036052611a21565b4260443511611a19576020806105005260146104a0527f46696e697368657320696e2074686520706173740000000000000000000000006104c0526104a08161050001603482825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06104e052806004016104fcfd5b604435610360525b61038051602435808201828110613a1c579050905061038052600f610320516020525f5260405f2061034051815561036051600182015561038051600282015550610320516323b872dd6104a052336104c052306104e0526024356105005260206104a060646104bc5f855af1611a9a573d5f5f3e3d5ffd5b3d611ab157803b15613a1c57600161052052611adb565b3d602081183d6020100218806104a0016104c011613a1c576104a0518060011c613a1c5761052052505b61052090505115613a1c57610320517f1ecc08cf4f4c06326e836da1a250282d8c384890b0d027466c2923183d9da0bd336104a0526024356104c052610360516104e05260606104a0a25f5f5d005b636e553f658118611ce357604436103417613a1c576024358060a01c613a1c57610540525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261056052803b15613a1c575f610560600461057c5f855af1611b8d573d5f5f3e3d5ffd5b5061054051604052611ba061056061287c565b610560516004351115611c4a57602080610600526022610580527f657263343632363a206465706f736974206d6f7265207468616e206d6178696d6105a0527f756d0000000000000000000000000000000000000000000000000000000000006105c0526105808161060001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105e052806004016105fcfd5b60043561030052611c5c6105806128a2565b61058051610560526105405161032052611c74612ec4565b336101a052610540516101c0526004356101e0526105605161020052611c986130fe565b611ca0613277565b6020613cb65f395f51633bdab8bf610580526020610580600461059c5f855af1611ccc573d5f5f3e3d5ffd5b60203d10613a1c57610580505060206105605f5f5df35b631de8b63181186122435734613a1c576020613cd660403960206040f35b6394bf804d811861224357604436103417613a1c576024358060a01c613a1c57610540525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261056052803b15613a1c575f610560600461057c5f855af1611d64573d5f5f3e3d5ffd5b5061054051604052611d776105606128c3565b610560516004351115611dfc576020806105e052601f610580527f657263343632363a206d696e74206d6f7265207468616e206d6178696d756d006105a052610580816105e001603f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06105c052806004016105dcfd5b60043561030052611e0e6105806128e9565b61058051610560526105405161032052611e26612ec4565b336101a05260406105406101c05e60043561020052611e436130fe565b611e4b613277565b6020613cb65f395f51633bdab8bf610580526020610580600461059c5f855af1611e77573d5f5f3e3d5ffd5b60203d10613a1c57610580505060206105605f5f5df35b63b460af94811861224357606436103417613a1c576024358060a01c613a1c57610540526044358060a01c613a1c57610560525f5c600114613a1c5760015f5d6020613cf65f395f51638fa5749261058052803b15613a1c575f610580600461059c5f855af1611f00573d5f5f3e3d5ffd5b506105605161030052611f1461058061290b565b610580516004351115611fbe576020806106205260236105a0527f657263343632363a207769746864726177206d6f7265207468616e206d6178696105c0527f6d756d00000000000000000000000000000000000000000000000000000000006105e0526105a08161062001604382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610600528060040161061cfd5b60043561030052611fd06105a0612938565b6105a051610580526105605161032052611fe8612ec4565b336102e05260406105406103005e60043561034052610580516103605261200d6135e5565b612015613277565b6020613cb65f395f51633bdab8bf6105a05260206105a060046105bc5f855af1612041573d5f5f3e3d5ffd5b60203d10613a1c576105a0505060206105805f5f5df35b63ffa1ad7481186122435734613a1c5760208060805260066040527f76312e302e300000000000000000000000000000000000000000000000000000606052604081608001602682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506080f35b6309dba08381186120eb5734613a1c576020613cb660403960206040f35b63c493dfeb811861224357602436103417613a1c576004358060a01c613a1c5760405260136040516020525f5260405f205460605260206060f35b63bfd9041b81186121445734613a1c576020613cf660403960206040f35b63963c94b981186122435734613a1c5760065460405260206040f35b632dd3100081146003361116156122435734613a1c576020613d1660403960206040f35b639d263dfc81186122435734613a1c5760115460405260125460605260406040f35b637d58777b811861224357602436103417613a1c576004358060a01c613a1c5760405260146040516020525f5260405f20805460605260018101546080525060406060f35b637e1e9cea811861224357604436103417613a1c576004358060a01c613a1c576040526024358060a01c613a1c5760605260156040516020525f5260405f20806060516020525f5260405f2090505460805260206080f35b5f5ffd5b6040516122e75760208061012052602460a0527f65726332303a20617070726f76652066726f6d20746865207a65726f2061646460c0527f726573730000000000000000000000000000000000000000000000000000000060e05260a08161012001604482825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610100528060040161011cfd5b6060516123875760208061012052602260a0527f65726332303a20617070726f766520746f20746865207a65726f20616464726560c0527f737300000000000000000000000000000000000000000000000000000000000060e05260a08161012001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610100528060040161011cfd5b60805160026040516020525f5260405f20806060516020525f5260405f209050556060516040517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560805160a052602060a0a3565b6020613c765f395f516370a0823160405230606052602060406024605c845afa612408573d5f5f3e3d5ffd5b60203d10613a1c576040905051815250565b6080516124965760208061012052601e60c0527f6d6174683a206d756c5f646976206469766973696f6e206279207a65726f000060e05260c08161012001603e82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610100528060040161011cfd5b6040516060517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183099050905060c0526060516040510260e0525f6101005260e05160c051106124f15760e05160c0510361010052612500565b600160e05160c0510303610100525b610100516125575760a051612515575f612531565b6040516060516080518015613a1c578082840990509050905015155b1561254857600160805160e0510401815250612746565b60805160e05104815250612746565b61010051608051116125db57602080610180526016610120527f6d6174683a206d756c5f646976206f766572666c6f7700000000000000000000610140526101208161018001603682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b6040516060516080518015613a1c57808284099050905090506101205260e0516101205111156126115760016101005103610100525b6101205160e0510360e0526080516080515f0316610140526101405160805104610160526101405160e0510460e052600161014051610140515f0304016101405261014051610100510260e0511760e05260026101605160030218610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805161016051026002036101805102610180526101805160e051026101a05260a051612707575f612723565b6040516060516080518015613a1c578082840990509050905015155b1561273e576101a05160018101818110613a1c5790506101a0525b6101a0518152505b565b6003546102205261022051612780576101e0516127666102406123dc565b61024051808201828110613a1c57905090508152506127e0565b6101e051610280526102205160018101818110613a1c5790506102a0526127a86102406123dc565b6102405160018101818110613a1c5790506102c052610200516102e052608061028060405e6127d861026061241a565b610260518152505b565b600354610220526102205161281a576101e0516128006102406123dc565b61024051808203828111613a1c579050905081525061287a565b6101e0516102805261282d6102406123dc565b6102405160018101818110613a1c5790506102a0526102205160018101818110613a1c5790506102c052610200516102e052608061028060405e61287261026061241a565b610260518152505b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815250565b610300516101e0525f610200526128ba610320612748565b61032051815250565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815250565b610300516101e0526001610200526129026103206127e2565b61032051815250565b6001610300516020525f5260405f20546101e0525f6102005261292f6103206127e2565b61032051815250565b610300516101e052600161020052612951610320612748565b61032051815250565b60016040516020525f5260405f2054815250565b610300516101e0525f610200526129866103206127e2565b61032051815250565b5f54331815612a095760208060a05260206040527f6f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260605260408160a001604082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060805280600401609cfd5b565b5f546060526040515f556040516060517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f6080a3565b600f6040516020525f5260405f2054612ac65760208060c05260096060527f4e6f20726577617264000000000000000000000000000000000000000000000060805260608160c001602982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b60146040516020525f5260405f206001810190505460605260106040516020525f5260405f2054608052600f6040516020525f5260405f206001810190505460a052600f6040516020525f5260405f206002810190505460c05260605160a05111612b34575f815250612bcb565b60c051608051808203828111613a1c579050905042606051808203828111613a1c5790509050808202811583838304141715613a1c579050905060a051606051808203828111613a1c57905090508015613a1c5780820490509050608051808201828110613a1c579050905060e05260e05160c05180828118828410021890509050608051808203828111613a1c57905090508152505b565b5f610160526020613cd65f395f516101205118612c7b5761014051612c2f576020613cb65f395f51633bdab8bf610180526020610180600461019c5f855af1612c18573d5f5f3e3d5ffd5b60203d10613a1c5761018090505161016052612cbc565b6020613cb65f395f5163e3a8d98a61018052306101a052426101c0526020610180604461019c845afa612c64573d5f5f3e3d5ffd5b60203d10613a1c5761018090505161016052612cbc565b61012051604052612c8d610180612a42565b61018051610160526010610120516020525f5260405f20805461016051808201828110613a1c57905090508155505b61016051815250565b60c03661024037601154610240526012546102605261026051421115612d4457610240516003544261026051808203828111613a1c57905090506ec097ce7bc90715b34b9f10000000008102816ec097ce7bc90715b34b9f1000000000820418613a1c57905004808201828110613a1c57905090506102405242610260525b6101e05115612ded5760146101e0516020525f5260405f2080546102805260018101546102a052506102a051421115612ded57610280516102405160136101e0516020525f5260405f2054808203828111613a1c579050905061020051808202811583838304141715613a1c5790509050426102a051808203828111613a1c57905090508015613a1c5780820490509050808201828110613a1c579050905061028052426102a0525b6102205115612eba576016610220516020525f5260405f20806101e0516020525f5260405f20905080546102c05260018101546102e052506102e051421115612eba576102c051610280516015610220516020525f5260405f20806101e0516020525f5260405f20905054808203828111613a1c57905090506040526001610220516020525f5260405f20546060526ec097ce7bc90715b34b9f10000000006080525f60a052612e9e61030061241a565b61030051808201828110613a1c57905090506102c052426102e0525b60c0610240825e50565b600654610340525f6008905b806103605261034051610360511815612fe857610360516008811015613a1c5760070154610380526103805161012052600161014052612f116103c0612bcd565b6103c0516103a05260406103806101e05e6103205161022052612f35610480612cc5565b61048060c0816103c05e5061036051612f57576103c0516011556103e0516012555b6103c0516013610380516020525f5260405f20556014610380516020525f5260405f2061040051815561042051600182015550610400516015610320516020525f5260405f2080610380516020525f5260405f209050556016610320516020525f5260405f2080610380516020525f5260405f20905061044051815561046051600182015550600101818118612ed0575b5050565b565b565b60a05161306d5760208061014052601f60e0527f65726332303a206d696e7420746f20746865207a65726f2061646472657373006101005260e08161014001603f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610120528060040161013cfd5b5f604052604060a060605e613080612fec565b60035460c051808201828110613a1c579050905060035560c051600160a0516020525f5260405f205401600160a0516020525f5260405f205560a0515f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60c05160e052602060e0a35f604052604060a060605e6130fc612fee565b565b6020613c765f395f516323b872dd610220526101a0516102405230610260526101e051610280526020610220606461023c5f855af161313f573d5f5f3e3d5ffd5b3d61315657803b15613a1c5760016102a052613180565b3d602081183d6020100218806102200161024011613a1c57610220518060011c613a1c576102a052505b6102a09050516132275760208061034052602f6102c0527f657263343632363a207472616e7366657246726f6d206f7065726174696f6e206102e0527f646964206e6f7420737563636565640000000000000000000000000000000000610300526102c08161034001604f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610320528060040161033cfd5b6101c05160a0526102005160c05261323d612ff0565b6101c0516101a0517fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760406101e06102205e6040610220a3565b6003546040526020613c965f395f516040511015613298576040511561329b565b60015b6133105760208060c05260196060527f657263343632363a206c65617665204d494e5f5348415245530000000000000060805260608160c001603982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b565b60026101a0516020525f5260405f20806101c0516020525f5260405f20905054610200527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6102005114613402576101e0516102005110156133e65760208061028052601d610220527f65726332303a20696e73756666696369656e7420616c6c6f77616e6365000000610240526102208161028001603d82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610260528060040161027cfd5b60406101a060405e6101e0516102005103608052613402612247565b565b60a0516134a65760208061016052602160e0527f65726332303a206275726e2066726f6d20746865207a65726f20616464726573610100527f73000000000000000000000000000000000000000000000000000000000000006101205260e08161016001604182825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610140528060040161015cfd5b60a0516040525f60605260c0516080526134be612fec565b600160a0516020525f5260405f205460e05260c05160e051101561357957602080610180526022610100527f65726332303a206275726e20616d6f756e7420657863656564732062616c616e610120527f6365000000000000000000000000000000000000000000000000000000000000610140526101008161018001604282825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b60c05160e05103600160a0516020525f5260405f205560c051600354036003555f60a0517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60c051610100526020610100a360a0516040525f60605260c0516080526135e3612fee565b565b610320516102e0511461361257610320516101a0526102e0516101c052610360516101e052613612613312565b6103205160a0526103605160c052613628613404565b6020613c765f395f5163a9059cbb61038052610300516103a052610340516103c0526020610380604461039c5f855af1613664573d5f5f3e3d5ffd5b3d61367b57803b15613a1c5760016103e0526136a5565b3d602081183d602010021880610380016103a011613a1c57610380518060011c613a1c576103e052505b6103e090505161374c5760208061048052602b610400527f657263343632363a207472616e73666572206f7065726174696f6e2064696420610420527f6e6f742073756363656564000000000000000000000000000000000000000000610440526104008161048001604b82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610460528060040161047cfd5b61032051610300516102e0517ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60406103406103805e6040610380a4565b60a05161382e57602080610180526025610100527f65726332303a207472616e736665722066726f6d20746865207a65726f206164610120527f6472657373000000000000000000000000000000000000000000000000000000610140526101008161018001604582825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b60c0516138d257602080610180526023610100527f65726332303a207472616e7366657220746f20746865207a65726f2061646472610120527f6573730000000000000000000000000000000000000000000000000000000000610140526101008161018001604382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610160528060040161017cfd5b606060a060405e6138e1612fec565b600160a0516020525f5260405f20546101005260e05161010051101561399e576020806101a0526026610120527f65726332303a207472616e7366657220616d6f756e7420657863656564732062610140527f616c616e6365000000000000000000000000000000000000000000000000000061016052610120816101a001604682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0610180528060040161019cfd5b60e0516101005103600160a0516020525f5260405f205560e051600160c0516020525f5260405f205401600160c0516020525f5260405f205560c05160a0517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60e051610120526020610120a3606060a060405e613a1a612fee565b565b5f80fd07f422430c891d012126001800e410c420580247224321a6224320cd22432184088406cb01b613f4011f0293216021eb0344224308b2072c22430ca7224322431e8e22430c6e0b8c16721b2a2243224311f1079306fe35ab3eebd56978e31fb68d8b88823557430ab32f50f11ae57ecabdfcce2d0d8800000000000000000000000000000000000000000000000000000000000000010000000000000000000000002a4671fd269df5b3da03103c74063da10d03e23c000000000000000000000000000000000000000000000000000000000000000b4a75737420736179206e6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009b29f4eab2afb955a939e5bb4e080257fdc8071103f99888124cf4197dffda0d0000000000000000000000000000000000000000000000000000000000000009746f2045495037313200000000000000000000000000000000000000000000124ca7bd70c5e2b6c43a1f5331172941165e5965688189aa73516af0c22165f110000000000000000000000000000000000000000000000000000000000000000c59422047617567653a202e2e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000567282e2e2900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000002b513ebe7070cff91cf699a0bfe5075020c732ff0000000000000000000000002b513ebe7070cff91cf699a0bfe5075020c732ff000000000000000000000000000000000000000000000000000000e8d4a510000000000000000000000000001be14811a3a06f6af4fa64310a636e1df04c1c2100000000000000000000000001791f726b4103694969820be083196cc7c045ff0000000000000000000000002b513ebe7070cff91cf699a0bfe5075020c732ff000000000000000000000000370a449febb9411c95bf897021377fe0b7d100c0

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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