Skip to content

LP Token Methods

Pool and LP tokens are the same smart contract. The pool itself acts as a LP Token.

When coins are deposited into a Curve pool, the depositor receives pool LP (liquidity provider) tokens in return. Each Curve pool has its unique ERC20 contract representing these LP tokens, making them transferable. Holding these LP tokens allows for their deposit and staking in the pool's liquidity gauge, earning CRV token rewards.Additionally, if a metapool supports the LP token, it can be deposited there to receive the metapool's distinct LP tokens.

Transfer Methods

transfer

LPToken.transfer(_to : address, _value : uint256) -> bool:

Function to transfer _value tokens to _to.

Returns: true (bool).

Emits: Transfer

Input Type Description
_to address address to transfer token to
_value uint256 amount of tokens to transfer
Source code
event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

@external
def transfer(_to : address, _value : uint256) -> bool:
    """
    @dev Transfer token for a specified address
    @param _to The address to transfer to.
    @param _value The amount to be transferred.
    """
    self._transfer(msg.sender, _to, _value)
    return True

@internal
def _transfer(_from: address, _to: address, _value: uint256):
    # # NOTE: vyper does not allow underflows
    # #       so the following subtraction would revert on insufficient balance
    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value

    log Transfer(_from, _to, _value)

transferFrom

LPToken.transferFrom(_from : address, _to : address, _value : uint256) -> bool:

Function to transfer _value tokens from _from to _to.

Returns: true (bool).

Emits: Transfer

Input Type Description
_from address address to transfer token from
_to address address to transfer token to
_value uint256 amount of tokens to transfer
Source code
event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

@external
def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
    """
    @dev Transfer tokens from one address to another.
    @param _from address The address which you want to send tokens from
    @param _to address The address which you want to transfer to
    @param _value uint256 the amount of tokens to be transferred
    """
    self._transfer(_from, _to, _value)

    _allowance: uint256 = self.allowance[_from][msg.sender]
    if _allowance != max_value(uint256):
        self.allowance[_from][msg.sender] = _allowance - _value

    return True

@internal
def _transfer(_from: address, _to: address, _value: uint256):
    # # NOTE: vyper does not allow underflows
    # #       so the following subtraction would revert on insufficient balance
    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value

    log Transfer(_from, _to, _value)

Allowance Methods

allowance

LPToken.allowance(arg0: address, arg1: address) -> uint256: view

Getter method to check the allowance of arg0 for funds of arg1.

Returns: allowed amount (uint256).

Input Type Description
arg0 address Address of the spender
arg1 address Address of the token owner
Source code
allowance: public(HashMap[address, HashMap[address, uint256]])

approve

LPToken.approve(_spender : address, _value : uint256) -> bool:

Function to approve _spender to transfer _value of tokens on behalf of msg.sender

Returns: true (bool).

Emits: Approval

Input Type Description
_spender address Address of the approved spender
_value uint256 Amount of tokens to approve
Source code
event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256

@external
def approve(_spender : address, _value : uint256) -> bool:
    """
    @notice Approve the passed address to transfer the specified amount of
            tokens on behalf of msg.sender
    @dev Beware that changing an allowance via this method brings the risk that
        someone may use both the old and new allowance by unfortunate transaction
        ordering: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    @param _spender The address which will transfer the funds
    @param _value The amount of tokens that may be transferred
    @return bool success
    """
    self.allowance[msg.sender][_spender] = _value

    log Approval(msg.sender, _spender, _value)
    return True

permit

LPToken.permit(_owner: address, _spender: address, _value: uint256, _deadline: uint256, _v: uint8, _r: bytes32, _s: bytes32) -> bool:

Function to permit spender to spend up to _value amount of _owner's tokens via a signature.

Returns: true (bool).

Emits: Approval

Input Type Description
_owner address Account which generated the signature and is granting an allowance
_spender address Account which will be granted an allowance
_value uint256 Amount to approve
_deadline uint256 Deadline by which signature must be submitted
_v uint8 The last byte of the ECDSA signature
_r bytes32 The first 32 bytes of the ECDSA signature
_s bytes32 The second 32 bytes of the ECDSA signature
Source code
event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256

@external
def permit(
    _owner: address,
    _spender: address,
    _value: uint256,
    _deadline: uint256,
    _v: uint8,
    _r: bytes32,
    _s: bytes32
) -> bool:
    """
    @notice Approves spender by owner's signature to expend owner's tokens.
        See https://eips.ethereum.org/EIPS/eip-2612.
    @dev Inspired by https://github.com/yearn/yearn-vaults/blob/main/contracts/Vault.vy#L753-L793
    @dev Supports smart contract wallets which implement ERC1271
        https://eips.ethereum.org/EIPS/eip-1271
    @param _owner The address which is a source of funds and has signed the Permit.
    @param _spender The address which is allowed to spend the funds.
    @param _value The amount of tokens to be spent.
    @param _deadline The timestamp after which the Permit is no longer valid.
    @param _v The bytes[64] of the valid secp256k1 signature of permit by owner
    @param _r The bytes[0:32] of the valid secp256k1 signature of permit by owner
    @param _s The bytes[32:64] of the valid secp256k1 signature of permit by owner
    @return True, if transaction completes successfully
    """
    assert _owner != empty(address)
    assert block.timestamp <= _deadline

    nonce: uint256 = self.nonces[_owner]
    digest: bytes32 = keccak256(
        concat(
            b"\x19\x01",
            self._domain_separator(),
            keccak256(_abi_encode(EIP2612_TYPEHASH, _owner, _spender, _value, nonce, _deadline))
        )
    )

    if _owner.is_contract:
        sig: Bytes[65] = concat(_abi_encode(_r, _s), slice(convert(_v, bytes32), 31, 1))
        # reentrancy not a concern since this is a staticcall
        assert ERC1271(_owner).isValidSignature(digest, sig) == ERC1271_MAGIC_VAL
    else:
        assert ecrecover(digest, convert(_v, uint256), convert(_r, uint256), convert(_s, uint256)) == _owner

    self.allowance[_owner][_spender] = _value
    self.nonces[_owner] = nonce + 1

    log Approval(_owner, _spender, _value)
    return True

