ETH Price: $1,789.43 (+10.08%)

Contract

0x05577790318929624B4613F5a7E3B73AB40E38de

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Approve1348933152025-04-23 5:16:474 hrs ago1745385407IN
0x05577790...AB40E38de
0 ETH0.0000050335170.00095709
Deposit1348933012025-04-23 5:16:194 hrs ago1745385379IN
0x05577790...AB40E38de
0 ETH0.0000043909650.00098608
Withdraw1348868642025-04-23 1:41:458 hrs ago1745372505IN
0x05577790...AB40E38de
0 ETH0.000001741780.0019643
Deposit1348771042025-04-22 20:16:2513 hrs ago1745352985IN
0x05577790...AB40E38de
0 ETH0.0000005286570.0007471
Redeem1348645882025-04-22 13:19:1320 hrs ago1745327953IN
0x05577790...AB40E38de
0 ETH0.000004640940.0012864
Deposit1348585252025-04-22 9:57:0724 hrs ago1745315827IN
0x05577790...AB40E38de
0 ETH0.0000003897410.0028443
Redeem1348518522025-04-22 6:14:4127 hrs ago1745302481IN
0x05577790...AB40E38de
0 ETH0.0000002793080.00210305
Redeem1348368652025-04-21 21:55:0736 hrs ago1745272507IN
0x05577790...AB40E38de
0 ETH0.0000002736650.00243088
Deposit1348343612025-04-21 20:31:3937 hrs ago1745267499IN
0x05577790...AB40E38de
0 ETH0.0000003951280.00301259
Approve1348275802025-04-21 16:45:3741 hrs ago1745253937IN
0x05577790...AB40E38de
0 ETH0.0000004994160.00528557
Deposit1348275702025-04-21 16:45:1741 hrs ago1745253917IN
0x05577790...AB40E38de
0 ETH0.0000008689020.0050195
Redeem1348122362025-04-21 8:14:092 days ago1745223249IN
0x05577790...AB40E38de
0 ETH0.0000005318440.0040482
Deposit1348021022025-04-21 2:36:212 days ago1745202981IN
0x05577790...AB40E38de
0 ETH0.0000002934930.0021516
Deposit1347686532025-04-20 8:01:233 days ago1745136083IN
0x05577790...AB40E38de
0 ETH0.0000002657150.0020235
Redeem1347203552025-04-19 5:11:274 days ago1745039487IN
0x05577790...AB40E38de
0 ETH0.0000001601540.0012061
Redeem1346985972025-04-18 17:06:114 days ago1744995971IN
0x05577790...AB40E38de
0 ETH0.0000007757190.0001289
Approve1346964332025-04-18 15:54:034 days ago1744991643IN
0x05577790...AB40E38de
0 ETH0.0000025143480.00112009
Deposit1346963352025-04-18 15:50:474 days ago1744991447IN
0x05577790...AB40E38de
0 ETH0.0000025155070.00111708
Deposit1346953992025-04-18 15:19:354 days ago1744989575IN
0x05577790...AB40E38de
0 ETH0.000004926740.0010547
Deposit1346943982025-04-18 14:46:134 days ago1744987573IN
0x05577790...AB40E38de
0 ETH0.0000069785880.00123291
Deposit1346941242025-04-18 14:37:054 days ago1744987025IN
0x05577790...AB40E38de
0 ETH0.0000017087720.001321
Deposit1346938162025-04-18 14:26:494 days ago1744986409IN
0x05577790...AB40E38de
0 ETH0.0000044485540.0014103
Deposit1346937842025-04-18 14:25:454 days ago1744986345IN
0x05577790...AB40E38de
0 ETH0.0000035833710.00161739
Deposit1346937782025-04-18 14:25:334 days ago1744986333IN
0x05577790...AB40E38de
0 ETH0.0000034207340.00142107
Deposit1346937492025-04-18 14:24:354 days ago1744986275IN
0x05577790...AB40E38de
0 ETH0.0000034239320.0014459
View all transactions

