Skip to content

Commit

Permalink
4626 updates (#4806)
Browse files Browse the repository at this point in the history
* 4626 cleanup

* format

Co-authored-by: Joey Santoro <[email protected]>
  • Loading branch information
Joeysantoro and Joey Santoro authored Feb 15, 2022
1 parent b76f12f commit 92b55f2
Showing 1 changed file with 31 additions and 87 deletions.
118 changes: 31 additions & 87 deletions EIPS/eip-4626.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,45 +21,42 @@ and withdrawing tokens and reading balances.
## Motivation

Tokenized Vaults have a lack of standardization leading to diverse implementation details.
Some various examples include lending markets (Compound, Aave, Fuse),
aggregators (Yearn, Rari Vaults, Idle), and intrinsically interest bearing tokens (xSushi).
This makes integration difficult at the aggregator or plugin layer for protocols which need to conform to many standards.
This forces each protocol to implement their own adapters which are error prone and waste development resources.
Some various examples include lending markets, aggregators, and intrinsically interest bearing tokens.
This makes integration difficult at the aggregator or plugin layer for protocols which need to conform to many standards, and forces each protocol to implement their own adapters which are error prone and waste development resources.

A standard for tokenized Vaults will allow for a similar cambrian explosion to ERC-20,
unlocking access to yield and other strategies in a variety of applications
with little specialized effort from developers.
A standard for tokenized Vaults will lower the integration effort for yield-bearing vaults, while creating more consistent and robust implementation patterns.

## Specification

All ERC-4626 tokenized Vaults MUST implement ERC-20 to represent shares.
If a Vault is to be non-transferrable, it MAY revert on calls to transfer or transferFrom.
The ERC-20 operations balanceOf, transfer, totalSupply, etc. operate on the Vault "shares"
If a Vault is to be non-transferrable, it MAY revert on calls to `transfer` or `transferFrom`.
The ERC-20 operations `balanceOf`, `transfer`, `totalSupply`, etc. operate on the Vault "shares"
which represent a claim to ownership on a fraction of the Vault's underlying holdings.

All ERC-4626 MUST implement ERC-20's optional metadata extensions.
The `name` and `symbol` functions should reflect the underlying token's `name` and `symbol` in some way.
The value of `decimals` can mirror the underlying's value of `decimals`,
All ERC-4626 tokenized Vaults MUST implement ERC-20's optional metadata extensions.
The `name` and `symbol` functions SHOULD reflect the underlying token's `name` and `symbol` in some way.
The value of `decimals` MUST mirror the underlying's value of `decimals`,
which may affect precision for computing the value of Vault shares

ERC-4626 MAY implement [EIP-2612](./eip-2612.md) to improve the UX of approving shares on various integrations.
ERC-4626 tokenized Vaults MAY implement [EIP-2612](./eip-2612.md) to improve the UX of approving shares on various integrations.

### Definitions:
- asset: The underlying token managed by the Vault.
Has units defined by the corresponding ERC20 contract.
Has units defined by the corresponding ERC-20 contract.
- share: The token of the Vault. Has a ratio of underlying assets
exchanged on mint/deposit/withdraw/redeem (defined by the Vault).
exchanged on mint/deposit/withdraw/redeem (as defined by the Vault).
- fee: An amount of assets or shares charged to the user by the Vault. Fees can exists for
deposits, yield, AUM, withdrawals, or anything else prescribed by the Vault.
- slippage: Any difference between advertised share price and economic realities of
deposit to or withdrawal from the Vault, which is not accounted by fees.
- fee: An amount of assets or shares charged to the Vault. Can be a fee on deposits, yield, AUM, withdrawal, or any other kind of fee.

### Methods

#### asset

The address of the underlying token used for the Vault uses for accounting, depositing, and withdrawing.
The address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
MUST be an ERC-20 token contract.
MUST *NOT* revert.
MUST _NOT_ revert.

```yaml
- name: asset
Expand All @@ -78,7 +75,7 @@ MUST *NOT* revert.
Total amount of the underlying asset that is "managed" by Vault.
SHOULD include any compounding that occurs from yield.
MUST be inclusive of any fees that are charged against assets in the Vault.
MUST *NOT* revert.
MUST _NOT_ revert.
```yaml
- name: totalAssets
Expand All @@ -92,64 +89,14 @@ MUST *NOT* revert.
type: uint256
```
#### assetsPerShare
The current exchange rate of shares to assets, quoted per unit share (share unit is `10 ** Vault.decimals()`).

MUST be inclusive of any fees that are charged against assets in the Vault.
MAY *NOT* be completely accurate according to slippage or other on-chain conditions,
when performing the actual exchange.
MUST *NOT* return 0.
MUST *NOT* revert.

In certain types of fee calculations, this calculation MAY *NOT* reflect the "per-user" price-per-share,
and instead should reflect the "average-user's" price-per-share,
meaning what the average user should expect to see when exchanging to and from.
The `assetsOf` method SHOULD be used for more accurate calculations of a user's underlying balance.

```yaml
- name: assetsPerShare
type: function
stateMutability: view
inputs: []
outputs:
- name: assetsPerUnitShare
type: uint256
```

#### assetsOf

Total number of underlying assets that `depositor`'s shares represent.

MAY be more accurate than using `assetsPerShare` or `totalAssets / Vault.totalSupply`
for certain types of fee calculations.
MAY *NOT* be completely accurate according to slippage or other on-chain conditions.
MUST *NOT* revert.

```yaml
- name: assetsOf
type: function
stateMutability: view
inputs:
- name: depositor
type: address
outputs:
- name: assets
type: uint256
```

#### maxDeposit
Total number of underlying assets that `caller` can be deposit.
Total number of underlying assets that `caller` can deposit.

MUST return a limited value if `caller` is subject to some deposit limit.
MUST return `2 ** 256 - 1` if there is no limit on the maximum amount of assets that may be deposited.
MAY be used in the `previewDeposit` or `deposit` methods for `assets` input parameter.
MUST *NOT* revert.
MUST _NOT_ revert.

```yaml
- name: maxDeposit
Expand All @@ -173,7 +120,7 @@ given current on-chain conditions.
MUST return the *exact* amount of Vault shares that would be minted if the caller were to deposit
a given *exact* amount of underlying assets using the `deposit` method.
MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
MUST *NOT* revert.
MUST _NOT_ revert.

Note that any discrepancy between `shares * assetsPerShare` and `assets` SHOULD be considered slippage
in share price or some other type of condition, meaning the depositor will lose assets by depositing.
Expand Down Expand Up @@ -223,12 +170,12 @@ Note that most implementations will require pre-approval of the Vault with the V

#### maxMint

Total number of underlying shares that `caller` can be mint.
Total number of underlying shares that `caller` can mint.

MUST return a limited value if `caller` is subject to some deposit limit.
MUST return `2 ** 256 - 1` if there is no limit on the maximum amount of shares that may be minted.
MAY be used in the `previewMint` or `mint` methods for `shares` input parameter.
MUST *NOT* revert.
MUST _NOT_ revert.

```yaml
- name: maxMint
Expand All @@ -252,7 +199,7 @@ given current on-chain conditions.
MUST return the *exact* amount of underlying assets that would be deposited by the caller in exchange
for minting a given *exact* amount of Vault shares using the `mint` method.
MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
MUST *NOT* revert.
MUST _NOT_ revert.

Note that any discrepancy between `assets / assetsPerShare` and `shares` SHOULD be considered slippage
in share price or some other type of condition, meaning the depositor will lose assets by minting.
Expand Down Expand Up @@ -307,7 +254,7 @@ Total number of underlying assets that `caller` can withdraw.
MUST return a limited value if `caller` is subject to some withdrawal limit or timelock.
MUST return `assetsOf(caller)` if `caller` is not subject to any withdrawal limit or timelock.
MAY be used in the `previewWithdraw` or `withdraw` methods for `assets` input parameter.
MUST *NOT* revert.
MUST _NOT_ revert.

```yaml
- name: maxWithdraw
Expand All @@ -331,7 +278,7 @@ given current on-chain conditions.
MUST return the *exact* amount of Vault shares that would be redeemed by the caller if withdrawing
a given *exact* amount of underlying assets using the `withdraw` method.
MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
MUST *NOT* revert.
MUST _NOT_ revert.

Note that any discrepancy between `shares / assetsPerShare` and `assets` SHOULD be considered slippage
in share price or some other type of condition, meaning the withdrawer will lose assets by withdrawing.
Expand Down Expand Up @@ -389,7 +336,7 @@ Total number of underlying shares that `caller` can redeem.
MUST return a limited value if `caller` is subject to some withdrawal limit or timelock.
MUST return `balanceOf(caller)` if `caller` is not subject to any withdrawal limit or timelock.
MAY be used in the `previewRedeem` or `redeem` methods for `shares` input parameter.
MUST *NOT* revert.
MUST _NOT_ revert.

```yaml
- name: maxRedeem
Expand All @@ -413,7 +360,7 @@ given current on-chain conditions.
MUST return the *exact* amount of underlying assets that would be withdrawn by the caller if redeeming
a given *exact* amount of Vault shares using the `redeem` method.
MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
MUST *NOT* revert.
MUST _NOT_ revert.

Note that any discrepancy between `assets * assetsPerShare` and `shares` SHOULD be considered slippage
in share price or some other type of condition, meaning the withdrawer will lose assets by redeeming.
Expand Down Expand Up @@ -470,7 +417,8 @@ Those methods should be performed separately.

`sender` has exchanged `assets` for `shares`, and transferred those `shares` to `receiver`.

MUST be emitted when tokens are deposited into the Vault in `ERC4626.mint` or `ERC4626.deposit` methods.
MUST be emitted when tokens are deposited into the Vault via the `mint` and `deposit` methods.


```yaml
- name: Deposit
Expand Down Expand Up @@ -528,7 +476,7 @@ This standardization makes the Vaults immediately compatible with all ERC-20 use

The mint method was included for symmetry and feature completeness.
Most current use cases of share-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).
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.

