Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP-4626: Preview functions #4705

Merged
merged 2 commits into from
Jan 22, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 36 additions & 21 deletions EIPS/eip-4626.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ All tokenized vaults MUST implement ERC-20. If a vault is to be non-transferrabl

Mints `shares` amount of vault tokens to `to` by depositing exactly `value` underlying tokens.

`shares` MUST equal the return value of a `previewMint` call, with `value` as a parameter, executed immediately before `deposit` in the same transaction.

MUST support the ERC-20 transferFrom flow where the vault has at least `value` approval over msg.sender's balance of underlying.

MAY support an additional flow in which the underlying tokens are owned by the vault contract before the `deposit` execution, and are accounted for during `deposit`.
Expand All @@ -45,14 +47,12 @@ MUST emit the `Deposit` event.

Mints exactly `shares` amount of vault tokens to `to` by depositing `value` underlying tokens.

`value` MUST equal the return value of a `calculateUnderlying` call, with `shares` as a parameter, executed immediately before `withdraw` in the same transaction.
`value` MUST equal the return value of a `previewMint` call, with `shares` as a parameter, executed immediately before `withdraw` in the same transaction.

MUST support the ERC-20 transferFrom flow where the vault has at least `value` approval over msg.sender's balance of underlying.

MAY support an additional flow in which the underlying tokens are owned by the vault contract before the `mint` execution, and are accounted for during `mint`.



MUST emit the `Deposit` event.

#### withdraw
Expand All @@ -61,7 +61,7 @@ MUST emit the `Deposit` event.

Burns `shares` vault tokens from `from`, withdrawing exactly `value` underlying tokens to `to`.

`shares` MUST equal the return value of a `calculateShares` call, with `value` as a parameter, executed immediately before `mint` in the same transaction.
`shares` MUST equal the return value of a `previewWithdraw` call, with `value` as a parameter, executed immediately before `mint` in the same transaction.

MUST support the ERC-20 flow in which the `from` address holds the `shares` vault tokens being burned. If `from != msg.sender`, then `msg.sender` MUST have ERC-20 approval over at least `shares` vault tokens from `from`.

Expand All @@ -75,40 +75,57 @@ MUST emit the `Withdraw` event.

Burns exactly `shares` vault tokens from `from`, withdrawing `value` underlying tokens to `to`.

`value` MUST equal the return value of a `previewRedeem` call, with `shares` as a parameter, executed immediately before `redeem` in the same transaction.

MUST support the ERC-20 flow in which the `from` address holds the `shares` vault tokens being burned. If `from != msg.sender`, then `msg.sender` MUST have ERC-20 approval over at least `shares` vault tokens from `from`.

MAY support an additional flow in which the vault tokens being burned are owned by the vault contract before the `redeem` execution, instead of being owned by `from`.

MUST emit the `Withdraw` event.

#### underlying
`function underlying() public view returns (address)`

Returns the address of the token the vault uses for accounting, depositing, and withdrawing.

MUST return the address of a token implementing the ERC-20 standard.

#### totalUnderlying
`function totalUnderlying() public view returns (uint256)`

Returns the total amount of underlying tokens held/managed by the vault.
Returns the total amount of underlying tokens managed by the vault.

#### balanceOfUnderlying
`function balanceOfUnderlying(address owner) public view returns (uint256)`

Returns the total amount underlying tokens held in the vault for `owner`.
Returns the value in underlying terms of the vault tokens held by `owner`. Equivalent to `previewRedeem(balanceOf(owner))`.

#### underlying
`function underlying() public view returns (address)`
#### exchangeRate
`function exchangeRate() public view returns (uint256)`

Returns the address of the token the vault uses for accounting, depositing, and withdrawing.
Returns the value in underlying terms of one vault token. Equivalent to `previewRedeem(10 ** decimals())`.

MUST return the address of a token implementing the ERC-20 standard.

