-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5eadf8d
commit fb9e76f
Showing
5 changed files
with
280 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[project] | ||
authors = ["Fuel Labs <[email protected]>"] | ||
entry = "src_5.sw" | ||
license = "Apache-2.0" | ||
name = "src_5" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<p align="center"> | ||
<picture> | ||
<source media="(prefers-color-scheme: dark)" srcset=".docs/src-5-logo-dark-theme.png"> | ||
<img alt="SRC-5 logo" width="400px" src=".docs/src-5-logo-light-theme.png"> | ||
</picture> | ||
</p> | ||
|
||
# Abstract | ||
The following standard allows for the implementation of a standard API for token vaults such as yield bearing token vaults. This standard is an optional add-on to the SRC-20 standard. | ||
|
||
# Motivation | ||
Token vaults allow users to own shares of variable amount of assets, such as lending protocols which may have growing assets due to profits from interest. This pattern is highly useful and would greatly benefit from standardisation | ||
|
||
# Prior Art | ||
Token vaults have been thoroughly explored on Ethereum and with [EIP 4626](https://eips.ethereum.org/EIPS/eip-4626) they have their own standard for it. However as Fuel's native assets are fundamentally different to Ethereum's ERC-20 tokens, the implementation will differ, but the interface may be used as reference. | ||
|
||
# Specification | ||
## Required public functions | ||
The following functions MUST be implemented (on top of the SRC-20 functions) to follow the SRC-6 standard | ||
|
||
### `fn deposit(receiver: Identity)` | ||
Method that allows depositing of the underlying asset in exchange for shares of the vault. | ||
|
||
MUST revert if any AssetId other than the underlying is forwarded. | ||
MUST mint `preview_deposit(deposited_assets)` amount of shares to `receiver` | ||
MUST increase `managed_assets` by `deposited_assets` (through any means including `std::context::this_balance(ASSET_ID)` if applicable) | ||
MUST increase `total_supply` by newly minted shares | ||
|
||
### `fn withdraw(asset: AssetId, receiver: Identity)` | ||
Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset | ||
|
||
MUST revert if any AssetId other than the AssetId of the self contract is forwarded. | ||
MUST send `preview_withdraw(redeemed_shares)` amount of assets to `receiver` | ||
MUST burn the received shares | ||
MUST reduce `total_assets` by `preview_withdraw(redeemed_shares)` | ||
MUST reduce `total_supply` by amount of burnt shares | ||
|
||
### `fn managed_assets(asset: AssetId) -> u64` | ||
Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault | ||
|
||
MUST return total amount of assets of underlying AssetId under management by vault | ||
|
||
### `fn convert_to_shares(asset: AssetId, assets: u64) -> Option<u64>` | ||
Helper method for converting | ||
|
||
|
||
|
||
## Required logs | ||
The following logs MUST be emitted at the specified occasions | ||
|
||
``` | ||
pub struct Deposit { | ||
caller: Identity, | ||
receiver: Identity, | ||
assets: u64, | ||
shares: u64, | ||
} | ||
``` | ||
`caller` has called the `deposit` method sending `assets` assets of the underlying asset_id, in exchange for `shares` shares sent to the receiver `receiver` | ||
|
||
The `Deposit` struct MUST be logged whenever new shares are minted via the `deposit` method | ||
|
||
``` | ||
pub struct Withdraw { | ||
caller: Identity, | ||
receiver: Identity, | ||
assets: u64, | ||
shares: u64, | ||
} | ||
``` | ||
`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets to the receiver `receiver` | ||
|
||
The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw` method | ||
|
||
# Rationale | ||
The ABI discussed is simple and covers the known use cases of token vaults while allowing safe implementations | ||
|
||
# Backwards compatibility | ||
This standard is fully compatible with the SRC-20 standard | ||
|
||
# Security Considerations | ||
Incorrect implementation of token vaults could allow attackers to steal underlying assets. It is recommended to properly audit any code using this standard to ensure exploits are not possible. | ||
|
||
# Reference implementation | ||
Full reference implementation can be seen [here](https://github.com/SwayStar123/vault-standard-reference-implementation/blob/master/src/main.sw) | ||
|
||
This is a draft standard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
library; | ||
|
||
// Required logs: | ||
|
||
/// Event logged when a deposit is made. | ||
pub struct Deposit { | ||
/// The caller of the deposit function. | ||
caller: Identity, | ||
/// The receiver of the deposit. | ||
receiver: Identity, | ||
/// The asset being deposited. | ||
asset: AssetId, | ||
/// The amount of assets being deposited. | ||
assets: u64, | ||
/// The amount of shares being minted. | ||
shares: u64, | ||
} | ||
|
||
/// Event logged when a withdrawal is made. | ||
pub struct Withdraw { | ||
/// The caller of the withdrawal function. | ||
caller: Identity, | ||
/// The receiver of the withdrawal. | ||
receiver: Identity, | ||
/// The asset being withdrawn. | ||
asset: AssetId, | ||
/// The amount of assets being withdrawn. | ||
assets: u64, | ||
/// The amount of shares being burned. | ||
shares: u64, | ||
} | ||
|
||
abi SRC6 { | ||
// SRC-6 | ||
// Deposit/Withdrawal | ||
|
||
/// Deposits assets into the contract and mints shares to the receiver. | ||
/// | ||
/// # Additional Information | ||
/// | ||
/// * Assets must be forwarded to the contract in the contract call. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `receiver`: [Identity] - The receiver of the shares. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [u64] - The amount of shares minted. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * If the asset is not supported by the contract. | ||
/// * If the amount of assets is zero. | ||
/// * The user crosses any global or user specific deposit limits. | ||
#[storage(read, write)] | ||
fn deposit(receiver: Identity) -> u64; | ||
/// Burns shares from the sender and transfers assets to the receiver. | ||
/// | ||
/// # Additional Information | ||
/// | ||
/// * Shares must be forwarded to the contract in the contract call. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the shares should be burned. | ||
/// * `receiver`: [Identity] - The receiver of the assets. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [u64] - The amount of assets transferred. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * If the asset is not supported by the contract. | ||
/// * If the amount of shares is zero. | ||
/// * If the transferred shares do not corresspond to the given asset. | ||
/// * The user crosses any global or user specific withdrawal limits. | ||
#[storage(read, write)] | ||
fn withdraw(asset: AssetId, receiver: Identity) -> u64; | ||
|
||
// Accounting | ||
|
||
/// Returns the amount of managed assets of the given asset. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the amount of managed assets should be returned. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [u64] - The amount of managed assets of the given asset. | ||
#[storage(read)] | ||
fn managed_assets(asset: AssetId) -> u64; | ||
/// Returns how many shares would be minted for the given amount of assets, in an ideal scenario (No accounting for slippage, or any limits). | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the amount of shares should be returned. | ||
/// * `assets`: [u64] - The amount of assets for which the amount of shares should be returned. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [Some(u64)] - The amount of shares that would be minted for the given amount of assets. | ||
/// * [None] - If the asset is not supported by the contract. | ||
#[storage(read)] | ||
fn convert_to_shares(asset: AssetId, assets: u64) -> Option<u64>; | ||
/// Returns how many assets would be transferred for the given amount of shares, in an ideal scenario (No accounting for slippage, or any limits). | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the amount of assets should be returned. | ||
/// * `shares`: [u64] - The amount of shares for which the amount of assets should be returned. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [Some(u64)] - The amount of assets that would be transferred for the given amount of shares. | ||
/// * [None] - If the asset is not supported by the contract. | ||
#[storage(read)] | ||
fn convert_to_assets(asset: AssetId, shares: u64) -> Option<u64>; | ||
/// Returns how many shares would have been minted for the given amount of assets, if this was a deposit call. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the amount of shares should be returned. | ||
/// * `assets`: [u64] - The amount of assets for which the amount of shares should be returned. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [u64] - The amount of shares that would have been minted for the given amount of assets. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * For any reason a deposit would revert. | ||
#[storage(read)] | ||
fn preview_deposit(asset: AssetId, assets: u64) -> u64; | ||
/// Returns how many assets would have been transferred for the given amount of shares, if this was a withdrawal call. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the amount of assets should be returned. | ||
/// * `shares`: [u64] - The amount of shares for which the amount of assets should be returned. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [u64] - The amount of assets that would have been transferred for the given amount of shares. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * For any reason a withdrawal would revert. | ||
#[storage(read)] | ||
fn preview_withdraw(asset: AssetId, shares: u64) -> u64; | ||
|
||
// Deposit/Withdrawal Limits | ||
|
||
/// Returns the maximum amount of assets that can be deposited into the contract, for the given asset. | ||
/// | ||
/// # Additional Information | ||
/// | ||
/// Does not account for any user or global limits. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the maximum amount of depositable assets should be returned. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [Some(u64)] - The maximum amount of assets that can be deposited into the contract, for the given asset. | ||
/// * [None] - If the asset is not supported by the contract. | ||
#[storage(read)] | ||
fn max_depositable(asset: AssetId) -> Option<u64>; | ||
/// Returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. | ||
/// | ||
/// # Additional Information | ||
/// | ||
/// Does not account for any user or global limits. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `asset`: [AssetId] - The asset for which the maximum amount of withdrawable assets should be returned. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * [Some(u64)] - The maximum amount of assets that can be withdrawn from the contract, for the given asset. | ||
/// * [None] - If the asset is not supported by the contract. | ||
#[storage(read)] | ||
fn max_withdrawable(asset: AssetId) -> Option<u64>; | ||
} |