Latest 3 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
1250722822024-09-07 21:09:01227 days ago1725743341
0x05577790...AB40E38de
 Contract Creation0 ETH
1250722822024-09-07 21:09:01227 days ago1725743341
0x05577790...AB40E38de
 Contract Creation0 ETH
1250722822024-09-07 21:09:01227 days ago1725743341  Contract Creation0 ETH

Loading...
Loading

Minimal Proxy Contract for 0x3b1df11b96b2f5525abe75eebefb1ce0928d2411

Contract Name:
Vault

Compiler Version
vyper:0.3.10

Optimization Enabled:
N/A

Other Settings:
default evmVersion, None license

Contract Source Code (Vyper language format)

# @version 0.3.10
"""
@title Vault
@notice ERC4626+ Vault for lending with crvUSD using LLAMMA algorithm
@author Curve.Fi
@license Copyright (c) Curve.Fi, 2020-2024 - all rights reserved
"""
from vyper.interfaces import ERC20 as ERC20Spec
from vyper.interfaces import ERC20Detailed


implements: ERC20Spec
implements: ERC20Detailed


interface ERC20:
    def transferFrom(_from: address, _to: address, _value: uint256) -> bool: nonpayable
    def transfer(_to: address, _value: uint256) -> bool: nonpayable
    def decimals() -> uint256: view
    def balanceOf(_from: address) -> uint256: view
    def symbol() -> String[32]: view
    def name() -> String[64]: view

interface AMM:
    def set_admin(_admin: address): nonpayable
    def rate() -> uint256: view

interface Controller:
    def total_debt() -> uint256: view
    def monetary_policy() -> address: view
    def check_lock() -> bool: view
    def save_rate(): nonpayable

interface PriceOracle:
    def price() -> uint256: view
    def price_w() -> uint256: nonpayable

interface Factory:
    def admin() -> address: view


# ERC20 events

event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256

event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

# ERC4626 events

event Deposit:
    sender: indexed(address)
    owner: indexed(address)
    assets: uint256
    shares: uint256

event Withdraw:
    sender: indexed(address)
    receiver: indexed(address)
    owner: indexed(address)
    assets: uint256
    shares: uint256

event SetMaxSupply:
    max_supply: uint256


# Limits
MIN_A: constant(uint256) = 2
MAX_A: constant(uint256) = 10000
MIN_FEE: constant(uint256) = 10**6  # 1e-12, still needs to be above 0
MAX_FEE: constant(uint256) = 10**17  # 10%
MAX_LOAN_DISCOUNT: constant(uint256) = 5 * 10**17
MIN_LIQUIDATION_DISCOUNT: constant(uint256) = 10**16
ADMIN_FEE: constant(uint256) = 0

# These are virtual shares from method proposed by OpenZeppelin
# see: https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks
# and
# https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol
DEAD_SHARES: constant(uint256) = 1000
MIN_ASSETS: constant(uint256) = 10000

borrowed_token: public(ERC20)
collateral_token: public(ERC20)

price_oracle: public(PriceOracle)
amm: public(AMM)
controller: public(Controller)
factory: public(Factory)

maxSupply: public(uint256)


# ERC20 publics

decimals: public(constant(uint8)) = 18
name: public(String[64])
symbol: public(String[34])

NAME_PREFIX: constant(String[16]) = 'Curve Vault for '
SYMBOL_PREFIX: constant(String[2]) = 'cv'

allowance: public(HashMap[address, HashMap[address, uint256]])
balanceOf: public(HashMap[address, uint256])
totalSupply: public(uint256)

precision: uint256


@external
def __init__():
    """
    @notice Template for Vault implementation
    """
    # The contract is made a "normal" template (not blueprint) so that we can get contract address before init
    # This is needed if we want to create a rehypothecation dual-market with two vaults
    # where vaults are collaterals of each other
    self.borrowed_token = ERC20(0x0000000000000000000000000000000000000001)


