if the vault is denominated in A on input and output, totalAssets should return the total value of A that would be received by liquidating the position in B.
Is B a derivative of A like cDAI:DAI?
if the vault is denominated in A on input and output, totalAssets should return the total value of A that would be received by liquidating the position in B.
Is B a derivative of A like cDAI:DAI?
Thanks for taking the time!
A is WETH and B is icETH, and the swapping happens through a DEX. icETH has a debt component of WETH and an equity component of stETH.
So, we would need an oracle to get DEX prices.
ideally the vault would report underlying in WETH as I mentioned above. Make sure the share price is manipulation resistant (an oracle would be a good way to do this).
What should be the flow for the native currency (ETH) as an underlying?
Is it better to change the deposit/withdraw to payable
or have an additional function for handling ETH deposits (depositETH/withdrawETH)?
Its a bit late now that the ERC is finalized, but I’m wondering why “minOut” / “maxIn” parameters were not included in the deposit
, mint
, withdraw
and redeem
functions.
While the preview functions give an accurate prediction, this may change between the moment a user signs a transaction and the moment its mined. Frontrunning in particular make this ERC possibly dangerous without these additional checks.
I would recommend this ERC gets extended to include
function deposit(uint256 assets, address receiver, uint256 minShares) external returns (uint256 shares) {
shares = deposit(assets, receiver);
require(shares >= minShares);
}
function mint(uint256 shares, address receiver, uint256 maxAssets) external returns (uint256 assets) {
assets = mint(shares, receiver);
require(assets <= maxAssets);
}
function withdraw(uint256 assets, address receiver, address owner, uint256 maxShares) external returns (uint256 shares) {
shares = withdraw(assets, receiver, owner);
require(shares <= maxShares);
}
function redeem(uint256 shares, address receiver, address owner, uint256 minAssets) external returns (uint256 assets) {
assets = redeem(shares, receiver, owner);
require(assets >= minAssets);
}
As per the spec,
“Total amount of the underlying asset that is “managed” by Vault.”
Should the totalAssets return the underlying asset deposited + extra assets including airdrops, donation etc OR only assets deposited to the vault ?
If its latter, then only returning vault balance of asset is not enough.
At mStable we are building a number of different EIP-4626 vaults. One of them deposits assets in an AMM. We have implemented a mechanism to protect against sandwich attacks by limiting the amount of slippage allowed on operational functions like deposit
, mint
, withdraw
and redeem
.
My question is in regards to the preview functions. Should the preview functions revert if there is too much slippage like the operational functions?
For previewDeposit
, the EIP states “MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also cause deposit to revert.”
So is too much slippage a “vault specific user/global limit”?
Or is it “other conditions that would also cause deposit to revert”?
Personally, don’t think the preview functions should revert if there is more slippage than what the vault allows.
Should totalAssets
include slippage or not?
The EIP for convertToShares
and convertToAssets
states
MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
Does this same statement apply to totalAssets
?
BTW, I don’t like the “or other on-chain conditions” statement. Transactions can only see on-chain conditions so it’s impossible for convertToShares
and convertToAssets
not to reflect on-chain conditions. eg the amount of shares and assets in the vault is an on-chain condition.
Personally, I think totalAssets
needs to be consistent with convertToShares
and convertToAssets
and not include slippage or fees.
I have another clarification to the preview functions.
The specification for previewDeposit
states
Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given current on-chain conditions.
The “current block” implies that the on-chain conditions is at a block level and not transaction level. That is, previewDeposit
needs to allow for other transactions being included before it in the block. For vaults that have slippage, that would mean previewDeposit
would have to return the worst case of a sandwich attacked transaction before it reverted with a slippage error.
But the previewDeposit
specification also states
MUST return as close to and no more than the exact amount of Vault shares that would be minted in a
deposit
call in the same transaction. I.e.deposit
should return the same or moreshares
aspreviewDeposit
if called in the same transaction.
This statement implies that the on-chain conditions is at a transaction level and not block level.
Personally, I think the preview functions should be at a transaction level rather than block level. I would recommend changing the first line of the previewDeposit
specification to
Allows an on-chain or off-chain user to simulate the effects of their deposit at the current transaction, given current on-chain conditions.
The same also applies to mint
, redeem
and withdraw
.
100% agree with that.
I think its for the caller to decide what outcomes are good for him.
I would like to suggest an extension of EIP-4626 that allows for more cost-efficient redemptions. Currently, redemptions return the underlying asset of a vault. However, in cases where yield is generated by taking positions in assets other than the vault’s underlying asset, it would be more efficient for an EOA to source their own liquidity upon redemption, for example via an off-chain RfQ.
A solution would be a multi-asset redeem function that returns a basket of tokens. The return values of such a function and the corresponding preview would be dynamic arrays address[] and uint256[] for the tokens and amounts (to be) returned.
To revert, or not to revert, that is the question.
The specifications does not explicitly state if a deposit
, mint
, withdraw
, redeem
should revert or not revert if zero amounts are returned.
Looking at the various implementations, most are going with they should not revert unless there is an integer overflow. For example, rounding down the result by subtracting it by one when the value is an unsigned zero will revert.
See Should ERC4626 txs revert with zero amounts? · Issue #314 · transmissions11/solmate · GitHub
I’m too late for this comment, given the standard has been finalized and is now seeming to get some traction (yay!). So I guess I’m asking for advice. In accounting, Assets - Liabilities == Equity. Given many vaults don’t have liabilities, Assets == Equity. However, for vaults that do have liabilities (accrued fees, or senior loans to the vault), they are not the same. I’d love to see totalLiabilities()
and totalEquity()
as part of the standard, but I’m a little late for that. Here’s the advice I’d like: seems like a lot of clients might make the assumption that totalAssets() == convertToAssets(totalSupply())
. So I have a choice: implement so totalAssets()
is actually equity value (assets - liabilities), so that assumption is correct, and provide a nonstandard totalLiabilities()
function so clients could add them to get actual total assets. Or, totalAssets()
can be the total amount managed by the vault, and there’s a separate function totalEquity()
which equals convertToAssets(totalSupply())
. Thoughts?
Could someone point out a compliant implementation of ERC4626 with fees? We don’t know how to interpret the specification’s wording about functions being “inclusive of fees”.
There are many different types of fees that you could use, but some common ones are:
In all cases, we designed 4626 to be inclusive of fees so that apples to apples comparisons of protocols are more possible. For example, on deposit and withdrawal, the language enforces that it must be the total amount coming in, and the final amount issued as well as the total amount redeemed and the final amount sent out. This means that withdrawal and deposit fees should be levied internally to the code, and the amount post fee is given as an output. The end result is the effective exchange rate you paid is worse, which means the vault would accurately describe the exchange of assets to shares and back again that is occurring.
Management fees and performance fees are a little easier, both are basically the rate at which the conversion functions change their output. The guidance there is that both preview and convert functions should be inclusive of these types of fees so that their answer remains accurate to what real depositors would see.
Originally we tried to be more specific about fees, but that’s a hard battle because there are so many different ways of imposing them. The guidance provided by ERC4626 is more general, essentially just try to make your functions be as honest as possible to what real depositors should expect.
It is unclear to me what the events should be when dealing with fees.
Lets take an example, where there is a 5% deposit fee,
In that context, previewDeposit(100)
is 95
. But what should the use for assets ? 100? 95?
Same question for a mint:
In that context, previewMint(100)
is 106
. But what should the use for assets in the event ? 100? 106?
FIY, the event is described as
Deposit
sender
has exchangedassets
forshares
, and transferred thoseshares
toowner
.MUST be emitted when tokens are deposited into the Vault via the
mint
anddeposit
methods.- name: Deposit type: event inputs: - name: sender indexed: true type: address - name: owner indexed: true type: address - name: assets indexed: false type: uint256 - name: shares indexed: false type: uint256
said otherwize, should the “assets” params in these event reflect:
How much the user paid/got
After some discussion we think this is the right option according to the guideline shared above:
Please who can help me with a list of platforms that talks with ERC 4626 standard? I mean platforms that expects to integrate dapps built on ERC 4626 → ERC-4626: Tokenized Vaults