erc_4626.flow

Documentation for eth_defi.erc_4626.flow Python module.

Deposit and redemption from ERC-4626 vaults.

Functions

approve_and_deposit_4626(vault, from_, amount)

two ERC-20 calls needed to deposit.

approve_and_redeem_4626(vault, from_, amount)

two ERC-20 calls needed to deposit.

deposit_4626(vault, from_[, amount, ...])

Craft a transaction for ERC-4626 vault deposit.

redeem_4626(vault, owner[, amount, ...])

Craft a transaction for ERC-4626 vault deposit.

deposit_4626(vault, from_, amount=None, raw_amount=None, check_max_deposit=True, check_enough_token=True, receiver=None)

Craft a transaction for ERC-4626 vault deposit.

Example:

amount = Decimal(100)

tx_hash = base_usdc.approve(
    vault.address,
    amount,
).transact({"from": depositor})
assert_transaction_success_with_explanation(web3, tx_hash)

bound_func = deposit_4626(
    vault,
    depositor,
    amount,
)
tx_hash = bound_func.transact({"from": depositor})
assert_transaction_success_with_explanation(web3, tx_hash)
tx_receipt = web3.eth.get_transaction_receipt(tx_hash)

# Analyse the ERC-4626 deposit transaction
analysis = analyse_4626_flow_transaction(
    vault=vault,
    tx_hash=tx_hash,
    tx_receipt=tx_receipt,
    direction="deposit",
)
assert analysis.path == [base_usdc.address_lower, vault.share_token.address_lower]
assert analysis.price == pytest.approx(Decimal("1.033566972663402121955991264"))

Another example how to use this with Lagoon, where from (TradingStrategyModuleV0) and receiver (Safe multisig) are different contracts:

fn_calls = approve_and_deposit_4626(
    vault=erc4626_vault,  # IPOR vault we trade
    amount=usdc_amount,
    from_=vault.address,  # Our Lagoon vault
    check_enough_token=False,
    receiver=vault.safe_address,  # Safe multisig address of our Lagoon vault
)
Parameters
Return type

web3.contract.contract.ContractFunction

redeem_4626(vault, owner, amount=None, raw_amount=None, check_enough_token=True, check_max_redeem=True, receiver=None, epsilon=0.005)

Craft a transaction for ERC-4626 vault deposit.

Note

You need at least 6_000_000 gas to redeem from IPOR vault.

Key Differences Between Redeem and Withdraw in ERC-4626

Aspect

Redeem

Withdraw

Input

Number of shares to burn

Number of assets to receive

Output

Assets received

Shares burned

User Intent

Burn a specific number of shares

Receive a specific amount of assets

Calculation

Shares → Assets

Assets → Shares

Example:

shares = vault.share_token.fetch_balance_of(depositor, "latest")
assert shares == pytest.approx(Decimal("96.7523176"))

# See how much we get after all this time
estimated_usdc = estimate_4626_redeem(
    vault,
    depositor,
    shares,
)
assert estimated_usdc == pytest.approx(Decimal("99.084206"))

tx_hash = vault.share_token.approve(vault.address, shares).transact({"from": depositor})
assert_transaction_success_with_explanation(web3, tx_hash)

tx_hash = redeem_4626(vault, depositor, shares).transact({"from": depositor})
assert_transaction_success_with_explanation(web3, tx_hash)

# Analyse the ERC-4626 deposit transaction
analysis = analyse_4626_flow_transaction(
    vault=vault,
    tx_hash=tx_hash,
    tx_receipt=tx_receipt,
    direction="redeem",
)
assert isinstance(analysis, TradeSuccess)

assert analysis.path == [vault.share_token.address_lower, base_usdc.address_lower]
assert analysis.amount_in == pytest.approx(9675231765)
assert analysis.amount_out == pytest.approx(100000000)
assert analysis.amount_in_decimals == 8  # IPOR has 8 decimals
assert analysis.price == pytest.approx(Decimal("1.033566972663402121955991264"))
Parameters
  • vault (eth_defi.erc_4626.vault.ERC4626Vault) – ERC-4626 vault from where we redeem.

  • amount (decimal.Decimal | None) – Share token mount in human readable form.

  • owner (eth_typing.evm.HexAddress) –

    The hot wallet/vault storage contract which will receive the tokens.

    Matters in complex vault setups. Like in the case of Lagoon vault, the receiver is the Safe multisig address of the vault.

  • epsilon (float | None) – Handle rounding errors in the case of close all.

  • raw_amount (int | None) –

Return type

web3.contract.contract.ContractFunction

approve_and_deposit_4626(vault, from_, amount, check_max_deposit=True, check_enough_token=True, receiver=None)

two ERC-20 calls needed to deposit.

For documentation see deposit_4626().

Parameters
Return type

tuple[web3.contract.contract.ContractFunction, web3.contract.contract.ContractFunction]

approve_and_redeem_4626(vault, from_, amount, check_enough_token=True, check_max_redeem=True, receiver=None)

two ERC-20 calls needed to deposit.

For documentation see redeem_4626().

Parameters
Return type

tuple[web3.contract.contract.ContractFunction, web3.contract.contract.ContractFunction]