@internal
@pure
def ln_int(_x: uint256) -> int256:
    """
    @notice Logarithm ln() function based on log2. Not very gas-efficient but brief
    """
    # adapted from: https://medium.com/coinmonks/9aef8515136e
    # and vyper log implementation
    # This can be much more optimal but that's not important here
    x: uint256 = _x
    res: uint256 = 0
    for i in range(8):
        t: uint256 = 2**(7 - i)
        p: uint256 = 2**t
        if x >= p * 10**18:
            x /= p
            res += t * 10**18
    d: uint256 = 10**18
    for i in range(59):  # 18 decimals: math.log2(10**10) == 59.7
        if (x >= 2 * 10**18):
            res += d
            x /= 2
        x = x * x / 10**18
        d /= 2
    # Now res = log2(x)
    # ln(x) = log2(x) / log2(e)
    return convert(res * 10**18 / 1442695040888963328, int256)


@external
def initialize(
        amm_impl: address,
        controller_impl: address,
        borrowed_token: ERC20,
        collateral_token: ERC20,
        A: uint256,
        fee: uint256,
        price_oracle: PriceOracle,  # Factory makes from template if needed, deploying with a from_pool()
        monetary_policy: address,  # Standard monetary policy set in factory
        loan_discount: uint256,
        liquidation_discount: uint256
    ) -> (address, address):
    """
    @notice Initializer for vaults
    @param amm_impl AMM implementation (blueprint)
    @param controller_impl Controller implementation (blueprint)
    @param borrowed_token Token which is being borrowed
    @param collateral_token Token used for collateral
    @param A Amplification coefficient: band size is ~1/A
    @param fee Fee for swaps in AMM (for ETH markets found to be 0.6%)
    @param price_oracle Already initialized price oracle
    @param monetary_policy Already initialized monetary policy
    @param loan_discount Maximum discount. LTV = sqrt(((A - 1) / A) ** 4) - loan_discount
    @param liquidation_discount Liquidation discount. LT = sqrt(((A - 1) / A) ** 4) - liquidation_discount
    """
    assert self.borrowed_token.address == empty(address)

    self.borrowed_token = borrowed_token
    self.collateral_token = collateral_token
    self.price_oracle = price_oracle

    assert A >= MIN_A and A <= MAX_A, "Wrong A"
    assert fee <= MAX_FEE, "Fee too high"
    assert fee >= MIN_FEE, "Fee too low"
    assert liquidation_discount >= MIN_LIQUIDATION_DISCOUNT, "Liquidation discount too low"
    assert loan_discount <= MAX_LOAN_DISCOUNT, "Loan discount too high"
    assert loan_discount > liquidation_discount, "need loan_discount>liquidation_discount"

    p: uint256 = price_oracle.price()  # This also validates price oracle ABI
    assert p > 0
    assert price_oracle.price_w() == p
    A_ratio: uint256 = 10**18 * A / (A - 1)

    borrowed_precision: uint256 = 10**(18 - borrowed_token.decimals())

    amm: address = create_from_blueprint(
        amm_impl,
        borrowed_token.address, borrowed_precision,
        collateral_token.address, 10**(18 - collateral_token.decimals()),
        A, isqrt(A_ratio * 10**18), self.ln_int(A_ratio),
        p, fee, ADMIN_FEE, price_oracle.address,
        code_offset=3)
    controller: address = create_from_blueprint(
        controller_impl,
        empty(address), monetary_policy, loan_discount, liquidation_discount, amm,
        code_offset=3)
    AMM(amm).set_admin(controller)

    self.amm = AMM(amm)
    self.controller = Controller(controller)
    self.factory = Factory(msg.sender)

    # ERC20 set up
    self.precision = borrowed_precision
    borrowed_symbol: String[32] = borrowed_token.symbol()
    self.name = concat(NAME_PREFIX, borrowed_symbol)
    # Symbol must be String[32], but we do String[34]. It doesn't affect contracts which read it (they will truncate)
    # However this will be changed as soon as Vyper can *properly* manipulate strings
    self.symbol = concat(SYMBOL_PREFIX, borrowed_symbol)

    self.maxSupply = max_value(uint256)

    # No events because it's the only market we would ever create in this contract

    return controller, amm