A single `assetsPerShare` method can only be guaranteed to be exact with one of the four mutable methods,
Expand All @@ -539,7 +487,7 @@ underlying need the result of a `withdraw` call. Similar use cases can be found

As such, the `assetsPerShare` method has been kept for ease of integration on part of the simpler use cases,
but `preview*` methods have been included for each one of the four mutable methods.
In each case, the value of a preview method is only guaranteed to equal the return value of the relted mutable method
In each case, the value of a preview method is only guaranteed to equal the return value of the related mutable method
if called immediately before in the same transaction.

The `max*` methods are used to check for deposit/withdraw limits on vault capacity. These can be consumed off-chain for more user focused applications or on-chain for more on-chain aggregation/integration use cases.
Expand Down Expand Up @@ -568,13 +516,9 @@ Fully permissionless use cases could fall prey to malicious implementations whic
It is recommended that all integrators review the implementation for potential ways of losing user deposits before integrating.

The methods `totalAssets`, `assetsPerShare` and `assetsOf` are estimates useful for display purposes,
and do *not* have to confer the *exact* amount of underlying assets their context suggests.
and do _not_ have to confer the _exact_ amount of underlying assets their context suggests.
Integrators of ERC-4626 Vaults should be aware of the difference between these view methods when integrating with this standard.

If the `preview*` methods are not exactly equivalent to the outcomes of their corresponding mutable methods,
there could be a denial-of-service effect from attempting the same action within the span of transaction.
Implementors must ensure that the quoted exchange rate is the same regardless of whether it is executed or not.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

0 comments on commit 92b55f2

Please sign in to comment.