Contract Info Methods

name

LPToken.name() -> String[64]: view

Getter for the name of the LP token.

Returns: name (String[64]).

Source code
name: public(immutable(String[64]))

@external
def __init__(
    _name: String[32],
    _symbol: String[10],
    _A: uint256,
    _fee: uint256,
    _offpeg_fee_multiplier: uint256,
    _ma_exp_time: uint256,
    _coins: DynArray[address, MAX_COINS],
    _rate_multipliers: DynArray[uint256, MAX_COINS],
    _asset_types: DynArray[uint8, MAX_COINS],
    _method_ids: DynArray[bytes4, MAX_COINS],
    _oracles: DynArray[address, MAX_COINS],
):
    ...

    name = _name

    ...
>>> LPToken.name()
'USDV-crvUSD'

symbol

LPToken.symbol() -> String[32]: view

Getter for the symbol of the LP token.

Returns: symbol (String[32]).

Source code
symbol: public(immutable(String[32]))

@external
def __init__(
    _name: String[32],
    _symbol: String[10],
    _A: uint256,
    _fee: uint256,
    _offpeg_fee_multiplier: uint256,
    _ma_exp_time: uint256,
    _coins: DynArray[address, MAX_COINS],
    _rate_multipliers: DynArray[uint256, MAX_COINS],
    _asset_types: DynArray[uint8, MAX_COINS],
    _method_ids: DynArray[bytes4, MAX_COINS],
    _oracles: DynArray[address, MAX_COINS],
):
    ...

    symbol = _symbol

    ...
>>> LPToken.symbol()
'USDVcrvUSD'

decimals

LPToken.decimals() -> uint8: view

Getter for the decimals of the LP token.

Returns: decimals (uint8).

Source code
decimals: public(constant(uint8)) = 18
>>> LPToken.decimals()
18

version

LPToken.version() -> String[8]: view

Getter for the version of the LP token.

Returns: version (String[8]).

Source code
version: public(constant(String[8])) = "v7.0.0"
>>> LPToken.version()
"v7.0.0"

balanceOf

LPToken.balanceOf(arg0: address) -> uint256: view

Getter for the LP token balance of arg0.

Returns: token balance (uint256).

Input Type Description
arg0 address address to check the balance of
Source code
balanceOf: public(HashMap[address, uint256])
>>> LPToken.balanceOf("0x7a16fF8270133F063aAb6C9977183D9e72835428")
999808484451757093697730

nonces

LPToken.nonces(arg0: address) -> uint256: view

Getter for the nonce.

Returns: nonces (uint256).

Input Type Description
arg0 address address
Source code
nonces: public(HashMap[address, uint256])
>>> LPToken.nonces('todo')
'todo'

salt

LPToken.salt() -> bytes32: view

Getter for the salt of the LP token.

Returns: salt (bytes32).

Source code
salt: public(immutable(bytes32))

@external
def __init__(
    _name: String[32],
    _symbol: String[10],
    _A: uint256,
    _fee: uint256,
    _offpeg_fee_multiplier: uint256,
    _ma_exp_time: uint256,
    _coins: DynArray[address, MAX_COINS],
    _rate_multipliers: DynArray[uint256, MAX_COINS],
    _asset_types: DynArray[uint8, MAX_COINS],
    _method_ids: DynArray[bytes4, MAX_COINS],
    _oracles: DynArray[address, MAX_COINS],
):
    ...

    # EIP712 related params -----------------
    NAME_HASH = keccak256(name)
    salt = block.prevhash
    CACHED_CHAIN_ID = chain.id
    CACHED_DOMAIN_SEPARATOR = keccak256(
        _abi_encode(
            EIP712_TYPEHASH,
            NAME_HASH,
            VERSION_HASH,
            chain.id,
            self,
            salt,
        )
    )

    ...
>>> LPToken.salt()
HexBytes('0x814188b56f08130fe7b283343b64baa08f4d207229dc52776968b62b977c8f46')

DOMAIN_SEPARATOR

LPToken.DOMAIN_SEPERATOR() -> bytes32: view

Getter for the domain seperator.

Returns: domain seperator (bytes32).

Source code
CACHED_DOMAIN_SEPARATOR: immutable(bytes32)

@view
@external
def DOMAIN_SEPARATOR() -> bytes32:
    """
    @notice EIP712 domain separator.
    @return bytes32 Domain Separator set for the current chain.
    """
    return self._domain_separator()

@view
@internal
def _domain_separator() -> bytes32:
    if chain.id != CACHED_CHAIN_ID:
        return keccak256(
            _abi_encode(
                EIP712_TYPEHASH,
                NAME_HASH,
                VERSION_HASH,
                chain.id,
                self,
                salt,
            )
        )
    return CACHED_DOMAIN_SEPARATOR
>>> LPToken.DOMAIN_SEPARATOR()
HexBytes('0xf60903716a331f2ad023b28477aceee88e5180cab4694c497f4f9cefac657989')