@external
def set_max_supply(max_supply: uint256):
    """
    @notice Set maximum depositable supply
    """
    assert msg.sender == self.factory.admin() or msg.sender == self.factory.address
    self.maxSupply = max_supply
    log SetMaxSupply(max_supply)


@external
@view
@nonreentrant('lock')
def borrow_apr() -> uint256:
    """
    @notice Borrow APR (annualized and 1e18-based)
    """
    return self.amm.rate() * (365 * 86400)


@external
@view
@nonreentrant('lock')
def lend_apr() -> uint256:
    """
    @notice Lending APR (annualized and 1e18-based)
    """
    debt: uint256 = self.controller.total_debt()
    if debt == 0:
        return 0
    else:
        return self.amm.rate() * (365 * 86400) * debt / self._total_assets()


@external
@view
def asset() -> ERC20:
    """
    @notice Asset which is the same as borrowed_token
    """
    return self.borrowed_token


@internal
@view
def _total_assets() -> uint256:
    # admin fee should be accounted for here when enabled
    self.controller.check_lock()
    return self.borrowed_token.balanceOf(self.controller.address) + self.controller.total_debt()


@external
@view
@nonreentrant('lock')
def totalAssets() -> uint256:
    """
    @notice Total assets which can be lent out or be in reserve
    """
    return self._total_assets()


@internal
@view
def _convert_to_shares(assets: uint256, is_floor: bool = True,
                       _total_assets: uint256 = max_value(uint256)) -> uint256:
    total_assets: uint256 = _total_assets
    if total_assets == max_value(uint256):
        total_assets = self._total_assets()
    precision: uint256 = self.precision
    numerator: uint256 = (self.totalSupply + DEAD_SHARES) * assets * precision
    denominator: uint256 = (total_assets * precision + 1)
    if is_floor:
        return numerator / denominator
    else:
        return (numerator + denominator - 1) / denominator


@internal
@view
def _convert_to_assets(shares: uint256, is_floor: bool = True,
                       _total_assets: uint256 = max_value(uint256)) -> uint256:
    total_assets: uint256 = _total_assets
    if total_assets == max_value(uint256):
        total_assets = self._total_assets()
    precision: uint256 = self.precision
    numerator: uint256 = shares * (total_assets * precision + 1)
    denominator: uint256 = (self.totalSupply + DEAD_SHARES) * precision
    if is_floor:
        return numerator / denominator
    else:
        return (numerator + denominator - 1) / denominator


@external
@view
@nonreentrant('lock')
def pricePerShare(is_floor: bool = True) -> uint256:
    """
    @notice Method which shows how much one pool share costs in asset tokens if they are normalized to 18 decimals
    """
    supply: uint256 = self.totalSupply
    if supply == 0:
        return 10**18 / DEAD_SHARES
    else:
        precision: uint256 = self.precision
        numerator: uint256 = 10**18 * (self._total_assets() * precision + 1)
        denominator: uint256 = (supply + DEAD_SHARES)
        pps: uint256 = 0
        if is_floor:
            pps = numerator / denominator
        else:
            pps = (numerator + denominator - 1) / denominator
        assert pps > 0
        return pps


@external
@view
@nonreentrant('lock')
def convertToShares(assets: uint256) -> uint256:
    """
    @notice Returns the amount of shares which the Vault would exchange for the given amount of shares provided
    """
    return self._convert_to_shares(assets)


@external
@view
@nonreentrant('lock')
def convertToAssets(shares: uint256) -> uint256:
    """
    @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided
    """
    return self._convert_to_assets(shares)


@external
@view
def maxDeposit(receiver: address) -> uint256:
    """
    @notice Maximum amount of assets which a given user can deposit (inf)
    """
    max_supply: uint256 = self.maxSupply
    if max_supply == max_value(uint256):
        return max_supply
    else:
        assets: uint256 = self._total_assets()
        return max(max_supply, assets) - assets


