From fb9e76ff99360910ab3ce39c68610457e9bc1cb7 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Sun, 17 Sep 2023 20:26:43 +0530 Subject: [PATCH 01/75] initial commit --- .../src_6/.docs/src-5-logo-dark-theme.png | Bin 0 -> 20263 bytes .../src_6/.docs/src-5-logo-light-theme.png | Bin 0 -> 23249 bytes standards/src_6/Forc.toml | 5 + standards/src_6/README.md | 87 ++++++++ standards/src_6/src/src_6.sw | 188 ++++++++++++++++++ 5 files changed, 280 insertions(+) create mode 100644 standards/src_6/.docs/src-5-logo-dark-theme.png create mode 100644 standards/src_6/.docs/src-5-logo-light-theme.png create mode 100644 standards/src_6/Forc.toml create mode 100644 standards/src_6/README.md create mode 100644 standards/src_6/src/src_6.sw diff --git a/standards/src_6/.docs/src-5-logo-dark-theme.png b/standards/src_6/.docs/src-5-logo-dark-theme.png new file mode 100644 index 0000000000000000000000000000000000000000..6808e847963c9ae9130efd09e6f5e77ed1c829cc GIT binary patch literal 20263 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"] +entry = "src_5.sw" +license = "Apache-2.0" +name = "src_5" diff --git a/standards/src_6/README.md b/standards/src_6/README.md new file mode 100644 index 0000000..194abca --- /dev/null +++ b/standards/src_6/README.md @@ -0,0 +1,87 @@ +

+ + + SRC-5 logo + +

+ +# 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` +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 diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw new file mode 100644 index 0000000..7dd71c8 --- /dev/null +++ b/standards/src_6/src/src_6.sw @@ -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; + /// 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; + /// 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; + /// 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; +} From bdbc811e06a8f95f5239ce7511c3a7e77a71006c Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 25 Sep 2023 19:40:08 +0530 Subject: [PATCH 02/75] Update readme --- standards/src_6/Forc.toml | 4 +- standards/src_6/README.md | 91 ++++++++++++++++++++++++++++++++------- 2 files changed, 77 insertions(+), 18 deletions(-) diff --git a/standards/src_6/Forc.toml b/standards/src_6/Forc.toml index 1c433be..7beb7a0 100644 --- a/standards/src_6/Forc.toml +++ b/standards/src_6/Forc.toml @@ -1,5 +1,5 @@ [project] authors = ["Fuel Labs "] -entry = "src_5.sw" +entry = "src_6.sw" license = "Apache-2.0" -name = "src_5" +name = "src_6" diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 194abca..9b06e74 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -18,57 +18,117 @@ Token vaults have been thoroughly explored on Ethereum and with [EIP 4626](https ## 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)` +### `fn deposit(receiver: Identity) -> u64` Method that allows depositing of the underlying asset in exchange for shares of the vault. +This function takes the receiver's identity as an argument and returns the amount of shares minted. 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 +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` of the share's AssetId by newly minted shares. +MUST increase `total_assets` by one if the the AssetId is minted for the first time. +MUST emit a `Deposit` log. -### `fn withdraw(asset: AssetId, receiver: Identity)` +### `fn withdraw(asset: AssetId, receiver: Identity) -> u64` Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset +This function takes the asset's AssetId and the receiver's identity as arguments and returns the amount of assets transferred. +The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. -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 +MUST revert if any AssetId other than the AssetId corresponding to the deposited asset is forwarded. +MUST send `preview_withdraw(redeemed_shares)` amount of assets to `receiver`. +MUST burn the received shares. +MUST reduce `managed_assets` by `preview_withdraw(redeemed_shares)`. +MUST reduce `total_supply` of the shares's AssetId by amount of burnt shares. +MUST emit a `Withdraw` log. ### `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 +Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. +This function takes the asset's AssetId as an argument and returns the total amount of assets of AssetId under management by vault. -MUST return total amount of assets of underlying AssetId under management by vault +MUST return total amount of assets of underlying AssetId under management by vault. +MUST return 0 if there are no assets of underlying AssetId under management by vault. +MUST NOT revert under any circumstances. ### `fn convert_to_shares(asset: AssetId, assets: u64) -> Option` -Helper method for converting +Helper method for converting assets to shares. +This function takes the asset's AssetId and the amount of assets as arguments and returns the amount of shares that would be minted for the given amount of assets, in an ideal condition without slippage. +MUST return an Option::Some of the amount of shares that would be minted for the given amount of assets, without accounting for any slippage, if the given asset is supported. +MUST return an Option::None if the given asset is not supported. +MUST NOT revert under any circumstances. +### `fn convert_to_assets(asset: AssetId, shares: u64) -> Option` +Helper method for converting shares to assets. +This function takes the asset's AssetId and the amount of shares as arguments and returns the amount of assets that would be transferred for the given amount of shares, in an ideal condition without slippage. + +MUST return an Option::Some of the amount of assets that would be transferred for the given amount of shares, if the given asset is supported. +MUST return an Option::None if the asset is not supported. +MUST NOT revert under any circumstances. + +### `fn preview_deposit(asset: AssetId, assets: u64) -> u64` +Helper method for previewing deposit. +This function takes the asset's AssetId and the amount of assets as arguments and returns the amount of shares that would have been minted for the given amount of assets. + +MUST return the amount of shares that would have been minted for the given amount of assets. +MUST revert for any reason the `deposit` function would revert given the same conditions. + +### `fn preview_withdraw(asset: AssetId, shares: u64) -> u64` +Helper method for previewing withdraw +This function takes the asset's AssetId and the amount of shares as arguments and returns the amount of assets that would have been transferred for the given amount of shares. + +MUST return the amount of assets that would have been transferred for the given amount of shares. +MUST revert for any reason the `withdraw` function would revert given the same conditions. + +### `fn max_depositable(asset: AssetId) -> Option` +Helper method for getting maximum depositable +This function takes the asset's AssetId as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. + +MUST return the maximum amount of assets that can be deposited into the contract, for the given asset. + +### `fn max_withdrawable(asset: AssetId) -> Option` +Helper method for getting maximum withdrawable +This function takes the asset's AssetId as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. + +MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset. ## Required logs The following logs MUST be emitted at the specified occasions ``` +/// 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, } ``` -`caller` has called the `deposit` method sending `assets` assets of the underlying asset_id, in exchange for `shares` shares sent to the receiver `receiver` +`caller` has called the `deposit` method sending `assets` assets of the `asset` AssetId, 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 ``` +/// 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, } ``` -`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets to the receiver `receiver` +`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets of the `asset` AssetId to the receiver `receiver` The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw` method @@ -84,4 +144,3 @@ Incorrect implementation of token vaults could allow attackers to steal underlyi # 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 From d99d57b46b39ef7a94bec9be9fcdfcf1eefa8d2c Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 25 Sep 2023 20:37:48 +0530 Subject: [PATCH 03/75] forc fmt --- standards/src_6/src/src_6.sw | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 7dd71c8..5e97065 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -33,7 +33,6 @@ pub struct Withdraw { abi SRC6 { // SRC-6 // Deposit/Withdrawal - /// Deposits assets into the contract and mints shares to the receiver. /// /// # Additional Information @@ -78,9 +77,8 @@ abi SRC6 { /// * The user crosses any global or user specific withdrawal limits. #[storage(read, write)] fn withdraw(asset: AssetId, receiver: Identity) -> u64; - - // Accounting + // Accounting /// Returns the amount of managed assets of the given asset. /// /// # Arguments @@ -152,7 +150,6 @@ abi SRC6 { 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 From 90fef86c25145f7060dfcb1e6b6685d668e0d450 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 3 Oct 2023 16:16:21 +0530 Subject: [PATCH 04/75] Improve wording --- standards/src_6/README.md | 4 ++-- standards/src_6/src/src_6.sw | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 9b06e74..75f5368 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -20,7 +20,7 @@ The following functions MUST be implemented (on top of the SRC-20 functions) to ### `fn deposit(receiver: Identity) -> u64` Method that allows depositing of the underlying asset in exchange for shares of the vault. -This function takes the receiver's identity as an argument and returns the amount of shares minted. +This function takes the receiver's identity as an argument and returns the amount of shares minted to the receiver. MUST revert if any AssetId other than the underlying is forwarded. MUST mint `preview_deposit(deposited_assets)` amount of shares to `receiver`. @@ -31,7 +31,7 @@ MUST emit a `Deposit` log. ### `fn withdraw(asset: AssetId, receiver: Identity) -> u64` Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset -This function takes the asset's AssetId and the receiver's identity as arguments and returns the amount of assets transferred. +This function takes the asset's AssetId and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. MUST revert if any AssetId other than the AssetId corresponding to the deposited asset is forwarded. diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 5e97065..474a25a 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -31,8 +31,6 @@ pub struct Withdraw { } abi SRC6 { - // SRC-6 - // Deposit/Withdrawal /// Deposits assets into the contract and mints shares to the receiver. /// /// # Additional Information @@ -50,7 +48,7 @@ abi SRC6 { /// # Reverts /// /// * If the asset is not supported by the contract. - /// * If the amount of assets is zero. + /// * If the amount of assets forwarded to the contract is zero. /// * The user crosses any global or user specific deposit limits. #[storage(read, write)] fn deposit(receiver: Identity) -> u64; @@ -78,7 +76,6 @@ abi SRC6 { #[storage(read, write)] fn withdraw(asset: AssetId, receiver: Identity) -> u64; - // Accounting /// Returns the amount of managed assets of the given asset. /// /// # Arguments @@ -129,7 +126,7 @@ abi SRC6 { /// /// # Reverts /// - /// * For any reason a deposit would revert. + /// * For any reason the `deposit` function would revert given the same conditions. #[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. @@ -145,11 +142,10 @@ abi SRC6 { /// /// # Reverts /// - /// * For any reason a withdrawal would revert. + /// * For any reason the `withdraw` function would revert given the same conditions. #[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 From eaae21d0e1cb5f21a26e1fce1eaa18f3f81e7e4c Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 3 Oct 2023 16:54:26 +0530 Subject: [PATCH 05/75] req changes --- standards/src_6/README.md | 12 ++++++++++-- standards/src_6/src/src_6.sw | 2 -- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 75f5368..d1e6a1f 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -6,15 +6,19 @@