#### calculateShares
`function calculateShares(uint256 underlyingAmount) public view returns (uint256 shareAmount)`
#### previewDeposit
`function previewDeposit(uint256 underlyingAmount) public view returns (uint256 shareAmount)`

Returns the amount of vault tokens that need to be burned to obtain a given amount of underlying tokens in a `withdraw` call.
#### calculateUnderlying
Returns the amount of vault tokens that would be obtained if depositing a given amount of underlying tokens in a `deposit` call.

#### previewMint

`function calculateUnderlying(uint256 shareAmount) public view returns (uint256 underlyingAmount)`;
`function previewMint(uint256 shareAmount) public view returns (uint256 underlyingAmount)`;

Returns the amount of underlying tokens that need to be given to the vault to obtain a given amount of vault tokens in a `mint` call.

#### previewWithdraw
`function previewWithdraw(uint256 underlyingAmount) public view returns (uint256 shareAmount)`

Returns the amount of vault tokens that need to be burned to obtain a given amount of underlying tokens in a `withdraw` call.

#### previewRedeem
`function previewRedeem(uint256 shareAmount) public view returns (uint256 underlyingAmount)`

Returns the amount of underlying tokens that would be obtained by redeeming a given amount of vault tokens in a `redeem` call.

### Events

#### Deposit
Expand All @@ -119,7 +136,6 @@ MUST be emitted when tokens are deposited into the vault.

Where `from` is the user who triggered the deposit for `value` underlying tokens to the vault, and `to` is the user who is able to withdraw the deposited tokens.


#### Withdraw

MUST be emitted when tokens are withdrawn from the vault by a depositor.
Expand All @@ -128,7 +144,6 @@ MUST be emitted when tokens are withdrawn from the vault by a depositor.

Where `from` is the owner who and held `value` underlying tokens in the vault, and `to` is the user who received the withdrawn tokens.


## Rationale

The vault interface is designed to be optimized for integrators with a feature complete yet minimal interface. Details such as accounting and allocation of deposited tokens are intentionally not specified, as vaults are expected to be treated as black boxes on-chain and inspected off-chain before use.
Expand All @@ -139,9 +154,9 @@ The vaults are opinionated on a default deposit/withdraw flow because it gives i

The mint function was included for symmetry and feature completeness. Most current use cases of shares based vaults do not ascribe special meaning to the shares such that a user would optimize for a specific number of shares (mint) rather than specific amount of underlying (deposit). However, it is easy to imagine future vault strategies which would have unique and independently useful share representations.

The `calculateShares` method cannot be guaranteed to be simultaneously exact with the return values for both `deposit` and `withdraw`. It matches the return value of `withdraw` to allow querying the vault for the exact amount of underlying that should be approved for transfer in a `withdraw` call for the current transaction. The inclusion of a `calculateSharesOnDeposit` function was considered unnecessary.
A single `exchangeRate()` function can only be guaranteed to be exact with one of the four mutable methods, unless significant conditions are placed on the use cases that can comply with this standard. Use cases that require to know the value of a vault position need to know the result of a `redeem` call, without executing it. On the other hand, integrators that intend to call `withdraw` on vaults with the user approving only the exact amount of underlying need the result of a `withdraw` call. Similar use cases can be found for `deposit` and `mint`.

The `calculateUnderlying` method cannot be guaranteed to be simultaneously exact with the return values for both `mint` and `redeem`. It matches the return value of `mint` to allow querying the vault for the exact amount of shares that should be taken from the caller in a `mint` call for the current transaction. The inclusion of a `calculateUnderlyingOnRedeem` function was considered unnecessary.
As such, the `exchangeRate()` function has been kept for ease of integration on part of the simpler use cases, but preview functions have been included for each one of the four mutable methods. In each case, the value of a preview function is only guaranteed to equal the return value of the relted mutable function if called immediately before in the same transaction.

## Backwards Compatibility

Expand Down