@external
@view
@nonreentrant('lock')
def previewDeposit(assets: uint256) -> uint256:
    """
    @notice Returns the amount of shares which can be obtained upon depositing assets
    """
    return self._convert_to_shares(assets)


@external
@nonreentrant('lock')
def deposit(assets: uint256, receiver: address = msg.sender) -> uint256:
    """
    @notice Deposit assets in return for whatever number of shares corresponds to the current conditions
    @param assets Amount of assets to deposit
    @param receiver Receiver of the shares who is optional. If not specified - receiver is the sender
    """
    controller: Controller = self.controller
    total_assets: uint256 = self._total_assets()
    assert total_assets + assets >= MIN_ASSETS, "Need more assets"
    assert total_assets + assets <= self.maxSupply, "Supply limit"
    to_mint: uint256 = self._convert_to_shares(assets, True, total_assets)
    assert self.borrowed_token.transferFrom(msg.sender, controller.address, assets, default_return_value=True)
    self._mint(receiver, to_mint)
    controller.save_rate()
    log Deposit(msg.sender, receiver, assets, to_mint)
    return to_mint


@external
@view
def maxMint(receiver: address) -> uint256:
    """
    @notice Return maximum amount of shares which a given user can mint (inf)
    """
    max_supply: uint256 = self.maxSupply
    if max_supply == max_value(uint256):
        return max_supply
    else:
        assets: uint256 = self._total_assets()
        return self._convert_to_shares(max(max_supply, assets) - assets)


@external
@view
@nonreentrant('lock')
def previewMint(shares: uint256) -> uint256:
    """
    @notice Calculate the amount of assets which is needed to exactly mint the given amount of shares
    """
    return self._convert_to_assets(shares, False)


@external
@nonreentrant('lock')
def mint(shares: uint256, receiver: address = msg.sender) -> uint256:
    """
    @notice Mint given amount of shares taking whatever number of assets it requires
    @param shares Number of sharess to mint
    @param receiver Optional receiver for the shares. If not specified - it's the sender
    """
    controller: Controller = self.controller
    total_assets: uint256 = self._total_assets()
    assets: uint256 = self._convert_to_assets(shares, False, total_assets)
    assert total_assets + assets >= MIN_ASSETS, "Need more assets"
    assert total_assets + assets <= self.maxSupply, "Supply limit"
    assert self.borrowed_token.transferFrom(msg.sender, controller.address, assets, default_return_value=True)
    self._mint(receiver, shares)
    controller.save_rate()
    log Deposit(msg.sender, receiver, assets, shares)
    return assets


@external
@view
@nonreentrant('lock')
def maxWithdraw(owner: address) -> uint256:
    """
    @notice Maximum amount of assets which a given user can withdraw. Aware of both user's balance and available liquidity
    """
    return min(
        self._convert_to_assets(self.balanceOf[owner]),
        self.borrowed_token.balanceOf(self.controller.address))


@external
@view
@nonreentrant('lock')
def previewWithdraw(assets: uint256) -> uint256:
    """
    @notice Calculate number of shares which gets burned when withdrawing given amount of asset
    """
    assert assets <= self.borrowed_token.balanceOf(self.controller.address)
    return self._convert_to_shares(assets, False)


@external
@nonreentrant('lock')
def withdraw(assets: uint256, receiver: address = msg.sender, owner: address = msg.sender) -> uint256:
    """
    @notice Withdraw given amount of asset and burn the corresponding amount of vault shares
    @param assets Amount of assets to withdraw
    @param receiver Receiver of the assets (optional, sender if not specified)
    @param owner Owner who's shares the caller takes. Only can take those if owner gave the approval to the sender. Optional
    """
    total_assets: uint256 = self._total_assets()
    assert total_assets - assets >= MIN_ASSETS or total_assets == assets, "Need more assets"
    shares: uint256 = self._convert_to_shares(assets, False, total_assets)
    if owner != msg.sender:
        allowance: uint256 = self.allowance[owner][msg.sender]
        if allowance != max_value(uint256):
            self._approve(owner, msg.sender, allowance - shares)

    controller: Controller = self.controller
    self._burn(owner, shares)
    assert self.borrowed_token.transferFrom(controller.address, receiver, assets, default_return_value=True)
    controller.save_rate()
    log Withdraw(msg.sender, receiver, owner, assets, shares)
    return shares