# 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 @@ -94,7 +98,7 @@ MUST return the maximum amount of assets that can be withdrawn from the contract ## Required logs The following logs MUST be emitted at the specified occasions -``` +```sway /// Event logged when a deposit is made. pub struct Deposit { /// The caller of the deposit function. @@ -113,7 +117,7 @@ pub struct Deposit { The `Deposit` struct MUST be logged whenever new shares are minted via the `deposit` method -``` +```sway /// Event logged when a withdrawal is made. pub struct Withdraw { /// The caller of the withdrawal function. @@ -133,14 +137,18 @@ pub struct Withdraw { 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) diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 474a25a..2895fb5 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -1,7 +1,5 @@ library; -// Required logs: - /// Event logged when a deposit is made. pub struct Deposit { /// The caller of the deposit function. From 614a197a178f26b9c7996335fdc53b96764cfa38 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 3 Oct 2023 17:30:29 +0530 Subject: [PATCH 06/75] add space between fn docs --- standards/src_6/src/src_6.sw | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 2895fb5..e3d054c 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -50,6 +50,7 @@ abi SRC6 { /// * 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 @@ -85,6 +86,7 @@ abi SRC6 { /// * [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 @@ -98,6 +100,7 @@ abi SRC6 { /// * [None] - If the asset is not supported by the contract. #[storage(read)] fn convert_to_shares(asset: AssetId, assets: u64) -> Option; + /// 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 @@ -111,6 +114,7 @@ abi SRC6 { /// * [None] - If the asset is not supported by the contract. #[storage(read)] fn convert_to_assets(asset: AssetId, shares: u64) -> Option; + /// Returns how many shares would have been minted for the given amount of assets, if this was a deposit call. /// /// # Arguments @@ -127,6 +131,7 @@ abi SRC6 { /// * For any reason the `deposit` function would revert given the same conditions. #[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 @@ -160,6 +165,7 @@ abi SRC6 { /// * [None] - If the asset is not supported by the contract. #[storage(read)] fn max_depositable(asset: AssetId) -> Option; + /// Returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. /// /// # Additional Information From 2967abcece136ebc3600cebd1456ad2565dfe550 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 3 Oct 2023 22:09:31 +0530 Subject: [PATCH 07/75] remove tab --- standards/src_6/src/src_6.sw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index e3d054c..cf3a443 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -50,7 +50,7 @@ abi SRC6 { /// * 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 From 0a25bf9e4bd59e6d334ca626e506095631c3ede2 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 10 Oct 2023 16:26:19 +0530 Subject: [PATCH 08/75] remove preview functions --- standards/src_6/README.md | 14 -------------- standards/src_6/src/src_6.sw | 34 ---------------------------------- 2 files changed, 48 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index d1e6a1f..1d4e105 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -69,20 +69,6 @@ MUST return an Option::Some of the amount of assets that would be transferred fo MUST return an Option::None if the asset is not supported. MUST NOT revert under any circumstances. -### `fn preview_deposit(asset: AssetId, assets: u64) -> u64` -Helper method for previewing deposit. -This function takes the asset's AssetId and the amount of assets as arguments and returns the amount of shares that would have been minted for the given amount of assets. - -MUST return the amount of shares that would have been minted for the given amount of assets. -MUST revert for any reason the `deposit` function would revert given the same conditions. - -### `fn preview_withdraw(asset: AssetId, shares: u64) -> u64` -Helper method for previewing withdraw -This function takes the asset's AssetId and the amount of shares as arguments and returns the amount of assets that would have been transferred for the given amount of shares. - -MUST return the amount of assets that would have been transferred for the given amount of shares. -MUST revert for any reason the `withdraw` function would revert given the same conditions. - ### `fn max_depositable(asset: AssetId) -> Option` Helper method for getting maximum depositable This function takes the asset's AssetId as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index cf3a443..85dea0f 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -115,40 +115,6 @@ abi SRC6 { #[storage(read)] fn convert_to_assets(asset: AssetId, shares: u64) -> Option; - /// 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 the `deposit` function would revert given the same conditions. - #[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 the `withdraw` function would revert given the same conditions. - #[storage(read)] - fn preview_withdraw(asset: AssetId, shares: u64) -> u64; - /// Returns the maximum amount of assets that can be deposited into the contract, for the given asset. /// /// # Additional Information From ac2f9134e246217c899b8ee7c7d50c0096e12f3b Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 17 Oct 2023 16:39:21 +0530 Subject: [PATCH 09/75] init --- standards/src_6/README.md | 22 ++++++++------- standards/src_6/src/src_6.sw | 52 +++++++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 1d4e105..2243796 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -22,7 +22,7 @@ Token vaults have been thoroughly explored on Ethereum and with [EIP 4626](https ## 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) -> u64` +### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` Method that allows depositing of the underlying asset in exchange for shares of the vault. This function takes the receiver's identity as an argument and returns the amount of shares minted to the receiver. @@ -33,7 +33,7 @@ MUST increase `total_supply` of the share's AssetId by newly minted shares. MUST increase `total_assets` by one if the the AssetId is minted for the first time. MUST emit a `Deposit` log. -### `fn withdraw(asset: AssetId, receiver: Identity) -> u64` +### `fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64` Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset This function takes the asset's AssetId and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. @@ -45,7 +45,7 @@ MUST reduce `managed_assets` by `preview_withdraw(redeemed_shares)`. MUST reduce `total_supply` of the shares's AssetId by amount of burnt shares. MUST emit a `Withdraw` log. -### `fn managed_assets(asset: AssetId) -> u64` +### `fn managed_assets(asset: AssetId, sub_id: SubId) -> u64` Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. This function takes the asset's AssetId as an argument and returns the total amount of assets of AssetId under management by vault. @@ -53,7 +53,7 @@ MUST return total amount of assets of underlying AssetId under management by vau MUST return 0 if there are no assets of underlying AssetId under management by vault. MUST NOT revert under any circumstances. -### `fn convert_to_shares(asset: AssetId, assets: u64) -> Option` +### `fn convert_to_shares(asset: AssetId, sub_id: SubId, assets: u64) -> Option` Helper method for converting assets to shares. This function takes the asset's AssetId and the amount of assets as arguments and returns the amount of shares that would be minted for the given amount of assets, in an ideal condition without slippage. @@ -61,7 +61,7 @@ MUST return an Option::Some of the amount of shares that would be minted for the MUST return an Option::None if the given asset is not supported. MUST NOT revert under any circumstances. -### `fn convert_to_assets(asset: AssetId, shares: u64) -> Option` +### `fn convert_to_assets(asset: AssetId, sub_id: SubId, shares: u64) -> Option` Helper method for converting shares to assets. This function takes the asset's AssetId and the amount of shares as arguments and returns the amount of assets that would be transferred for the given amount of shares, in an ideal condition without slippage. @@ -69,13 +69,13 @@ MUST return an Option::Some of the amount of assets that would be transferred fo MUST return an Option::None if the asset is not supported. MUST NOT revert under any circumstances. -### `fn max_depositable(asset: AssetId) -> Option` +### `fn max_depositable(asset: AssetId, sub_id: SubId) -> Option` Helper method for getting maximum depositable This function takes the asset's AssetId as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. MUST return the maximum amount of assets that can be deposited into the contract, for the given asset. -### `fn max_withdrawable(asset: AssetId) -> Option` +### `fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option` Helper method for getting maximum withdrawable This function takes the asset's AssetId as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. @@ -93,13 +93,15 @@ pub struct Deposit { receiver: Identity, /// The asset being deposited. asset: AssetId, + /// The SubId of the vault. + sub_id: SubId, /// The amount of assets being deposited. assets: u64, /// The amount of shares being minted. shares: u64, } ``` -`caller` has called the `deposit` method sending `assets` assets of the `asset` AssetId, in exchange for `shares` shares sent to the receiver `receiver` +`caller` has called the `deposit` method sending `assets` assets of the `asset` AssetId to the subvault of `sub_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 @@ -112,13 +114,15 @@ pub struct Withdraw { receiver: Identity, /// The asset being withdrawn. asset: AssetId, + /// The SubId of the vault. + sub_id: SubId, /// The amount of assets being withdrawn. assets: u64, /// The amount of shares being burned. shares: u64, } ``` -`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets of the `asset` AssetId to the receiver `receiver` +`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets of the `asset` AssetId from the subvault of `sub_id` to the receiver `receiver` The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw` method diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 85dea0f..5f4cc9c 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -8,6 +8,8 @@ pub struct Deposit { receiver: Identity, /// The asset being deposited. asset: AssetId, + /// The SubId of the vault. + sub_id: SubId, /// The amount of assets being deposited. assets: u64, /// The amount of shares being minted. @@ -22,6 +24,8 @@ pub struct Withdraw { receiver: Identity, /// The asset being withdrawn. asset: AssetId, + /// The SubId of the vault. + sub_id: SubId, /// The amount of assets being withdrawn. assets: u64, /// The amount of shares being burned. @@ -38,6 +42,7 @@ abi SRC6 { /// # Arguments /// /// * `receiver`: [Identity] - The receiver of the shares. + /// * `sub_id`: [SubId] - The SubId of the vault. /// /// # Returns /// @@ -49,7 +54,7 @@ abi SRC6 { /// * If the amount of assets forwarded to the contract is zero. /// * The user crosses any global or user specific deposit limits. #[storage(read, write)] - fn deposit(receiver: Identity) -> u64; + fn deposit(receiver: Identity, sub_id: SubId) -> u64; /// Burns shares from the sender and transfers assets to the receiver. /// @@ -60,6 +65,7 @@ abi SRC6 { /// # Arguments /// /// * `asset`: [AssetId] - The asset for which the shares should be burned. + /// * `sub_id`: [SubId] - The SubId of the vault. /// * `receiver`: [Identity] - The receiver of the assets. /// /// # Returns @@ -73,25 +79,27 @@ abi SRC6 { /// * 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; + fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64; /// 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. + /// * `sub_id`: [SubId] - The SubId of the vault. /// /// # Returns /// /// * [u64] - The amount of managed assets of the given asset. #[storage(read)] - fn managed_assets(asset: AssetId) -> u64; + fn managed_assets(asset: AssetId, sub_id: SubId) -> 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. + /// * `sub_id`: [SubId] - The SubId of the vault. /// * `assets`: [u64] - The amount of assets for which the amount of shares should be returned. /// /// # Returns @@ -99,13 +107,14 @@ abi SRC6 { /// * [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; + fn convert_to_shares(asset: AssetId, sub_id: SubId, assets: u64) -> Option; /// 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. + /// * `sub_id`: [SubId] - The SubId of the vault. /// * `shares`: [u64] - The amount of shares for which the amount of assets should be returned. /// /// # Returns @@ -113,7 +122,7 @@ abi SRC6 { /// * [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; + fn convert_to_assets(asset: AssetId, sub_id: SubId, shares: u64) -> Option; /// Returns the maximum amount of assets that can be deposited into the contract, for the given asset. /// @@ -124,13 +133,14 @@ abi SRC6 { /// # Arguments /// /// * `asset`: [AssetId] - The asset for which the maximum amount of depositable assets should be returned. + /// * `sub_id`: [SubId] - The SubId of the vault. /// /// # 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; + fn max_depositable(asset: AssetId, sub_id: SubId) -> Option; /// Returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. /// @@ -141,11 +151,39 @@ abi SRC6 { /// # Arguments /// /// * `asset`: [AssetId] - The asset for which the maximum amount of withdrawable assets should be returned. + /// * `sub_id`: [SubId] - The SubId of the vault. /// /// # 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; + fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option; + + /// Returns the AssetId of the vault shares for the given asset and sub vault. + /// + /// # Arguments + /// + /// * `asset`: [AssetId] - The asset for which the vault shares should be returned. + /// * `sub_id`: [SubId] - The SubId of the vault. + /// + /// # Returns + /// + /// * [Some(AssetId)] - The AssetId of the vault shares for the given asset and sub vault. + /// * [None] - If the asset is not supported by the contract. + #[storage(read)] + fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option; + + /// Returns the AssetId of the asset of the vault for the given AssetId of the vault shares. + /// + /// # Arguments + /// + /// * `vault_asset_id`: [AssetId] - The AssetId of the vault shares for which the asset of the vault should be returned. + /// + /// # Returns + /// + /// * [Some(AssetId)] - The AssetId of the asset of the vault for the given AssetId of the vault shares. + /// * [None] - If the asset is not supported by the contract or the vault has not been initialised. + #[storage(read)] + fn asset_of_vault(vault_asset_id: AssetId) -> Option; } From 8d9f65e74b151e0ccf8b45f556bdb68b4e9486aa Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 17 Oct 2023 16:42:36 +0530 Subject: [PATCH 10/75] specs --- standards/src_6/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 2243796..661dafe 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -81,6 +81,22 @@ This function takes the asset's AssetId as an argument and returns the maximum a MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset. +### `fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option` +Method that returns the AssetId of the vault shares for the given asset and sub vault. +This function takes the asset's AssetId and the SubId of the vault as arguments and returns the AssetId of the vault shares for the given asset and sub vault. + +MUST return an Option::Some of the AssetId of the vault shares for the given asset and sub vault, if the given asset is supported. +MUST return an Option::None if the given asset is not supported. +MUST NOT revert under any circumstances. + +### `fn asset_of_vault(vault_asset_id: AssetId) -> Option` +Method that returns the AssetId of the asset of the vault for the given AssetId of the vault shares. +This function takes the AssetId of the vault shares as an argument and returns the AssetId of the asset of the vault for the given AssetId of the vault shares. + +MUST return an Option::Some of the AssetId of the asset of the vault for the given AssetId of the vault shares, if the given asset is supported and the vault has been initialised. +MUST return an Option::None if the given asset is not supported or the vault has not been initialised. +MUST NOT revert under any circumstances. + ## Required logs The following logs MUST be emitted at the specified occasions From ad9d8351798dea24c94db88066dca1c6b0a02ce3 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 17 Oct 2023 16:44:29 +0530 Subject: [PATCH 11/75] specs --- standards/src_6/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 661dafe..c57eeb8 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -24,7 +24,7 @@ The following functions MUST be implemented (on top of the SRC-20 functions) to ### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` Method that allows depositing of the underlying asset in exchange for shares of the vault. -This function takes the receiver's identity as an argument and returns the amount of shares minted to the receiver. +This function takes the receiver's identity and the sub_id of the sub vault as an argument and returns the amount of shares minted to the receiver. MUST revert if any AssetId other than the underlying is forwarded. MUST mint `preview_deposit(deposited_assets)` amount of shares to `receiver`. @@ -35,7 +35,7 @@ MUST emit a `Deposit` log. ### `fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64` Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset -This function takes the asset's AssetId and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. +This function takes the asset's AssetId, the sub_id of the sub vault, and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. MUST revert if any AssetId other than the AssetId corresponding to the deposited asset is forwarded. @@ -47,7 +47,7 @@ MUST emit a `Withdraw` log. ### `fn managed_assets(asset: AssetId, sub_id: SubId) -> u64` Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. -This function takes the asset's AssetId as an argument and returns the total amount of assets of AssetId under management by vault. +This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. MUST return total amount of assets of underlying AssetId under management by vault. MUST return 0 if there are no assets of underlying AssetId under management by vault. @@ -55,7 +55,7 @@ MUST NOT revert under any circumstances. ### `fn convert_to_shares(asset: AssetId, sub_id: SubId, assets: u64) -> Option` Helper method for converting assets to shares. -This function takes the asset's AssetId and the amount of assets as arguments and returns the amount of shares that would be minted for the given amount of assets, in an ideal condition without slippage. +This function takes the asset's AssetId, the sub_id of the sub vault, and the amount of assets as arguments and returns the amount of shares that would be minted for the given amount of assets, in an ideal condition without slippage. MUST return an Option::Some of the amount of shares that would be minted for the given amount of assets, without accounting for any slippage, if the given asset is supported. MUST return an Option::None if the given asset is not supported. @@ -63,7 +63,7 @@ MUST NOT revert under any circumstances. ### `fn convert_to_assets(asset: AssetId, sub_id: SubId, shares: u64) -> Option` Helper method for converting shares to assets. -This function takes the asset's AssetId and the amount of shares as arguments and returns the amount of assets that would be transferred for the given amount of shares, in an ideal condition without slippage. +This function takes the asset's AssetId, the sub_id of the sub vault, and the amount of shares as arguments and returns the amount of assets that would be transferred for the given amount of shares, in an ideal condition without slippage. MUST return an Option::Some of the amount of assets that would be transferred for the given amount of shares, if the given asset is supported. MUST return an Option::None if the asset is not supported. @@ -71,13 +71,13 @@ MUST NOT revert under any circumstances. ### `fn max_depositable(asset: AssetId, sub_id: SubId) -> Option` Helper method for getting maximum depositable -This function takes the asset's AssetId as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. +This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. MUST return the maximum amount of assets that can be deposited into the contract, for the given asset. ### `fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option` Helper method for getting maximum withdrawable -This function takes the asset's AssetId as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. +This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset. From f7a804ca33cfcfb3d1e66cee66447eaba79d0ee7 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Thu, 26 Oct 2023 17:51:11 +0530 Subject: [PATCH 12/75] add example --- standards/Forc.toml | 2 +- standards/src_6/examples/simple_vault/main.sw | 186 ++++++++++++++++++ 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 standards/src_6/examples/simple_vault/main.sw diff --git a/standards/Forc.toml b/standards/Forc.toml index 0ca2b5e..70b44c3 100644 --- a/standards/Forc.toml +++ b/standards/Forc.toml @@ -1,2 +1,2 @@ [workspace] -members = ["src_3", "src_5", "src_20"] +members = ["src_3", "src_5", "src_6", "src_20"] diff --git a/standards/src_6/examples/simple_vault/main.sw b/standards/src_6/examples/simple_vault/main.sw new file mode 100644 index 0000000..563e4de --- /dev/null +++ b/standards/src_6/examples/simple_vault/main.sw @@ -0,0 +1,186 @@ +contract; + +use std::{ + auth::msg_sender, + call_frames::msg_asset_id, + context::msg_amount, + hash::Hash, + storage::{storage_map::*, storage_string::StorageString}, + token::{transfer, mint, burn}, +}; + +use src_6::{SRC6, Deposit, Withdraw} +use src_20::SRC20; +use std::string::String; + +storage { + total_assets: u64 = 0, + total_supply: StorageMap = StorageMap {}, + name: StorageMap = StorageMap {}, + symbol: StorageMap = StorageMap {}, + decimals: StorageMap = StorageMap {}, +} + +impl SRC20 for Contract { + #[storage(read)] + fn total_assets() -> u64 { + storage.total_assets.try_read().unwrap_or(0) + } + + #[storage(read)] + fn total_supply(asset: AssetId) -> Option { + storage.total_supply.get(asset).try_read() + } + + #[storage(read)] + fn name(asset: AssetId) -> Option { + storage.name.get(asset).read_slice() + } + + #[storage(read)] + fn symbol(asset: AssetId) -> Option { + storage.symbol.get(asset).read_slice() + } + + #[storage(read)] + fn decimals(asset: AssetId) -> Option { + storage.decimals.get(asset).try_read() + } +} + +impl SRC6 for Contract { + #[storage(read)] + fn managed_assets(asset: AssetId) -> u64 { + managed_assets(asset) // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + } + + #[storage(read, write)] + fn deposit(receiver: Identity) -> u64 { + let assets = msg_amount(); + let asset = msg_asset_id(); + let shares = preview_deposit(asset, assets); + require(assets != 0, "ZERO_ASSETS"); + + let _ = _mint(receiver, asset.into(), shares); // Using the asset_id as the sub_id for shares. + storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); + after_deposit(); + + log(Deposit { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + assets: assets, + shares: shares, + }); + + shares + } + + #[storage(read, write)] + fn withdraw(asset: AssetId, receiver: Identity) -> u64 { + let shares = msg_amount(); + require(shares != 0, "ZERO_SHARES"); + require(msg_asset_id() == AssetId::new(ContractId::this(), asset.into()), "INVALID_ASSET_ID"); + let assets = preview_withdraw(asset, shares); + + _burn(asset.into(), shares); + storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); + after_withdraw(); + + transfer(receiver, asset, assets); + + log(Withdraw { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + assets: assets, + shares: shares, + }); + + assets + } + + #[storage(read)] + fn convert_to_shares(asset: AssetId, assets: u64) -> Option { + Option::Some(preview_deposit(asset, assets)) + } + + + #[storage(read)] + fn convert_to_assets(asset: AssetId, shares: u64) -> Option { + Option::Some(preview_withdraw(asset, shares)) + } + + #[storage(read)] + fn max_depositable(asset: AssetId) -> Option { + Option::Some(18_446_744_073_709_551_615 - managed_assets(asset)) // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. + } + + #[storage(read)] + fn max_withdrawable(asset: AssetId) -> Option { + Option::Some(managed_assets(asset)) // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + } +} + +fn managed_assets(asset: AssetId) -> u64 { + std::context::this_balance(asset) +} + +#[storage(read)] +fn preview_deposit(asset: AssetId, assets: u64) -> u64 { + let shares_supply = storage.total_supply.get(AssetId::new(ContractId::this(), asset.into())).read(); + if shares_supply == 0 { + assets + } else { + assets * shares_supply / managed_assets(asset) + } +} + +#[storage(read)] +fn preview_withdraw(asset: AssetId, shares: u64) -> u64 { + let supply = storage.total_supply.get(AssetId::new(ContractId::this(), asset.into())).read(); + if supply == shares { + managed_assets(asset) + } else { + shares * (managed_assets(asset) / supply) + } +} + +fn after_deposit() { + // Does nothing, only for demonstration purposes. +} + +fn after_withdraw() { + // Does nothing, only for demonstration purposes. +} + +#[storage(read, write)] +pub fn _mint( + recipient: Identity, + sub_id: SubId, + amount: u64, +) -> AssetId { + let asset_id = AssetId::new(contract_id(), sub_id); + let supply = storage.total_supply.get(asset).try_read(); + // Only increment the number of assets minted by this contract if it hasn't been minted before. + if supply.is_none() { + storage.total_assets.write(_total_assets(storage.total_assets) + 1); + } + let current_supply = supply.unwrap_or(0); + storage.total_supply.insert(asset_id, current_supply + amount); + mint_to(recipient, sub_id, amount); + asset_id +} + +#[storage(read, write)] +pub fn _burn( + sub_id: SubId, + amount: u64, +) { + let asset_id = AssetId::new(contract_id(), sub_id); + require(this_balance(asset_id) >= amount, BurnError::NotEnoughTokens); + // If we pass the check above, we can assume it is safe to unwrap. + let supply = storage.total_supply.get(asset).try_read().unwrap(); + storage.total_supply.insert(asset_id, supply - amount); + burn(sub_id, amount); +} \ No newline at end of file From 5b07a7c2958df9b44937845d36d87d0f18d8cda9 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 30 Oct 2023 23:55:36 +0530 Subject: [PATCH 13/75] move file out of folder --- .../src_6/examples/{simple_vault/main.sw => simple_vault.sw} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename standards/src_6/examples/{simple_vault/main.sw => simple_vault.sw} (99%) diff --git a/standards/src_6/examples/simple_vault/main.sw b/standards/src_6/examples/simple_vault.sw similarity index 99% rename from standards/src_6/examples/simple_vault/main.sw rename to standards/src_6/examples/simple_vault.sw index 563e4de..f455e2a 100644 --- a/standards/src_6/examples/simple_vault/main.sw +++ b/standards/src_6/examples/simple_vault.sw @@ -10,8 +10,8 @@ use std::{ }; use src_6::{SRC6, Deposit, Withdraw} -use src_20::SRC20; -use std::string::String; +use src_20string::SRC20; +use std::::String; storage { total_assets: u64 = 0, From 2b7ebf3b240429acd2787c5c7784452f4d9ca6dd Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 31 Oct 2023 18:06:54 +0530 Subject: [PATCH 14/75] fix imports --- standards/src_6/examples/simple_vault.sw | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/standards/src_6/examples/simple_vault.sw b/standards/src_6/examples/simple_vault.sw index f455e2a..e44489a 100644 --- a/standards/src_6/examples/simple_vault.sw +++ b/standards/src_6/examples/simple_vault.sw @@ -9,9 +9,9 @@ use std::{ token::{transfer, mint, burn}, }; -use src_6::{SRC6, Deposit, Withdraw} -use src_20string::SRC20; -use std::::String; +use src_6::{SRC6, Deposit, Withdraw}; +use src_20::SRC20; +use std::string::String; storage { total_assets: u64 = 0, From 610bfca836028f776fcd3ba946e93e3fd54133da Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 31 Oct 2023 18:10:20 +0530 Subject: [PATCH 15/75] fmt --- standards/src_6/examples/simple_vault.sw | 33 ++++++++++++------------ 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/standards/src_6/examples/simple_vault.sw b/standards/src_6/examples/simple_vault.sw index e44489a..9bf5663 100644 --- a/standards/src_6/examples/simple_vault.sw +++ b/standards/src_6/examples/simple_vault.sw @@ -5,11 +5,18 @@ use std::{ call_frames::msg_asset_id, context::msg_amount, hash::Hash, - storage::{storage_map::*, storage_string::StorageString}, - token::{transfer, mint, burn}, + storage::{ + storage_map::*, + storage_string::StorageString, + }, + token::{ + burn, + mint, + transfer, + }, }; -use src_6::{SRC6, Deposit, Withdraw}; +use src_6::{Deposit, SRC6, Withdraw}; use src_20::SRC20; use std::string::String; @@ -53,14 +60,14 @@ impl SRC6 for Contract { fn managed_assets(asset: AssetId) -> u64 { managed_assets(asset) // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. } - + #[storage(read, write)] fn deposit(receiver: Identity) -> u64 { let assets = msg_amount(); let asset = msg_asset_id(); let shares = preview_deposit(asset, assets); require(assets != 0, "ZERO_ASSETS"); - + let _ = _mint(receiver, asset.into(), shares); // Using the asset_id as the sub_id for shares. storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); after_deposit(); @@ -82,7 +89,7 @@ impl SRC6 for Contract { require(shares != 0, "ZERO_SHARES"); require(msg_asset_id() == AssetId::new(ContractId::this(), asset.into()), "INVALID_ASSET_ID"); let assets = preview_withdraw(asset, shares); - + _burn(asset.into(), shares); storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); after_withdraw(); @@ -105,7 +112,6 @@ impl SRC6 for Contract { Option::Some(preview_deposit(asset, assets)) } - #[storage(read)] fn convert_to_assets(asset: AssetId, shares: u64) -> Option { Option::Some(preview_withdraw(asset, shares)) @@ -155,11 +161,7 @@ fn after_withdraw() { } #[storage(read, write)] -pub fn _mint( - recipient: Identity, - sub_id: SubId, - amount: u64, -) -> AssetId { +pub fn _mint(recipient: Identity, sub_id: SubId, amount: u64) -> AssetId { let asset_id = AssetId::new(contract_id(), sub_id); let supply = storage.total_supply.get(asset).try_read(); // Only increment the number of assets minted by this contract if it hasn't been minted before. @@ -173,14 +175,11 @@ pub fn _mint( } #[storage(read, write)] -pub fn _burn( - sub_id: SubId, - amount: u64, -) { +pub fn _burn(sub_id: SubId, amount: u64) { let asset_id = AssetId::new(contract_id(), sub_id); require(this_balance(asset_id) >= amount, BurnError::NotEnoughTokens); // If we pass the check above, we can assume it is safe to unwrap. let supply = storage.total_supply.get(asset).try_read().unwrap(); storage.total_supply.insert(asset_id, supply - amount); burn(sub_id, amount); -} \ No newline at end of file +} From 0573079af994b7620414108784df28f2604ded1d Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 31 Oct 2023 18:12:03 +0530 Subject: [PATCH 16/75] move impl block up --- standards/src_6/examples/simple_vault.sw | 54 ++++++++++++------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/standards/src_6/examples/simple_vault.sw b/standards/src_6/examples/simple_vault.sw index 9bf5663..872cc4d 100644 --- a/standards/src_6/examples/simple_vault.sw +++ b/standards/src_6/examples/simple_vault.sw @@ -28,33 +28,6 @@ storage { decimals: StorageMap = StorageMap {}, } -impl SRC20 for Contract { - #[storage(read)] - fn total_assets() -> u64 { - storage.total_assets.try_read().unwrap_or(0) - } - - #[storage(read)] - fn total_supply(asset: AssetId) -> Option { - storage.total_supply.get(asset).try_read() - } - - #[storage(read)] - fn name(asset: AssetId) -> Option { - storage.name.get(asset).read_slice() - } - - #[storage(read)] - fn symbol(asset: AssetId) -> Option { - storage.symbol.get(asset).read_slice() - } - - #[storage(read)] - fn decimals(asset: AssetId) -> Option { - storage.decimals.get(asset).try_read() - } -} - impl SRC6 for Contract { #[storage(read)] fn managed_assets(asset: AssetId) -> u64 { @@ -128,6 +101,33 @@ impl SRC6 for Contract { } } +impl SRC20 for Contract { + #[storage(read)] + fn total_assets() -> u64 { + storage.total_assets.try_read().unwrap_or(0) + } + + #[storage(read)] + fn total_supply(asset: AssetId) -> Option { + storage.total_supply.get(asset).try_read() + } + + #[storage(read)] + fn name(asset: AssetId) -> Option { + storage.name.get(asset).read_slice() + } + + #[storage(read)] + fn symbol(asset: AssetId) -> Option { + storage.symbol.get(asset).read_slice() + } + + #[storage(read)] + fn decimals(asset: AssetId) -> Option { + storage.decimals.get(asset).try_read() + } +} + fn managed_assets(asset: AssetId) -> u64 { std::context::this_balance(asset) } From e3ae07ebb83b932c651751debe623734fd0f00fc Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Thu, 2 Nov 2023 15:23:10 +0530 Subject: [PATCH 17/75] fmted moved ex --- examples/src_6/simple_vault/.gitignore | 2 + examples/src_6/simple_vault/Forc.toml | 9 + examples/src_6/simple_vault/src/main.sw | 239 +++++++++++++++++++++++ standards/src_6/examples/simple_vault.sw | 185 ------------------ standards/src_6/src/src_6.sw | 12 +- 5 files changed, 256 insertions(+), 191 deletions(-) create mode 100644 examples/src_6/simple_vault/.gitignore create mode 100644 examples/src_6/simple_vault/Forc.toml create mode 100644 examples/src_6/simple_vault/src/main.sw delete mode 100644 standards/src_6/examples/simple_vault.sw diff --git a/examples/src_6/simple_vault/.gitignore b/examples/src_6/simple_vault/.gitignore new file mode 100644 index 0000000..77d3844 --- /dev/null +++ b/examples/src_6/simple_vault/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/examples/src_6/simple_vault/Forc.toml b/examples/src_6/simple_vault/Forc.toml new file mode 100644 index 0000000..bfec4a0 --- /dev/null +++ b/examples/src_6/simple_vault/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "simple_vault" + +[dependencies] +src_20 = { path = "../../../standards/src_20" } +src_6 = { path = "../../../standards/src_6" } diff --git a/examples/src_6/simple_vault/src/main.sw b/examples/src_6/simple_vault/src/main.sw new file mode 100644 index 0000000..e9c02c4 --- /dev/null +++ b/examples/src_6/simple_vault/src/main.sw @@ -0,0 +1,239 @@ +contract; + +use std::{ + auth::msg_sender, + call_frames::msg_asset_id, + context::msg_amount, + hash::{ + Hash, + sha256, + }, + storage::{ + storage_map::*, + storage_string::*, + }, + token::{ + transfer, + }, +}; + +use src_6::{Deposit, SRC6, Withdraw}; +use src_20::SRC20; +use std::string::String; + +pub struct VaultInfo { + /// Amount of assets currently managed by this vault + managed_assets: u64, + /// The sub_id of this vault. + sub_id: SubId, + /// The asset being managed by this vault + asset: AssetId, +} + +storage { + total_assets: u64 = 0, + total_supply: StorageMap = StorageMap {}, + name: StorageMap = StorageMap {}, + symbol: StorageMap = StorageMap {}, + decimals: StorageMap = StorageMap {}, + /// Vault share AssetId -> VaultInfo + vault_info: StorageMap = StorageMap {}, +} + +impl SRC6 for Contract { + #[storage(read)] + fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { + let vault_share_asset = vault_asset_id(asset, sub_id).0; + managed_assets(vault_share_asset) // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + } + + #[storage(read, write)] + fn deposit(receiver: Identity, sub_id: SubId) -> u64 { + let assets = msg_amount(); + let asset = msg_asset_id(); + let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, assets); + require(assets != 0, "ZERO_ASSETS"); + + _mint(receiver, share_asset, share_asset_sub_id, shares); + storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); + + let mut vault_info = storage.vault_info.get(share_asset).read(); + vault_info.managed_assets = vault_info.managed_assets + assets; + storage.vault_info.insert(share_asset, vault_info); + + after_deposit(); + + log(Deposit { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + sub_id: sub_id, + assets: assets, + shares: shares, + }); + + shares + } + + #[storage(read, write)] + fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64 { + let shares = msg_amount(); + require(shares != 0, "ZERO_SHARES"); + + let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); + + require(msg_asset_id() == share_asset_id, "INVALID_ASSET_ID"); + let assets = preview_withdraw(share_asset_id, shares); + + _burn(share_asset_id, share_asset_sub_id, shares); + storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); + after_withdraw(); + + transfer(receiver, asset, assets); + + log(Withdraw { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + sub_id: sub_id, + assets: assets, + shares: shares, + }); + + assets + } + + #[storage(read)] + fn convert_to_shares(asset: AssetId, sub_id: SubId, assets: u64) -> Option { + Option::Some(preview_deposit(asset, sub_id, assets).0) + } + + #[storage(read)] + fn convert_to_assets(asset: AssetId, sub_id: SubId, shares: u64) -> Option { + Option::Some(preview_withdraw(AssetId::new(ContractId::this(), sha256((asset.into(), sub_id))), shares)) + } + + #[storage(read)] + fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { + Option::Some(18_446_744_073_709_551_615 - managed_assets(asset)) // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. + } + + #[storage(read)] + fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { + Option::Some(managed_assets(asset)) // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + } + + #[storage(read)] + fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)> { + Some(vault_asset_id(asset, sub_id)) + } + + #[storage(read)] + fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)> { + let vault_info = storage.vault_info.get(vault_asset_id).read(); + Some((vault_info.asset, vault_info.sub_id)) + } +} + +impl SRC20 for Contract { + #[storage(read)] + fn total_assets() -> u64 { + storage.total_assets.try_read().unwrap_or(0) + } + + #[storage(read)] + fn total_supply(asset: AssetId) -> Option { + storage.total_supply.get(asset).try_read() + } + + #[storage(read)] + fn name(asset: AssetId) -> Option { + storage.name.get(asset).read_slice() + } + + #[storage(read)] + fn symbol(asset: AssetId) -> Option { + storage.symbol.get(asset).read_slice() + } + + #[storage(read)] + fn decimals(asset: AssetId) -> Option { + storage.decimals.get(asset).try_read() + } +} + +/// Returns the vault shares assetid and subid for the given assets assetid and the vaults sub id +fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { + let share_asset_sub_id = sha256((asset.into(), sub_id)); + let share_asset_id = AssetId::new(ContractId::this(), share_asset_sub_id); + (share_asset_id, share_asset_sub_id) +} + +#[storage(read)] +fn managed_assets(share_asset: AssetId) -> u64 { + storage.vault_info.get(share_asset).read().managed_assets +} + +#[storage(read)] +fn preview_deposit(asset: AssetId, sub_id: SubId, assets: u64) -> (u64, AssetId, SubId) { + let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); + + let shares_supply = storage.total_supply.get(share_asset_id).read(); + if shares_supply == 0 { + (assets, share_asset_id, share_asset_sub_id) + } else { + ( + assets * shares_supply / managed_assets(share_asset_id), + share_asset_id, + share_asset_sub_id, + ) + } +} + +#[storage(read)] +fn preview_withdraw(share_asset_id: AssetId, shares: u64) -> u64 { + let supply = storage.total_supply.get(share_asset_id).read(); + if supply == shares { + managed_assets(share_asset_id) + } else { + shares * (managed_assets(share_asset_id) / supply) + } +} + +fn after_deposit() { + // Does nothing, only for demonstration purposes. +} + +fn after_withdraw() { + // Does nothing, only for demonstration purposes. +} + +#[storage(read, write)] +pub fn _mint( + recipient: Identity, + asset_id: AssetId, + sub_id: SubId, + amount: u64, +) { + use std::token::mint_to; + + let supply = storage.total_supply.get(asset_id).try_read(); + // Only increment the number of assets minted by this contract if it hasn't been minted before. + if supply.is_none() { + storage.total_assets.write(storage.total_assets.read() + 1); + } + let current_supply = supply.unwrap_or(0); + storage.total_supply.insert(asset_id, current_supply + amount); + mint_to(recipient, sub_id, amount); +} + +#[storage(read, write)] +pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { + use std::{context::this_balance, token::burn}; + + require(this_balance(asset_id) >= amount, "BurnError::NotEnoughTokens"); + // If we pass the check above, we can assume it is safe to unwrap. + let supply = storage.total_supply.get(asset_id).try_read().unwrap(); + storage.total_supply.insert(asset_id, supply - amount); + burn(sub_id, amount); +} diff --git a/standards/src_6/examples/simple_vault.sw b/standards/src_6/examples/simple_vault.sw deleted file mode 100644 index 872cc4d..0000000 --- a/standards/src_6/examples/simple_vault.sw +++ /dev/null @@ -1,185 +0,0 @@ -contract; - -use std::{ - auth::msg_sender, - call_frames::msg_asset_id, - context::msg_amount, - hash::Hash, - storage::{ - storage_map::*, - storage_string::StorageString, - }, - token::{ - burn, - mint, - transfer, - }, -}; - -use src_6::{Deposit, SRC6, Withdraw}; -use src_20::SRC20; -use std::string::String; - -storage { - total_assets: u64 = 0, - total_supply: StorageMap = StorageMap {}, - name: StorageMap = StorageMap {}, - symbol: StorageMap = StorageMap {}, - decimals: StorageMap = StorageMap {}, -} - -impl SRC6 for Contract { - #[storage(read)] - fn managed_assets(asset: AssetId) -> u64 { - managed_assets(asset) // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. - } - - #[storage(read, write)] - fn deposit(receiver: Identity) -> u64 { - let assets = msg_amount(); - let asset = msg_asset_id(); - let shares = preview_deposit(asset, assets); - require(assets != 0, "ZERO_ASSETS"); - - let _ = _mint(receiver, asset.into(), shares); // Using the asset_id as the sub_id for shares. - storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); - after_deposit(); - - log(Deposit { - caller: msg_sender().unwrap(), - receiver: receiver, - asset: asset, - assets: assets, - shares: shares, - }); - - shares - } - - #[storage(read, write)] - fn withdraw(asset: AssetId, receiver: Identity) -> u64 { - let shares = msg_amount(); - require(shares != 0, "ZERO_SHARES"); - require(msg_asset_id() == AssetId::new(ContractId::this(), asset.into()), "INVALID_ASSET_ID"); - let assets = preview_withdraw(asset, shares); - - _burn(asset.into(), shares); - storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); - after_withdraw(); - - transfer(receiver, asset, assets); - - log(Withdraw { - caller: msg_sender().unwrap(), - receiver: receiver, - asset: asset, - assets: assets, - shares: shares, - }); - - assets - } - - #[storage(read)] - fn convert_to_shares(asset: AssetId, assets: u64) -> Option { - Option::Some(preview_deposit(asset, assets)) - } - - #[storage(read)] - fn convert_to_assets(asset: AssetId, shares: u64) -> Option { - Option::Some(preview_withdraw(asset, shares)) - } - - #[storage(read)] - fn max_depositable(asset: AssetId) -> Option { - Option::Some(18_446_744_073_709_551_615 - managed_assets(asset)) // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. - } - - #[storage(read)] - fn max_withdrawable(asset: AssetId) -> Option { - Option::Some(managed_assets(asset)) // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. - } -} - -impl SRC20 for Contract { - #[storage(read)] - fn total_assets() -> u64 { - storage.total_assets.try_read().unwrap_or(0) - } - - #[storage(read)] - fn total_supply(asset: AssetId) -> Option { - storage.total_supply.get(asset).try_read() - } - - #[storage(read)] - fn name(asset: AssetId) -> Option { - storage.name.get(asset).read_slice() - } - - #[storage(read)] - fn symbol(asset: AssetId) -> Option { - storage.symbol.get(asset).read_slice() - } - - #[storage(read)] - fn decimals(asset: AssetId) -> Option { - storage.decimals.get(asset).try_read() - } -} - -fn managed_assets(asset: AssetId) -> u64 { - std::context::this_balance(asset) -} - -#[storage(read)] -fn preview_deposit(asset: AssetId, assets: u64) -> u64 { - let shares_supply = storage.total_supply.get(AssetId::new(ContractId::this(), asset.into())).read(); - if shares_supply == 0 { - assets - } else { - assets * shares_supply / managed_assets(asset) - } -} - -#[storage(read)] -fn preview_withdraw(asset: AssetId, shares: u64) -> u64 { - let supply = storage.total_supply.get(AssetId::new(ContractId::this(), asset.into())).read(); - if supply == shares { - managed_assets(asset) - } else { - shares * (managed_assets(asset) / supply) - } -} - -fn after_deposit() { - // Does nothing, only for demonstration purposes. -} - -fn after_withdraw() { - // Does nothing, only for demonstration purposes. -} - -#[storage(read, write)] -pub fn _mint(recipient: Identity, sub_id: SubId, amount: u64) -> AssetId { - let asset_id = AssetId::new(contract_id(), sub_id); - let supply = storage.total_supply.get(asset).try_read(); - // Only increment the number of assets minted by this contract if it hasn't been minted before. - if supply.is_none() { - storage.total_assets.write(_total_assets(storage.total_assets) + 1); - } - let current_supply = supply.unwrap_or(0); - storage.total_supply.insert(asset_id, current_supply + amount); - mint_to(recipient, sub_id, amount); - asset_id -} - -#[storage(read, write)] -pub fn _burn(sub_id: SubId, amount: u64) { - let asset_id = AssetId::new(contract_id(), sub_id); - require(this_balance(asset_id) >= amount, BurnError::NotEnoughTokens); - // If we pass the check above, we can assume it is safe to unwrap. - let supply = storage.total_supply.get(asset).try_read().unwrap(); - storage.total_supply.insert(asset_id, supply - amount); - burn(sub_id, amount); -} diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 5f4cc9c..11a4674 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -160,7 +160,7 @@ abi SRC6 { #[storage(read)] fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option; - /// Returns the AssetId of the vault shares for the given asset and sub vault. + /// Returns the AssetId and SubId of the vault shares for the given asset and sub vault. /// /// # Arguments /// @@ -169,12 +169,12 @@ abi SRC6 { /// /// # Returns /// - /// * [Some(AssetId)] - The AssetId of the vault shares for the given asset and sub vault. + /// * [Some((AssetId, SubId))] - The AssetId and SubId of the vault shares for the given asset and sub vault. /// * [None] - If the asset is not supported by the contract. #[storage(read)] - fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option; + fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)>; - /// Returns the AssetId of the asset of the vault for the given AssetId of the vault shares. + /// Returns the AssetId of the asset of the vault for the given AssetId of the vault shares, and the sub_id of the vault. /// /// # Arguments /// @@ -182,8 +182,8 @@ abi SRC6 { /// /// # Returns /// - /// * [Some(AssetId)] - The AssetId of the asset of the vault for the given AssetId of the vault shares. + /// * [Some((AssetId, SubId))] - The AssetId of the asset of the vault for the given AssetId of the vault shares, and the sub_id of the vault. /// * [None] - If the asset is not supported by the contract or the vault has not been initialised. #[storage(read)] - fn asset_of_vault(vault_asset_id: AssetId) -> Option; + fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)>; } From a49f72520b4d84094cafa7c2d599ae37ff140dcb Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Thu, 30 Nov 2023 13:29:14 +0530 Subject: [PATCH 18/75] update banners --- standards/src_6/.docs/src-5-logo-dark-theme.png | Bin 20263 -> 0 bytes .../src_6/.docs/src-5-logo-light-theme.png | Bin 23249 -> 0 bytes standards/src_6/.docs/src-6-logo-dark-theme.png | Bin 0 -> 16110 bytes .../src_6/.docs/src-6-logo-light-theme.png | Bin 0 -> 17150 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 standards/src_6/.docs/src-5-logo-dark-theme.png delete mode 100644 standards/src_6/.docs/src-5-logo-light-theme.png create mode 100644 standards/src_6/.docs/src-6-logo-dark-theme.png create mode 100644 standards/src_6/.docs/src-6-logo-light-theme.png diff --git a/standards/src_6/.docs/src-5-logo-dark-theme.png b/standards/src_6/.docs/src-5-logo-dark-theme.png deleted file mode 100644 index 6808e847963c9ae9130efd09e6f5e77ed1c829cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20263 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 literal 0 HcmV?d00001 diff --git a/standards/src_6/.docs/src-6-logo-light-theme.png b/standards/src_6/.docs/src-6-logo-light-theme.png new file mode 100644 index 0000000000000000000000000000000000000000..4ddfc7d7fb8eb47c91bcc6be58e64c167f8a367e GIT binary patch literal 17150 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 literal 0 HcmV?d00001 From e82ed1a98853fc8df2664644d7d200683ab935dd Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Thu, 30 Nov 2023 14:00:52 +0530 Subject: [PATCH 19/75] resolve some req changes --- examples/src_6/simple_vault/Forc.toml | 2 +- examples/src_6/simple_vault/src/main.sw | 16 +++------------- standards/src_6/README.md | 7 ++----- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/examples/src_6/simple_vault/Forc.toml b/examples/src_6/simple_vault/Forc.toml index bfec4a0..aa47674 100644 --- a/examples/src_6/simple_vault/Forc.toml +++ b/examples/src_6/simple_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "simple_vault" [dependencies] -src_20 = { path = "../../../standards/src_20" } src_6 = { path = "../../../standards/src_6" } +src_20 = { path = "../../../standards/src_20" } diff --git a/examples/src_6/simple_vault/src/main.sw b/examples/src_6/simple_vault/src/main.sw index e9c02c4..59318f5 100644 --- a/examples/src_6/simple_vault/src/main.sw +++ b/examples/src_6/simple_vault/src/main.sw @@ -44,12 +44,13 @@ impl SRC6 for Contract { #[storage(read)] fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { let vault_share_asset = vault_asset_id(asset, sub_id).0; - managed_assets(vault_share_asset) // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + managed_assets(vault_share_asset) } #[storage(read, write)] fn deposit(receiver: Identity, sub_id: SubId) -> u64 { - let assets = msg_amount(); + let asset_amount = msg_amount(); let asset = msg_asset_id(); let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, assets); require(assets != 0, "ZERO_ASSETS"); @@ -61,8 +62,6 @@ impl SRC6 for Contract { vault_info.managed_assets = vault_info.managed_assets + assets; storage.vault_info.insert(share_asset, vault_info); - after_deposit(); - log(Deposit { caller: msg_sender().unwrap(), receiver: receiver, @@ -87,7 +86,6 @@ impl SRC6 for Contract { _burn(share_asset_id, share_asset_sub_id, shares); storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); - after_withdraw(); transfer(receiver, asset, assets); @@ -200,14 +198,6 @@ fn preview_withdraw(share_asset_id: AssetId, shares: u64) -> u64 { } } -fn after_deposit() { - // Does nothing, only for demonstration purposes. -} - -fn after_withdraw() { - // Does nothing, only for demonstration purposes. -} - #[storage(read, write)] pub fn _mint( recipient: Identity, diff --git a/standards/src_6/README.md b/standards/src_6/README.md index c57eeb8..db73ba8 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -1,7 +1,7 @@

- - SRC-5 logo + + SRC-6 logo

@@ -27,7 +27,6 @@ Method that allows depositing of the underlying asset in exchange for shares of This function takes the receiver's identity and the sub_id of the sub vault as an argument and returns the amount of shares minted to the receiver. 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` of the share's AssetId by newly minted shares. MUST increase `total_assets` by one if the the AssetId is minted for the first time. @@ -39,9 +38,7 @@ This function takes the asset's AssetId, the sub_id of the sub vault, and the re The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. MUST revert if any AssetId other than the AssetId corresponding to the deposited asset is forwarded. -MUST send `preview_withdraw(redeemed_shares)` amount of assets to `receiver`. MUST burn the received shares. -MUST reduce `managed_assets` by `preview_withdraw(redeemed_shares)`. MUST reduce `total_supply` of the shares's AssetId by amount of burnt shares. MUST emit a `Withdraw` log. From c2821d6c96cc8ea6ec1a5f69a840b9cecd544e77 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 1 Dec 2023 22:09:11 +0530 Subject: [PATCH 20/75] address some of the req changes --- examples/src_6/simple_vault/src/main.sw | 11 ++++++--- standards/src_6/README.md | 33 ++++++++++++++++--------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/examples/src_6/simple_vault/src/main.sw b/examples/src_6/simple_vault/src/main.sw index 59318f5..70a4956 100644 --- a/examples/src_6/simple_vault/src/main.sw +++ b/examples/src_6/simple_vault/src/main.sw @@ -31,13 +31,14 @@ pub struct VaultInfo { } storage { + /// Vault share AssetId -> VaultInfo + vault_info: StorageMap = StorageMap {}, + total_assets: u64 = 0, total_supply: StorageMap = StorageMap {}, name: StorageMap = StorageMap {}, symbol: StorageMap = StorageMap {}, decimals: StorageMap = StorageMap {}, - /// Vault share AssetId -> VaultInfo - vault_info: StorageMap = StorageMap {}, } impl SRC6 for Contract { @@ -113,12 +114,14 @@ impl SRC6 for Contract { #[storage(read)] fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { - Option::Some(18_446_744_073_709_551_615 - managed_assets(asset)) // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. + // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. + Option::Some(u64::MAX - managed_assets(asset)) } #[storage(read)] fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { - Option::Some(managed_assets(asset)) // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + Option::Some(managed_assets(asset)) } #[storage(read)] diff --git a/standards/src_6/README.md b/standards/src_6/README.md index db73ba8..9b3b090 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -20,9 +20,11 @@ Token vaults have been thoroughly explored on Ethereum and with [EIP 4626](https # Specification ## Required public functions -The following functions MUST be implemented (on top of the SRC-20 functions) to follow the SRC-6 standard + +The following functions MUST be implemented to follow the SRC-6 standard. Any contract that implements the SRC-7 standard MUST implement the SRC-20 standard. ### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` + Method that allows depositing of the underlying asset in exchange for shares of the vault. This function takes the receiver's identity and the sub_id of the sub vault as an argument and returns the amount of shares minted to the receiver. @@ -33,6 +35,7 @@ MUST increase `total_assets` by one if the the AssetId is minted for the first t MUST emit a `Deposit` log. ### `fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64` + Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset This function takes the asset's AssetId, the sub_id of the sub vault, and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. @@ -43,6 +46,7 @@ MUST reduce `total_supply` of the shares's AssetId by amount of burnt shares. MUST emit a `Withdraw` log. ### `fn managed_assets(asset: AssetId, sub_id: SubId) -> u64` + Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. @@ -51,50 +55,57 @@ MUST return 0 if there are no assets of underlying AssetId under management by v MUST NOT revert under any circumstances. ### `fn convert_to_shares(asset: AssetId, sub_id: SubId, assets: u64) -> Option` + Helper method for converting assets to shares. This function takes the asset's AssetId, the sub_id of the sub vault, and the amount of assets as arguments and returns the amount of shares that would be minted for the given amount of assets, in an ideal condition without slippage. -MUST return an Option::Some of the amount of shares that would be minted for the given amount of assets, without accounting for any slippage, if the given asset is supported. -MUST return an Option::None if the given asset is not supported. +MUST return an `Option::Some(amount)` of shares that would be minted for the given amount of assets, without accounting for any slippage, if the given asset is supported. +MUST return an `Option::None` if the given asset is not supported. MUST NOT revert under any circumstances. ### `fn convert_to_assets(asset: AssetId, sub_id: SubId, shares: u64) -> Option` + Helper method for converting shares to assets. This function takes the asset's AssetId, the sub_id of the sub vault, and the amount of shares as arguments and returns the amount of assets that would be transferred for the given amount of shares, in an ideal condition without slippage. -MUST return an Option::Some of the amount of assets that would be transferred for the given amount of shares, if the given asset is supported. -MUST return an Option::None if the asset is not supported. +MUST return an `Option::Some(amount)` of assets that would be transferred for the given amount of shares, if the given asset is supported. +MUST return an `Option::None` if the asset is not supported. MUST NOT revert under any circumstances. ### `fn max_depositable(asset: AssetId, sub_id: SubId) -> Option` + Helper method for getting maximum depositable This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. MUST return the maximum amount of assets that can be deposited into the contract, for the given asset. ### `fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option` + Helper method for getting maximum withdrawable This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset. ### `fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option` + Method that returns the AssetId of the vault shares for the given asset and sub vault. This function takes the asset's AssetId and the SubId of the vault as arguments and returns the AssetId of the vault shares for the given asset and sub vault. -MUST return an Option::Some of the AssetId of the vault shares for the given asset and sub vault, if the given asset is supported. -MUST return an Option::None if the given asset is not supported. +MUST return an `Option::Some(AssetId)` of the vault shares for the given asset and sub vault, if the given asset is supported. +MUST return an `Option::None` if the given asset is not supported. MUST NOT revert under any circumstances. ### `fn asset_of_vault(vault_asset_id: AssetId) -> Option` + Method that returns the AssetId of the asset of the vault for the given AssetId of the vault shares. This function takes the AssetId of the vault shares as an argument and returns the AssetId of the asset of the vault for the given AssetId of the vault shares. -MUST return an Option::Some of the AssetId of the asset of the vault for the given AssetId of the vault shares, if the given asset is supported and the vault has been initialised. -MUST return an Option::None if the given asset is not supported or the vault has not been initialised. +MUST return an `Option::Some(AssetId)` of the asset of the vault for the given AssetId of the vault shares, if the given asset is supported and the vault has been initialised. +MUST return an `Option::None` if the given asset is not supported or the vault has not been initialised. MUST NOT revert under any circumstances. ## Required logs + The following logs MUST be emitted at the specified occasions ```sway @@ -141,9 +152,9 @@ The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via # Rationale -The ABI discussed is simple and covers the known use cases of token vaults while allowing safe implementations +The ABI discussed and covers the known use cases of token vaults while allowing safe implementations -# Backwards compatibility +# Backwards Compatibility This standard is fully compatible with the SRC-20 standard From 9a248c811433f78eb18a6dda58f815136b601c19 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 4 Dec 2023 16:23:33 +0530 Subject: [PATCH 21/75] remove unnecessary funcs --- examples/src_6/simple_vault/src/main.sw | 20 +++++------------ standards/src_6/README.md | 18 --------------- standards/src_6/src/src_6.sw | 30 ------------------------- 3 files changed, 5 insertions(+), 63 deletions(-) diff --git a/examples/src_6/simple_vault/src/main.sw b/examples/src_6/simple_vault/src/main.sw index 70a4956..c3a7461 100644 --- a/examples/src_6/simple_vault/src/main.sw +++ b/examples/src_6/simple_vault/src/main.sw @@ -53,14 +53,14 @@ impl SRC6 for Contract { fn deposit(receiver: Identity, sub_id: SubId) -> u64 { let asset_amount = msg_amount(); let asset = msg_asset_id(); - let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, assets); - require(assets != 0, "ZERO_ASSETS"); + let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, asset_amount); + require(asset_amount != 0, "ZERO_ASSETS"); _mint(receiver, share_asset, share_asset_sub_id, shares); storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); let mut vault_info = storage.vault_info.get(share_asset).read(); - vault_info.managed_assets = vault_info.managed_assets + assets; + vault_info.managed_assets = vault_info.managed_assets + asset_amount; storage.vault_info.insert(share_asset, vault_info); log(Deposit { @@ -68,7 +68,7 @@ impl SRC6 for Contract { receiver: receiver, asset: asset, sub_id: sub_id, - assets: assets, + assets: asset_amount, shares: shares, }); @@ -102,20 +102,10 @@ impl SRC6 for Contract { assets } - #[storage(read)] - fn convert_to_shares(asset: AssetId, sub_id: SubId, assets: u64) -> Option { - Option::Some(preview_deposit(asset, sub_id, assets).0) - } - - #[storage(read)] - fn convert_to_assets(asset: AssetId, sub_id: SubId, shares: u64) -> Option { - Option::Some(preview_withdraw(AssetId::new(ContractId::this(), sha256((asset.into(), sub_id))), shares)) - } - #[storage(read)] fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. - Option::Some(u64::MAX - managed_assets(asset)) + Option::Some(u64::max() - managed_assets(asset)) } #[storage(read)] diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 9b3b090..8672ec4 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -54,24 +54,6 @@ MUST return total amount of assets of underlying AssetId under management by vau MUST return 0 if there are no assets of underlying AssetId under management by vault. MUST NOT revert under any circumstances. -### `fn convert_to_shares(asset: AssetId, sub_id: SubId, assets: u64) -> Option` - -Helper method for converting assets to shares. -This function takes the asset's AssetId, the sub_id of the sub vault, and the amount of assets as arguments and returns the amount of shares that would be minted for the given amount of assets, in an ideal condition without slippage. - -MUST return an `Option::Some(amount)` of shares that would be minted for the given amount of assets, without accounting for any slippage, if the given asset is supported. -MUST return an `Option::None` if the given asset is not supported. -MUST NOT revert under any circumstances. - -### `fn convert_to_assets(asset: AssetId, sub_id: SubId, shares: u64) -> Option` - -Helper method for converting shares to assets. -This function takes the asset's AssetId, the sub_id of the sub vault, and the amount of shares as arguments and returns the amount of assets that would be transferred for the given amount of shares, in an ideal condition without slippage. - -MUST return an `Option::Some(amount)` of assets that would be transferred for the given amount of shares, if the given asset is supported. -MUST return an `Option::None` if the asset is not supported. -MUST NOT revert under any circumstances. - ### `fn max_depositable(asset: AssetId, sub_id: SubId) -> Option` Helper method for getting maximum depositable diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 11a4674..78874c0 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -94,36 +94,6 @@ abi SRC6 { #[storage(read)] fn managed_assets(asset: AssetId, sub_id: SubId) -> 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. - /// * `sub_id`: [SubId] - The SubId of the vault. - /// * `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, sub_id: SubId, assets: u64) -> Option; - - /// 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. - /// * `sub_id`: [SubId] - The SubId of the vault. - /// * `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, sub_id: SubId, shares: u64) -> Option; - /// Returns the maximum amount of assets that can be deposited into the contract, for the given asset. /// /// # Additional Information From 7d202c7b7c5fc689900334406bbddc3e126c06fc Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 4 Dec 2023 16:25:51 +0530 Subject: [PATCH 22/75] fmt --- examples/src_6/simple_vault/Forc.toml | 2 +- examples/src_6/simple_vault/src/main.sw | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/src_6/simple_vault/Forc.toml b/examples/src_6/simple_vault/Forc.toml index aa47674..bfec4a0 100644 --- a/examples/src_6/simple_vault/Forc.toml +++ b/examples/src_6/simple_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "simple_vault" [dependencies] -src_6 = { path = "../../../standards/src_6" } src_20 = { path = "../../../standards/src_20" } +src_6 = { path = "../../../standards/src_6" } diff --git a/examples/src_6/simple_vault/src/main.sw b/examples/src_6/simple_vault/src/main.sw index c3a7461..d984406 100644 --- a/examples/src_6/simple_vault/src/main.sw +++ b/examples/src_6/simple_vault/src/main.sw @@ -33,7 +33,6 @@ pub struct VaultInfo { storage { /// Vault share AssetId -> VaultInfo vault_info: StorageMap = StorageMap {}, - total_assets: u64 = 0, total_supply: StorageMap = StorageMap {}, name: StorageMap = StorageMap {}, From 789b449676650ad49b5057f823878171aaca4a10 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 4 Dec 2023 17:34:51 +0530 Subject: [PATCH 23/75] add second example --- .../.gitignore | 0 .../Forc.toml | 2 +- .../src/main.sw | 2 +- examples/src_6/single_token_vault/.gitignore | 2 + examples/src_6/single_token_vault/Forc.toml | 9 + examples/src_6/single_token_vault/src/main.sw | 264 ++++++++++++++++++ standards/src_6/README.md | 36 ++- 7 files changed, 311 insertions(+), 4 deletions(-) rename examples/src_6/{simple_vault => multi_token_vault}/.gitignore (100%) rename examples/src_6/{simple_vault => multi_token_vault}/Forc.toml (88%) rename examples/src_6/{simple_vault => multi_token_vault}/src/main.sw (99%) create mode 100644 examples/src_6/single_token_vault/.gitignore create mode 100644 examples/src_6/single_token_vault/Forc.toml create mode 100644 examples/src_6/single_token_vault/src/main.sw diff --git a/examples/src_6/simple_vault/.gitignore b/examples/src_6/multi_token_vault/.gitignore similarity index 100% rename from examples/src_6/simple_vault/.gitignore rename to examples/src_6/multi_token_vault/.gitignore diff --git a/examples/src_6/simple_vault/Forc.toml b/examples/src_6/multi_token_vault/Forc.toml similarity index 88% rename from examples/src_6/simple_vault/Forc.toml rename to examples/src_6/multi_token_vault/Forc.toml index bfec4a0..7451256 100644 --- a/examples/src_6/simple_vault/Forc.toml +++ b/examples/src_6/multi_token_vault/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "simple_vault" +name = "multi_token_vault" [dependencies] src_20 = { path = "../../../standards/src_20" } diff --git a/examples/src_6/simple_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw similarity index 99% rename from examples/src_6/simple_vault/src/main.sw rename to examples/src_6/multi_token_vault/src/main.sw index d984406..6faecaf 100644 --- a/examples/src_6/simple_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -8,6 +8,7 @@ use std::{ Hash, sha256, }, + string::String, storage::{ storage_map::*, storage_string::*, @@ -19,7 +20,6 @@ use std::{ use src_6::{Deposit, SRC6, Withdraw}; use src_20::SRC20; -use std::string::String; pub struct VaultInfo { /// Amount of assets currently managed by this vault diff --git a/examples/src_6/single_token_vault/.gitignore b/examples/src_6/single_token_vault/.gitignore new file mode 100644 index 0000000..77d3844 --- /dev/null +++ b/examples/src_6/single_token_vault/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/examples/src_6/single_token_vault/Forc.toml b/examples/src_6/single_token_vault/Forc.toml new file mode 100644 index 0000000..72a79eb --- /dev/null +++ b/examples/src_6/single_token_vault/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "single_token_vault" + +[dependencies] +src_20 = { path = "../../../standards/src_20" } +src_6 = { path = "../../../standards/src_6" } diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw new file mode 100644 index 0000000..56c3223 --- /dev/null +++ b/examples/src_6/single_token_vault/src/main.sw @@ -0,0 +1,264 @@ +contract; + +use std::{ + auth::msg_sender, + call_frames::msg_asset_id, + context::msg_amount, + hash::{ + Hash, + sha256, + }, + string::String, + storage::{ + storage_map::*, + storage_string::*, + }, + token::{ + transfer, + }, +}; + +use src_6::{Deposit, SRC6, Withdraw}; +use src_20::SRC20; + +pub struct VaultInfo { + /// Amount of assets currently managed by this vault + managed_assets: u64, + /// The sub_id of this vault. + sub_id: SubId, + /// The asset being managed by this vault + asset: AssetId, +} + +storage { + /// Vault share AssetId -> VaultInfo + vault_info: StorageMap = StorageMap {}, + total_assets: u64 = 0, + total_supply: StorageMap = StorageMap {}, + name: StorageMap = StorageMap {}, + symbol: StorageMap = StorageMap {}, + decimals: StorageMap = StorageMap {}, +} + +configurable { + ACCEPTED_TOKEN: AssetId = std::constants::BASE_ASSET_ID, +} + +impl SRC6 for Contract { + #[storage(read)] + fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { + match asset { + ACCEPTED_TOKEN => { + let vault_share_asset = vault_asset_id(asset, sub_id).0; + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + managed_assets(vault_share_asset) + }, + _ => { + 0 + } + } + } + + #[storage(read, write)] + fn deposit(receiver: Identity, sub_id: SubId) -> u64 { + let asset_amount = msg_amount(); + let asset = msg_asset_id(); + + require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); + let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, asset_amount); + require(asset_amount != 0, "ZERO_ASSETS"); + + _mint(receiver, share_asset, share_asset_sub_id, shares); + storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); + + let mut vault_info = storage.vault_info.get(share_asset).read(); + vault_info.managed_assets = vault_info.managed_assets + asset_amount; + storage.vault_info.insert(share_asset, vault_info); + + log(Deposit { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + sub_id: sub_id, + assets: asset_amount, + shares: shares, + }); + + shares + } + + #[storage(read, write)] + fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64 { + let shares = msg_amount(); + require(shares != 0, "ZERO_SHARES"); + + let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); + + require(msg_asset_id() == share_asset_id, "INVALID_ASSET_ID"); + let assets = preview_withdraw(share_asset_id, shares); + + _burn(share_asset_id, share_asset_sub_id, shares); + storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); + + transfer(receiver, asset, assets); + + log(Withdraw { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + sub_id: sub_id, + assets: assets, + shares: shares, + }); + + assets + } + + #[storage(read)] + fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { + match asset { + ACCEPTED_TOKEN => { + // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. + Option::Some(u64::max() - managed_assets(asset)) + }, + _ => { + None + } + } + } + + #[storage(read)] + fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { + match asset { + ACCEPTED_TOKEN => { + // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + Option::Some(managed_assets(asset)) + }, + _ => { + None + } + } + } + + #[storage(read)] + fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)> { + match asset { + ACCEPTED_TOKEN => { + Some(vault_asset_id(asset, sub_id)) + }, + _ => { + None + } + } + + } + + #[storage(read)] + fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)> { + let asset = storage.vault_info.get(vault_asset_id).read().asset; + match asset { + ACCEPTED_TOKEN => { + let vault_info = storage.vault_info.get(vault_asset_id).read(); + Some((vault_info.asset, vault_info.sub_id)) + } + _ => { + None + } + } + } +} + +impl SRC20 for Contract { + #[storage(read)] + fn total_assets() -> u64 { + storage.total_assets.try_read().unwrap_or(0) + } + + #[storage(read)] + fn total_supply(asset: AssetId) -> Option { + storage.total_supply.get(asset).try_read() + } + + #[storage(read)] + fn name(asset: AssetId) -> Option { + storage.name.get(asset).read_slice() + } + + #[storage(read)] + fn symbol(asset: AssetId) -> Option { + storage.symbol.get(asset).read_slice() + } + + #[storage(read)] + fn decimals(asset: AssetId) -> Option { + storage.decimals.get(asset).try_read() + } +} + +/// Returns the vault shares assetid and subid for the given assets assetid and the vaults sub id +fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { + let share_asset_sub_id = sha256((asset.into(), sub_id)); + let share_asset_id = AssetId::new(ContractId::this(), share_asset_sub_id); + (share_asset_id, share_asset_sub_id) +} + +#[storage(read)] +fn managed_assets(share_asset: AssetId) -> u64 { + storage.vault_info.get(share_asset).read().managed_assets +} + +#[storage(read)] +fn preview_deposit(asset: AssetId, sub_id: SubId, assets: u64) -> (u64, AssetId, SubId) { + let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); + + let shares_supply = storage.total_supply.get(share_asset_id).read(); + if shares_supply == 0 { + (assets, share_asset_id, share_asset_sub_id) + } else { + ( + assets * shares_supply / managed_assets(share_asset_id), + share_asset_id, + share_asset_sub_id, + ) + } +} + +#[storage(read)] +fn preview_withdraw(share_asset_id: AssetId, shares: u64) -> u64 { + let supply = storage.total_supply.get(share_asset_id).read(); + if supply == shares { + managed_assets(share_asset_id) + } else { + shares * (managed_assets(share_asset_id) / supply) + } +} + +#[storage(read, write)] +pub fn _mint( + recipient: Identity, + asset_id: AssetId, + sub_id: SubId, + amount: u64, +) { + use std::token::mint_to; + + let supply = storage.total_supply.get(asset_id).try_read(); + // Only increment the number of assets minted by this contract if it hasn't been minted before. + if supply.is_none() { + storage.total_assets.write(storage.total_assets.read() + 1); + } + let current_supply = supply.unwrap_or(0); + storage.total_supply.insert(asset_id, current_supply + amount); + mint_to(recipient, sub_id, amount); +} + +#[storage(read, write)] +pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { + use std::{context::this_balance, token::burn}; + + require(this_balance(asset_id) >= amount, "BurnError::NotEnoughTokens"); + // If we pass the check above, we can assume it is safe to unwrap. + let supply = storage.total_supply.get(asset_id).try_read().unwrap(); + storage.total_supply.insert(asset_id, supply - amount); + burn(sub_id, amount); +} diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 8672ec4..384986e 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -144,7 +144,39 @@ This standard is fully compatible with the SRC-20 standard 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 +# Example ABI -Full reference implementation can be seen [here](https://github.com/SwayStar123/vault-standard-reference-implementation/blob/master/src/main.sw) +```sway +abi SRC6 { + #[storage(read, write)] + fn deposit(receiver: Identity, sub_id: SubId) -> u64; + + #[storage(read, write)] + fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64; + + #[storage(read)] + fn managed_assets(asset: AssetId, sub_id: SubId) -> u64; + + #[storage(read)] + fn max_depositable(asset: AssetId, sub_id: SubId) -> Option; + + #[storage(read)] + fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option; + + #[storage(read)] + fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)>; + + #[storage(read)] + fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)>; +} +``` + +# Example Implementation + +## [Multi Token Vault](../../examples/src_6/multi_token_vault/) + +A barebones implementation of the vault standard that supports any number of sub vaults being created for every AssetId. + +## [Single Token Vault](../../examples/src_6/single_token_vault/) +A barebones implemenation of the vault standard demonstrating how to constrict deposits and withdrawals to a single AssetId. From c015568432d2a98ff2408df9b88e386259a647a5 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 4 Dec 2023 17:35:04 +0530 Subject: [PATCH 24/75] fmt --- examples/src_6/single_token_vault/src/main.sw | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 56c3223..84d3894 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -8,11 +8,11 @@ use std::{ Hash, sha256, }, - string::String, storage::{ storage_map::*, storage_string::*, }, + string::String, token::{ transfer, }, @@ -150,7 +150,6 @@ impl SRC6 for Contract { None } } - } #[storage(read)] From 505f119e483485e90f544814cde8d0f00fdd0600 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 4 Dec 2023 17:42:39 +0530 Subject: [PATCH 25/75] use if instead of match --- examples/src_6/single_token_vault/src/main.sw | 68 ++++++++----------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 84d3894..9668b2a 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -47,15 +47,12 @@ configurable { impl SRC6 for Contract { #[storage(read)] fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { - match asset { - ACCEPTED_TOKEN => { - let vault_share_asset = vault_asset_id(asset, sub_id).0; - // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. - managed_assets(vault_share_asset) - }, - _ => { - 0 - } + if asset == ACCEPTED_TOKEN { + let vault_share_asset = vault_asset_id(asset, sub_id).0; + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + managed_assets(vault_share_asset) + } else { + 0 } } @@ -116,54 +113,43 @@ impl SRC6 for Contract { #[storage(read)] fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { - match asset { - ACCEPTED_TOKEN => { - // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. - Option::Some(u64::max() - managed_assets(asset)) - }, - _ => { - None - } + if asset == ACCEPTED_TOKEN { + // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. + Option::Some(u64::max() - managed_assets(asset)) + } else { + None } } #[storage(read)] fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { - match asset { - ACCEPTED_TOKEN => { - // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. - Option::Some(managed_assets(asset)) - }, - _ => { - None - } + if asset == ACCEPTED_TOKEN { + // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + Option::Some(managed_assets(asset)) + } else { + None } } #[storage(read)] fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)> { - match asset { - ACCEPTED_TOKEN => { - Some(vault_asset_id(asset, sub_id)) - }, - _ => { - None - } + if asset == ACCEPTED_TOKEN { + Some(vault_asset_id(asset, sub_id)) + } else { + None } } #[storage(read)] fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)> { let asset = storage.vault_info.get(vault_asset_id).read().asset; - match asset { - ACCEPTED_TOKEN => { - let vault_info = storage.vault_info.get(vault_asset_id).read(); - Some((vault_info.asset, vault_info.sub_id)) - } - _ => { - None - } - } + + if asset == ACCEPTED_TOKEN { + let vault_info = storage.vault_info.get(vault_asset_id).read(); + Some((vault_info.asset, vault_info.sub_id)) + } else { + None + } } } From 0aa72b7a510b485dfed3915eccc5682698c5dbaa Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Mon, 4 Dec 2023 19:17:41 +0530 Subject: [PATCH 26/75] add third example --- examples/src_6/multi_token_vault/src/main.sw | 4 +- .../single_token_single_sub_vault/.gitignore | 2 + .../single_token_single_sub_vault/Forc.toml | 9 + .../single_token_single_sub_vault/src/main.sw | 226 ++++++++++++++++++ examples/src_6/single_token_vault/src/main.sw | 4 +- 5 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 examples/src_6/single_token_single_sub_vault/.gitignore create mode 100644 examples/src_6/single_token_single_sub_vault/Forc.toml create mode 100644 examples/src_6/single_token_single_sub_vault/src/main.sw diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 6faecaf..e4c904d 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -104,13 +104,13 @@ impl SRC6 for Contract { #[storage(read)] fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. - Option::Some(u64::max() - managed_assets(asset)) + Some(u64::max() - managed_assets(asset)) } #[storage(read)] fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. - Option::Some(managed_assets(asset)) + Some(managed_assets(asset)) } #[storage(read)] diff --git a/examples/src_6/single_token_single_sub_vault/.gitignore b/examples/src_6/single_token_single_sub_vault/.gitignore new file mode 100644 index 0000000..77d3844 --- /dev/null +++ b/examples/src_6/single_token_single_sub_vault/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/examples/src_6/single_token_single_sub_vault/Forc.toml b/examples/src_6/single_token_single_sub_vault/Forc.toml new file mode 100644 index 0000000..6446f7a --- /dev/null +++ b/examples/src_6/single_token_single_sub_vault/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "single_token_single_sub_vault" + +[dependencies] +src_20 = { path = "../../../standards/src_20" } +src_6 = { path = "../../../standards/src_6" } diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw new file mode 100644 index 0000000..cf13a15 --- /dev/null +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -0,0 +1,226 @@ +contract; + +use std::{ + auth::msg_sender, + call_frames::msg_asset_id, + context::msg_amount, + hash::{ + Hash, + sha256, + }, + storage::{ + storage_map::*, + storage_string::*, + }, + string::String, + token::{ + transfer, + }, +}; + +use src_6::{Deposit, SRC6, Withdraw}; +use src_20::SRC20; + +configurable { + ACCEPTED_TOKEN: AssetId = std::constants::BASE_ASSET_ID, + ACCEPTED_SUB_VAULT: SubId = std::constants::ZERO_B256, + // Calculated as sha256((ACCEPTED_TOKEN, ACCEPTED_SUB_VAULT)) + PRE_CALCULATED_SHARE_SUB_ID: SubId = 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b, +} + +storage { + managed_assets: u64 = 0, + total_assets: u64 = 0, + total_supply: u64 = 0, + minted: bool = false, +} + +impl SRC6 for Contract { + #[storage(read)] + fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { + if asset == ACCEPTED_TOKEN && sub_id == ACCEPTED_SUB_VAULT { + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + storage.managed_assets.read() + } else { + 0 + } + } + + #[storage(read, write)] + fn deposit(receiver: Identity, sub_id: SubId) -> u64 { + require(sub_id == ACCEPTED_SUB_VAULT, "INVALID_SUB_ID"); + + let asset = msg_asset_id(); + require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); + + let asset_amount = msg_amount(); + let (shares, share_asset) = preview_deposit(asset_amount); + require(asset_amount != 0, "ZERO_ASSETS"); + + _mint(receiver, share_asset, shares); + storage.total_supply.write(storage.total_supply.read() + shares); + + storage.managed_assets.write(storage.managed_assets.read() + asset_amount); + + log(Deposit { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + sub_id: sub_id, + assets: asset_amount, + shares: shares, + }); + + shares + } + + #[storage(read, write)] + fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64 { + require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); + require(sub_id == ACCEPTED_SUB_VAULT, "INVALID_SUB_ID"); + + let shares = msg_amount(); + require(shares != 0, "ZERO_SHARES"); + + let share_asset_id = vault_assetid(); + + require(msg_asset_id() == share_asset_id, "INVALID_ASSET_ID"); + let assets = preview_withdraw(shares); + + _burn(share_asset_id, shares); + storage.total_supply.write(storage.total_supply.read() - shares); + + transfer(receiver, asset, assets); + + log(Withdraw { + caller: msg_sender().unwrap(), + receiver: receiver, + asset: asset, + sub_id: sub_id, + assets: assets, + shares: shares, + }); + + assets + } + + #[storage(read)] + fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { + if asset == ACCEPTED_TOKEN { + // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. + Some(u64::max() - storage.managed_assets.read()) + } else { + None + } + } + + #[storage(read)] + fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { + if asset == ACCEPTED_TOKEN { + // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + Some(storage.managed_assets.read()) + } else { + None + } + } + + #[storage(read)] + fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)> { + if asset == ACCEPTED_TOKEN && sub_id == ACCEPTED_SUB_VAULT { + Some((vault_assetid(), PRE_CALCULATED_SHARE_SUB_ID)) + } else { + None + } + } + + #[storage(read)] + fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)> { + if vault_assetid() == vault_asset_id { + Some((ACCEPTED_TOKEN, ACCEPTED_SUB_VAULT)) + } else { + None + } + } +} + +impl SRC20 for Contract { + #[storage(read)] + fn total_assets() -> u64 { + 1 + } + + #[storage(read)] + fn total_supply(asset: AssetId) -> Option { + Some(storage.total_supply.read()) + } + + #[storage(read)] + fn name(asset: AssetId) -> Option { + Some(String::from_ascii_str("Vault Shares")) + } + + #[storage(read)] + fn symbol(asset: AssetId) -> Option { + Some(String::from_ascii_str("VLTSHR")) + } + + #[storage(read)] + fn decimals(asset: AssetId) -> Option { + Some(9_u8) + } +} + +/// Returns the vault shares assetid for the given assets assetid and the vaults sub id +fn vault_assetid() -> AssetId { + let share_asset_id = AssetId::new(ContractId::this(), PRE_CALCULATED_SHARE_SUB_ID); + share_asset_id +} + +#[storage(read)] +fn preview_deposit(assets: u64) -> (u64, AssetId) { + let share_asset_id = vault_assetid(); + + let shares_supply = storage.total_supply.read(); + if shares_supply == 0 { + (assets, share_asset_id) + } else { + ( + assets * shares_supply / storage.managed_assets.read(), + share_asset_id, + ) + } +} + +#[storage(read)] +fn preview_withdraw(shares: u64) -> u64 { + let supply = storage.total_supply.read(); + if supply == shares { + storage.managed_assets.read() + } else { + shares * (storage.managed_assets.read() / supply) + } +} + +#[storage(read, write)] +pub fn _mint( + recipient: Identity, + asset_id: AssetId, + amount: u64, +) { + use std::token::mint_to; + + let supply = storage.total_supply.read(); + storage.total_supply.write(supply + amount); + mint_to(recipient, PRE_CALCULATED_SHARE_SUB_ID, amount); +} + +#[storage(read, write)] +pub fn _burn(asset_id: AssetId, amount: u64) { + use std::{context::this_balance, token::burn}; + + require(this_balance(asset_id) >= amount, "BurnError::NotEnoughTokens"); + // If we pass the check above, we can assume it is safe to unwrap. + let supply = storage.total_supply.read(); + storage.total_supply.write(supply - amount); + burn(PRE_CALCULATED_SHARE_SUB_ID, amount); +} diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 9668b2a..9b982a0 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -115,7 +115,7 @@ impl SRC6 for Contract { fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { if asset == ACCEPTED_TOKEN { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. - Option::Some(u64::max() - managed_assets(asset)) + Some(u64::max() - managed_assets(asset)) } else { None } @@ -125,7 +125,7 @@ impl SRC6 for Contract { fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { if asset == ACCEPTED_TOKEN { // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. - Option::Some(managed_assets(asset)) + Some(managed_assets(asset)) } else { None } From 80a651d4656c964c387eb15da4a10a3fe4cac00a Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 5 Dec 2023 18:55:25 +0530 Subject: [PATCH 27/75] finishing touches --- examples/src_6/multi_token_vault/src/main.sw | 17 +---- .../single_token_single_sub_vault/src/main.sw | 29 +-------- examples/src_6/single_token_vault/src/main.sw | 25 +------- standards/src_6/README.md | 62 ++++++++----------- standards/src_6/src/src_6.sw | 38 ++---------- 5 files changed, 40 insertions(+), 131 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index e4c904d..ceb2df6 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -8,11 +8,11 @@ use std::{ Hash, sha256, }, - string::String, storage::{ storage_map::*, storage_string::*, }, + string::String, token::{ transfer, }, @@ -75,7 +75,7 @@ impl SRC6 for Contract { } #[storage(read, write)] - fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64 { + fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64 { let shares = msg_amount(); require(shares != 0, "ZERO_SHARES"); @@ -102,7 +102,7 @@ impl SRC6 for Contract { } #[storage(read)] - fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { + fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. Some(u64::max() - managed_assets(asset)) } @@ -112,17 +112,6 @@ impl SRC6 for Contract { // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. Some(managed_assets(asset)) } - - #[storage(read)] - fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)> { - Some(vault_asset_id(asset, sub_id)) - } - - #[storage(read)] - fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)> { - let vault_info = storage.vault_info.get(vault_asset_id).read(); - Some((vault_info.asset, vault_info.sub_id)) - } } impl SRC20 for Contract { diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index cf13a15..a4aa712 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -24,7 +24,6 @@ use src_20::SRC20; configurable { ACCEPTED_TOKEN: AssetId = std::constants::BASE_ASSET_ID, ACCEPTED_SUB_VAULT: SubId = std::constants::ZERO_B256, - // Calculated as sha256((ACCEPTED_TOKEN, ACCEPTED_SUB_VAULT)) PRE_CALCULATED_SHARE_SUB_ID: SubId = 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b, } @@ -75,7 +74,7 @@ impl SRC6 for Contract { } #[storage(read, write)] - fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64 { + fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64 { require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); require(sub_id == ACCEPTED_SUB_VAULT, "INVALID_SUB_ID"); @@ -105,7 +104,7 @@ impl SRC6 for Contract { } #[storage(read)] - fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { + fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { if asset == ACCEPTED_TOKEN { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. Some(u64::max() - storage.managed_assets.read()) @@ -123,24 +122,6 @@ impl SRC6 for Contract { None } } - - #[storage(read)] - fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)> { - if asset == ACCEPTED_TOKEN && sub_id == ACCEPTED_SUB_VAULT { - Some((vault_assetid(), PRE_CALCULATED_SHARE_SUB_ID)) - } else { - None - } - } - - #[storage(read)] - fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)> { - if vault_assetid() == vault_asset_id { - Some((ACCEPTED_TOKEN, ACCEPTED_SUB_VAULT)) - } else { - None - } - } } impl SRC20 for Contract { @@ -202,11 +183,7 @@ fn preview_withdraw(shares: u64) -> u64 { } #[storage(read, write)] -pub fn _mint( - recipient: Identity, - asset_id: AssetId, - amount: u64, -) { +pub fn _mint(recipient: Identity, asset_id: AssetId, amount: u64) { use std::token::mint_to; let supply = storage.total_supply.read(); diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 9b982a0..f63c17e 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -85,7 +85,7 @@ impl SRC6 for Contract { } #[storage(read, write)] - fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64 { + fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64 { let shares = msg_amount(); require(shares != 0, "ZERO_SHARES"); @@ -112,7 +112,7 @@ impl SRC6 for Contract { } #[storage(read)] - fn max_depositable(asset: AssetId, sub_id: SubId) -> Option { + fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { if asset == ACCEPTED_TOKEN { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. Some(u64::max() - managed_assets(asset)) @@ -130,27 +130,6 @@ impl SRC6 for Contract { None } } - - #[storage(read)] - fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)> { - if asset == ACCEPTED_TOKEN { - Some(vault_asset_id(asset, sub_id)) - } else { - None - } - } - - #[storage(read)] - fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)> { - let asset = storage.vault_info.get(vault_asset_id).read().asset; - - if asset == ACCEPTED_TOKEN { - let vault_info = storage.vault_info.get(vault_asset_id).read(); - Some((vault_info.asset, vault_info.sub_id)) - } else { - None - } - } } impl SRC20 for Contract { diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 384986e..04b855a 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -28,22 +28,25 @@ The following functions MUST be implemented to follow the SRC-6 standard. Any co Method that allows depositing of the underlying asset in exchange for shares of the vault. This function takes the receiver's identity and the sub_id of the sub vault as an argument and returns the amount of shares minted to the receiver. -MUST revert if any AssetId other than the underlying is forwarded. -MUST increase `managed_assets` by `deposited_assets` (through any means including `std::context::this_balance(ASSET_ID)` if applicable). +MUST revert if any unaccepted AssetId is forwarded. +MUST increase `managed_assets` by amount of deposited assets (through any means including `std::context::this_balance(ASSET_ID)` if applicable). +MUST mint a token representing the pro-rata share of the vault, with the AssetId of `sha256((asset, sub_id))`, a hash of the AssetId of the deposited asset, and the `sub_id` of the vault. MUST increase `total_supply` of the share's AssetId by newly minted shares. MUST increase `total_assets` by one if the the AssetId is minted for the first time. MUST emit a `Deposit` log. +MUST return amount of minted shares. -### `fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64` +### `fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64` Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset This function takes the asset's AssetId, the sub_id of the sub vault, and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. -MUST revert if any AssetId other than the AssetId corresponding to the deposited asset is forwarded. +MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `sub_id` is forwarded. MUST burn the received shares. MUST reduce `total_supply` of the shares's AssetId by amount of burnt shares. MUST emit a `Withdraw` log. +MUST return amount of assets transferred to the receiver. ### `fn managed_assets(asset: AssetId, sub_id: SubId) -> u64` @@ -54,37 +57,26 @@ MUST return total amount of assets of underlying AssetId under management by vau MUST return 0 if there are no assets of underlying AssetId under management by vault. MUST NOT revert under any circumstances. -### `fn max_depositable(asset: AssetId, sub_id: SubId) -> Option` +### `fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option` Helper method for getting maximum depositable -This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. +This function takes the hypothetical receivers `Identity`, the asset's `AssetId`, and the `sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. -MUST return the maximum amount of assets that can be deposited into the contract, for the given asset. +MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. +MUST return an `Option::Some(amount)` if the given vault exists. +MUST return an `Option::None` if the given vault does not exist. +MUST account for both global and user specific limits. For example: if deposits are disabled, even temporarily, MUST return 0. -### `fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option` -Helper method for getting maximum withdrawable -This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. - -MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset. - -### `fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option` - -Method that returns the AssetId of the vault shares for the given asset and sub vault. -This function takes the asset's AssetId and the SubId of the vault as arguments and returns the AssetId of the vault shares for the given asset and sub vault. +### `fn max_withdrawable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option` -MUST return an `Option::Some(AssetId)` of the vault shares for the given asset and sub vault, if the given asset is supported. -MUST return an `Option::None` if the given asset is not supported. -MUST NOT revert under any circumstances. - -### `fn asset_of_vault(vault_asset_id: AssetId) -> Option` +Helper method for getting maximum withdrawable +This function takes the hypothetical receive's `Identity`, the asset's `AssetId`, and the `sub_id`` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. -Method that returns the AssetId of the asset of the vault for the given AssetId of the vault shares. -This function takes the AssetId of the vault shares as an argument and returns the AssetId of the asset of the vault for the given AssetId of the vault shares. - -MUST return an `Option::Some(AssetId)` of the asset of the vault for the given AssetId of the vault shares, if the given asset is supported and the vault has been initialised. -MUST return an `Option::None` if the given asset is not supported or the vault has not been initialised. -MUST NOT revert under any circumstances. +MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. +MUST return an `Option::Some(amount)` if the given vault exists. +MUST return an `Option::None` if the given vault does not exist. +MUST account for global limits. For example: if withdrawals are disabled, even temporarily, MUST return 0. ## Required logs @@ -152,22 +144,16 @@ abi SRC6 { fn deposit(receiver: Identity, sub_id: SubId) -> u64; #[storage(read, write)] - fn withdraw(asset: AssetId, sub_id: SubId, receiver: Identity) -> u64; + fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64; #[storage(read)] fn managed_assets(asset: AssetId, sub_id: SubId) -> u64; #[storage(read)] - fn max_depositable(asset: AssetId, sub_id: SubId) -> Option; + fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option; #[storage(read)] fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option; - - #[storage(read)] - fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)>; - - #[storage(read)] - fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)>; } ``` @@ -180,3 +166,7 @@ A barebones implementation of the vault standard that supports any number of sub ## [Single Token Vault](../../examples/src_6/single_token_vault/) A barebones implemenation of the vault standard demonstrating how to constrict deposits and withdrawals to a single AssetId. + +## [Single Token Single Sub Vault](../../examples/src_6/single_token_single_sub_vault/) + +A barebones implementation of the vault standard demonstrating how to constrict deposits and withdrawals to a single AssetId, and to a single Sub vault. \ No newline at end of file diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 78874c0..8af8ea3 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -64,9 +64,9 @@ abi SRC6 { /// /// # Arguments /// + /// * `receiver`: [Identity] - The receiver of the assets. /// * `asset`: [AssetId] - The asset for which the shares should be burned. /// * `sub_id`: [SubId] - The SubId of the vault. - /// * `receiver`: [Identity] - The receiver of the assets. /// /// # Returns /// @@ -79,7 +79,7 @@ abi SRC6 { /// * 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, sub_id: SubId, receiver: Identity) -> u64; + fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64; /// Returns the amount of managed assets of the given asset. /// @@ -98,10 +98,11 @@ abi SRC6 { /// /// # Additional Information /// - /// Does not account for any user or global limits. + /// Must account for any user or global limits. /// /// # Arguments /// + /// * `receiver`: [Identity] - The hypothetical receiver of the shares. /// * `asset`: [AssetId] - The asset for which the maximum amount of depositable assets should be returned. /// * `sub_id`: [SubId] - The SubId of the vault. /// @@ -110,13 +111,13 @@ abi SRC6 { /// * [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, sub_id: SubId) -> Option; + fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option; /// 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. + /// Must account for any global limits. /// /// # Arguments /// @@ -129,31 +130,4 @@ abi SRC6 { /// * [None] - If the asset is not supported by the contract. #[storage(read)] fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option; - - /// Returns the AssetId and SubId of the vault shares for the given asset and sub vault. - /// - /// # Arguments - /// - /// * `asset`: [AssetId] - The asset for which the vault shares should be returned. - /// * `sub_id`: [SubId] - The SubId of the vault. - /// - /// # Returns - /// - /// * [Some((AssetId, SubId))] - The AssetId and SubId of the vault shares for the given asset and sub vault. - /// * [None] - If the asset is not supported by the contract. - #[storage(read)] - fn vault_asset_id(asset: AssetId, sub_id: SubId) -> Option<(AssetId, SubId)>; - - /// Returns the AssetId of the asset of the vault for the given AssetId of the vault shares, and the sub_id of the vault. - /// - /// # Arguments - /// - /// * `vault_asset_id`: [AssetId] - The AssetId of the vault shares for which the asset of the vault should be returned. - /// - /// # Returns - /// - /// * [Some((AssetId, SubId))] - The AssetId of the asset of the vault for the given AssetId of the vault shares, and the sub_id of the vault. - /// * [None] - If the asset is not supported by the contract or the vault has not been initialised. - #[storage(read)] - fn asset_of_vault(vault_asset_id: AssetId) -> Option<(AssetId, SubId)>; } From b9733f1105ba598c8098b27d3c03e83c807387a6 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:29:10 +0530 Subject: [PATCH 28/75] Update examples/src_6/multi_token_vault/Forc.toml Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/multi_token_vault/Forc.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src_6/multi_token_vault/Forc.toml b/examples/src_6/multi_token_vault/Forc.toml index 7451256..7f0fe94 100644 --- a/examples/src_6/multi_token_vault/Forc.toml +++ b/examples/src_6/multi_token_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "multi_token_vault" [dependencies] -src_20 = { path = "../../../standards/src_20" } src_6 = { path = "../../../standards/src_6" } +src_20 = { path = "../../../standards/src_20" } From c3bcd225dad81b9fa93eb7bd933c66f896136e9a Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:29:27 +0530 Subject: [PATCH 29/75] Update examples/src_6/multi_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/multi_token_vault/src/main.sw | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index ceb2df6..f884e19 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -1,7 +1,6 @@ contract; use std::{ - auth::msg_sender, call_frames::msg_asset_id, context::msg_amount, hash::{ From e069a72b7396438b7cf47add6479cdd5220e4dcc Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:29:43 +0530 Subject: [PATCH 30/75] Update examples/src_6/multi_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/multi_token_vault/src/main.sw | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index f884e19..1038b93 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -7,10 +7,7 @@ use std::{ Hash, sha256, }, - storage::{ - storage_map::*, - storage_string::*, - }, + storage::storage_string::*, string::String, token::{ transfer, From 96780da8d90e598922c4b37c46f8857690ea92b6 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:30:05 +0530 Subject: [PATCH 31/75] Update examples/src_6/single_token_single_sub_vault/Forc.toml Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/single_token_single_sub_vault/Forc.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src_6/single_token_single_sub_vault/Forc.toml b/examples/src_6/single_token_single_sub_vault/Forc.toml index 6446f7a..6d03590 100644 --- a/examples/src_6/single_token_single_sub_vault/Forc.toml +++ b/examples/src_6/single_token_single_sub_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "single_token_single_sub_vault" [dependencies] -src_20 = { path = "../../../standards/src_20" } src_6 = { path = "../../../standards/src_6" } +src_20 = { path = "../../../standards/src_20" } From e07126351fae7236f74d49844a72ca689f981f6b Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:30:21 +0530 Subject: [PATCH 32/75] Update examples/src_6/single_token_single_sub_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/single_token_single_sub_vault/src/main.sw | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index a4aa712..c53e7fd 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -1,7 +1,6 @@ contract; use std::{ - auth::msg_sender, call_frames::msg_asset_id, context::msg_amount, hash::{ From 4d4e87bd100e84adc80ef5eda658350c357fe535 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:31:04 +0530 Subject: [PATCH 33/75] Update examples/src_6/single_token_single_sub_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/single_token_single_sub_vault/src/main.sw | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index c53e7fd..7e6117b 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -7,10 +7,7 @@ use std::{ Hash, sha256, }, - storage::{ - storage_map::*, - storage_string::*, - }, + storage::storage_string::*, string::String, token::{ transfer, From 2ab2c861eb56eddf7582ecf333aa0c4853644ac9 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:31:30 +0530 Subject: [PATCH 34/75] Update examples/src_6/single_token_vault/Forc.toml Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/single_token_vault/Forc.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src_6/single_token_vault/Forc.toml b/examples/src_6/single_token_vault/Forc.toml index 72a79eb..0d9305f 100644 --- a/examples/src_6/single_token_vault/Forc.toml +++ b/examples/src_6/single_token_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "single_token_vault" [dependencies] -src_20 = { path = "../../../standards/src_20" } src_6 = { path = "../../../standards/src_6" } +src_20 = { path = "../../../standards/src_20" } From 4efbc427bf301476f90c92377a6731469ad184d0 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:31:47 +0530 Subject: [PATCH 35/75] Update examples/src_6/single_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/single_token_vault/src/main.sw | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index f63c17e..b39eefe 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -1,7 +1,6 @@ contract; use std::{ - auth::msg_sender, call_frames::msg_asset_id, context::msg_amount, hash::{ From f84708b53424a9362cb09e903fefb1daf823c688 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:32:01 +0530 Subject: [PATCH 36/75] Update examples/src_6/single_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/single_token_vault/src/main.sw | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index b39eefe..3c8d8ca 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -7,10 +7,7 @@ use std::{ Hash, sha256, }, - storage::{ - storage_map::*, - storage_string::*, - }, + storage::storage_string::*, string::String, token::{ transfer, From 8a9255337d749d09fa0c6edfd00c9b35fce3427b Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:32:18 +0530 Subject: [PATCH 37/75] Update standards/src_6/README.md Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 04b855a..39ed3d7 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -21,7 +21,7 @@ Token vaults have been thoroughly explored on Ethereum and with [EIP 4626](https ## Required public functions -The following functions MUST be implemented to follow the SRC-6 standard. Any contract that implements the SRC-7 standard MUST implement the SRC-20 standard. +The following functions MUST be implemented to follow the SRC-6 standard. Any contract that implements the SRC-6 standard MUST implement the SRC-20 standard. ### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` From 6fc1d91b67c512bd704fada381e565b0e47cc2bc Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:32:35 +0530 Subject: [PATCH 38/75] Update standards/src_6/README.md Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- standards/src_6/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 39ed3d7..0e2b974 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -120,6 +120,7 @@ pub struct Withdraw { shares: u64, } ``` + `caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets of the `asset` AssetId from the subvault of `sub_id` to the receiver `receiver` The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw` method From c03c4595e95d8cbd10e112c67b3fcdc48b487d01 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:33:55 +0530 Subject: [PATCH 39/75] Update examples/src_6/multi_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/multi_token_vault/src/main.sw | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 1038b93..4bc748f 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -189,8 +189,7 @@ pub fn _mint( if supply.is_none() { storage.total_assets.write(storage.total_assets.read() + 1); } - let current_supply = supply.unwrap_or(0); - storage.total_supply.insert(asset_id, current_supply + amount); + storage.total_supply.insert(asset_id, supply.unwrap_or(0) + amount); mint_to(recipient, sub_id, amount); } From c49c5459c4a24fc76b6ede14f41d12e7c20ff23e Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:34:25 +0530 Subject: [PATCH 40/75] Update examples/src_6/multi_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/multi_token_vault/src/main.sw | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 4bc748f..d824955 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -87,11 +87,11 @@ impl SRC6 for Contract { log(Withdraw { caller: msg_sender().unwrap(), - receiver: receiver, - asset: asset, - sub_id: sub_id, - assets: assets, - shares: shares, + receiver, + asset, + sub_id, + assets, + shares, }); assets From cbb1ad4451c05d612ad1c9941a8e06234366a43f Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:34:53 +0530 Subject: [PATCH 41/75] Update examples/src_6/multi_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/multi_token_vault/src/main.sw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index d824955..5c7b4fa 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -47,9 +47,10 @@ impl SRC6 for Contract { #[storage(read, write)] fn deposit(receiver: Identity, sub_id: SubId) -> u64 { let asset_amount = msg_amount(); + require(asset_amount != 0, "ZERO_ASSETS"); + let asset = msg_asset_id(); let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, asset_amount); - require(asset_amount != 0, "ZERO_ASSETS"); _mint(receiver, share_asset, share_asset_sub_id, shares); storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); From ab37a33908022a76331dc7618b6cb12950c71619 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:35:59 +0530 Subject: [PATCH 42/75] Update examples/src_6/multi_token_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/multi_token_vault/src/main.sw | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 5c7b4fa..f565a09 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -61,11 +61,11 @@ impl SRC6 for Contract { log(Deposit { caller: msg_sender().unwrap(), - receiver: receiver, - asset: asset, - sub_id: sub_id, + receiver, + asset, + sub_id, assets: asset_amount, - shares: shares, + shares, }); shares From 35310ca4b9ae249b3daae581c75fa4da9eeef93a Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:36:21 +0530 Subject: [PATCH 43/75] Update examples/src_6/single_token_single_sub_vault/src/main.sw Co-authored-by: Braqzen <103777923+Braqzen@users.noreply.github.com> --- examples/src_6/single_token_single_sub_vault/src/main.sw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index 7e6117b..8782e8c 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -49,8 +49,8 @@ impl SRC6 for Contract { require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); let asset_amount = msg_amount(); - let (shares, share_asset) = preview_deposit(asset_amount); require(asset_amount != 0, "ZERO_ASSETS"); + let (shares, share_asset) = preview_deposit(asset_amount); _mint(receiver, share_asset, shares); storage.total_supply.write(storage.total_supply.read() + shares); From 82895398a6d61d30d0b6b2479f3ffd1e8d4b735e Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Thu, 7 Dec 2023 18:14:53 +0530 Subject: [PATCH 44/75] Add documentation and fix bug --- examples/src_6/multi_token_vault/Forc.toml | 2 +- examples/src_6/multi_token_vault/src/main.sw | 24 +++++++----- .../single_token_single_sub_vault/Forc.toml | 2 +- .../single_token_single_sub_vault/src/main.sw | 36 +++++++++++------- examples/src_6/single_token_vault/Forc.toml | 2 +- examples/src_6/single_token_vault/src/main.sw | 37 +++++++++++-------- 6 files changed, 61 insertions(+), 42 deletions(-) diff --git a/examples/src_6/multi_token_vault/Forc.toml b/examples/src_6/multi_token_vault/Forc.toml index 7f0fe94..7451256 100644 --- a/examples/src_6/multi_token_vault/Forc.toml +++ b/examples/src_6/multi_token_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "multi_token_vault" [dependencies] -src_6 = { path = "../../../standards/src_6" } src_20 = { path = "../../../standards/src_20" } +src_6 = { path = "../../../standards/src_6" } diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index f565a09..ddf3bef 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -27,23 +27,21 @@ pub struct VaultInfo { } storage { - /// Vault share AssetId -> VaultInfo + /// Vault share AssetId -> VaultInfo. vault_info: StorageMap = StorageMap {}, + /// Number of different assets managed by this contract. total_assets: u64 = 0, + /// Total supply of shares for each asset. total_supply: StorageMap = StorageMap {}, + /// Asset name. name: StorageMap = StorageMap {}, + /// Asset symbol. symbol: StorageMap = StorageMap {}, + /// Asset decimals. decimals: StorageMap = StorageMap {}, } impl SRC6 for Contract { - #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { - let vault_share_asset = vault_asset_id(asset, sub_id).0; - // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. - managed_assets(vault_share_asset) - } - #[storage(read, write)] fn deposit(receiver: Identity, sub_id: SubId) -> u64 { let asset_amount = msg_amount(); @@ -53,7 +51,7 @@ impl SRC6 for Contract { let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, asset_amount); _mint(receiver, share_asset, share_asset_sub_id, shares); - storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); + storage.total_supply.insert(share_asset, storage.total_supply.get(share_asset).read() + shares); let mut vault_info = storage.vault_info.get(share_asset).read(); vault_info.managed_assets = vault_info.managed_assets + asset_amount; @@ -82,7 +80,7 @@ impl SRC6 for Contract { let assets = preview_withdraw(share_asset_id, shares); _burn(share_asset_id, share_asset_sub_id, shares); - storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); + storage.total_supply.insert(share_asset_id, storage.total_supply.get(share_asset_id).read() - shares); transfer(receiver, asset, assets); @@ -97,6 +95,12 @@ impl SRC6 for Contract { assets } + #[storage(read)] + fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { + let vault_share_asset = vault_asset_id(asset, sub_id).0; + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + managed_assets(vault_share_asset) + } #[storage(read)] fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { diff --git a/examples/src_6/single_token_single_sub_vault/Forc.toml b/examples/src_6/single_token_single_sub_vault/Forc.toml index 6d03590..6446f7a 100644 --- a/examples/src_6/single_token_single_sub_vault/Forc.toml +++ b/examples/src_6/single_token_single_sub_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "single_token_single_sub_vault" [dependencies] -src_6 = { path = "../../../standards/src_6" } src_20 = { path = "../../../standards/src_20" } +src_6 = { path = "../../../standards/src_6" } diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index 8782e8c..26f8aed 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -2,6 +2,10 @@ contract; use std::{ call_frames::msg_asset_id, + constants::{ + BASE_ASSET_ID, + ZERO_B256, + }, context::msg_amount, hash::{ Hash, @@ -18,29 +22,23 @@ use src_6::{Deposit, SRC6, Withdraw}; use src_20::SRC20; configurable { - ACCEPTED_TOKEN: AssetId = std::constants::BASE_ASSET_ID, - ACCEPTED_SUB_VAULT: SubId = std::constants::ZERO_B256, + /// The only asset that can be deposited and withdrawn from this vault. + ACCEPTED_TOKEN: AssetId = BASE_ASSET_ID, + /// The only sub vault that can be deposited and withdrawn from this vault. + ACCEPTED_SUB_VAULT: SubId = ZERO_B256, PRE_CALCULATED_SHARE_SUB_ID: SubId = 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b, } storage { + /// The total amount of assets managed by this vault. managed_assets: u64 = 0, - total_assets: u64 = 0, + /// The total amount of shares minted by this vault. total_supply: u64 = 0, + /// Whether the vault shares have been minted. minted: bool = false, } impl SRC6 for Contract { - #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { - if asset == ACCEPTED_TOKEN && sub_id == ACCEPTED_SUB_VAULT { - // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. - storage.managed_assets.read() - } else { - 0 - } - } - #[storage(read, write)] fn deposit(receiver: Identity, sub_id: SubId) -> u64 { require(sub_id == ACCEPTED_SUB_VAULT, "INVALID_SUB_ID"); @@ -99,6 +97,16 @@ impl SRC6 for Contract { assets } + #[storage(read)] + fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { + if asset == ACCEPTED_TOKEN && sub_id == ACCEPTED_SUB_VAULT { + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + storage.managed_assets.read() + } else { + 0 + } + } + #[storage(read)] fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { if asset == ACCEPTED_TOKEN { @@ -112,7 +120,7 @@ impl SRC6 for Contract { #[storage(read)] fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { if asset == ACCEPTED_TOKEN { - // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. Some(storage.managed_assets.read()) } else { None diff --git a/examples/src_6/single_token_vault/Forc.toml b/examples/src_6/single_token_vault/Forc.toml index 0d9305f..72a79eb 100644 --- a/examples/src_6/single_token_vault/Forc.toml +++ b/examples/src_6/single_token_vault/Forc.toml @@ -5,5 +5,5 @@ license = "Apache-2.0" name = "single_token_vault" [dependencies] -src_6 = { path = "../../../standards/src_6" } src_20 = { path = "../../../standards/src_20" } +src_6 = { path = "../../../standards/src_6" } diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 3c8d8ca..b6406ea 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -2,6 +2,7 @@ contract; use std::{ call_frames::msg_asset_id, + constants::BASE_ASSET_ID, context::msg_amount, hash::{ Hash, @@ -27,31 +28,26 @@ pub struct VaultInfo { } storage { - /// Vault share AssetId -> VaultInfo + /// Vault share AssetId -> VaultInfo. vault_info: StorageMap = StorageMap {}, + /// Number of different assets managed by this contract. total_assets: u64 = 0, + /// Total supply of shares. total_supply: StorageMap = StorageMap {}, + /// Asset name. name: StorageMap = StorageMap {}, + /// Asset symbol. symbol: StorageMap = StorageMap {}, + /// Asset decimals. decimals: StorageMap = StorageMap {}, } configurable { - ACCEPTED_TOKEN: AssetId = std::constants::BASE_ASSET_ID, + /// The only asset that can be deposited and withdrawn from this vault. + ACCEPTED_TOKEN: AssetId = BASE_ASSET_ID, } impl SRC6 for Contract { - #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { - if asset == ACCEPTED_TOKEN { - let vault_share_asset = vault_asset_id(asset, sub_id).0; - // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. - managed_assets(vault_share_asset) - } else { - 0 - } - } - #[storage(read, write)] fn deposit(receiver: Identity, sub_id: SubId) -> u64 { let asset_amount = msg_amount(); @@ -62,7 +58,7 @@ impl SRC6 for Contract { require(asset_amount != 0, "ZERO_ASSETS"); _mint(receiver, share_asset, share_asset_sub_id, shares); - storage.total_supply.insert(asset, storage.total_supply.get(asset).read() + shares); + storage.total_supply.insert(share_asset, storage.total_supply.get(share_asset).read() + shares); let mut vault_info = storage.vault_info.get(share_asset).read(); vault_info.managed_assets = vault_info.managed_assets + asset_amount; @@ -91,7 +87,7 @@ impl SRC6 for Contract { let assets = preview_withdraw(share_asset_id, shares); _burn(share_asset_id, share_asset_sub_id, shares); - storage.total_supply.insert(asset, storage.total_supply.get(asset).read() - shares); + storage.total_supply.insert(share_asset_id, storage.total_supply.get(share_asset_id).read() - shares); transfer(receiver, asset, assets); @@ -107,6 +103,17 @@ impl SRC6 for Contract { assets } + #[storage(read)] + fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { + if asset == ACCEPTED_TOKEN { + let vault_share_asset = vault_asset_id(asset, sub_id).0; + // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. + managed_assets(vault_share_asset) + } else { + 0 + } + } + #[storage(read)] fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { if asset == ACCEPTED_TOKEN { From 6cb7bd0923362d69925e40af3bd6e684460a90a1 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Thu, 7 Dec 2023 18:15:56 +0530 Subject: [PATCH 45/75] remove unnecessary into --- examples/src_6/multi_token_vault/src/main.sw | 2 +- examples/src_6/single_token_vault/src/main.sw | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index ddf3bef..041335a 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -144,7 +144,7 @@ impl SRC20 for Contract { /// Returns the vault shares assetid and subid for the given assets assetid and the vaults sub id fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { - let share_asset_sub_id = sha256((asset.into(), sub_id)); + let share_asset_sub_id = sha256((asset, sub_id)); let share_asset_id = AssetId::new(ContractId::this(), share_asset_sub_id); (share_asset_id, share_asset_sub_id) } diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index b6406ea..443a11e 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -164,7 +164,7 @@ impl SRC20 for Contract { /// Returns the vault shares assetid and subid for the given assets assetid and the vaults sub id fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { - let share_asset_sub_id = sha256((asset.into(), sub_id)); + let share_asset_sub_id = sha256((asset, sub_id)); let share_asset_id = AssetId::new(ContractId::this(), share_asset_sub_id); (share_asset_id, share_asset_sub_id) } From 18361e55c670e0b5e8876a7f8b1bb42a560df211 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Thu, 7 Dec 2023 18:19:50 +0530 Subject: [PATCH 46/75] unsafe reads fixed --- examples/src_6/multi_token_vault/src/main.sw | 7 +++++-- examples/src_6/single_token_single_sub_vault/src/main.sw | 4 ++-- examples/src_6/single_token_vault/src/main.sw | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 041335a..fa28a41 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -151,14 +151,17 @@ fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { #[storage(read)] fn managed_assets(share_asset: AssetId) -> u64 { - storage.vault_info.get(share_asset).read().managed_assets + match storage.vault_info.get(share_asset).try_read() { + Some(vault_info) => vault_info.managed_assets, + None => 0, + } } #[storage(read)] fn preview_deposit(asset: AssetId, sub_id: SubId, assets: u64) -> (u64, AssetId, SubId) { let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); - let shares_supply = storage.total_supply.get(share_asset_id).read(); + let shares_supply = storage.total_supply.get(share_asset_id).try_read().unwrap_or(0); if shares_supply == 0 { (assets, share_asset_id, share_asset_sub_id) } else { diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index 26f8aed..7227f1a 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -165,12 +165,12 @@ fn vault_assetid() -> AssetId { fn preview_deposit(assets: u64) -> (u64, AssetId) { let share_asset_id = vault_assetid(); - let shares_supply = storage.total_supply.read(); + let shares_supply = storage.total_supply.try_read().unwrap_or(0); if shares_supply == 0 { (assets, share_asset_id) } else { ( - assets * shares_supply / storage.managed_assets.read(), + assets * shares_supply / storage.managed_assets.try_read().unwrap_or(0), share_asset_id, ) } diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 443a11e..5790cff 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -171,14 +171,17 @@ fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { #[storage(read)] fn managed_assets(share_asset: AssetId) -> u64 { - storage.vault_info.get(share_asset).read().managed_assets + match storage.vault_info.get(share_asset).try_read() { + Some(vault_info) => vault_info.managed_assets, + None => 0, + } } #[storage(read)] fn preview_deposit(asset: AssetId, sub_id: SubId, assets: u64) -> (u64, AssetId, SubId) { let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); - let shares_supply = storage.total_supply.get(share_asset_id).read(); + let shares_supply = storage.total_supply.get(share_asset_id).try_read().unwrap_or(0); if shares_supply == 0 { (assets, share_asset_id, share_asset_sub_id) } else { From 00062e2cf47668339c0c2e83764339758cffc639 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 8 Dec 2023 00:31:38 +0530 Subject: [PATCH 47/75] remove doubling --- .../single_token_single_sub_vault/src/main.sw | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index 7227f1a..b54f3f7 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -57,11 +57,11 @@ impl SRC6 for Contract { log(Deposit { caller: msg_sender().unwrap(), - receiver: receiver, - asset: asset, - sub_id: sub_id, + receiver, + asset, + sub_id, assets: asset_amount, - shares: shares, + shares, }); shares @@ -87,11 +87,11 @@ impl SRC6 for Contract { log(Withdraw { caller: msg_sender().unwrap(), - receiver: receiver, - asset: asset, - sub_id: sub_id, - assets: assets, - shares: shares, + receiver, + asset, + sub_id, + assets, + shares, }); assets From a012f6650196d045486d14e1dffcbf7f6a7a88d5 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 8 Dec 2023 00:34:31 +0530 Subject: [PATCH 48/75] forc fmt --- examples/src_6/multi_token_vault/src/main.sw | 32 ++++++++++++++++--- .../single_token_single_sub_vault/src/main.sw | 17 +++++++--- examples/src_6/single_token_vault/src/main.sw | 32 ++++++++++++++++--- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index fa28a41..50fe69b 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -51,10 +51,19 @@ impl SRC6 for Contract { let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, asset_amount); _mint(receiver, share_asset, share_asset_sub_id, shares); - storage.total_supply.insert(share_asset, storage.total_supply.get(share_asset).read() + shares); + storage + .total_supply + .insert( + share_asset, + storage + .total_supply + .get(share_asset) + .read() + shares, + ); let mut vault_info = storage.vault_info.get(share_asset).read(); - vault_info.managed_assets = vault_info.managed_assets + asset_amount; + vault_info.managed_assets = vault_info + .managed_assets + asset_amount; storage.vault_info.insert(share_asset, vault_info); log(Deposit { @@ -80,7 +89,15 @@ impl SRC6 for Contract { let assets = preview_withdraw(share_asset_id, shares); _burn(share_asset_id, share_asset_sub_id, shares); - storage.total_supply.insert(share_asset_id, storage.total_supply.get(share_asset_id).read() - shares); + storage + .total_supply + .insert( + share_asset_id, + storage + .total_supply + .get(share_asset_id) + .read() - shares, + ); transfer(receiver, asset, assets); @@ -197,7 +214,9 @@ pub fn _mint( if supply.is_none() { storage.total_assets.write(storage.total_assets.read() + 1); } - storage.total_supply.insert(asset_id, supply.unwrap_or(0) + amount); + storage + .total_supply + .insert(asset_id, supply.unwrap_or(0) + amount); mint_to(recipient, sub_id, amount); } @@ -205,7 +224,10 @@ pub fn _mint( pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { use std::{context::this_balance, token::burn}; - require(this_balance(asset_id) >= amount, "BurnError::NotEnoughTokens"); + require( + this_balance(asset_id) >= amount, + "BurnError::NotEnoughTokens", + ); // If we pass the check above, we can assume it is safe to unwrap. let supply = storage.total_supply.get(asset_id).try_read().unwrap(); storage.total_supply.insert(asset_id, supply - amount); diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index b54f3f7..488d22d 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -51,9 +51,13 @@ impl SRC6 for Contract { let (shares, share_asset) = preview_deposit(asset_amount); _mint(receiver, share_asset, shares); - storage.total_supply.write(storage.total_supply.read() + shares); + storage + .total_supply + .write(storage.total_supply.read() + shares); - storage.managed_assets.write(storage.managed_assets.read() + asset_amount); + storage + .managed_assets + .write(storage.managed_assets.read() + asset_amount); log(Deposit { caller: msg_sender().unwrap(), @@ -81,7 +85,9 @@ impl SRC6 for Contract { let assets = preview_withdraw(shares); _burn(share_asset_id, shares); - storage.total_supply.write(storage.total_supply.read() - shares); + storage + .total_supply + .write(storage.total_supply.read() - shares); transfer(receiver, asset, assets); @@ -199,7 +205,10 @@ pub fn _mint(recipient: Identity, asset_id: AssetId, amount: u64) { pub fn _burn(asset_id: AssetId, amount: u64) { use std::{context::this_balance, token::burn}; - require(this_balance(asset_id) >= amount, "BurnError::NotEnoughTokens"); + require( + this_balance(asset_id) >= amount, + "BurnError::NotEnoughTokens", + ); // If we pass the check above, we can assume it is safe to unwrap. let supply = storage.total_supply.read(); storage.total_supply.write(supply - amount); diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 5790cff..691e980 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -58,10 +58,19 @@ impl SRC6 for Contract { require(asset_amount != 0, "ZERO_ASSETS"); _mint(receiver, share_asset, share_asset_sub_id, shares); - storage.total_supply.insert(share_asset, storage.total_supply.get(share_asset).read() + shares); + storage + .total_supply + .insert( + share_asset, + storage + .total_supply + .get(share_asset) + .read() + shares, + ); let mut vault_info = storage.vault_info.get(share_asset).read(); - vault_info.managed_assets = vault_info.managed_assets + asset_amount; + vault_info.managed_assets = vault_info + .managed_assets + asset_amount; storage.vault_info.insert(share_asset, vault_info); log(Deposit { @@ -87,7 +96,15 @@ impl SRC6 for Contract { let assets = preview_withdraw(share_asset_id, shares); _burn(share_asset_id, share_asset_sub_id, shares); - storage.total_supply.insert(share_asset_id, storage.total_supply.get(share_asset_id).read() - shares); + storage + .total_supply + .insert( + share_asset_id, + storage + .total_supply + .get(share_asset_id) + .read() - shares, + ); transfer(receiver, asset, assets); @@ -218,7 +235,9 @@ pub fn _mint( storage.total_assets.write(storage.total_assets.read() + 1); } let current_supply = supply.unwrap_or(0); - storage.total_supply.insert(asset_id, current_supply + amount); + storage + .total_supply + .insert(asset_id, current_supply + amount); mint_to(recipient, sub_id, amount); } @@ -226,7 +245,10 @@ pub fn _mint( pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { use std::{context::this_balance, token::burn}; - require(this_balance(asset_id) >= amount, "BurnError::NotEnoughTokens"); + require( + this_balance(asset_id) >= amount, + "BurnError::NotEnoughTokens", + ); // If we pass the check above, we can assume it is safe to unwrap. let supply = storage.total_supply.get(asset_id).try_read().unwrap(); storage.total_supply.insert(asset_id, supply - amount); From 16023858218a851fa7c97c4e3d1965eea7fc74fc Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 8 Dec 2023 17:23:17 +0530 Subject: [PATCH 49/75] remove unncessary braces --- examples/src_6/multi_token_vault/src/main.sw | 4 +--- examples/src_6/single_token_single_sub_vault/src/main.sw | 4 +--- examples/src_6/single_token_vault/src/main.sw | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 50fe69b..759dc63 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -9,9 +9,7 @@ use std::{ }, storage::storage_string::*, string::String, - token::{ - transfer, - }, + token::transfer }; use src_6::{Deposit, SRC6, Withdraw}; diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index 488d22d..5a4ccd2 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -13,9 +13,7 @@ use std::{ }, storage::storage_string::*, string::String, - token::{ - transfer, - }, + token::transfer }; use src_6::{Deposit, SRC6, Withdraw}; diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 691e980..22b1c22 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -10,9 +10,7 @@ use std::{ }, storage::storage_string::*, string::String, - token::{ - transfer, - }, + token::transfer }; use src_6::{Deposit, SRC6, Withdraw}; From c71f8ba1c362c8538a3dfd0df763631901af2137 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 8 Dec 2023 20:00:13 +0530 Subject: [PATCH 50/75] fmt --- examples/src_6/multi_token_vault/src/main.sw | 2 +- examples/src_6/single_token_single_sub_vault/src/main.sw | 2 +- examples/src_6/single_token_vault/src/main.sw | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 759dc63..7ac2c5f 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -9,7 +9,7 @@ use std::{ }, storage::storage_string::*, string::String, - token::transfer + token::transfer, }; use src_6::{Deposit, SRC6, Withdraw}; diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index 5a4ccd2..e57ab53 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -13,7 +13,7 @@ use std::{ }, storage::storage_string::*, string::String, - token::transfer + token::transfer, }; use src_6::{Deposit, SRC6, Withdraw}; diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 22b1c22..bda46b4 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -10,7 +10,7 @@ use std::{ }, storage::storage_string::*, string::String, - token::transfer + token::transfer, }; use src_6::{Deposit, SRC6, Withdraw}; From 3c02c47fe5833e88b969493a7f896bd3f9e69787 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 12 Dec 2023 13:43:42 +0530 Subject: [PATCH 51/75] change logo --- .../src_6/.docs/src-6-logo-dark-theme.png | Bin 16110 -> 18103 bytes .../src_6/.docs/src-6-logo-light-theme.png | Bin 17150 -> 19333 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/standards/src_6/.docs/src-6-logo-dark-theme.png b/standards/src_6/.docs/src-6-logo-dark-theme.png index 802bbe196da643790d672ebe3ff47fe5524e1e24..5795bb9ed7cc0c486df8d9fae9b198cb167f329b 100644 GIT binary patch delta 14372 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 Zd8?z*&V7o;A_({g*EPOXtL>cdzW}r&=kfpm delta 12363 zcmbVycTiJN7bg&q(1X&Xh><2zL+>a>nuwr)C{0SJLI5H37Z3%csVEYPC{hHZMri>F zh@cX>ln8++N++O{h@tG`n{Q`lXLe?HmOmcDeUEeRx%b?2&hPwAQwAe7?x7@O&m$>u zV2TR@=cM~Q$UKkA?A4mKT0SP$am*+jT`5%nyUP~RyAapvXbcN)EfKX!e?C+!bxoSY z^L60IyRhDhoX_pl#xX^f970Nce~1Y-9IyQ98nW->*>H{{zQ zB$D7MC%^ty5VyKKq4XxXLn7;!Fg$#{2>2XUn>sorD8Sprm>>fQQNuJ+uE;`9`m)}u zx4Y8NyP5>q)huVDv9xPDRR~)7lru0e-t#jyzG7i)d>R!RjPwiiW?+ach>$>wryq;@09L_?L);>Ut_~pK(p0%jMwTwUa3i{X=6bAfDdv4HvDsc+D z{lz)qmw7tDRPs?G^rU*=3nmWU8|rqKO8g9|-^C;LWJ5py{Kg>Bt5>19?;*yv$nIzQ_TH2Z_nn(q2H7_p(H8oYF!YyTOZ3TojQr*i_OH*47 ziOkkuso+AWsw!)#X{%}~t0UC1S6PC%5IU;L*AS{YDr!2)YS})=;Q#vw?&+~hOpDB!&6n=+bdfdYQcp-DEu#RxSMQ#Q0BeJ zC&JmEco6`{DOL@(ZO+;-28PoN7A6<2MSfc=MCZ=fV`+votOfScw-VWhNtdIcjC_10 zB@eH-OnKZ4cbq`GIikaDVdH;V*Q;tQR`D?{D>W>2Oib)hw$rAJej{lKu+wY`4>hn} zkF{y^UhS+C9x9t}Wd~Jf2gCIpPw$Rx%FWKk4a5Ne4-}pRGy4C2n234kH;i$)DGMia z_I4S#vtrgDZ!wyTcmKrWzcnoYG;+?==ppWzcN)pnkzRX|zS`Phml+p)*ik-5JDvrE z1uu+`HKN^oY!2P1E&O<3rR;XAKLBZjbiCRvm|d(FH2Nx$VNd=xey9;UcO^xELWkfm z5}oCkHP&?I`wU$E(ZhYT-JZSK<9Fam%h6rnoLgbD()yIQ2Ga&vDqOVZ+V zxIfd;2f8;phSP%!m_=C&nA*63$m+c7TPGq$wE0da!H#d~r|pg~=t@I26HE!i=hN~W z!Hsz>bpb7&K)OcpqCnl-@*KdSMSY{EjjFu4T%xJ1qS^WaP9aDJk}$w{+BMR23PHonM`3UBIDzIY@C0#x$b@<8raY99&tCa{%g zh(9`ve;EJp7AxY>pbiYw3ua_KbR-FWK@faME`pDwhc7seUi?RD%9jfDDhE~_%xf#h zr;Tcl@oq2vjC{zg&2WsobdTO3+$(vcT)ea%_bOrX{^+r{DG~)?Py6o7bf8Ooj{NkZf6}a--AqH??3WCr{Bi4{dIV?y;nIs!ovy`8 z)7!0=_|4`4&jbl&H)vbx6V8dk+;vH*HZsc_!oIXdW3|^0AKl7O=V~jng;R;yo2)%| z+)EU5VMb5P0JWUo1BME)XMKBR4WD8!WfE-|2VT&FBFxFFD+#P2@fMtpun(hZ*JMTN z!-9^5&^PhGTT>H&rplH$dO7qdVcwgI5b4f6U(VPI z$u@ttKsKFMf}npmLn1hC-z~b;HS1Wuf7Qz%<4ON}%-4QJgdn&Xd|OQYx#H%lT9_vf zr7kGtGq%(R`d-OO!oaXeF&WfJ~ZC88JWD2@oC!Jq2?ZQGZ5u8X||Zi2Ja@owmM5jDk}(H$L=kd3%okM z)owa(LG+n>pL^|?Mg<7o;X7BtnTZ2NnY z_nA&0=3#+=QGY-8#7&PGEW<*)FzU?bsA}Es(`;=<=dAI^X*WslO%n*P~b4FI8-{HMJ{LAwIY z7*^T(4LD_?c{YiDqsRG5_3p3a$2~-wF0Dc}WKB>6=q_1|xWpC?2rG|K_c|eZDoTf2JcZ{N1pt{Gr%&PE7$A;evbY1c{3^g5xrd6ib9;HA%V z4-niTG%jz^3GHZgfE|8eU6wPF%TIpi^oGEV4h>(12fHHMKh%d4rDQqxIeu_1=CbD)QqDdORq;$A(Pgkd0$RMFr0>&7Gfr%diT^E;W#HvC|$;{_xOV(+6K;^2!g_OI|eKw+T6S!;a$PX_b}U9>^p zr?4rZunX$<6)rwJPMPl-bJf(J5TSo z9gn$l>RQz{kAHOyepFv^UxO2d2$l?Y8yqP0<1m-HMUKJ=BCTVDu3t!Z#Dy*3lCJFL zMp**m2xZU*!5YMCsQpYJBv`D%TX45pT4TvZUE! zSV#|!dXuZ|&%1w$_rA6E@x7K+F)VyyGc;-Kb;^Pb#q-c|w5BsoOktr(b-B&oWZt?2 z{_vhqIb*Ua<^+W(&m{P)e#REjb2sMv(4ZP_{`iC+iy|-@U<+l74jy8-#K3*bFn4~3 zO|AQ1wUy1IsF(Tsd^+uALMQR{@|%H*r_|T82XJNavWdX>vVhIb=6suHM^>r zMFk-8GW7tsy=2VNUx` z>ZA}#Ci9!2CFQBf6$4v>e zQZG+Oo^7=DRIAnk<57~(K7&(c*LwKr(ziIKYO8>bOXtFISyI@Zf(v=R-YTDEYw@7} z<06Qgv!VJ@L&RPUOu3daHzP;1c8#KN=*{!@HuUP+((SA4-V1n&TAlNgFZa0swf*q* z&z+KcyCZJNQ#XW#pAU99RC&C|YtmEse1xx}FnFHp3H0s2+4q%}xH2aym+X_Wei?6E zRepO+h`b-?6p=feCego2WvA_HsLCw?EfF-jF_gB_zy@AKInGI*)$5e_Izz9Jss_Gc;<`V|AkRLHNo~j^JYF2jk!mO}o8($=lTJ`<|+0Yy5&6V9PM1x1spZ(#r zeKb~u&&S&g(0Unnjo)sF*!+<`yLW${-Y7PiXL!+#={ciA_8&v4Dvnj{xl%Xb#1_MI zmD)lQLBQRGD>dr0Hi5qlAlVEmeWcb{!5OK%6k(4&e(H*E;2Q_cn5zPtiG?fEd+6e~ zubU((WOQZ4goLhMVCeTV?PnwxV?3bBVw*k*z5W-6blXWj3(UGV$uf9DMgdZkMVVYX# ztwM9hRq2fYc5SFo%H$buQ2*%p%3%Z1+)v}RYW3T4`}8(D&6t-1u?EUnPqYo*LJ@8@ zUyyDW(kB{T?b}wuI)9G5C7+IJoT=jb70#Fi;O}n8oarQQ2ixXfM@4C##-sj$Xeg0SiOpYwuhiWeT>3&a89#0-=+7zeYgK;XQ#1JbfPE*H+UNG zCbR0F;n#D9>wQggsFSMoM5=pl`y)N4_bY|wBFQdBU&~(z3SDlPE`W?5E|=(9jUvCl zhiPU1Om)5F_f4)u_6mS)Cpn%lVg-|uD6jWmT>3l^?id^~hIPyeHQ7|4y1u2~O8k9$L=xutnIzfIZjRM)-{n!%_TP{ShdS-!F4w!xt;^3f z`;(Tp3lTkjt?!Z|)ic8HC~}n?uiNkRac@hifAC%-e>W_6=U$0jVa=H^nHFHC{gSY% z+vRk};oe!(N_xD|)xp2adqrlW$`N=y*58wXj^&x_y zLy54n_~oxU#mtNrXHRFAejF>1$taNT^f|0EAKOA_#n>!ypC~q9DHL6!-VKqT55Sbu zul>iA*95TW2`WqQ4jo9aLUr)d!tLd)MJ|4+G}K1pZ2AD1==&Ufur1tl+-q#O-xEI1 zg4@VZE4~@J5tQeeMYlL(Jky?9(#Cbcv_?oi#s^1nE64&EH`b96=BapB$qThz9HXmx zls0nBQWW8tWi#t3b~y1`z|LKUV(vj%>ma7&#Eg>dn{i>8fGlH>XocEsIQU!mqZFZ9 zCLHIMOb?!HTtj%gnPv>`v-9j5c~nwQH)5I&v>R`izOkgOh^F;Rz4tYXtV~=)54Yeu zeo$vaX%fcJQDdmv;zc5Ux$`=A+YGr#K4c85y$m8~za(y1Z7N1`@lvAL6sEsDnz?od z>2@hk9k_k`V+_uabB~F(65@7MU3bDU23KU6cftBmlntPsJS5=R#{BnuYSnWt=Nr}+ z2IqDSD=E&G*AsT4w9W1r%6-4v`zP$+HB}kDtZAe~ghibF%M0t>ZphUf!ZM(R{l?!y z(qIGN+6xK%&9h&2)~bYlS5$-f*%JoM?4Jxxz{8*I`VA>roVH?LQXkla(b~UN_6TJu zdU8gaLSGuT${sZE(TDazid$HcUWZ*!O8Iwz(u-N|oiA;dxKYT4!ZkpgZ&5dDEFTtJ z4&F(|1f>3E*U@os@MHf<$SM7>Sm67M?=cU}mweD3X)G-_>0{|!{+T?uESqY8OeZ=p3!DZtl@k`^Rr1&g!Q+$z z2IowAb$4@)?Sj1=V-41eFHEK9hbUGqzn#X?=b0{uyUAq7TVQ?p^pt{*IvOxbTz$S_j_An z0^m}Fe#qr7T_l&m^I(Wz1f5c7#M|1km-RPF{rV+GbF)L4rbX>C6Bb1j<&B2~TVv9& z?G5=?PC52;D?P)K#-HnGqs7;#z1fx{^GsLCaiO=4H76cW56Z!m+%@nHpd&ITJ0c%A zCb;D&Lnve~01=9u6eIQcba0nbUoKEHo^EFx<`r+ZgDlECPWkr)*7X6=6GIFPVzXUz zM*|!ivoR^tR%=p=soyqjsRxRxbSpIQ3ah?s$uVrUo~vWn@zUwjynFg9Pe1pmk>z_V zpu;u$8Mt%8oU~mUi38m3(G>y%ZhjtD7~4WB-N7k+x~(j%P1t7rQlF?Fqse=lVdh5h zM$O9y4z-A$--sS>>iYrWftc0>55=T2ThF~vnK|X(FBKR1glH@*HrpY1?no09PWR_E z8kR=k+)UFQ=iX=D@8Rx=YgEylP_W9lmZx#=2}4uv*Z!JMZHF6xC)({s@!vx5io=Y~ zN@f&#A!}trI_z=L8Ho2He{-C$(}*(i#B_Gw-e5 zl4VG1)F4DpDS(W4)a?vrz;1|R3uoQWC4I4U0ps2+gUu)clbzqUhcz?zK#j;|mKc1V znC__$Z$NYf>QHbk&tVa1s3Kmz2t1Lf@$s=0W8O1OHQGytb=|dxZ7JoG47nZ#NCL-f z!#JNHYKL?C8Bg`B3ApZ3kv9ykN7Fn(1YlgQ3DEVx=@6g_39Jc4bMYKt`k~#?Zn-eg zUDZx{$}rK<(nZ$9l0F?DkMc|pDaH>XaCU}Y&t(pHru*bMna(Ux512j&e9t2Ik2rJK zKn8!!ezUWh*b3tFppf4hC&Xcl>ms3dHQqgbJo2FYwv)s``N&%qLjKtxgH6yYv;ze8 z>EPn(YMnBKtd6+p!W+L$3m2+HcmU0cQJUK6Yjr4RzY1JV@(ieIEa?NToP{a+r>XW$4Ow5)U3oba7OBR z_(VL2_{}hKslP)#VufkkAjkwjEVMFmYxkAMg-l|WQ5ix#0sAz2?ZA$?8-3Aoi22a|!OYLqGR~aGOpH%{J@l|2-)PP=wERPVWq4v)`^R*i82B#KK z8y}BwK}|0aok3h@s`*V5v8AP z@G9fe_peQpgOI@ro`pE#s;2s0Cx1gWIhtHa)_j(CK5<4+lgw=QZ0nMq-sP3Y<*6TT zoczr@YsEYb4UrE@zN>V)zcW@DjM{>2B)2meSU0OJITEQp2X-zDGxb&tCX|jSP(!{y zowge|qSg9Z4Cp+2y)(YGeCJWMt5R)OM5f}$v3_zeCwxl|fkrERzy=*d;i%(5w)`2) z?SlhoJ=B@Wh`Opyan>CH^^Rk?X}cAK-;#19>bEz_!(ZC9o+TXS6ox1$EZ9ph1_@1i zQML*76f@iDOF_jz=q(%eR;q0UigMC(CypXEta&1qvQ zn~;g+(8)&z%CYAre^YP?`&-ImsOu-XB&hM472S0*#UuV+O*{x3y!4GHQfd3ce0*to zxWOXT4fw3u$v-v!%AfpdhK$aMNJ;om<#kn?Z8*g?XOoSB;=q zOQ|_8Xc{^9P@Kx_LOcekYV+j#QMWE{rh@gVoI01j;jNOr+`*5(*)v0+vH@|I4%km+ zHB7E#6gATu{OK?9o$TMZ_P^2ZY3?Li?kc-Hy#FTcP$&fvpYpsPvg?UmIE+UZiFxh; zIw(B0nz0e0K#gbExJbE!Hf&L@au(b0IJwfsqve)`V{TWHz22NDoe>u!F#2$+>}C2| zhIB@Vc#G9f*UT5VzIwja*qbKO>=Xd zopXNDb8n3A4!T1#Y2yliRxk_jMOXF)v*9u|I2{oW`72g8Kx}NKqg1B`$ytyYPI+p^ zr*Wc3`fplEl%UCkUM^Rvu%+)ToEqPb2l~lMs<>YB)D#JFoF#Xtz~ggaz=2K@>QSCk zqN2%uoPC~)ZP3=_M^+>C7SX>Z*hgzTJA7k1ws+{BY|*qN*p1EJ!Fnmz^-e+yG9t)P z|0K2MBDEr*TpCt9$Py=lvUpm&$*oEcdFr;&)J#_hANneYr>C{fJ@_Hx&&1XWE7ps@ zUb^P&STVNZYM^64rPk*FB3emxVt+$zs2|8v%Rl4y-sAhEY`~iSS!3nk2-=waGTo2)HP9gQ@BR(* z2Vo;7GHbgNwq|SVC2#(|l$5|8QycC)FR;x~@g}F~hC{7O`_B%TXDq|tqT>OhXu(bg z3J0?B4SuBYlvc8!XL|4*S{iY+pTEGE`8`L0xY6rA>JqF==Fhe(5~&bvDYf`?_oUHZ)AZlm=tI5@ zxT;*VA|o0&_4g$ainz%{p9+OE6idgIz3~AeS)V@01B9WfW!4nk(bn7YBS^JmI@B8 zCC;b@GUg1&4lIoE+3%gn2$8Q7%4H==wa8_Dru}uGL{ZpAk`yNLNx}VZX7xL$@g?{{ z3F}Xx49Yn_g-#||@9J+Uqq4CsB%A%^m{*0u)BDV-F@^ZS&+F9!sv=9&4`{Zo#_YXK zw=cJ83;?PKOZGw9EPXy1$@@>kT?z$3b}&06G%c{c8SmH-_3hD0^qNHEcp<6^j@bqb zPeoIT_o{x)Ji;g76KWSLBS@FU2wb}|l8aKN*U*@149f6>!Tb848|~qr%||ZzCEx9b zN4@PEw+BoAF6{rL>+l=*@gV`#Y2!gI$ITn-fYAg~cMgp9r*j~!Wg^BNJ>cKOMMzr} z-C=)qs4;F4!((Hsy-BzXw;t5F)btW$K%)7#)=FAFH%;8j1uI<4%3x7i&s`vo{b&X; z4xRJN>*l~Xi?tJB;jY3N@B5YcF5n9?M>O27Htxo=w_qtdK9gAfSmoOhxy1;;7vJ3$ z9&POo0d?-Ltg~zG6+zU};^Ci$x z2n%$gr7^&17z;So{B+$=65g z0f*+#Y$oO^odzP=qZrHU1&KgE5ywl(9`?*5(!F0s%R))tQg6C%htf62O38i(R`Ww}TH5 zo{m#Qy}^pHiBhQ93B$V*0IZH{5~|1Zh6Qkd@Fc_DR}1igUhh@v<9_~|6CLdqz^yQNGI{o-W;L1+k_0lpb^yObvS*i^)lSmW&@ZJ5NTdb zt}==js$xDkVV%y)B@7zL~;pqt&u)tbV z(Lygz7{rp?-=#c!F(ECnSirQ+_k=;FHIssDrL(KXWZZZa)E)a8fB2O+a4i5lsGEpB4<_-s>m1H90HRh7A-+m|mQRxP=K{CfB`-4EFRzVcijGCom}PA@6A!FY zTfhk-?#y&mS&f!4N{lHNr!DR=tKM`jG1t3=6l|d@5VDaw>~$n^GL{rc0c&Eykta|M zJ%RMqy!T^71LwrQho_qPnjw*0M2&}*Sk`eb0H0I*?_!zg_eGHa#BV6w0zK6S85WEV=wH+3B~WDw_u z@5L*n1%B!H_0} zV2E>8#EG$BHQX@1hyx{1ar5t4cQ^O5L%^|g9(bUVM~7+xPb(M{0-XiZGW$C2ZXTd$ z)rg(|%z7^ALF`O>oPILH;gzIZB~2XdbEl2@5M8j}iGbclI%?w2=6Gz%ovX3Z#6?gz zb{(yG1C9+q4mycDUb$*abyR~uj1m*zgM3Nc6gk$$A6bPzWQw#BcOD!KRWt@1J!aTr z%{>$)7x!gUlp=99{T}fup9k!@QN?_`-|T*d_I3+(Ad!N(r1AK#A5ikBM_93Iof@t@ z&i=@;OFMZ(X4Zdp&gAS~fZlpXjR%j?P;FQn>AHcO$Za|MG=n;WM3Q%wb4iA+bh=0S zGlmI@Mxb--wecoK=T)3 zjT)}}---pEPW!`ZiSBy`nPpK_#U*35sRm~ZlgqPv$T$CW%J$29U^OUkRo&+9m1*YK z5%ORJ?H+OmczsI5maB`wfcCv)_qE_JolQT`|MV9~o=Y9+cy^++vc4Lrdeav<%iz#L z5B5l352f9Y7wCWPjg%39&)YEIjG*FdaOYqo=m;`lU48JRDI+L&SYBwuS#s0%Z$B}I z?(LIqmAUJU2a@Ox^&Tz9Bi){fV4Du6CLa)E>Cf@2Wr3 z_RN^n^o;tfo?zpVzI+n&sVcr-nBHs25c)5YSBqPfmV#U9v=|h96cgZ?ez;8K2WV$o z=+dfFGD#bn@Fejh7*!qjZ0GcJ%ncfYs%}k+r-4jTUD=}GRVWQh`b|B!ChpS1)*jg* z%D$KOToismNkJ$0Gm~qs`t5TS5n785F#FgGcPJnfV#Gy_C`Dt3U3ew(y}r zkCv-V*25QQrJom99^Y~z*f8FNiY7FWOb1h=)o`1b?CJfQQ`3WHVDh!};i>|1kLIZE zo2pZi(%2!Lgo=QEPlhM;8bNO($4?nu7c^>COxkEFVg8(98W;fG;0E-yL1(2ev6)tW zdj9IBVDp)2QY9U+drLcPuO3IYfcks9^vw*OvI52Pt& z28*deH@iIo0ycoh{Mp{Yrml1=@alv)c{pC0$UejOa=j4Ll!FbG$7H|tuC7DWsQGNt zMh&b>5?!=N4GyD85v)mXNRIq3ZW~{wJO+7+} zS4tP-0QHT5GlJ_?OS(npJg^e}8=*6f-72i}cJDldT)I_Ow)xoDqL2SMzw#KYmL$5g zk<3<9(p=N)@``Y+?_7~xQu)1kz(sB16>nDVe)>-nI^O^ zZ<>CMjJf&HiGJMe!UPd=i`~~O&0@MeykIsMVz)X95r)2DYrib zk>mXM7qu32GKikY0C8xvZe3f7>0xV1fL4k5_YV84457)y=a)P$`Y?h#eE$_M#eWx` zfRX4R3#)&^bI+k78wCozlJp@DZ$_y!h)PI8b>I!1yNhQ-Xy2s@=m*sJINnmgRo?dED$6x+-xjI%&ovZ@KPDUYSnV@T`zG5(q}3dxac73LTD;XT?4B zbb7Q5%urm^nd6=X^VHx>L_EiJKV+|9{l1(rba3nYZd`pzR=)A{evi;xylKjAMaeFO z4z?Z;!RonBt5X?o^CY=<4fy5k$`f0WlGQL}3`H;7@;<#X6;fdhY3=3bEB_+T8>igE%m_S%mIwiPq^R@NNBM zn0Uexd+WbxSI|~1w;{{`iOizio%=gWjjzJ0qjAnBHtP4}mgY*c23C@(2d7l?-MW*% z(fYJy&>dPyDBLL<+uyz68K-DakUO{e++~pdTr(e5d>C8UTojBvB-tdb^AMa`dS5&@ z$ekw604vn0=tbcf_Pq=$60yOo|FkTF$mD8{$v2(F`lo!mB?DXe>8t^!1|YStY{SZL z)O_kM2fDT@+FvzhfH;q*8-oDz7cv3~y@fwzgMdkFN&oCuw3K;V(E2SVR0g>thXxz_ z;>~zW!>H6*H0^^C)NuKk(i2z>V_6H`2B>N#_3xkmT151u8@}!epZ-oQLf}l1I}bo% z;Bvt7_m8oe)mIN81!om?X4$uVCB2Y0ji9q^aM3yHXo3x%4l-Pi((>`OpR=2YobcGw zNgGBT@fArM9?c=vkczZFeFrRdcvb-mP0?QN@H35Aq zt8L>Ci9U+s64H{3E@@Ga3adEw!tnX9hkog23$5L&Lf; zX>}PX_-lx}k^6e;J(&%N`s`bfU6|=p^Rjgm#J^5**of(*-miQ9Jvc%=^{8XfWQ{`L zrkpI8{Q>-Tog6Mh@*ed!zE+4}%7SP@(BBW#BJp{qN8OIa5x%VB3FKqb7?S11=Qz{; zGe>=owz}Q&^Bt^sM&aOIVOIy-e_A5HI(rR>5!Bt$h@V@6zIx`VC=edD!qhPku@d1; z-2^w!_oAB%QecA=IQq_*weG$eV-KK|Fjbei;HTqLo(Fbhf)i@^4nEplPgud^3+?Qw zP98t%s5%m3bQv>unPN$CAQnB#o@S){SNQ;$mdx%Z2d&ISxpu%(Cg3ffOirJml`w#K`b#MA%Vp zXPPj4#3?UA3MJCR!P$Dc5|jgOod4b1cOr1L4Dn{0+EriWk3g#6zIgd4V~{$sgC(9T zUZh)aOz%I#?=HNQU&|tp32TIQwRhE>2Cx1rI9}*p@7@$v;*Un%0tR3W>0sOoqR1Le z${)4#Jr~?Mre1p1c&JH=(Z@6M(*%PJqgK%u;NycR z-8z0>mT@11+dbTI;pfG-eppSu{xrn$;0p+uK~(*Jec1dzeDi<$WO!l^kk_vqr07x` Q7{DJ3)5|6`M(&CK110U_tpET3 diff --git a/standards/src_6/.docs/src-6-logo-light-theme.png b/standards/src_6/.docs/src-6-logo-light-theme.png index 4ddfc7d7fb8eb47c91bcc6be58e64c167f8a367e..f635d2ab923e280b281e23b3537b266fcdd8d78f 100644 GIT binary patch delta 15606 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 From 88c4a788db56e8fc4593ac7739abc40cc4d62363 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 12 Dec 2023 14:13:09 +0530 Subject: [PATCH 52/75] modify a line to remove ambiguity --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 0e2b974..4540def 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -28,7 +28,7 @@ The following functions MUST be implemented to follow the SRC-6 standard. Any co Method that allows depositing of the underlying asset in exchange for shares of the vault. This function takes the receiver's identity and the sub_id of the sub vault as an argument and returns the amount of shares minted to the receiver. -MUST revert if any unaccepted AssetId is forwarded. +This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. MUST increase `managed_assets` by amount of deposited assets (through any means including `std::context::this_balance(ASSET_ID)` if applicable). MUST mint a token representing the pro-rata share of the vault, with the AssetId of `sha256((asset, sub_id))`, a hash of the AssetId of the deposited asset, and the `sub_id` of the vault. MUST increase `total_supply` of the share's AssetId by newly minted shares. From 3f8568631dd5a0a791d753a7aec5bd5811eb11b9 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:17:54 +0530 Subject: [PATCH 53/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 4540def..128d385 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -15,7 +15,7 @@ Token vaults allow users to own shares of variable amount of assets, such as len # 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. +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](https://docs.fuel.network/docs/sway/blockchain-development/native_assets) are fundamentally different from Ethereum's ERC-20 tokens, the implementation will differ, but the interface may be used as a reference. # Specification From 60d7860e217c523981ad22201dd0d531dfcfadee Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:18:17 +0530 Subject: [PATCH 54/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 128d385..749e2ce 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -34,7 +34,7 @@ MUST mint a token representing the pro-rata share of the vault, with the AssetId MUST increase `total_supply` of the share's AssetId by newly minted shares. MUST increase `total_assets` by one if the the AssetId is minted for the first time. MUST emit a `Deposit` log. -MUST return amount of minted shares. +This function MUST return the amount of minted shares. ### `fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64` From f7ee8baed620750aa5172e2fc6b25485a9c76084 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:18:26 +0530 Subject: [PATCH 55/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 749e2ce..08501bf 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -33,7 +33,7 @@ MUST increase `managed_assets` by amount of deposited assets (through any means MUST mint a token representing the pro-rata share of the vault, with the AssetId of `sha256((asset, sub_id))`, a hash of the AssetId of the deposited asset, and the `sub_id` of the vault. MUST increase `total_supply` of the share's AssetId by newly minted shares. MUST increase `total_assets` by one if the the AssetId is minted for the first time. -MUST emit a `Deposit` log. +This function MUST emit a `Deposit` log. This function MUST return the amount of minted shares. ### `fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64` From e09d6ce5138ba8e3f473472d393a46ed66980f27 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:22:03 +0530 Subject: [PATCH 56/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 08501bf..3c05a42 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -31,7 +31,7 @@ This function takes the receiver's identity and the sub_id of the sub vault as a This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. MUST increase `managed_assets` by amount of deposited assets (through any means including `std::context::this_balance(ASSET_ID)` if applicable). MUST mint a token representing the pro-rata share of the vault, with the AssetId of `sha256((asset, sub_id))`, a hash of the AssetId of the deposited asset, and the `sub_id` of the vault. -MUST increase `total_supply` of the share's AssetId by newly minted shares. +This function MUST increase the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) total supply of the sub-vault's asset. MUST increase `total_assets` by one if the the AssetId is minted for the first time. This function MUST emit a `Deposit` log. This function MUST return the amount of minted shares. From 3256873b24cd44b3a36c02dc11297921c38297ab Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:23:27 +0530 Subject: [PATCH 57/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 3c05a42..c3f81d9 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -11,7 +11,7 @@ The following standard allows for the implementation of a standard API for token # 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 +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 standardization # Prior Art From b1af20edda1390355b754e1e3de1a7f44dfd2304 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:24:27 +0530 Subject: [PATCH 58/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index c3f81d9..cf7bb45 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -25,7 +25,7 @@ The following functions MUST be implemented to follow the SRC-6 standard. Any co ### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` -Method that allows depositing of the underlying asset in exchange for shares of the vault. +This function MUST allow for depositing of the underlying asset in exchange for shares of the vault. This function takes the receiver's identity and the sub_id of the sub vault as an argument and returns the amount of shares minted to the receiver. This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. From 3e7535f77ce8fce899918857bb066667ece3bb5a Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:24:45 +0530 Subject: [PATCH 59/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index cf7bb45..2779b11 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -26,7 +26,7 @@ The following functions MUST be implemented to follow the SRC-6 standard. Any co ### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` This function MUST allow for depositing of the underlying asset in exchange for shares of the vault. -This function takes the receiver's identity and the sub_id of the sub vault as an argument and returns the amount of shares minted to the receiver. +This function takes the `receiver` Identity and the SubId `sub_id` of the sub-vault as an argument and returns the amount of shares minted to the receiver. This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. MUST increase `managed_assets` by amount of deposited assets (through any means including `std::context::this_balance(ASSET_ID)` if applicable). From 9d87ba9709b6042fac4b281550a9b73696138868 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Tue, 12 Dec 2023 14:31:25 +0530 Subject: [PATCH 60/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 2779b11..d75662f 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -30,7 +30,7 @@ This function takes the `receiver` Identity and the SubId `sub_id` of the sub-va This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. MUST increase `managed_assets` by amount of deposited assets (through any means including `std::context::this_balance(ASSET_ID)` if applicable). -MUST mint a token representing the pro-rata share of the vault, with the AssetId of `sha256((asset, sub_id))`, a hash of the AssetId of the deposited asset, and the `sub_id` of the vault. +This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((asset, sub_id))` digest, where `asset` is the AssetId of the deposited asset and the `sub_id` is the id of the vault. This function MUST increase the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) total supply of the sub-vault's asset. MUST increase `total_assets` by one if the the AssetId is minted for the first time. This function MUST emit a `Deposit` log. From 82c4e130c8d119edca45492083e0c4c1e6b031cf Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 12 Dec 2023 14:34:22 +0530 Subject: [PATCH 61/75] remove unnecessary line --- standards/src_6/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index d75662f..7a5209f 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -29,7 +29,6 @@ This function MUST allow for depositing of the underlying asset in exchange for This function takes the `receiver` Identity and the SubId `sub_id` of the sub-vault as an argument and returns the amount of shares minted to the receiver. This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. -MUST increase `managed_assets` by amount of deposited assets (through any means including `std::context::this_balance(ASSET_ID)` if applicable). This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((asset, sub_id))` digest, where `asset` is the AssetId of the deposited asset and the `sub_id` is the id of the vault. This function MUST increase the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) total supply of the sub-vault's asset. MUST increase `total_assets` by one if the the AssetId is minted for the first time. From 8b5d96998e9a62acc431628a878dde2e4bbc446c Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 12 Dec 2023 14:36:42 +0530 Subject: [PATCH 62/75] rem,ove unnecessary line --- standards/src_6/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 7a5209f..e32e1b3 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -30,7 +30,6 @@ This function takes the `receiver` Identity and the SubId `sub_id` of the sub-va This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((asset, sub_id))` digest, where `asset` is the AssetId of the deposited asset and the `sub_id` is the id of the vault. -This function MUST increase the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) total supply of the sub-vault's asset. MUST increase `total_assets` by one if the the AssetId is minted for the first time. This function MUST emit a `Deposit` log. This function MUST return the amount of minted shares. @@ -43,7 +42,6 @@ The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, mean MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `sub_id` is forwarded. MUST burn the received shares. -MUST reduce `total_supply` of the shares's AssetId by amount of burnt shares. MUST emit a `Withdraw` log. MUST return amount of assets transferred to the receiver. From c16209f99d5fe35cc819e08ca2330fee98acb40f Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 12 Dec 2023 14:39:23 +0530 Subject: [PATCH 63/75] abstract elaboration --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index e32e1b3..e23f903 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -7,7 +7,7 @@ # 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. +The following standard allows for the implementation of a standard API for token vaults such as yield-bearing token vaults or asset wrappers. This standard is an optional add-on to the SRC-20 standard. # Motivation From db0351598a1da50fb255731606fd5dc6a6aad196 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Tue, 12 Dec 2023 15:01:26 +0530 Subject: [PATCH 64/75] This function --- standards/src_6/README.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index e23f903..3f14b7f 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -30,7 +30,6 @@ This function takes the `receiver` Identity and the SubId `sub_id` of the sub-va This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((asset, sub_id))` digest, where `asset` is the AssetId of the deposited asset and the `sub_id` is the id of the vault. -MUST increase `total_assets` by one if the the AssetId is minted for the first time. This function MUST emit a `Deposit` log. This function MUST return the amount of minted shares. @@ -40,29 +39,29 @@ Method that allows the redeeming of the vault shares in exchange for a pro-rata This function takes the asset's AssetId, the sub_id of the sub vault, and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. -MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `sub_id` is forwarded. -MUST burn the received shares. -MUST emit a `Withdraw` log. -MUST return amount of assets transferred to the receiver. +This function MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `sub_id` is forwarded. +This function MUST burn the received shares. +This function MUST emit a `Withdraw` log. +This function MUST return amount of assets transferred to the receiver. ### `fn managed_assets(asset: AssetId, sub_id: SubId) -> u64` Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. -MUST return total amount of assets of underlying AssetId under management by vault. -MUST return 0 if there are no assets of underlying AssetId under management by vault. -MUST NOT revert under any circumstances. +This function MUST return total amount of assets of underlying AssetId under management by vault. +This function MUST return 0 if there are no assets of underlying AssetId under management by vault. +This function MUST NOT revert under any circumstances. ### `fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option` Helper method for getting maximum depositable This function takes the hypothetical receivers `Identity`, the asset's `AssetId`, and the `sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. -MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. -MUST return an `Option::Some(amount)` if the given vault exists. -MUST return an `Option::None` if the given vault does not exist. -MUST account for both global and user specific limits. For example: if deposits are disabled, even temporarily, MUST return 0. +This function MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. +This function MUST return an `Option::Some(amount)` if the given vault exists. +This function MUST return an `Option::None` if the given vault does not exist. +This function MUST account for both global and user specific limits. For example: if deposits are disabled, even temporarily, MUST return 0. ### `fn max_withdrawable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option` @@ -70,10 +69,10 @@ MUST account for both global and user specific limits. For example: if deposits Helper method for getting maximum withdrawable This function takes the hypothetical receive's `Identity`, the asset's `AssetId`, and the `sub_id`` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. -MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. -MUST return an `Option::Some(amount)` if the given vault exists. -MUST return an `Option::None` if the given vault does not exist. -MUST account for global limits. For example: if withdrawals are disabled, even temporarily, MUST return 0. +This function MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. +This function MUST return an `Option::Some(amount)` if the given vault exists. +This function MUST return an `Option::None` if the given vault does not exist. +This function MUST account for global limits. For example: if withdrawals are disabled, even temporarily, MUST return 0. ## Required logs From ecb4ec3c18c3bf8e9fb3298ace04220734a543d6 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 13 Dec 2023 20:56:50 +0530 Subject: [PATCH 65/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 3f14b7f..6c23d65 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -7,7 +7,7 @@ # Abstract -The following standard allows for the implementation of a standard API for token vaults such as yield-bearing token vaults or asset wrappers. This standard is an optional add-on to the SRC-20 standard. +The following standard allows for the implementation of a standard API for token vaults such as yield-bearing token vaults or asset wrappers. This standard is an optional add-on to the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) standard. # Motivation From 9e447b684301f0e663591e07928379aab458f047 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 13 Dec 2023 20:57:12 +0530 Subject: [PATCH 66/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 6c23d65..f3dce7e 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -11,7 +11,7 @@ The following standard allows for the implementation of a standard API for token # 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 standardization +Token vaults allow users to own shares of variable amounts 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 standardization. # Prior Art From 27134120d59d7dd1c2991b6de9014974c7edcc2d Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Wed, 13 Dec 2023 20:57:26 +0530 Subject: [PATCH 67/75] Update standards/src_6/README.md Co-authored-by: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index f3dce7e..826b576 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -25,7 +25,7 @@ The following functions MUST be implemented to follow the SRC-6 standard. Any co ### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` -This function MUST allow for depositing of the underlying asset in exchange for shares of the vault. +This function MUST allow for the depositing of an underlying asset in exchange for shares of the vault. This function takes the `receiver` Identity and the SubId `sub_id` of the sub-vault as an argument and returns the amount of shares minted to the receiver. This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. From e34bf5646017a82819a78cf3c421ebebcf7f4219 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 15:02:15 +0530 Subject: [PATCH 68/75] change par names --- examples/src_6/multi_token_vault/src/main.sw | 76 ++++++++++------- .../single_token_single_sub_vault/src/main.sw | 69 +++++++-------- examples/src_6/single_token_vault/src/main.sw | 84 +++++++++++-------- standards/src_3/README.md | 16 ++-- standards/src_3/src/src_3.sw | 14 ++-- standards/src_6/README.md | 51 ++++++----- standards/src_6/src/src_6.sw | 36 ++++---- 7 files changed, 186 insertions(+), 160 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index 7ac2c5f..d74512f 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -18,8 +18,8 @@ use src_20::SRC20; pub struct VaultInfo { /// Amount of assets currently managed by this vault managed_assets: u64, - /// The sub_id of this vault. - sub_id: SubId, + /// The vault_sub_id of this vault. + vault_sub_id: SubId, /// The asset being managed by this vault asset: AssetId, } @@ -41,14 +41,14 @@ storage { impl SRC6 for Contract { #[storage(read, write)] - fn deposit(receiver: Identity, sub_id: SubId) -> u64 { + fn deposit(receiver: Identity, vault_sub_id: SubId) -> u64 { let asset_amount = msg_amount(); require(asset_amount != 0, "ZERO_ASSETS"); - let asset = msg_asset_id(); - let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, asset_amount); + let underlying_asset = msg_asset_id(); + let (shares, share_asset, share_asset_vault_sub_id) = preview_deposit(underlying_asset, vault_sub_id, asset_amount); - _mint(receiver, share_asset, share_asset_sub_id, shares); + _mint(receiver, share_asset, share_asset_vault_sub_id, shares); storage .total_supply .insert( @@ -67,8 +67,8 @@ impl SRC6 for Contract { log(Deposit { caller: msg_sender().unwrap(), receiver, - asset, - sub_id, + underlying_asset, + vault_sub_id, assets: asset_amount, shares, }); @@ -77,16 +77,20 @@ impl SRC6 for Contract { } #[storage(read, write)] - fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64 { + fn withdraw( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> u64 { let shares = msg_amount(); require(shares != 0, "ZERO_SHARES"); - let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); + let (share_asset_id, share_asset_vault_sub_id) = vault_asset_id(underlying_asset, vault_sub_id); require(msg_asset_id() == share_asset_id, "INVALID_ASSET_ID"); let assets = preview_withdraw(share_asset_id, shares); - _burn(share_asset_id, share_asset_sub_id, shares); + _burn(share_asset_id, share_asset_vault_sub_id, shares); storage .total_supply .insert( @@ -97,13 +101,13 @@ impl SRC6 for Contract { .read() - shares, ); - transfer(receiver, asset, assets); + transfer(receiver, underlying_asset, assets); log(Withdraw { caller: msg_sender().unwrap(), receiver, - asset, - sub_id, + underlying_asset, + vault_sub_id, assets, shares, }); @@ -111,22 +115,26 @@ impl SRC6 for Contract { assets } #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { - let vault_share_asset = vault_asset_id(asset, sub_id).0; + fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64 { + let vault_share_asset = vault_asset_id(underlying_asset, vault_sub_id).0; // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. managed_assets(vault_share_asset) } #[storage(read)] - fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { + fn max_depositable( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> Option { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. - Some(u64::max() - managed_assets(asset)) + Some(u64::max() - managed_assets(underlying_asset)) } #[storage(read)] - fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { + fn max_withdrawable(underlying_asset: AssetId, vault_sub_id: SubId) -> Option { // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. - Some(managed_assets(asset)) + Some(managed_assets(underlying_asset)) } } @@ -158,10 +166,10 @@ impl SRC20 for Contract { } /// Returns the vault shares assetid and subid for the given assets assetid and the vaults sub id -fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { - let share_asset_sub_id = sha256((asset, sub_id)); - let share_asset_id = AssetId::new(ContractId::this(), share_asset_sub_id); - (share_asset_id, share_asset_sub_id) +fn vault_asset_id(asset: AssetId, vault_sub_id: SubId) -> (AssetId, SubId) { + let share_asset_vault_sub_id = sha256((asset, vault_sub_id)); + let share_asset_id = AssetId::new(ContractId::this(), share_asset_vault_sub_id); + (share_asset_id, share_asset_vault_sub_id) } #[storage(read)] @@ -173,17 +181,21 @@ fn managed_assets(share_asset: AssetId) -> u64 { } #[storage(read)] -fn preview_deposit(asset: AssetId, sub_id: SubId, assets: u64) -> (u64, AssetId, SubId) { - let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); +fn preview_deposit( + underlying_asset: AssetId, + vault_sub_id: SubId, + assets: u64, +) -> (u64, AssetId, SubId) { + let (share_asset_id, share_asset_vault_sub_id) = vault_asset_id(underlying_asset, vault_sub_id); let shares_supply = storage.total_supply.get(share_asset_id).try_read().unwrap_or(0); if shares_supply == 0 { - (assets, share_asset_id, share_asset_sub_id) + (assets, share_asset_id, share_asset_vault_sub_id) } else { ( assets * shares_supply / managed_assets(share_asset_id), share_asset_id, - share_asset_sub_id, + share_asset_vault_sub_id, ) } } @@ -202,7 +214,7 @@ fn preview_withdraw(share_asset_id: AssetId, shares: u64) -> u64 { pub fn _mint( recipient: Identity, asset_id: AssetId, - sub_id: SubId, + vault_sub_id: SubId, amount: u64, ) { use std::token::mint_to; @@ -215,11 +227,11 @@ pub fn _mint( storage .total_supply .insert(asset_id, supply.unwrap_or(0) + amount); - mint_to(recipient, sub_id, amount); + mint_to(recipient, vault_sub_id, amount); } #[storage(read, write)] -pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { +pub fn _burn(asset_id: AssetId, vault_sub_id: SubId, amount: u64) { use std::{context::this_balance, token::burn}; require( @@ -229,5 +241,5 @@ pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { // If we pass the check above, we can assume it is safe to unwrap. let supply = storage.total_supply.get(asset_id).try_read().unwrap(); storage.total_supply.insert(asset_id, supply - amount); - burn(sub_id, amount); + burn(vault_sub_id, amount); } diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index e57ab53..eefee59 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -24,7 +24,7 @@ configurable { ACCEPTED_TOKEN: AssetId = BASE_ASSET_ID, /// The only sub vault that can be deposited and withdrawn from this vault. ACCEPTED_SUB_VAULT: SubId = ZERO_B256, - PRE_CALCULATED_SHARE_SUB_ID: SubId = 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b, + PRE_CALCULATED_SHARE_VAULT_SUB_ID: SubId = 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b, } storage { @@ -38,17 +38,17 @@ storage { impl SRC6 for Contract { #[storage(read, write)] - fn deposit(receiver: Identity, sub_id: SubId) -> u64 { - require(sub_id == ACCEPTED_SUB_VAULT, "INVALID_SUB_ID"); + fn deposit(receiver: Identity, vault_sub_id: SubId) -> u64 { + require(vault_sub_id == ACCEPTED_SUB_VAULT, "INVALID_vault_sub_id"); - let asset = msg_asset_id(); - require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); + let underlying_asset = msg_asset_id(); + require(underlying_asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); let asset_amount = msg_amount(); require(asset_amount != 0, "ZERO_ASSETS"); - let (shares, share_asset) = preview_deposit(asset_amount); + let shares = preview_deposit(asset_amount); - _mint(receiver, share_asset, shares); + _mint(receiver, shares); storage .total_supply .write(storage.total_supply.read() + shares); @@ -60,8 +60,8 @@ impl SRC6 for Contract { log(Deposit { caller: msg_sender().unwrap(), receiver, - asset, - sub_id, + underlying_asset, + vault_sub_id, assets: asset_amount, shares, }); @@ -70,9 +70,13 @@ impl SRC6 for Contract { } #[storage(read, write)] - fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64 { - require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); - require(sub_id == ACCEPTED_SUB_VAULT, "INVALID_SUB_ID"); + fn withdraw( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> u64 { + require(underlying_asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); + require(vault_sub_id == ACCEPTED_SUB_VAULT, "INVALID_vault_sub_id"); let shares = msg_amount(); require(shares != 0, "ZERO_SHARES"); @@ -87,13 +91,13 @@ impl SRC6 for Contract { .total_supply .write(storage.total_supply.read() - shares); - transfer(receiver, asset, assets); + transfer(receiver, underlying_asset, assets); log(Withdraw { caller: msg_sender().unwrap(), receiver, - asset, - sub_id, + underlying_asset, + vault_sub_id, assets, shares, }); @@ -102,8 +106,8 @@ impl SRC6 for Contract { } #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { - if asset == ACCEPTED_TOKEN && sub_id == ACCEPTED_SUB_VAULT { + fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64 { + if underlying_asset == ACCEPTED_TOKEN && vault_sub_id == ACCEPTED_SUB_VAULT { // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. storage.managed_assets.read() } else { @@ -112,8 +116,12 @@ impl SRC6 for Contract { } #[storage(read)] - fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { - if asset == ACCEPTED_TOKEN { + fn max_depositable( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> Option { + if underlying_asset == ACCEPTED_TOKEN { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. Some(u64::max() - storage.managed_assets.read()) } else { @@ -122,8 +130,8 @@ impl SRC6 for Contract { } #[storage(read)] - fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { - if asset == ACCEPTED_TOKEN { + fn max_withdrawable(underlying_asset: AssetId, vault_sub_id: SubId) -> Option { + if underlying_asset == ACCEPTED_TOKEN { // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. Some(storage.managed_assets.read()) } else { @@ -161,22 +169,17 @@ impl SRC20 for Contract { /// Returns the vault shares assetid for the given assets assetid and the vaults sub id fn vault_assetid() -> AssetId { - let share_asset_id = AssetId::new(ContractId::this(), PRE_CALCULATED_SHARE_SUB_ID); + let share_asset_id = AssetId::new(ContractId::this(), PRE_CALCULATED_SHARE_VAULT_SUB_ID); share_asset_id } #[storage(read)] -fn preview_deposit(assets: u64) -> (u64, AssetId) { - let share_asset_id = vault_assetid(); - +fn preview_deposit(assets: u64) -> u64 { let shares_supply = storage.total_supply.try_read().unwrap_or(0); if shares_supply == 0 { - (assets, share_asset_id) + assets } else { - ( - assets * shares_supply / storage.managed_assets.try_read().unwrap_or(0), - share_asset_id, - ) + assets * shares_supply / storage.managed_assets.try_read().unwrap_or(0) } } @@ -191,12 +194,12 @@ fn preview_withdraw(shares: u64) -> u64 { } #[storage(read, write)] -pub fn _mint(recipient: Identity, asset_id: AssetId, amount: u64) { +pub fn _mint(recipient: Identity, amount: u64) { use std::token::mint_to; let supply = storage.total_supply.read(); storage.total_supply.write(supply + amount); - mint_to(recipient, PRE_CALCULATED_SHARE_SUB_ID, amount); + mint_to(recipient, PRE_CALCULATED_SHARE_VAULT_SUB_ID, amount); } #[storage(read, write)] @@ -210,5 +213,5 @@ pub fn _burn(asset_id: AssetId, amount: u64) { // If we pass the check above, we can assume it is safe to unwrap. let supply = storage.total_supply.read(); storage.total_supply.write(supply - amount); - burn(PRE_CALCULATED_SHARE_SUB_ID, amount); + burn(PRE_CALCULATED_SHARE_VAULT_SUB_ID, amount); } diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index bda46b4..75b4bbf 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -19,8 +19,8 @@ use src_20::SRC20; pub struct VaultInfo { /// Amount of assets currently managed by this vault managed_assets: u64, - /// The sub_id of this vault. - sub_id: SubId, + /// The vault_sub_id of this vault. + vault_sub_id: SubId, /// The asset being managed by this vault asset: AssetId, } @@ -47,15 +47,15 @@ configurable { impl SRC6 for Contract { #[storage(read, write)] - fn deposit(receiver: Identity, sub_id: SubId) -> u64 { + fn deposit(receiver: Identity, vault_sub_id: SubId) -> u64 { let asset_amount = msg_amount(); - let asset = msg_asset_id(); + let underlying_asset = msg_asset_id(); - require(asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); - let (shares, share_asset, share_asset_sub_id) = preview_deposit(asset, sub_id, asset_amount); + require(underlying_asset == ACCEPTED_TOKEN, "INVALID_ASSET_ID"); + let (shares, share_asset, share_asset_vault_sub_id) = preview_deposit(underlying_asset, vault_sub_id, asset_amount); require(asset_amount != 0, "ZERO_ASSETS"); - _mint(receiver, share_asset, share_asset_sub_id, shares); + _mint(receiver, share_asset, share_asset_vault_sub_id, shares); storage .total_supply .insert( @@ -74,8 +74,8 @@ impl SRC6 for Contract { log(Deposit { caller: msg_sender().unwrap(), receiver: receiver, - asset: asset, - sub_id: sub_id, + underlying_asset, + vault_sub_id: vault_sub_id, assets: asset_amount, shares: shares, }); @@ -84,16 +84,20 @@ impl SRC6 for Contract { } #[storage(read, write)] - fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64 { + fn withdraw( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> u64 { let shares = msg_amount(); require(shares != 0, "ZERO_SHARES"); - let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); + let (share_asset_id, share_asset_vault_sub_id) = vault_asset_id(underlying_asset, vault_sub_id); require(msg_asset_id() == share_asset_id, "INVALID_ASSET_ID"); let assets = preview_withdraw(share_asset_id, shares); - _burn(share_asset_id, share_asset_sub_id, shares); + _burn(share_asset_id, share_asset_vault_sub_id, shares); storage .total_supply .insert( @@ -104,13 +108,13 @@ impl SRC6 for Contract { .read() - shares, ); - transfer(receiver, asset, assets); + transfer(receiver, underlying_asset, assets); log(Withdraw { caller: msg_sender().unwrap(), receiver: receiver, - asset: asset, - sub_id: sub_id, + underlying_asset, + vault_sub_id: vault_sub_id, assets: assets, shares: shares, }); @@ -119,9 +123,9 @@ impl SRC6 for Contract { } #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64 { - if asset == ACCEPTED_TOKEN { - let vault_share_asset = vault_asset_id(asset, sub_id).0; + fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64 { + if underlying_asset == ACCEPTED_TOKEN { + let vault_share_asset = vault_asset_id(underlying_asset, vault_sub_id).0; // In this implementation managed_assets and max_withdrawable are the same. However in case of lending out of assets, managed_assets should be greater than max_withdrawable. managed_assets(vault_share_asset) } else { @@ -130,20 +134,24 @@ impl SRC6 for Contract { } #[storage(read)] - fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option { - if asset == ACCEPTED_TOKEN { + fn max_depositable( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> Option { + if underlying_asset == ACCEPTED_TOKEN { // This is the max value of u64 minus the current managed_assets. Ensures that the sum will always be lower than u64::MAX. - Some(u64::max() - managed_assets(asset)) + Some(u64::max() - managed_assets(underlying_asset)) } else { None } } #[storage(read)] - fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option { - if asset == ACCEPTED_TOKEN { + fn max_withdrawable(underlying_asset: AssetId, vault_sub_id: SubId) -> Option { + if underlying_asset == ACCEPTED_TOKEN { // In this implementation total_assets and max_withdrawable are the same. However in case of lending out of assets, total_assets should be greater than max_withdrawable. - Some(managed_assets(asset)) + Some(managed_assets(underlying_asset)) } else { None } @@ -178,10 +186,10 @@ impl SRC20 for Contract { } /// Returns the vault shares assetid and subid for the given assets assetid and the vaults sub id -fn vault_asset_id(asset: AssetId, sub_id: SubId) -> (AssetId, SubId) { - let share_asset_sub_id = sha256((asset, sub_id)); - let share_asset_id = AssetId::new(ContractId::this(), share_asset_sub_id); - (share_asset_id, share_asset_sub_id) +fn vault_asset_id(underlying_asset: AssetId, vault_sub_id: SubId) -> (AssetId, SubId) { + let share_asset_vault_sub_id = sha256((underlying_asset, vault_sub_id)); + let share_asset_id = AssetId::new(ContractId::this(), share_asset_vault_sub_id); + (share_asset_id, share_asset_vault_sub_id) } #[storage(read)] @@ -193,17 +201,21 @@ fn managed_assets(share_asset: AssetId) -> u64 { } #[storage(read)] -fn preview_deposit(asset: AssetId, sub_id: SubId, assets: u64) -> (u64, AssetId, SubId) { - let (share_asset_id, share_asset_sub_id) = vault_asset_id(asset, sub_id); +fn preview_deposit( + underlying_asset: AssetId, + vault_sub_id: SubId, + assets: u64, +) -> (u64, AssetId, SubId) { + let (share_asset_id, share_asset_vault_sub_id) = vault_asset_id(underlying_asset, vault_sub_id); let shares_supply = storage.total_supply.get(share_asset_id).try_read().unwrap_or(0); if shares_supply == 0 { - (assets, share_asset_id, share_asset_sub_id) + (assets, share_asset_id, share_asset_vault_sub_id) } else { ( assets * shares_supply / managed_assets(share_asset_id), share_asset_id, - share_asset_sub_id, + share_asset_vault_sub_id, ) } } @@ -222,7 +234,7 @@ fn preview_withdraw(share_asset_id: AssetId, shares: u64) -> u64 { pub fn _mint( recipient: Identity, asset_id: AssetId, - sub_id: SubId, + vault_sub_id: SubId, amount: u64, ) { use std::token::mint_to; @@ -236,11 +248,11 @@ pub fn _mint( storage .total_supply .insert(asset_id, current_supply + amount); - mint_to(recipient, sub_id, amount); + mint_to(recipient, vault_sub_id, amount); } #[storage(read, write)] -pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { +pub fn _burn(asset_id: AssetId, vault_sub_id: SubId, amount: u64) { use std::{context::this_balance, token::burn}; require( @@ -250,5 +262,5 @@ pub fn _burn(asset_id: AssetId, sub_id: SubId, amount: u64) { // If we pass the check above, we can assume it is safe to unwrap. let supply = storage.total_supply.get(asset_id).try_read().unwrap(); storage.total_supply.insert(asset_id, supply - amount); - burn(sub_id, amount); + burn(vault_sub_id, amount); } diff --git a/standards/src_3/README.md b/standards/src_3/README.md index e4d6d30..3a582e3 100644 --- a/standards/src_3/README.md +++ b/standards/src_3/README.md @@ -16,27 +16,27 @@ Minting and burning were initially added to the [SRC-20](https://github.com/Fuel The following functions MUST be implemented to follow the SRC-3 standard: -### `fn mint(recipient: Identity, sub_id: SubId, amount: u64)` +### `fn mint(recipient: Identity, vault_sub_id: SubId, amount: u64)` -This function MUST mint `amount` tokens with sub-identifier `sub_id` and transfer them to the `recipient`. +This function MUST mint `amount` tokens with sub-identifier `vault_sub_id` and transfer them to the `recipient`. This function MAY contain arbitrary conditions for minting, and revert if those conditions are not met. ##### Arguments * `recipient` - The `Identity` to which the newly minted tokens are transferred to. -* `sub_id` - The sub-identifier of the asset to mint. +* `vault_sub_id` - The sub-identifier of the asset to mint. * `amount` - The quantity of tokens to mint. -### `fn burn(sub_id: SubId, amount: u64)` +### `fn burn(vault_sub_id: SubId, amount: u64)` -This function MUST burn `amount` tokens with the sub-identifier `sub_id` and MUST ensure the `AssetId` of the token is the sha-256 hash of `(ContractId, SubId)` for the implementing contract. +This function MUST burn `amount` tokens with the sub-identifier `vault_sub_id` and MUST ensure the `AssetId` of the token is the sha-256 hash of `(ContractId, SubId)` for the implementing contract. This function MUST ensure at least `amount` tokens have been transferred to the implementing contract. This function MUST update the total supply defined in the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) standard. This function MAY contain arbitrary conditions for burning, and revert if those conditions are not met. ##### Arguments -* `sub_id` - The sub-identifier of the asset to burn. +* `vault_sub_id` - The sub-identifier of the asset to burn. * `amount` - The quantity of tokens to burn. # Rationale @@ -56,8 +56,8 @@ The burn function may also introduce a security consideration if the total suppl ```rust abi MySRC3Token { - fn mint(recipient: Identity, sub_id: SubId, amount: u64); - fn burn(sub_id: SubId, amount: u64); + fn mint(recipient: Identity, vault_sub_id: SubId, amount: u64); + fn burn(vault_sub_id: SubId, amount: u64); } ``` diff --git a/standards/src_3/src/src_3.sw b/standards/src_3/src/src_3.sw index 987be34..4383811 100644 --- a/standards/src_3/src/src_3.sw +++ b/standards/src_3/src/src_3.sw @@ -1,12 +1,12 @@ library; abi SRC3 { - /// Mints new tokens using the `sub_id` sub-identifier. + /// Mints new tokens using the `vault_sub_id` sub-identifier. /// /// # Arguments /// /// * `recipient`: [Identity] - The user to which the newly minted tokens are transferred to. - /// * `sub_id`: [SubId] - The sub-identifier of the newly minted token. + /// * `vault_sub_id`: [SubId] - The sub-identifier of the newly minted token. /// * `amount`: [u64] - The quantity of tokens to mint. /// /// # Examples @@ -20,18 +20,18 @@ abi SRC3 { /// } /// ``` #[storage(read, write)] - fn mint(recipient: Identity, sub_id: SubId, amount: u64); + fn mint(recipient: Identity, vault_sub_id: SubId, amount: u64); - /// Burns tokens sent with the given `sub_id`. + /// Burns tokens sent with the given `vault_sub_id`. /// /// # Additional Information /// /// NOTE: The sha-256 hash of `(ContractId, SubId)` must match the `AssetId` where `ContractId` is the id of - /// the implementing contract and `SubId` is the given `sub_id` argument. + /// the implementing contract and `SubId` is the given `vault_sub_id` argument. /// /// # Arguments /// - /// * `sub_id`: [SubId] - The sub-identifier of the token to burn. + /// * `vault_sub_id`: [SubId] - The sub-identifier of the token to burn. /// * `amount`: [u64] - The quantity of tokens to burn. /// /// # Examples @@ -49,5 +49,5 @@ abi SRC3 { /// } /// ``` #[storage(read, write)] - fn burn(sub_id: SubId, amount: u64); + fn burn(vault_sub_id: SubId, amount: u64); } diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 3f14b7f..9a896e0 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -23,40 +23,39 @@ Token vaults have been thoroughly explored on Ethereum and with [EIP 4626](https The following functions MUST be implemented to follow the SRC-6 standard. Any contract that implements the SRC-6 standard MUST implement the SRC-20 standard. -### `fn deposit(receiver: Identity, sub_id: SubId) -> u64` +### `fn deposit(receiver: Identity, vault_sub_id: SubId) -> u64` -This function MUST allow for depositing of the underlying asset in exchange for shares of the vault. -This function takes the `receiver` Identity and the SubId `sub_id` of the sub-vault as an argument and returns the amount of shares minted to the receiver. +This function MUST allow for depositing of the underlying asset in exchange for pro-rata shares of the vault. +This function takes the `receiver` Identity and the SubId `vault_sub_id` of the sub-vault as an argument and returns the amount of shares minted to the `receiver`. This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. -This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((asset, sub_id))` digest, where `asset` is the AssetId of the deposited asset and the `sub_id` is the id of the vault. +This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((underlying_asset, vault_sub_id))` digest, where `underlying_asset` is the AssetId of the deposited asset and the `vault_sub_id` is the id of the vault. This function MUST emit a `Deposit` log. This function MUST return the amount of minted shares. -### `fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64` +### `fn withdraw(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> u64` -Method that allows the redeeming of the vault shares in exchange for a pro-rata amount of the underlying asset -This function takes the asset's AssetId, the sub_id of the sub vault, and the receiver's identity as arguments and returns the amount of assets transferred to the receiver. -The AssetId of the asset, and the AssetId of the shares MUST be one-to-one, meaning every deposited AssetId shall have a unique corresponding shares AssetId. +This function MUST allow for redeeming of the vault shares in exchange for a pro-rata amount of the underlying assets. +This function takes the `underlying_asset` AssetId, the `vault_sub_id` of the sub vault, and the `receiver` Identity as arguments and returns the amount of assets transferred to the `receiver`. -This function MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `sub_id` is forwarded. +This function MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `vault_sub_id` is forwarded. (i.e. transferred share's AssetId must be equal to `AssetId::new(ContractId::this(), sha256((underlying_asset, vault_sub_id))`) This function MUST burn the received shares. This function MUST emit a `Withdraw` log. This function MUST return amount of assets transferred to the receiver. -### `fn managed_assets(asset: AssetId, sub_id: SubId) -> u64` +### `fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64` Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. -This function takes the asset's AssetId and the sub_id of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. +This function takes the asset's AssetId and the vault_sub_id of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. This function MUST return total amount of assets of underlying AssetId under management by vault. This function MUST return 0 if there are no assets of underlying AssetId under management by vault. This function MUST NOT revert under any circumstances. -### `fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option` +### `fn max_depositable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` Helper method for getting maximum depositable -This function takes the hypothetical receivers `Identity`, the asset's `AssetId`, and the `sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. +This function takes the hypothetical receivers `Identity`, the asset's `AssetId`, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. This function MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. This function MUST return an `Option::Some(amount)` if the given vault exists. @@ -64,10 +63,10 @@ This function MUST return an `Option::None` if the given vault does not exist. This function MUST account for both global and user specific limits. For example: if deposits are disabled, even temporarily, MUST return 0. -### `fn max_withdrawable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option` +### `fn max_withdrawable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` Helper method for getting maximum withdrawable -This function takes the hypothetical receive's `Identity`, the asset's `AssetId`, and the `sub_id`` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. +This function takes the hypothetical receive's `Identity`, the asset's `AssetId`, and the `vault_sub_id`` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. This function MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. This function MUST return an `Option::Some(amount)` if the given vault exists. @@ -86,16 +85,16 @@ pub struct Deposit { /// The receiver of the deposit. receiver: Identity, /// The asset being deposited. - asset: AssetId, + underlying_asset: AssetId, /// The SubId of the vault. - sub_id: SubId, + vault_sub_id: SubId, /// The amount of assets being deposited. assets: u64, /// The amount of shares being minted. shares: u64, } ``` -`caller` has called the `deposit` method sending `assets` assets of the `asset` AssetId to the subvault of `sub_id`, in exchange for `shares` shares sent to the receiver `receiver` +`caller` has called the `deposit` method sending `assets` assets of the `underlying_asset` AssetId to the subvault of `vault_sub_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 @@ -107,9 +106,9 @@ pub struct Withdraw { /// The receiver of the withdrawal. receiver: Identity, /// The asset being withdrawn. - asset: AssetId, + underlying_asset: AssetId, /// The SubId of the vault. - sub_id: SubId, + vault_sub_id: SubId, /// The amount of assets being withdrawn. assets: u64, /// The amount of shares being burned. @@ -117,7 +116,7 @@ pub struct Withdraw { } ``` -`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets of the `asset` AssetId from the subvault of `sub_id` to the receiver `receiver` +`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets of the `underlying_asset` AssetId from the subvault of `vault_sub_id` to the receiver `receiver` The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw` method @@ -138,19 +137,19 @@ Incorrect implementation of token vaults could allow attackers to steal underlyi ```sway abi SRC6 { #[storage(read, write)] - fn deposit(receiver: Identity, sub_id: SubId) -> u64; + fn deposit(receiver: Identity, vault_sub_id: SubId) -> u64; #[storage(read, write)] - fn withdraw(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64; + fn withdraw(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> u64; #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64; + fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64; #[storage(read)] - fn max_depositable(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option; + fn max_depositable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option; #[storage(read)] - fn max_withdrawable(asset: AssetId, sub_id: SubId) -> Option; + fn max_withdrawable(underlying_asset: AssetId, vault_sub_id: SubId) -> Option; } ``` diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 8af8ea3..1d9c4f2 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -7,9 +7,9 @@ pub struct Deposit { /// The receiver of the deposit. receiver: Identity, /// The asset being deposited. - asset: AssetId, + underlying_asset: AssetId, /// The SubId of the vault. - sub_id: SubId, + vault_sub_id: SubId, /// The amount of assets being deposited. assets: u64, /// The amount of shares being minted. @@ -23,9 +23,9 @@ pub struct Withdraw { /// The receiver of the withdrawal. receiver: Identity, /// The asset being withdrawn. - asset: AssetId, + underlying_asset: AssetId, /// The SubId of the vault. - sub_id: SubId, + vault_sub_id: SubId, /// The amount of assets being withdrawn. assets: u64, /// The amount of shares being burned. @@ -42,7 +42,7 @@ abi SRC6 { /// # Arguments /// /// * `receiver`: [Identity] - The receiver of the shares. - /// * `sub_id`: [SubId] - The SubId of the vault. + /// * `vault_sub_id`: [SubId] - The SubId of the vault. /// /// # Returns /// @@ -54,7 +54,7 @@ abi SRC6 { /// * If the amount of assets forwarded to the contract is zero. /// * The user crosses any global or user specific deposit limits. #[storage(read, write)] - fn deposit(receiver: Identity, sub_id: SubId) -> u64; + fn deposit(receiver: Identity, vault_sub_id: SubId) -> u64; /// Burns shares from the sender and transfers assets to the receiver. /// @@ -65,8 +65,8 @@ abi SRC6 { /// # Arguments /// /// * `receiver`: [Identity] - The receiver of the assets. - /// * `asset`: [AssetId] - The asset for which the shares should be burned. - /// * `sub_id`: [SubId] - The SubId of the vault. + /// * `underlying_asset`: [AssetId] - The asset for which the shares should be burned. + /// * `vault_sub_id`: [SubId] - The SubId of the vault. /// /// # Returns /// @@ -79,20 +79,20 @@ abi SRC6 { /// * 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(receiver: Identity, asset: AssetId, sub_id: SubId) -> u64; + fn withdraw(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> u64; /// 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. - /// * `sub_id`: [SubId] - The SubId of the vault. + /// * `underlying_asset`: [AssetId] - The asset for which the amount of managed assets should be returned. + /// * `vault_sub_id`: [SubId] - The SubId of the vault. /// /// # Returns /// /// * [u64] - The amount of managed assets of the given asset. #[storage(read)] - fn managed_assets(asset: AssetId, sub_id: SubId) -> u64; + fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64; /// Returns the maximum amount of assets that can be deposited into the contract, for the given asset. /// @@ -103,15 +103,15 @@ abi SRC6 { /// # Arguments /// /// * `receiver`: [Identity] - The hypothetical receiver of the shares. - /// * `asset`: [AssetId] - The asset for which the maximum amount of depositable assets should be returned. - /// * `sub_id`: [SubId] - The SubId of the vault. + /// * `underlying_asset`: [AssetId] - The asset for which the maximum amount of depositable assets should be returned. + /// * `vault_sub_id`: [SubId] - The SubId of the vault. /// /// # 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(receiver: Identity, asset: AssetId, sub_id: SubId) -> Option; + fn max_depositable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option; /// Returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. /// @@ -121,13 +121,13 @@ abi SRC6 { /// /// # Arguments /// - /// * `asset`: [AssetId] - The asset for which the maximum amount of withdrawable assets should be returned. - /// * `sub_id`: [SubId] - The SubId of the vault. + /// * `underlying_asset`: [AssetId] - The asset for which the maximum amount of withdrawable assets should be returned. + /// * `vault_sub_id`: [SubId] - The SubId of the vault. /// /// # 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, sub_id: SubId) -> Option; + fn max_withdrawable(underlying_asset: AssetId, vault_sub_id: SubId) -> Option; } From 1b8d424ee50107df02d2ee7dd8373004e634af52 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 15:05:38 +0530 Subject: [PATCH 69/75] fix position of params --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 586eea7..aef61fc 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -36,7 +36,7 @@ This function MUST return the amount of minted shares. ### `fn withdraw(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> u64` This function MUST allow for redeeming of the vault shares in exchange for a pro-rata amount of the underlying assets. -This function takes the `underlying_asset` AssetId, the `vault_sub_id` of the sub vault, and the `receiver` Identity as arguments and returns the amount of assets transferred to the `receiver`. +This function takes the `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` of the sub vault, as arguments and returns the amount of assets transferred to the `receiver`. This function MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `vault_sub_id` is forwarded. (i.e. transferred share's AssetId must be equal to `AssetId::new(ContractId::this(), sha256((underlying_asset, vault_sub_id))`) This function MUST burn the received shares. From 8c019fbd43064fd6b3bf11fbb895fec11beedf78 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 15:08:37 +0530 Subject: [PATCH 70/75] fix some descriptions --- standards/src_6/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index aef61fc..bff8928 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -46,16 +46,16 @@ This function MUST return amount of assets transferred to the receiver. ### `fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64` Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. -This function takes the asset's AssetId and the vault_sub_id of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. +This function takes the `underlying_asset` AssetId and the `vault_sub_id` of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. -This function MUST return total amount of assets of underlying AssetId under management by vault. -This function MUST return 0 if there are no assets of underlying AssetId under management by vault. +This function MUST return total amount of assets of `underlying_asset` AssetId under management by vault. +This function MUST return 0 if there are no assets of `underlying_asset` AssetId under management by vault. This function MUST NOT revert under any circumstances. ### `fn max_depositable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` Helper method for getting maximum depositable -This function takes the hypothetical receivers `Identity`, the asset's `AssetId`, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. +This function takes the hypothetical `receiver` `Identity`, the `underlying_asset` `AssetId`, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. This function MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. This function MUST return an `Option::Some(amount)` if the given vault exists. @@ -66,7 +66,7 @@ This function MUST account for both global and user specific limits. For example ### `fn max_withdrawable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` Helper method for getting maximum withdrawable -This function takes the hypothetical receive's `Identity`, the asset's `AssetId`, and the `vault_sub_id`` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. +This function takes the hypothetical `receiver` `Identity`, the `underlying_asset` `AssetId`, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. This function MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. This function MUST return an `Option::Some(amount)` if the given vault exists. From fa3b6607c76b92a2505e1e96e58e9a09320bada8 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 15:33:21 +0530 Subject: [PATCH 71/75] changed log var names --- examples/src_6/multi_token_vault/src/main.sw | 8 +- .../single_token_single_sub_vault/src/main.sw | 8 +- examples/src_6/single_token_vault/src/main.sw | 8 +- standards/src_6/README.md | 143 ++++++++++-------- standards/src_6/src/src_6.sw | 8 +- 5 files changed, 97 insertions(+), 78 deletions(-) diff --git a/examples/src_6/multi_token_vault/src/main.sw b/examples/src_6/multi_token_vault/src/main.sw index d74512f..3648807 100644 --- a/examples/src_6/multi_token_vault/src/main.sw +++ b/examples/src_6/multi_token_vault/src/main.sw @@ -69,8 +69,8 @@ impl SRC6 for Contract { receiver, underlying_asset, vault_sub_id, - assets: asset_amount, - shares, + deposited_assets: asset_amount, + minted_shares, }); shares @@ -108,8 +108,8 @@ impl SRC6 for Contract { receiver, underlying_asset, vault_sub_id, - assets, - shares, + withdrawn_assets: assets, + burned_shares: shares, }); assets diff --git a/examples/src_6/single_token_single_sub_vault/src/main.sw b/examples/src_6/single_token_single_sub_vault/src/main.sw index eefee59..f20be31 100644 --- a/examples/src_6/single_token_single_sub_vault/src/main.sw +++ b/examples/src_6/single_token_single_sub_vault/src/main.sw @@ -62,8 +62,8 @@ impl SRC6 for Contract { receiver, underlying_asset, vault_sub_id, - assets: asset_amount, - shares, + deposited_assets: asset_amount, + minted_shares: shares, }); shares @@ -98,8 +98,8 @@ impl SRC6 for Contract { receiver, underlying_asset, vault_sub_id, - assets, - shares, + withdrawn_assets: assets, + burned_shares: shares, }); assets diff --git a/examples/src_6/single_token_vault/src/main.sw b/examples/src_6/single_token_vault/src/main.sw index 75b4bbf..06c7270 100644 --- a/examples/src_6/single_token_vault/src/main.sw +++ b/examples/src_6/single_token_vault/src/main.sw @@ -76,8 +76,8 @@ impl SRC6 for Contract { receiver: receiver, underlying_asset, vault_sub_id: vault_sub_id, - assets: asset_amount, - shares: shares, + deposited_assets: asset_amount, + minted_shares: shares, }); shares @@ -115,8 +115,8 @@ impl SRC6 for Contract { receiver: receiver, underlying_asset, vault_sub_id: vault_sub_id, - assets: assets, - shares: shares, + withdrawn_assets: assets, + burned_shares: shares, }); assets diff --git a/standards/src_6/README.md b/standards/src_6/README.md index bff8928..523a80f 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -25,101 +25,120 @@ The following functions MUST be implemented to follow the SRC-6 standard. Any co ### `fn deposit(receiver: Identity, vault_sub_id: SubId) -> u64` -This function MUST allow for depositing of the underlying asset in exchange for pro-rata shares of the vault. This function takes the `receiver` Identity and the SubId `vault_sub_id` of the sub-vault as an argument and returns the amount of shares minted to the `receiver`. -This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. -This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((underlying_asset, vault_sub_id))` digest, where `underlying_asset` is the AssetId of the deposited asset and the `vault_sub_id` is the id of the vault. -This function MUST emit a `Deposit` log. -This function MUST return the amount of minted shares. +- This function MUST allow for depositing of the underlying asset in exchange for pro-rata shares of the vault. +- This function MAY reject arbitrary assets based on implementation and MUST revert if unaccepted assets are forwarded. +- This function MUST mint an asset representing the pro-rata share of the vault, with the SubId of the `sha256((underlying_asset, vault_sub_id))` digest, where `underlying_asset` is the AssetId of the deposited asset and the `vault_sub_id` is the id of the vault. +- This function MUST emit a `Deposit` log. +- This function MUST return the amount of minted shares. ### `fn withdraw(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> u64` -This function MUST allow for redeeming of the vault shares in exchange for a pro-rata amount of the underlying assets. This function takes the `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` of the sub vault, as arguments and returns the amount of assets transferred to the `receiver`. -This function MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `vault_sub_id` is forwarded. (i.e. transferred share's AssetId must be equal to `AssetId::new(ContractId::this(), sha256((underlying_asset, vault_sub_id))`) -This function MUST burn the received shares. -This function MUST emit a `Withdraw` log. -This function MUST return amount of assets transferred to the receiver. +- This function MUST allow for redeeming of the vault shares in exchange for a pro-rata amount of the underlying assets. +- This function MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `vault_sub_id` is forwarded. (i.e. transferred share's AssetId must be equal to `AssetId::new(ContractId::this(), sha256((underlying_asset, vault_sub_id))`) +- This function MUST burn the received shares. +- This function MUST emit a `Withdraw` log. +- This function MUST return amount of assets transferred to the receiver. ### `fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64` Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. This function takes the `underlying_asset` AssetId and the `vault_sub_id` of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. -This function MUST return total amount of assets of `underlying_asset` AssetId under management by vault. -This function MUST return 0 if there are no assets of `underlying_asset` AssetId under management by vault. -This function MUST NOT revert under any circumstances. +- This function MUST return total amount of assets of `underlying_asset` AssetId under management by vault. +- This function MUST return 0 if there are no assets of `underlying_asset` AssetId under management by vault. +- This function MUST NOT revert under any circumstances. ### `fn max_depositable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` -Helper method for getting maximum depositable -This function takes the hypothetical `receiver` `Identity`, the `underlying_asset` `AssetId`, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be deposited into the contract, for the given asset. - -This function MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. -This function MUST return an `Option::Some(amount)` if the given vault exists. -This function MUST return an `Option::None` if the given vault does not exist. -This function MUST account for both global and user specific limits. For example: if deposits are disabled, even temporarily, MUST return 0. +This is a helper function for getting the maximum amount of assets that can be deposited. It takes the hypothetical `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` of the sub vault as an arguments and returns the maximum amount of assets that can be deposited into the contract, for the given asset. +- This function MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. +- This function MUST return an `Some(amount)` if the given vault exists. +- This function MUST return an `None` if the given vault does not exist. +- This function MUST account for both global and user specific limits. For example: if deposits are disabled, even temporarily, MUST return 0. ### `fn max_withdrawable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` -Helper method for getting maximum withdrawable -This function takes the hypothetical `receiver` `Identity`, the `underlying_asset` `AssetId`, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. +This is a helper function for getting maximum withdrawable. It takes the hypothetical `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. -This function MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. -This function MUST return an `Option::Some(amount)` if the given vault exists. -This function MUST return an `Option::None` if the given vault does not exist. -This function MUST account for global limits. For example: if withdrawals are disabled, even temporarily, MUST return 0. +- This function MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. +- This function MUST return an `Some(amount)` if the given vault exists. +- This function MUST return an `None` if the given vault does not exist. +- This function MUST account for global limits. For example: if withdrawals are disabled, even temporarily, MUST return 0. ## Required logs The following logs MUST be emitted at the specified occasions -```sway -/// 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. - underlying_asset: AssetId, - /// The SubId of the vault. - vault_sub_id: SubId, - /// The amount of assets being deposited. - assets: u64, - /// The amount of shares being minted. - shares: u64, -} -``` -`caller` has called the `deposit` method sending `assets` assets of the `underlying_asset` AssetId to the subvault of `vault_sub_id`, in exchange for `shares` shares sent to the receiver `receiver` + +### `Deposit` + +`caller` has called the `deposit()` method sending `deposited_amount` assets of the `underlying_asset` Asset to the subvault of `vault_sub_id`, in exchange for `minted_shares` shares sent to the receiver `receiver` The `Deposit` struct MUST be logged whenever new shares are minted via the `deposit` method -```sway -/// 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. - underlying_asset: AssetId, - /// The SubId of the vault. - vault_sub_id: SubId, - /// The amount of assets being withdrawn. - assets: u64, - /// The amount of shares being burned. - shares: u64, -} -``` +The `Deposit` log SHALL have the following fields. + +#### - `caller`: Identity + +The `caller` field MUST represent the Identity which called the deposit function. + +#### - `receiver`: Identity + +The `receiver` field MUST represent the Identity which received the vault shares. + +#### - `underlying_asset`: AssetId + +The `underlying_asset` field MUST represent the AssetId of the asset which was deposited into the vault. + +#### - `vault_sub_id`: SubId + +The `vault_sub_id` field MUST represent the SubId of the vault which was deposited into. + +#### - `deposited_amount`: u64 -`caller` has called the `withdraw` method sending `shares` shares in exchange for `assets` assets of the `underlying_asset` AssetId from the subvault of `vault_sub_id` to the receiver `receiver` +The `deposited_amount` field MUST represent the u64 amount of assets deposited into the vault. + +#### - `minted_shares`: u64 + +The `minted_shares` field MUST represent the u64 amount of shares minted. + +### `Withdraw` + +`caller` has called the `withdraw()` method sending `burned_shares` shares in exchange for `withdrawn_amount` assets of the `underlying_asset` Asset from the subvault of `vault_sub_id` to the receiver `receiver` The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw` method +The `Withdraw` log SHALL have the following fields. + +#### - `caller`: Identity + +The `caller` field MUST represent the Identity which called the withdraw function. + +#### - `receiver`: Identity + +The `receiver` field MUST represent the Identity which received the withdrawn assets. + +#### - `underlying_asset`: AssetId + +The `underlying_asset` field MUST represent the AssetId of the asset that was withdrawn. + +#### - `vault_sub_id`: SubId + +The `vault_sub_id` field MUST represent the SubId of the vault from which was withdrawn. + +#### - `withdrawn_amount`: u64 + +The `withdrawn_amount` field MUST represent the u64 amount of tokens withdrawn. + +#### - `burned_shares`: u64 + +The `burned_shares` field MUST represent the u64 amount of shares burned. + # Rationale The ABI discussed and covers the known use cases of token vaults while allowing safe implementations diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index 1d9c4f2..fb6296e 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -11,9 +11,9 @@ pub struct Deposit { /// The SubId of the vault. vault_sub_id: SubId, /// The amount of assets being deposited. - assets: u64, + deposited_amount: u64, /// The amount of shares being minted. - shares: u64, + minted_shares: u64, } /// Event logged when a withdrawal is made. @@ -27,9 +27,9 @@ pub struct Withdraw { /// The SubId of the vault. vault_sub_id: SubId, /// The amount of assets being withdrawn. - assets: u64, + withdrawn_amount: u64, /// The amount of shares being burned. - shares: u64, + burned_shares: u64, } abi SRC6 { From b0a59288bb73e8f7f6cac14f0b47e76c40b00b26 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 15:54:19 +0530 Subject: [PATCH 72/75] standardize readme --- standards/src_6/README.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 523a80f..ea772cf 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -38,15 +38,14 @@ This function takes the `receiver` Identity and the SubId `vault_sub_id` of the This function takes the `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` of the sub vault, as arguments and returns the amount of assets transferred to the `receiver`. - This function MUST allow for redeeming of the vault shares in exchange for a pro-rata amount of the underlying assets. -- This function MUST revert if any AssetId other than the AssetId representing the deposited asset's shares for the given sub vault at `vault_sub_id` is forwarded. (i.e. transferred share's AssetId must be equal to `AssetId::new(ContractId::this(), sha256((underlying_asset, vault_sub_id))`) +- This function MUST revert if any AssetId other than the AssetId representing the underlying asset's shares for the given sub vault at `vault_sub_id` is forwarded. (i.e. transferred share's AssetId must be equal to `AssetId::new(ContractId::this(), sha256((underlying_asset, vault_sub_id))`) - This function MUST burn the received shares. - This function MUST emit a `Withdraw` log. - This function MUST return amount of assets transferred to the receiver. ### `fn managed_assets(underlying_asset: AssetId, vault_sub_id: SubId) -> u64` -Method that returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. -This function takes the `underlying_asset` AssetId and the `vault_sub_id` of the sub vault as an argument and returns the total amount of assets of AssetId under management by vault. +This function returns the total assets under management by vault. Includes assets controlled by the vault but not directly possessed by vault. It takes the `underlying_asset` AssetId and the `vault_sub_id` of the sub vault as arguments and returns the total amount of assets of AssetId under management by vault. - This function MUST return total amount of assets of `underlying_asset` AssetId under management by vault. - This function MUST return 0 if there are no assets of `underlying_asset` AssetId under management by vault. @@ -54,26 +53,25 @@ This function takes the `underlying_asset` AssetId and the `vault_sub_id` of the ### `fn max_depositable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` -This is a helper function for getting the maximum amount of assets that can be deposited. It takes the hypothetical `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` of the sub vault as an arguments and returns the maximum amount of assets that can be deposited into the contract, for the given asset. +This is a helper function for getting the maximum amount of assets that can be deposited. It takes the hypothetical `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` SubId of the sub vault as an arguments and returns the maximum amount of assets that can be deposited into the contract, for the given asset. -- This function MUST return the maximum amount of assets that can be deposited into the contract, for the given asset, if the given vault exists. -- This function MUST return an `Some(amount)` if the given vault exists. -- This function MUST return an `None` if the given vault does not exist. +- This function MUST return the maximum amount of assets that can be deposited into the contract, for the given `underlying_asset`, if the given `vault_sub_id` vault exists. +- This function MUST return an `Some(amount)` if the given `vault_sub_id` vault exists. +- This function MUST return an `None` if the given `vault_sub_id` vault does not exist. - This function MUST account for both global and user specific limits. For example: if deposits are disabled, even temporarily, MUST return 0. ### `fn max_withdrawable(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option` -This is a helper function for getting maximum withdrawable. It takes the hypothetical `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. +This is a helper function for getting maximum withdrawable. It takes the hypothetical `receiver` Identity, the `underlying_asset` AssetId, and the `vault_sub_id` SubId of the sub vault as an argument and returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. -- This function MUST return the maximum amount of assets that can be withdrawn from the contract, for the given asset, if the given vault exists. -- This function MUST return an `Some(amount)` if the given vault exists. -- This function MUST return an `None` if the given vault does not exist. +- This function MUST return the maximum amount of assets that can be withdrawn from the contract, for the given `underlying_asset`, if the given `vault_sub_id` vault exists. +- This function MUST return an `Some(amount)` if the given `vault_sub_id` vault exists. +- This function MUST return an `None` if the given `vault_sub_id` vault does not exist. - This function MUST account for global limits. For example: if withdrawals are disabled, even temporarily, MUST return 0. ## Required logs -The following logs MUST be emitted at the specified occasions - +The following logs MUST be emitted at the specified occasions. ### `Deposit` @@ -141,11 +139,11 @@ The `burned_shares` field MUST represent the u64 amount of shares burned. # Rationale -The ABI discussed and covers the known use cases of token vaults while allowing safe implementations +The ABI discussed covers the known use cases of token vaults while allowing safe implementations # Backwards Compatibility -This standard is fully compatible with the SRC-20 standard +This standard is fully compatible with the [SRC-20 standard](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20). # Security Considerations From d498552a9bf33137cba5d6b775a251f85db9c78b Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 15:59:01 +0530 Subject: [PATCH 73/75] fmt --- standards/src_6/src/src_6.sw | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/standards/src_6/src/src_6.sw b/standards/src_6/src/src_6.sw index fb6296e..3c9cbf5 100644 --- a/standards/src_6/src/src_6.sw +++ b/standards/src_6/src/src_6.sw @@ -79,7 +79,11 @@ abi SRC6 { /// * 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(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> u64; + fn withdraw( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> u64; /// Returns the amount of managed assets of the given asset. /// @@ -111,7 +115,11 @@ abi SRC6 { /// * [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(receiver: Identity, underlying_asset: AssetId, vault_sub_id: SubId) -> Option; + fn max_depositable( + receiver: Identity, + underlying_asset: AssetId, + vault_sub_id: SubId, + ) -> Option; /// Returns the maximum amount of assets that can be withdrawn from the contract, for the given asset. /// From 0f321c5e8e3fb9c44dfd19f31b2b772e0ab3637b Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 16:45:09 +0530 Subject: [PATCH 74/75] add periods --- standards/src_6/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index ea772cf..4881a2f 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -75,9 +75,9 @@ The following logs MUST be emitted at the specified occasions. ### `Deposit` -`caller` has called the `deposit()` method sending `deposited_amount` assets of the `underlying_asset` Asset to the subvault of `vault_sub_id`, in exchange for `minted_shares` shares sent to the receiver `receiver` +`caller` has called the `deposit()` method sending `deposited_amount` assets of the `underlying_asset` Asset to the subvault of `vault_sub_id`, in exchange for `minted_shares` shares sent to the receiver `receiver`. -The `Deposit` struct MUST be logged whenever new shares are minted via the `deposit` method +The `Deposit` struct MUST be logged whenever new shares are minted via the `deposit()` method. The `Deposit` log SHALL have the following fields. @@ -107,9 +107,9 @@ The `minted_shares` field MUST represent the u64 amount of shares minted. ### `Withdraw` -`caller` has called the `withdraw()` method sending `burned_shares` shares in exchange for `withdrawn_amount` assets of the `underlying_asset` Asset from the subvault of `vault_sub_id` to the receiver `receiver` +`caller` has called the `withdraw()` method sending `burned_shares` shares in exchange for `withdrawn_amount` assets of the `underlying_asset` Asset from the subvault of `vault_sub_id` to the receiver `receiver`. -The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw` method +The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw()` method The `Withdraw` log SHALL have the following fields. @@ -139,7 +139,7 @@ The `burned_shares` field MUST represent the u64 amount of shares burned. # Rationale -The ABI discussed covers the known use cases of token vaults while allowing safe implementations +The ABI discussed covers the known use cases of token vaults while allowing safe implementations. # Backwards Compatibility From e4f843a868894590a650b19842f5d2d765f94d73 Mon Sep 17 00:00:00 2001 From: SwayStar123 Date: Fri, 15 Dec 2023 16:46:17 +0530 Subject: [PATCH 75/75] period. --- standards/src_6/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/src_6/README.md b/standards/src_6/README.md index 4881a2f..6114f24 100644 --- a/standards/src_6/README.md +++ b/standards/src_6/README.md @@ -109,7 +109,7 @@ The `minted_shares` field MUST represent the u64 amount of shares minted. `caller` has called the `withdraw()` method sending `burned_shares` shares in exchange for `withdrawn_amount` assets of the `underlying_asset` Asset from the subvault of `vault_sub_id` to the receiver `receiver`. -The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw()` method +The `Withdraw` struct MUST be logged whenever shares are redeemed for assets via the `withdraw()` method. The `Withdraw` log SHALL have the following fields.