@external
@view
@nonreentrant('lock')
def maxRedeem(owner: address) -> uint256:
    """
    @notice Calculate maximum amount of shares which a given user can redeem
    """
    return min(
        self._convert_to_shares(self.borrowed_token.balanceOf(self.controller.address), False),
        self.balanceOf[owner])


@external
@view
@nonreentrant('lock')
def previewRedeem(shares: uint256) -> uint256:
    """
    @notice Calculate the amount of assets which can be obtained by redeeming the given amount of shares
    """
    if self.totalSupply == 0:
        assert shares == 0
        return 0

    else:
        assets_to_redeem: uint256 = self._convert_to_assets(shares)
        assert assets_to_redeem <= self.borrowed_token.balanceOf(self.controller.address)
        return assets_to_redeem


@external
@nonreentrant('lock')
def redeem(shares: uint256, receiver: address = msg.sender, owner: address = msg.sender) -> uint256:
    """
    @notice Burn given amount of shares and give corresponding assets to the user
    @param shares Amount of shares to burn
    @param receiver Optional receiver of the assets
    @param owner Optional owner of the shares. Can only redeem if owner gave approval to the sender
    """
    if owner != msg.sender:
        allowance: uint256 = self.allowance[owner][msg.sender]
        if allowance != max_value(uint256):
            self._approve(owner, msg.sender, allowance - shares)

    total_assets: uint256 = self._total_assets()
    assets_to_redeem: uint256 = self._convert_to_assets(shares, True, total_assets)
    if total_assets - assets_to_redeem < MIN_ASSETS:
        if shares == self.totalSupply:
            # This is the last withdrawal, so we can take everything
            assets_to_redeem = total_assets
        else:
            raise "Need more assets"
    self._burn(owner, shares)
    controller: Controller = self.controller
    assert self.borrowed_token.transferFrom(controller.address, receiver, assets_to_redeem, default_return_value=True)
    controller.save_rate()
    log Withdraw(msg.sender, receiver, owner, assets_to_redeem, shares)
    return assets_to_redeem


# ERC20 methods

@internal
def _approve(_owner: address, _spender: address, _value: uint256):
    self.allowance[_owner][_spender] = _value

    log Approval(_owner, _spender, _value)


@internal
def _burn(_from: address, _value: uint256):
    self.balanceOf[_from] -= _value
    self.totalSupply -= _value

    log Transfer(_from, empty(address), _value)


@internal
def _mint(_to: address, _value: uint256):
    self.balanceOf[_to] += _value
    self.totalSupply += _value

    log Transfer(empty(address), _to, _value)


@internal
def _transfer(_from: address, _to: address, _value: uint256):
    assert _to not in [self, empty(address)]

    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value

    log Transfer(_from, _to, _value)


@external
def transferFrom(_from: address, _to: address, _value: uint256) -> bool:
    """
    @notice Transfer tokens from one account to another.
    @dev The caller needs to have an allowance from account `_from` greater than or
        equal to the value being transferred. An allowance equal to the uint256 type's
        maximum, is considered infinite and does not decrease.
    @param _from The account which tokens will be spent from.
    @param _to The account which tokens will be sent to.
    @param _value The amount of tokens to be transferred.
    """
    allowance: uint256 = self.allowance[_from][msg.sender]
    if allowance != max_value(uint256):
        self._approve(_from, msg.sender, allowance - _value)

    self._transfer(_from, _to, _value)
    return True


@external
def transfer(_to: address, _value: uint256) -> bool:
    """
    @notice Transfer tokens to `_to`.
    @param _to The account to transfer tokens to.
    @param _value The amount of tokens to transfer.
    """
    self._transfer(msg.sender, _to, _value)
    return True


@external
def approve(_spender: address, _value: uint256) -> bool:
    """
    @notice Allow `_spender` to transfer up to `_value` amount of tokens from the caller's account.
    @dev Non-zero to non-zero approvals are allowed, but should be used cautiously. The methods
        increaseAllowance + decreaseAllowance are available to prevent any front-running that
        may occur.
    @param _spender The account permitted to spend up to `_value` amount of caller's funds.
    @param _value The amount of tokens `_spender` is allowed to spend.
    """
    self._approve(msg.sender, _spender, _value)
    return True


@external
def increaseAllowance(_spender: address, _add_value: uint256) -> bool:
    """
    @notice Increase the allowance granted to `_spender`.
    @dev This function will never overflow, and instead will bound
        allowance to MAX_UINT256. This has the potential to grant an
        infinite approval.
    @param _spender The account to increase the allowance of.
    @param _add_value The amount to increase the allowance by.
    """
    cached_allowance: uint256 = self.allowance[msg.sender][_spender]
    allowance: uint256 = unsafe_add(cached_allowance, _add_value)

    # check for an overflow
    if allowance < cached_allowance:
        allowance = max_value(uint256)

    if allowance != cached_allowance:
        self._approve(msg.sender, _spender, allowance)

    return True


@external
def decreaseAllowance(_spender: address, _sub_value: uint256) -> bool:
    """
    @notice Decrease the allowance granted to `_spender`.
    @dev This function will never underflow, and instead will bound
        allowance to 0.
    @param _spender The account to decrease the allowance of.
    @param _sub_value The amount to decrease the allowance by.
    """
    cached_allowance: uint256 = self.allowance[msg.sender][_spender]
    allowance: uint256 = unsafe_sub(cached_allowance, _sub_value)

    # check for an underflow
    if cached_allowance < allowance:
        allowance = 0

    if allowance != cached_allowance:
        self._approve(msg.sender, _spender, allowance)

    return True


@external
@view
def admin() -> address:
    return self.factory.admin()

Contract ABI

API
[{"name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true},{"name":"spender","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Transfer","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Deposit","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"owner","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"shares","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Withdraw","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"owner","type":"address","indexed":true},{"name":"assets","type":"uint256","indexed":false},{"name":"shares","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetMaxSupply","inputs":[{"name":"max_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"initialize","inputs":[{"name":"amm_impl","type":"address"},{"name":"controller_impl","type":"address"},{"name":"borrowed_token","type":"address"},{"name":"collateral_token","type":"address"},{"name":"A","type":"uint256"},{"name":"fee","type":"uint256"},{"name":"price_oracle","type":"address"},{"name":"monetary_policy","type":"address"},{"name":"loan_discount","type":"uint256"},{"name":"liquidation_discount","type":"uint256"}],"outputs":[{"name":"","type":"address"},{"name":"","type":"address"}]},{"stateMutability":"nonpayable","type":"function","name":"set_max_supply","inputs":[{"name":"max_supply","type":"uint256"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"borrow_apr","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"lend_apr","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"asset","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"totalAssets","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"pricePerShare","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"pricePerShare","inputs":[{"name":"is_floor","type":"bool"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"convertToShares","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"convertToAssets","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxDeposit","inputs":[{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewDeposit","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"deposit","inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxMint","inputs":[{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewMint","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"mint","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"mint","inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxWithdraw","inputs":[{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewWithdraw","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"assets","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"assets","type":"uint256"},{"name":"receiver","type":"address"},{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"maxRedeem","inputs":[{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"previewRedeem","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"shares","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"redeem","inputs":[{"name":"shares","type":"uint256"},{"name":"receiver","type":"address"},{"name":"owner","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"transferFrom","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"transfer","inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"approve","inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"increaseAllowance","inputs":[{"name":"_spender","type":"address"},{"name":"_add_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"decreaseAllowance","inputs":[{"name":"_spender","type":"address"},{"name":"_sub_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"admin","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"borrowed_token","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"collateral_token","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"price_oracle","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"amm","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"controller","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"factory","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"maxSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8"}]},{"stateMutability":"view","type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"allowance","inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"balanceOf","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}]}]

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.