From 6adf1b1d970ad25b49edb8d13816047ee2f45677 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 16 Aug 2024 15:56:50 +0200 Subject: [PATCH 01/29] refactor: fungibles pallet --- pallets/api/Cargo.toml | 2 +- pallets/api/src/fungibles/mod.rs | 227 +++++++++++++++-------------- pallets/api/src/fungibles/tests.rs | 202 +++++++++++++------------ 3 files changed, 224 insertions(+), 207 deletions(-) diff --git a/pallets/api/Cargo.toml b/pallets/api/Cargo.toml index a813a09c..f9a807a3 100644 --- a/pallets/api/Cargo.toml +++ b/pallets/api/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pallet-api" authors.workspace = true -description = "Api pallet, enabling smart(er) contracts with the power of Polkadot" +description = "API pallet, enabling smart(er) contracts with the power of Polkadot" edition.workspace = true license.workspace = true version = "0.1.0" diff --git a/pallets/api/src/fungibles/mod.rs b/pallets/api/src/fungibles/mod.rs index 7aa9ac00..feb34a21 100644 --- a/pallets/api/src/fungibles/mod.rs +++ b/pallets/api/src/fungibles/mod.rs @@ -1,6 +1,11 @@ -/// The fungibles pallet serves as a wrapper around the pallet_assets, offering a streamlined -/// interface for interacting with fungible assets. The goal is to provide a simplified, consistent -/// API that adheres to standards in the smart contract space. +//! The fungibles pallet offers a streamlined interface for interacting with fungible assets. The +//! goal is to provide a simplified, consistent API that adheres to standards in the smart contract +//! space. + +use frame_support::traits::fungibles::{metadata::Inspect as MetadataInspect, Inspect}; +pub use pallet::*; +use pallet_assets::WeightInfo as AssetsWeightInfoTrait; +use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -8,11 +13,6 @@ mod benchmarking; mod tests; pub mod weights; -use frame_support::traits::fungibles::{metadata::Inspect as MetadataInspect, Inspect}; -pub use pallet::*; -use pallet_assets::WeightInfo as AssetsWeightInfoTrait; -use weights::WeightInfo; - type AccountIdOf = ::AccountId; type AssetIdOf = > as Inspect< ::AccountId, @@ -41,42 +41,42 @@ pub mod pallet { }; use sp_std::vec::Vec; - /// State reads for the fungibles api with required input. + /// State reads for the fungibles API with required input. #[derive(Encode, Decode, Debug, MaxEncodedLen)] #[repr(u8)] #[allow(clippy::unnecessary_cast)] pub enum Read { - /// Total token supply for a given asset ID. + /// Total token supply for a specified asset. #[codec(index = 0)] TotalSupply(AssetIdOf), - /// Account balance for a given asset ID. + /// Account balance for a specified `asset` and `owner`. #[codec(index = 1)] BalanceOf { - /// The asset ID. - id: AssetIdOf, - /// The account ID of the owner. + /// The asset. + asset: AssetIdOf, + /// The owner of the asset. owner: AccountIdOf, }, - /// Allowance for a spender approved by an owner, for a given asset ID. + /// Allowance for a `spender` approved by an `owner`, for a specified `asset`. #[codec(index = 2)] Allowance { - /// The asset ID. - id: AssetIdOf, - /// The account ID of the owner. + /// The asset. + asset: AssetIdOf, + /// The owner of the asset. owner: AccountIdOf, - /// The account ID of the spender. + /// The spender with an allowance. spender: AccountIdOf, }, - /// Token name for a given asset ID. + /// Name of the specified asset. #[codec(index = 8)] TokenName(AssetIdOf), - /// Token symbol for a given asset ID. + /// Symbol for the specified asset. #[codec(index = 9)] TokenSymbol(AssetIdOf), - /// Token decimals for a given asset ID. + /// Decimals for the specified asset. #[codec(index = 10)] TokenDecimals(AssetIdOf), - /// Check if token with a given asset ID exists. + /// Check if a specified asset exists. #[codec(index = 18)] AssetExists(AssetIdOf), } @@ -101,62 +101,61 @@ pub mod pallet { pub enum Event { /// Event emitted when allowance by `owner` to `spender` changes. Approval { - /// The ID of the asset. - id: AssetIdOf, - /// Account providing allowance. + /// The asset. + asset: AssetIdOf, + /// The owner providing the allowance. owner: AccountIdOf, - /// Allowance beneficiary. + /// The beneficiary of the allowance. spender: AccountIdOf, - /// New allowance amount. + /// The new allowance amount. value: BalanceOf, }, - /// Event emitted when transfer of tokens occurs. + /// Event emitted when an asset transfer occurs. Transfer { - /// The ID of the asset. - id: AssetIdOf, - /// Transfer sender. `None` in case of minting new tokens. + /// The asset. + asset: AssetIdOf, + /// The source of the transfer. `None` when minting. from: Option>, - /// Transfer recipient. `None` in case of burning tokens. + /// The recipient of the transfer. `None` when burning. to: Option>, - /// Amount of tokens transferred (or minted/burned). + /// The amount transferred (or minted/burned). value: BalanceOf, }, - /// Event emitted when a token class is created. + /// Event emitted when an asset is created. Create { - /// The ID of the asset. + /// The asset identifier. id: AssetIdOf, - /// Creator of the asset. + /// The creator of the asset. creator: AccountIdOf, - /// Admin of the asset. + /// The administrator of the asset. admin: AccountIdOf, }, } #[pallet::call] impl Pallet { - /// Transfers `value` amount of tokens from the caller's account to account `to`, with additional - /// `data` in unspecified format. + /// Transfers `value` amount of tokens from the caller's account to account `to`. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to transfer. /// - `to` - The recipient account. /// - `value` - The number of tokens to transfer. #[pallet::call_index(3)] #[pallet::weight(AssetsWeightInfoOf::::transfer_keep_alive())] pub fn transfer( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, to: AccountIdOf, value: BalanceOf, ) -> DispatchResult { + let from = ensure_signed(origin.clone())?; AssetsOf::::transfer_keep_alive( - origin.clone(), - id.clone().into(), + origin, + asset.clone().into(), T::Lookup::unlookup(to.clone()), value, )?; - let from = ensure_signed(origin)?; - Self::deposit_event(Event::Transfer { id, from: Some(from), to: Some(to), value }); + Self::deposit_event(Event::Transfer { asset, from: Some(from), to: Some(to), value }); Ok(()) } @@ -164,7 +163,7 @@ pub mod pallet { /// in unspecified format. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to transfer. /// - `from` - The account from which the asset balance will be withdrawn. /// - `to` - The recipient account. /// - `value` - The number of tokens to transfer. @@ -172,39 +171,39 @@ pub mod pallet { #[pallet::weight(AssetsWeightInfoOf::::transfer_approved())] pub fn transfer_from( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, from: AccountIdOf, to: AccountIdOf, value: BalanceOf, ) -> DispatchResult { AssetsOf::::transfer_approved( origin, - id.clone().into(), + asset.clone().into(), T::Lookup::unlookup(from.clone()), T::Lookup::unlookup(to.clone()), value, )?; - Self::deposit_event(Event::Transfer { id, from: Some(from), to: Some(to), value }); + Self::deposit_event(Event::Transfer { asset, from: Some(from), to: Some(to), value }); Ok(()) } /// Approves an account to spend a specified number of tokens on behalf of the caller. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to approve. /// - `spender` - The account that is allowed to spend the tokens. /// - `value` - The number of tokens to approve. #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::approve(1, 1))] pub fn approve( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, spender: AccountIdOf, value: BalanceOf, ) -> DispatchResultWithPostInfo { let owner = ensure_signed(origin.clone()) .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; - let current_allowance = AssetsOf::::allowance(id.clone(), &owner, &spender); + let current_allowance = AssetsOf::::allowance(asset.clone(), &owner, &spender); let weight = match value.cmp(¤t_allowance) { // If the new value is equal to the current allowance, do nothing. @@ -214,7 +213,7 @@ pub mod pallet { Greater => { AssetsOf::::approve_transfer( origin, - id.clone().into(), + asset.clone().into(), T::Lookup::unlookup(spender.clone()), value.saturating_sub(current_allowance), ) @@ -224,37 +223,42 @@ pub mod pallet { // If the new value is less than the current allowance, cancel the approval and // set the new value. Less => { - let id_param: AssetIdParameterOf = id.clone().into(); + let asset_param: AssetIdParameterOf = asset.clone().into(); let spender_source = T::Lookup::unlookup(spender.clone()); AssetsOf::::cancel_approval( origin.clone(), - id_param.clone(), + asset_param.clone(), spender_source.clone(), ) .map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?; if value.is_zero() { Self::weight_approve(0, 1) } else { - AssetsOf::::approve_transfer(origin, id_param, spender_source, value)?; + AssetsOf::::approve_transfer( + origin, + asset_param, + spender_source, + value, + )?; Self::weight_approve(1, 1) } }, }; - Self::deposit_event(Event::Approval { id, owner, spender, value }); + Self::deposit_event(Event::Approval { asset, owner, spender, value }); Ok(Some(weight).into()) } - /// Increases the allowance of a spender. + /// Increases the allowance of a spender and asset. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to have an allowance increased. /// - `spender` - The account that is allowed to spend the tokens. /// - `value` - The number of tokens to increase the allowance by. #[pallet::call_index(6)] #[pallet::weight(::WeightInfo::approve(1, 0))] pub fn increase_allowance( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, spender: AccountIdOf, value: BalanceOf, ) -> DispatchResultWithPostInfo { @@ -262,27 +266,27 @@ pub mod pallet { .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; AssetsOf::::approve_transfer( origin, - id.clone().into(), + asset.clone().into(), T::Lookup::unlookup(spender.clone()), value, ) .map_err(|e| e.with_weight(AssetsWeightInfoOf::::approve_transfer()))?; - let value = AssetsOf::::allowance(id.clone(), &owner, &spender); - Self::deposit_event(Event::Approval { id, owner, spender, value }); + let value = AssetsOf::::allowance(asset.clone(), &owner, &spender); + Self::deposit_event(Event::Approval { asset, owner, spender, value }); Ok(().into()) } - /// Decreases the allowance of a spender. + /// Decreases the allowance of a spender and asset. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to have an allowance decreased. /// - `spender` - The account that is allowed to spend the tokens. /// - `value` - The number of tokens to decrease the allowance by. #[pallet::call_index(7)] #[pallet::weight(::WeightInfo::approve(1, 1))] pub fn decrease_allowance( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, spender: AccountIdOf, value: BalanceOf, ) -> DispatchResultWithPostInfo { @@ -291,14 +295,14 @@ pub mod pallet { if value.is_zero() { return Ok(Some(Self::weight_approve(0, 0)).into()); } - let current_allowance = AssetsOf::::allowance(id.clone(), &owner, &spender); + let current_allowance = AssetsOf::::allowance(asset.clone(), &owner, &spender); let spender_source = T::Lookup::unlookup(spender.clone()); - let id_param: AssetIdParameterOf = id.clone().into(); + let asset_param: AssetIdParameterOf = asset.clone().into(); // Cancel the approval and set the new value if `new_allowance` is more than zero. AssetsOf::::cancel_approval( origin.clone(), - id_param.clone(), + asset_param.clone(), spender_source.clone(), ) .map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?; @@ -306,17 +310,22 @@ pub mod pallet { let weight = if new_allowance.is_zero() { Self::weight_approve(0, 1) } else { - AssetsOf::::approve_transfer(origin, id_param, spender_source, new_allowance)?; + AssetsOf::::approve_transfer( + origin, + asset_param, + spender_source, + new_allowance, + )?; Self::weight_approve(1, 1) }; - Self::deposit_event(Event::Approval { id, owner, spender, value: new_allowance }); + Self::deposit_event(Event::Approval { asset, owner, spender, value: new_allowance }); Ok(Some(weight).into()) } - /// Create a new token with a given asset ID. + /// Create a new token with a given identifier. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `id` - The identifier of the asset. /// - `admin` - The account that will administer the asset. /// - `min_balance` - The minimum balance required for accounts holding this asset. #[pallet::call_index(11)] @@ -338,92 +347,90 @@ pub mod pallet { Ok(()) } - /// Start the process of destroying a token with a given asset ID. + /// Start the process of destroying a token. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to be destroyed. #[pallet::call_index(12)] #[pallet::weight(AssetsWeightInfoOf::::start_destroy())] - pub fn start_destroy(origin: OriginFor, id: AssetIdOf) -> DispatchResult { - AssetsOf::::start_destroy(origin, id.into()) + pub fn start_destroy(origin: OriginFor, asset: AssetIdOf) -> DispatchResult { + AssetsOf::::start_destroy(origin, asset.into()) } - /// Set the metadata for a token with a given asset ID. + /// Set the metadata for a token. /// /// # Parameters - /// - `id`: The identifier of the asset to update. - /// - `name`: The user friendly name of this asset. Limited in length by - /// `pallet_assets::Config::StringLimit`. - /// - `symbol`: The exchange symbol for this asset. Limited in length by - /// `pallet_assets::Config::StringLimit`. + /// - `asset`: The asset to update. + /// - `name`: The user friendly name of this asset. + /// - `symbol`: The exchange symbol for this asset. /// - `decimals`: The number of decimals this asset uses to represent one unit. #[pallet::call_index(16)] #[pallet::weight(AssetsWeightInfoOf::::set_metadata(name.len() as u32, symbol.len() as u32))] pub fn set_metadata( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, name: Vec, symbol: Vec, decimals: u8, ) -> DispatchResult { - AssetsOf::::set_metadata(origin, id.into(), name, symbol, decimals) + AssetsOf::::set_metadata(origin, asset.into(), name, symbol, decimals) } - /// Clear the metadata for a token with a given asset ID. + /// Clear the metadata for a token. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to update. #[pallet::call_index(17)] #[pallet::weight(AssetsWeightInfoOf::::clear_metadata())] - pub fn clear_metadata(origin: OriginFor, id: AssetIdOf) -> DispatchResult { - AssetsOf::::clear_metadata(origin, id.into()) + pub fn clear_metadata(origin: OriginFor, asset: AssetIdOf) -> DispatchResult { + AssetsOf::::clear_metadata(origin, asset.into()) } /// Creates `value` amount of tokens and assigns them to `account`, increasing the total supply. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - The asset to mint. /// - `account` - The account to be credited with the created tokens. /// - `value` - The number of tokens to mint. #[pallet::call_index(19)] #[pallet::weight(AssetsWeightInfoOf::::mint())] pub fn mint( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, account: AccountIdOf, value: BalanceOf, ) -> DispatchResult { AssetsOf::::mint( origin, - id.clone().into(), + asset.clone().into(), T::Lookup::unlookup(account.clone()), value, )?; - Self::deposit_event(Event::Transfer { id, from: None, to: Some(account), value }); + Self::deposit_event(Event::Transfer { asset, from: None, to: Some(account), value }); Ok(()) } /// Destroys `value` amount of tokens from `account`, reducing the total supply. /// /// # Parameters - /// - `id` - The ID of the asset. + /// - `asset` - the asset to burn. /// - `account` - The account from which the tokens will be destroyed. /// - `value` - The number of tokens to destroy. #[pallet::call_index(20)] #[pallet::weight(AssetsWeightInfoOf::::burn())] pub fn burn( origin: OriginFor, - id: AssetIdOf, + asset: AssetIdOf, account: AccountIdOf, value: BalanceOf, ) -> DispatchResult { AssetsOf::::burn( origin, - id.clone().into(), + asset.clone().into(), T::Lookup::unlookup(account.clone()), value, )?; - Self::deposit_event(Event::Transfer { id, from: Some(account), to: None, value }); + Self::deposit_event(Event::Transfer { asset, from: Some(account), to: None, value }); Ok(()) } } @@ -441,25 +448,25 @@ pub mod pallet { use Read::*; match value { - TotalSupply(id) => AssetsOf::::total_supply(id).encode(), - BalanceOf { id, owner } => AssetsOf::::balance(id, owner).encode(), - Allowance { id, owner, spender } => { - AssetsOf::::allowance(id, &owner, &spender).encode() + TotalSupply(asset) => AssetsOf::::total_supply(asset).encode(), + BalanceOf { asset, owner } => AssetsOf::::balance(asset, owner).encode(), + Allowance { asset, owner, spender } => { + AssetsOf::::allowance(asset, &owner, &spender).encode() }, - TokenName(id) => { - as MetadataInspect>>::name(id).encode() + TokenName(asset) => { + as MetadataInspect>>::name(asset).encode() }, - TokenSymbol(id) => { - as MetadataInspect>>::symbol(id).encode() + TokenSymbol(asset) => { + as MetadataInspect>>::symbol(asset).encode() }, - TokenDecimals(id) => { - as MetadataInspect>>::decimals(id).encode() + TokenDecimals(asset) => { + as MetadataInspect>>::decimals(asset).encode() }, - AssetExists(id) => AssetsOf::::asset_exists(id).encode(), + AssetExists(asset) => AssetsOf::::asset_exists(asset).encode(), } } - pub fn weight_approve(approve: u32, cancel: u32) -> Weight { + fn weight_approve(approve: u32, cancel: u32) -> Weight { ::WeightInfo::approve(cancel, approve) } } diff --git a/pallets/api/src/fungibles/tests.rs b/pallets/api/src/fungibles/tests.rs index ca2a85c9..9610139e 100644 --- a/pallets/api/src/fungibles/tests.rs +++ b/pallets/api/src/fungibles/tests.rs @@ -16,16 +16,16 @@ type Event = crate::fungibles::Event; fn transfer_works() { new_test_ext().execute_with(|| { let value: Balance = 100 * UNIT; - let id = ASSET; + let asset = ASSET; let from = Some(ALICE); let to = Some(BOB); - create_asset_and_mint_to(ALICE, id, ALICE, value * 2); - let balance_before_transfer = Assets::balance(id, &BOB); - assert_ok!(Fungibles::transfer(signed(ALICE), id, BOB, value)); - let balance_after_transfer = Assets::balance(id, &BOB); + create_asset_and_mint_to(ALICE, asset, ALICE, value * 2); + let balance_before_transfer = Assets::balance(asset, &BOB); + assert_ok!(Fungibles::transfer(signed(ALICE), asset, BOB, value)); + let balance_after_transfer = Assets::balance(asset, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + value); - System::assert_last_event(Event::Transfer { id, from, to, value }.into()); + System::assert_last_event(Event::Transfer { asset, from, to, value }.into()); }); } @@ -33,22 +33,22 @@ fn transfer_works() { fn transfer_from_works() { new_test_ext().execute_with(|| { let value: Balance = 100 * UNIT; - let id = ASSET; + let asset = ASSET; let from = Some(ALICE); let to = Some(BOB); // Approve CHARLIE to transfer up to `value` to BOB. - create_asset_mint_and_approve(ALICE, id, ALICE, value * 2, CHARLIE, value); + create_asset_mint_and_approve(ALICE, asset, ALICE, value * 2, CHARLIE, value); // Successfully call transfer from. - let alice_balance_before_transfer = Assets::balance(id, &ALICE); - let bob_balance_before_transfer = Assets::balance(id, &BOB); - assert_ok!(Fungibles::transfer_from(signed(CHARLIE), id, ALICE, BOB, value)); - let alice_balance_after_transfer = Assets::balance(id, &ALICE); - let bob_balance_after_transfer = Assets::balance(id, &BOB); + let alice_balance_before_transfer = Assets::balance(asset, &ALICE); + let bob_balance_before_transfer = Assets::balance(asset, &BOB); + assert_ok!(Fungibles::transfer_from(signed(CHARLIE), asset, ALICE, BOB, value)); + let alice_balance_after_transfer = Assets::balance(asset, &ALICE); + let bob_balance_after_transfer = Assets::balance(asset, &BOB); // Check that BOB receives the `value` and ALICE `amount` is spent successfully by CHARLIE. assert_eq!(bob_balance_after_transfer, bob_balance_before_transfer + value); assert_eq!(alice_balance_after_transfer, alice_balance_before_transfer - value); - System::assert_last_event(Event::Transfer { id, from, to, value }.into()); + System::assert_last_event(Event::Transfer { asset, from, to, value }.into()); }); } @@ -57,31 +57,37 @@ fn transfer_from_works() { fn approve_works() { new_test_ext().execute_with(|| { let value: Balance = 100 * UNIT; - let id = ASSET; + let asset = ASSET; let owner = ALICE; let spender = BOB; - create_asset_and_mint_to(ALICE, id, ALICE, value); - assert_eq!(0, Assets::allowance(id, &ALICE, &BOB)); - assert_ok!(Fungibles::approve(signed(ALICE), id, BOB, value)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value); - System::assert_last_event(Event::Approval { id, owner, spender, value }.into()); + create_asset_and_mint_to(ALICE, asset, ALICE, value); + assert_eq!(0, Assets::allowance(asset, &ALICE, &BOB)); + assert_ok!(Fungibles::approve(signed(ALICE), asset, BOB, value)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value); + System::assert_last_event(Event::Approval { asset, owner, spender, value }.into()); // Approves an value to spend that is lower than the current allowance. - assert_ok!(Fungibles::approve(signed(ALICE), id, BOB, value / 2)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value / 2); - System::assert_last_event(Event::Approval { id, owner, spender, value: value / 2 }.into()); + assert_ok!(Fungibles::approve(signed(ALICE), asset, BOB, value / 2)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value / 2); + System::assert_last_event( + Event::Approval { asset, owner, spender, value: value / 2 }.into(), + ); // Approves an value to spend that is higher than the current allowance. - assert_ok!(Fungibles::approve(signed(ALICE), id, BOB, value * 2)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value * 2); - System::assert_last_event(Event::Approval { id, owner, spender, value: value * 2 }.into()); + assert_ok!(Fungibles::approve(signed(ALICE), asset, BOB, value * 2)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value * 2); + System::assert_last_event( + Event::Approval { asset, owner, spender, value: value * 2 }.into(), + ); // Approves an value to spend that is equal to the current allowance. - assert_ok!(Fungibles::approve(signed(ALICE), id, BOB, value * 2)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value * 2); - System::assert_last_event(Event::Approval { id, owner, spender, value: value * 2 }.into()); + assert_ok!(Fungibles::approve(signed(ALICE), asset, BOB, value * 2)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value * 2); + System::assert_last_event( + Event::Approval { asset, owner, spender, value: value * 2 }.into(), + ); // Sets allowance to zero. - assert_ok!(Fungibles::approve(signed(ALICE), id, BOB, 0)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), 0); - System::assert_last_event(Event::Approval { id, owner, spender, value: 0 }.into()); + assert_ok!(Fungibles::approve(signed(ALICE), asset, BOB, 0)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), 0); + System::assert_last_event(Event::Approval { asset, owner, spender, value: 0 }.into()); }); } @@ -89,19 +95,21 @@ fn approve_works() { fn increase_allowance_works() { new_test_ext().execute_with(|| { let value: Balance = 100 * UNIT; - let id = ASSET; + let asset = ASSET; let owner = ALICE; let spender = BOB; - create_asset_and_mint_to(ALICE, id, ALICE, value); - assert_eq!(0, Assets::allowance(id, &ALICE, &BOB)); - assert_ok!(Fungibles::increase_allowance(signed(ALICE), id, BOB, value)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value); - System::assert_last_event(Event::Approval { id, owner, spender, value }.into()); + create_asset_and_mint_to(ALICE, asset, ALICE, value); + assert_eq!(0, Assets::allowance(asset, &ALICE, &BOB)); + assert_ok!(Fungibles::increase_allowance(signed(ALICE), asset, BOB, value)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value); + System::assert_last_event(Event::Approval { asset, owner, spender, value }.into()); // Additive. - assert_ok!(Fungibles::increase_allowance(signed(ALICE), id, BOB, value)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value * 2); - System::assert_last_event(Event::Approval { id, owner, spender, value: value * 2 }.into()); + assert_ok!(Fungibles::increase_allowance(signed(ALICE), asset, BOB, value)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value * 2); + System::assert_last_event( + Event::Approval { asset, owner, spender, value: value * 2 }.into(), + ); }); } @@ -109,23 +117,25 @@ fn increase_allowance_works() { fn decrease_allowance_works() { new_test_ext().execute_with(|| { let value: Balance = 100 * UNIT; - let id = ASSET; + let asset = ASSET; let owner = ALICE; let spender = BOB; - create_asset_mint_and_approve(ALICE, id, ALICE, value, BOB, value); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value); + create_asset_mint_and_approve(ALICE, asset, ALICE, value, BOB, value); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value); // Owner balance is not changed if decreased by zero. - assert_ok!(Fungibles::decrease_allowance(signed(ALICE), id, BOB, 0)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value); + assert_ok!(Fungibles::decrease_allowance(signed(ALICE), asset, BOB, 0)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value); // Decrease allowance successfully. - assert_ok!(Fungibles::decrease_allowance(signed(ALICE), id, BOB, value / 2)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), value / 2); - System::assert_last_event(Event::Approval { id, owner, spender, value: value / 2 }.into()); + assert_ok!(Fungibles::decrease_allowance(signed(ALICE), asset, BOB, value / 2)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), value / 2); + System::assert_last_event( + Event::Approval { asset, owner, spender, value: value / 2 }.into(), + ); // Saturating if current allowance is decreased more than the owner balance. - assert_ok!(Fungibles::decrease_allowance(signed(ALICE), id, BOB, value)); - assert_eq!(Assets::allowance(id, &ALICE, &BOB), 0); - System::assert_last_event(Event::Approval { id, owner, spender, value: 0 }.into()); + assert_ok!(Fungibles::decrease_allowance(signed(ALICE), asset, BOB, value)); + assert_eq!(Assets::allowance(asset, &ALICE, &BOB), 0); + System::assert_last_event(Event::Approval { asset, owner, spender, value: 0 }.into()); }); } @@ -146,45 +156,45 @@ fn create_works() { #[test] fn start_destroy_works() { new_test_ext().execute_with(|| { - let id = ASSET; + let asset = ASSET; - create_asset(ALICE, id); - assert_ok!(Fungibles::start_destroy(signed(ALICE), id)); + create_asset(ALICE, asset); + assert_ok!(Fungibles::start_destroy(signed(ALICE), asset)); }); } #[test] fn set_metadata_works() { new_test_ext().execute_with(|| { - let id = ASSET; + let asset = ASSET; let name = vec![42]; let symbol = vec![42]; let decimals = 42; - create_asset(ALICE, id); + create_asset(ALICE, asset); assert_ok!(Fungibles::set_metadata( signed(ALICE), - id, + asset, name.clone(), symbol.clone(), decimals )); - assert_eq!(Assets::name(id), name); - assert_eq!(Assets::symbol(id), symbol); - assert_eq!(Assets::decimals(id), decimals); + assert_eq!(Assets::name(asset), name); + assert_eq!(Assets::symbol(asset), symbol); + assert_eq!(Assets::decimals(asset), decimals); }); } #[test] fn clear_metadata_works() { new_test_ext().execute_with(|| { - let id = ASSET; + let asset = ASSET; - create_asset_and_set_metadata(ALICE, id, vec![42], vec![42], 42); - assert_ok!(Fungibles::clear_metadata(signed(ALICE), id)); - assert!(Assets::name(id).is_empty()); - assert!(Assets::symbol(id).is_empty()); - assert!(Assets::decimals(id).is_zero()); + create_asset_and_set_metadata(ALICE, asset, vec![42], vec![42], 42); + assert_ok!(Fungibles::clear_metadata(signed(ALICE), asset)); + assert!(Assets::name(asset).is_empty()); + assert!(Assets::symbol(asset).is_empty()); + assert!(Assets::decimals(asset).is_zero()); }); } @@ -192,16 +202,16 @@ fn clear_metadata_works() { fn mint_works() { new_test_ext().execute_with(|| { let value: Balance = 100 * UNIT; - let id = ASSET; + let asset = ASSET; let from = None; let to = Some(BOB); - create_asset(ALICE, id); - let balance_before_mint = Assets::balance(id, &BOB); - assert_ok!(Fungibles::mint(signed(ALICE), id, BOB, value)); - let balance_after_mint = Assets::balance(id, &BOB); + create_asset(ALICE, asset); + let balance_before_mint = Assets::balance(asset, &BOB); + assert_ok!(Fungibles::mint(signed(ALICE), asset, BOB, value)); + let balance_after_mint = Assets::balance(asset, &BOB); assert_eq!(balance_after_mint, balance_before_mint + value); - System::assert_last_event(Event::Transfer { id, from, to, value }.into()); + System::assert_last_event(Event::Transfer { asset, from, to, value }.into()); }); } @@ -209,16 +219,16 @@ fn mint_works() { fn burn_works() { new_test_ext().execute_with(|| { let value: Balance = 100 * UNIT; - let id = ASSET; + let asset = ASSET; let from = Some(BOB); let to = None; - create_asset_and_mint_to(ALICE, id, BOB, value); - let balance_before_burn = Assets::balance(id, &BOB); - assert_ok!(Fungibles::burn(signed(ALICE), id, BOB, value)); - let balance_after_burn = Assets::balance(id, &BOB); + create_asset_and_mint_to(ALICE, asset, BOB, value); + let balance_before_burn = Assets::balance(asset, &BOB); + assert_ok!(Fungibles::burn(signed(ALICE), asset, BOB, value)); + let balance_after_burn = Assets::balance(asset, &BOB); assert_eq!(balance_after_burn, balance_before_burn - value); - System::assert_last_event(Event::Transfer { id, from, to, value }.into()); + System::assert_last_event(Event::Transfer { asset, from, to, value }.into()); }); } @@ -236,7 +246,7 @@ fn balance_of_works() { create_asset_and_mint_to(ALICE, ASSET, ALICE, 100); assert_eq!( Assets::balance(ASSET, ALICE).encode(), - Fungibles::read_state(BalanceOf { id: ASSET, owner: ALICE }) + Fungibles::read_state(BalanceOf { asset: ASSET, owner: ALICE }) ); }); } @@ -247,7 +257,7 @@ fn allowance_works() { create_asset_mint_and_approve(ALICE, ASSET, BOB, 100, ALICE, 50); assert_eq!( Assets::allowance(ASSET, &ALICE, &BOB).encode(), - Fungibles::read_state(Allowance { id: ASSET, owner: ALICE, spender: BOB }) + Fungibles::read_state(Allowance { asset: ASSET, owner: ALICE, spender: BOB }) ); }); } @@ -277,48 +287,48 @@ fn signed(account: AccountId) -> RuntimeOrigin { RuntimeOrigin::signed(account) } -fn create_asset(owner: AccountId, asset_id: AssetId) { - assert_ok!(Assets::create(signed(owner), asset_id, owner, 1)); +fn create_asset(owner: AccountId, asset_asset: AssetId) { + assert_ok!(Assets::create(signed(owner), asset_asset, owner, 1)); } -fn mint_asset(owner: AccountId, asset_id: AssetId, to: AccountId, value: Balance) { - assert_ok!(Assets::mint(signed(owner), asset_id, to, value)); +fn mint_asset(owner: AccountId, asset_asset: AssetId, to: AccountId, value: Balance) { + assert_ok!(Assets::mint(signed(owner), asset_asset, to, value)); } -fn create_asset_and_mint_to(owner: AccountId, asset_id: AssetId, to: AccountId, value: Balance) { - create_asset(owner, asset_id); - mint_asset(owner, asset_id, to, value) +fn create_asset_and_mint_to(owner: AccountId, asset_asset: AssetId, to: AccountId, value: Balance) { + create_asset(owner, asset_asset); + mint_asset(owner, asset_asset, to, value) } fn create_asset_mint_and_approve( owner: AccountId, - asset_id: AssetId, + asset_asset: AssetId, to: AccountId, mint: Balance, spender: AccountId, approve: Balance, ) { - create_asset_and_mint_to(owner, asset_id, to, mint); - assert_ok!(Assets::approve_transfer(signed(to), asset_id, spender, approve,)); + create_asset_and_mint_to(owner, asset_asset, to, mint); + assert_ok!(Assets::approve_transfer(signed(to), asset_asset, spender, approve,)); } fn create_asset_and_set_metadata( owner: AccountId, - asset_id: AssetId, + asset_asset: AssetId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::create(signed(owner), asset_id, owner, 100)); - set_metadata_asset(owner, asset_id, name, symbol, decimals); + assert_ok!(Assets::create(signed(owner), asset_asset, owner, 100)); + set_metadata_asset(owner, asset_asset, name, symbol, decimals); } fn set_metadata_asset( owner: AccountId, - asset_id: AssetId, + asset_asset: AssetId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::set_metadata(signed(owner), asset_id, name, symbol, decimals)); + assert_ok!(Assets::set_metadata(signed(owner), asset_asset, name, symbol, decimals)); } From fa448bb16dcb9dce1b77ed83ebd696c6c05e9954 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:48:03 +0700 Subject: [PATCH 02/29] fix: invalid imported crates & crate visibility --- pop-api/src/v0/assets/fungibles.rs | 12 +++++------- runtime/devnet/src/config/mod.rs | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pop-api/src/v0/assets/fungibles.rs b/pop-api/src/v0/assets/fungibles.rs index c881f823..435e1789 100644 --- a/pop-api/src/v0/assets/fungibles.rs +++ b/pop-api/src/v0/assets/fungibles.rs @@ -11,9 +11,9 @@ use crate::{ primitives::{AccountId, AssetId, Balance}, Result, StatusCode, }; -pub use asset_management::*; use constants::*; use ink::{env::chain_extension::ChainExtensionMethod, prelude::vec::Vec}; +pub use management::*; pub use metadata::*; // Helper method to build a dispatch call. @@ -485,13 +485,11 @@ mod tests { use super::FungiblesError; use crate::{ constants::{ASSETS, BALANCES}, - primitives::error::{ - ArithmeticError::*, - Error::{self, *}, - TokenError::*, - TransactionalError::*, - }, + ArithmeticError::*, + Error::{self, *}, StatusCode, + TokenError::*, + TransactionalError::*, }; fn error_into_status_code(error: Error) -> StatusCode { diff --git a/runtime/devnet/src/config/mod.rs b/runtime/devnet/src/config/mod.rs index 1dcd44da..1ef83bc1 100644 --- a/runtime/devnet/src/config/mod.rs +++ b/runtime/devnet/src/config/mod.rs @@ -1,5 +1,6 @@ mod api; -mod assets; +// Public due to pop api integration tests crate. +pub mod assets; mod contracts; mod proxy; // Public due to integration tests crate. From 84c2840d002003ea1c2d031fdd98340ce8d942a2 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:06:47 +0700 Subject: [PATCH 03/29] fix: revert primitive error imports --- pop-api/src/v0/assets/fungibles.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pop-api/src/v0/assets/fungibles.rs b/pop-api/src/v0/assets/fungibles.rs index 435e1789..4f270e6b 100644 --- a/pop-api/src/v0/assets/fungibles.rs +++ b/pop-api/src/v0/assets/fungibles.rs @@ -485,11 +485,13 @@ mod tests { use super::FungiblesError; use crate::{ constants::{ASSETS, BALANCES}, - ArithmeticError::*, - Error::{self, *}, + primitives::error::{ + ArithmeticError::*, + Error::{self, *}, + TokenError::*, + TransactionalError::*, + }, StatusCode, - TokenError::*, - TransactionalError::*, }; fn error_into_status_code(error: Error) -> StatusCode { From 83a65b81abdd6180772c082159aff7086990e025 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Mon, 19 Aug 2024 09:29:44 +0200 Subject: [PATCH 04/29] style: fix tests asset_asset parameter --- pallets/api/src/fungibles/tests.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/pallets/api/src/fungibles/tests.rs b/pallets/api/src/fungibles/tests.rs index 9610139e..d881a3c1 100644 --- a/pallets/api/src/fungibles/tests.rs +++ b/pallets/api/src/fungibles/tests.rs @@ -287,48 +287,48 @@ fn signed(account: AccountId) -> RuntimeOrigin { RuntimeOrigin::signed(account) } -fn create_asset(owner: AccountId, asset_asset: AssetId) { - assert_ok!(Assets::create(signed(owner), asset_asset, owner, 1)); +fn create_asset(owner: AccountId, asset: AssetId) { + assert_ok!(Assets::create(signed(owner), asset, owner, 1)); } -fn mint_asset(owner: AccountId, asset_asset: AssetId, to: AccountId, value: Balance) { - assert_ok!(Assets::mint(signed(owner), asset_asset, to, value)); +fn mint_asset(owner: AccountId, asset: AssetId, to: AccountId, value: Balance) { + assert_ok!(Assets::mint(signed(owner), asset, to, value)); } -fn create_asset_and_mint_to(owner: AccountId, asset_asset: AssetId, to: AccountId, value: Balance) { - create_asset(owner, asset_asset); - mint_asset(owner, asset_asset, to, value) +fn create_asset_and_mint_to(owner: AccountId, asset: AssetId, to: AccountId, value: Balance) { + create_asset(owner, asset); + mint_asset(owner, asset, to, value) } fn create_asset_mint_and_approve( owner: AccountId, - asset_asset: AssetId, + asset: AssetId, to: AccountId, mint: Balance, spender: AccountId, approve: Balance, ) { - create_asset_and_mint_to(owner, asset_asset, to, mint); - assert_ok!(Assets::approve_transfer(signed(to), asset_asset, spender, approve,)); + create_asset_and_mint_to(owner, asset, to, mint); + assert_ok!(Assets::approve_transfer(signed(to), asset, spender, approve,)); } fn create_asset_and_set_metadata( owner: AccountId, - asset_asset: AssetId, + asset: AssetId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::create(signed(owner), asset_asset, owner, 100)); - set_metadata_asset(owner, asset_asset, name, symbol, decimals); + assert_ok!(Assets::create(signed(owner), asset, owner, 100)); + set_metadata_asset(owner, asset, name, symbol, decimals); } fn set_metadata_asset( owner: AccountId, - asset_asset: AssetId, + asset: AssetId, name: Vec, symbol: Vec, decimals: u8, ) { - assert_ok!(Assets::set_metadata(signed(owner), asset_asset, name, symbol, decimals)); + assert_ok!(Assets::set_metadata(signed(owner), asset, name, symbol, decimals)); } From 2cdc71aa969f2ba6befb66209a45b313545e6365 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:23:33 +0700 Subject: [PATCH 05/29] test: assert events emitted from contract --- pop-api/integration-tests/Cargo.toml | 13 ++++++- .../create_token_in_constructor/lib.rs | 4 +- .../contracts/fungibles/lib.rs | 38 +++++++++++++++---- .../integration-tests/src/fungibles/mod.rs | 37 +++++++++++++++++- .../integration-tests/src/fungibles/utils.rs | 31 ++++++++++++--- pop-api/src/primitives.rs | 6 +++ 6 files changed, 109 insertions(+), 20 deletions(-) diff --git a/pop-api/integration-tests/Cargo.toml b/pop-api/integration-tests/Cargo.toml index cc56630a..42e22cff 100644 --- a/pop-api/integration-tests/Cargo.toml +++ b/pop-api/integration-tests/Cargo.toml @@ -5,29 +5,38 @@ edition = "2021" [dev-dependencies] env_logger = "0.11.2" -scale = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } frame-support = { version = "29.0.0", default-features = false } frame-system = { version = "29.0.0", default-features = false } pallet-balances = { version = "29.0.2", default-features = false } pallet-assets = { version = "30.0.0", default-features = false } pallet-contracts = { version = "28.0.0", default-features = false } +pop-api = { path = "../../pop-api", default-features = false, features = [ + "fungibles", +] } pop-primitives = { path = "../../primitives", default-features = false } pop-runtime-devnet = { path = "../../runtime/devnet", default-features = false } sp-io = { version = "31.0.0", default-features = false } sp-runtime = { version = "32.0.0", default-features = false } +# TODO +ink = { version = "5.0.0", default-features = false } [features] default = ["std"] std = [ "frame-support/std", "frame-system/std", + "ink/std", "pallet-balances/std", "pallet-assets/std", "pallet-contracts/std", + "pop-api/std", "pop-primitives/std", "pop-runtime-devnet/std", "scale/std", "sp-io/std", "sp-runtime/std", -] \ No newline at end of file +] diff --git a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs index e9e5d127..69086d4b 100755 --- a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs +++ b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs @@ -1,8 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] -use ink::prelude::vec::Vec; use pop_api::{ - assets::fungibles::{self as api}, + assets::fungibles::{self as api, events::Create}, primitives::AssetId, StatusCode, }; @@ -25,6 +24,7 @@ mod create_token_in_constructor { // AccountId of the contract which will be set to the owner of the fungible token. let owner = contract.env().account_id(); api::create(id, owner, min_balance)?; + contract.env().emit_event(Create { id, creator: owner, admin: owner }); Ok(contract) } diff --git a/pop-api/integration-tests/contracts/fungibles/lib.rs b/pop-api/integration-tests/contracts/fungibles/lib.rs index 239d3a2d..116aa81c 100755 --- a/pop-api/integration-tests/contracts/fungibles/lib.rs +++ b/pop-api/integration-tests/contracts/fungibles/lib.rs @@ -7,7 +7,10 @@ /// use ink::prelude::vec::Vec; use pop_api::{ - assets::fungibles::{self as api}, + assets::fungibles::{ + self as api, + events::{Approval, ClearMetadata, Create, SetMetadata, StartDestroy, Transfer}, + }, primitives::AssetId, StatusCode, }; @@ -61,7 +64,13 @@ mod fungibles { #[ink(message)] pub fn transfer(&self, id: AssetId, to: AccountId, value: Balance) -> Result<()> { - api::transfer(id, to, value) + let result = api::transfer(id, to, value); + self.env().emit_event(Transfer { + from: Some(self.env().account_id()), + to: Some(to), + value, + }); + result } #[ink(message)] @@ -74,12 +83,17 @@ mod fungibles { // In the PSP-22 standard a `[u8]`, but the size needs to be known at compile time. _data: Vec, ) -> Result<()> { - api::transfer_from(id, from, to, value) + let result = api::transfer_from(id, from, to, value); + self.env().emit_event(Transfer { from: Some(from), to: Some(to), value }); + result } #[ink(message)] pub fn approve(&self, id: AssetId, spender: AccountId, value: Balance) -> Result<()> { - api::approve(id, spender, value) + let result = api::approve(id, spender, value); + self.env() + .emit_event(Approval { owner: self.env().account_id(), spender, value }); + result } #[ink(message)] @@ -131,12 +145,16 @@ mod fungibles { #[ink(message)] pub fn create(&self, id: AssetId, admin: AccountId, min_balance: Balance) -> Result<()> { - api::create(id, admin, min_balance) + let result = api::create(id, admin, min_balance); + self.env().emit_event(Create { id, creator: admin, admin }); + result } #[ink(message)] pub fn start_destroy(&self, id: AssetId) -> Result<()> { - api::start_destroy(id) + let result = api::start_destroy(id); + self.env().emit_event(StartDestroy { id }); + result } #[ink(message)] @@ -147,12 +165,16 @@ mod fungibles { symbol: Vec, decimals: u8, ) -> Result<()> { - api::set_metadata(id, name, symbol, decimals) + let result = api::set_metadata(id, name.clone(), symbol.clone(), decimals); + self.env().emit_event(SetMetadata { id, name, symbol, decimals }); + result } #[ink(message)] pub fn clear_metadata(&self, id: AssetId) -> Result<()> { - api::clear_metadata(id) + let result = api::clear_metadata(id); + self.env().emit_event(ClearMetadata { id }); + result } #[ink(message)] diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 0ca7d4f9..586b6fbe 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,4 +1,10 @@ use super::*; +use pop_api::{ + assets::fungibles::events::{ + Approval, ClearMetadata, Create, SetMetadata, StartDestroy, Transfer, + }, + primitives::account_id_from_slice, +}; use pop_primitives::error::{ ArithmeticError::*, Error::{self, *}, @@ -186,6 +192,14 @@ fn approve_works() { assert_eq!(0, Assets::allowance(asset, &addr, &BOB)); assert_ok!(approve(addr.clone(), asset, BOB, amount)); assert_eq!(Assets::allowance(asset, &addr, &BOB), amount); + // Successfully emit an event from approving. + let expected = Approval { + owner: account_id_from_slice(addr.clone().as_ref()), + spender: account_id_from_slice(BOB.as_ref()), + value: amount, + } + .encode(); + assert_eq!(latest_contract_event(), expected.as_slice()); // Non-additive, sets new value. assert_ok!(approve(addr.clone(), asset, BOB, amount / 2)); assert_eq!(Assets::allowance(asset, &addr, &BOB), amount / 2); @@ -345,6 +359,10 @@ fn create_works() { assert_eq!(create(addr.clone(), ASSET_ID, BOB, 0), Err(Module { index: 52, error: 7 }),); // Create asset successfully. assert_ok!(create(addr.clone(), ASSET_ID, BOB, 1)); + // Successfully emit an event from creating a new asset class. + let admin = account_id_from_slice(BOB.as_ref()); + let expected = Create { id: ASSET_ID, creator: admin, admin }.encode(); + assert_eq!(latest_contract_event(), expected.as_slice()); // Asset ID is already taken. assert_eq!(create(addr.clone(), ASSET_ID, BOB, 1), Err(Module { index: 52, error: 5 }),); }); @@ -364,8 +382,14 @@ fn instantiate_and_create_fungible_works() { Err(Module { index: 52, error: 5 }) ); // Successfully create an asset when instantiating the contract. - assert_ok!(instantiate_and_create_fungible(contract, ASSET_ID, 1)); + let instantiator = + instantiate_and_create_fungible(contract, ASSET_ID, 1).expect("Should work"); assert!(Assets::asset_exists(ASSET_ID)); + // Successfully emit an event from instantiating a new fungible. + let instantiator = account_id_from_slice(instantiator.as_ref()); + let expected = + Create { id: ASSET_ID, creator: instantiator.clone(), admin: instantiator }.encode(); + assert_eq!(latest_contract_event(), expected.as_slice()); }); } @@ -383,6 +407,9 @@ fn start_destroy_works() { assert_eq!(start_destroy(addr.clone(), asset), Err(Module { index: 52, error: 2 }),); let asset = create_asset(addr.clone(), ASSET_ID, 1); assert_ok!(start_destroy(addr.clone(), asset)); + // Successfully emit an event from destroying an asset. + let expected = StartDestroy { id: ASSET_ID }.encode(); + assert_eq!(latest_contract_event(), expected.as_slice()); }); } @@ -423,7 +450,10 @@ fn set_metadata_works() { Err(Module { index: 52, error: 9 }), ); // Set metadata successfully. - assert_ok!(set_metadata(addr.clone(), ASSET_ID, name, symbol, decimals)); + assert_ok!(set_metadata(addr.clone(), ASSET_ID, name.clone(), symbol.clone(), decimals)); + // Successfully emit an event from set asset metadata. + let expected = SetMetadata { id: ASSET_ID, name, symbol, decimals }.encode(); + assert_eq!(latest_contract_event(), expected.as_slice()); // Asset is not live, i.e. frozen or being destroyed. start_destroy_asset(addr.clone(), asset); assert_eq!( @@ -458,6 +488,9 @@ fn clear_metadata_works() { set_metadata_asset(addr.clone(), asset, name, symbol, decimals); // Clear metadata successfully. assert_ok!(clear_metadata(addr.clone(), ASSET_ID)); + // Successfully emit an event from set asset metadata. + let expected = ClearMetadata { id: ASSET_ID }.encode(); + assert_eq!(latest_contract_event(), expected.as_slice()); // Asset is not live, i.e. frozen or being destroyed. start_destroy_asset(addr.clone(), asset); assert_eq!( diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 33a25f7a..5e7456e6 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -315,7 +315,7 @@ pub(super) fn instantiate_and_create_fungible( contract: &str, asset_id: AssetId, min_balance: Balance, -) -> Result<(), Error> { +) -> Result { let function = function_selector("new"); let input = [function, asset_id.encode(), min_balance.encode()].concat(); let (wasm_binary, _) = @@ -329,11 +329,30 @@ pub(super) fn instantiate_and_create_fungible( input, vec![], DEBUG_OUTPUT, - CollectEvents::Skip, + CollectEvents::UnsafeCollect, ) .result - .expect("should work") - .result; - decoded::>(result.clone()) - .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) + .expect("should work"); + let account_id = result.clone().account_id; + let result = decoded::>(result.clone().result.clone()) + .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)); + match result { + Ok(_) => Ok(account_id), + Err(error) => Err(error), + } +} + +/// Get the latest event from pallet contracts. +pub(super) fn latest_contract_event() -> Vec { + let events = System::read_events_for_pallet::>(); + let contract_events = events + .iter() + .filter_map(|event| match event { + pallet_contracts::Event::::ContractEmitted { data, .. } => { + Some(data.as_slice()) + }, + _ => None, + }) + .collect::>(); + contract_events.last().unwrap().to_vec() } diff --git a/pop-api/src/primitives.rs b/pop-api/src/primitives.rs index a3d596a5..9fec4dd3 100644 --- a/pop-api/src/primitives.rs +++ b/pop-api/src/primitives.rs @@ -1,5 +1,11 @@ use ink::env::{DefaultEnvironment, Environment}; +use ink::scale::Decode; pub use pop_primitives::*; pub(crate) type AccountId = ::AccountId; pub(crate) type Balance = ::Balance; + +/// Decode slice of bytes to environment associated type AccountId. +pub fn account_id_from_slice(s: &[u8; 32]) -> AccountId { + AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") +} From 393e1c11aaf2de7b0f8ea8ad4c512c924dac828a Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Wed, 11 Sep 2024 17:27:59 +0200 Subject: [PATCH 06/29] refactor: api integration tests --- pop-api/examples/fungibles/lib.rs | 101 +----- .../create_token_in_constructor/Cargo.toml | 13 +- .../contracts/fungibles/Cargo.toml | 13 +- .../integration-tests/src/fungibles/mod.rs | 334 +++++++++--------- .../integration-tests/src/fungibles/utils.rs | 130 +++---- pop-api/integration-tests/src/lib.rs | 18 +- 6 files changed, 274 insertions(+), 335 deletions(-) diff --git a/pop-api/examples/fungibles/lib.rs b/pop-api/examples/fungibles/lib.rs index 1ad36de0..1f9200f4 100755 --- a/pop-api/examples/fungibles/lib.rs +++ b/pop-api/examples/fungibles/lib.rs @@ -1,14 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] -/// Local Fungibles: -/// 1. PSP-22 Interface -/// 2. PSP-22 Metadata Interface -/// 3. Asset Management -/// use ink::prelude::vec::Vec; use pop_api::{ assets::fungibles::{self as api}, - primitives::AssetId, + primitives::TokenId, StatusCode, }; @@ -29,30 +24,20 @@ mod fungibles { Default::default() } - /// 1. PSP-22 Interface: - /// - total_supply - /// - balance_of - /// - allowance - /// - transfer - /// - transfer_from - /// - approve - /// - increase_allowance - /// - decrease_allowance - #[ink(message)] - pub fn total_supply(&self, id: AssetId) -> Result { + pub fn total_supply(&self, id: TokenId) -> Result { api::total_supply(id) } #[ink(message)] - pub fn balance_of(&self, id: AssetId, owner: AccountId) -> Result { + pub fn balance_of(&self, id: TokenId, owner: AccountId) -> Result { api::balance_of(id, owner) } #[ink(message)] pub fn allowance( &self, - id: AssetId, + id: TokenId, owner: AccountId, spender: AccountId, ) -> Result { @@ -60,32 +45,31 @@ mod fungibles { } #[ink(message)] - pub fn transfer(&mut self, id: AssetId, to: AccountId, value: Balance) -> Result<()> { + pub fn transfer(&mut self, id: TokenId, to: AccountId, value: Balance) -> Result<()> { api::transfer(id, to, value) } #[ink(message)] pub fn transfer_from( &mut self, - id: AssetId, + id: TokenId, from: AccountId, to: AccountId, value: Balance, - // In the PSP-22 standard a `[u8]`, but the size needs to be known at compile time. _data: Vec, ) -> Result<()> { api::transfer_from(id, from, to, value) } #[ink(message)] - pub fn approve(&mut self, id: AssetId, spender: AccountId, value: Balance) -> Result<()> { + pub fn approve(&mut self, id: TokenId, spender: AccountId, value: Balance) -> Result<()> { api::approve(id, spender, value) } #[ink(message)] pub fn increase_allowance( &mut self, - id: AssetId, + id: TokenId, spender: AccountId, value: Balance, ) -> Result<()> { @@ -95,82 +79,27 @@ mod fungibles { #[ink(message)] pub fn decrease_allowance( &mut self, - id: AssetId, + id: TokenId, spender: AccountId, value: Balance, ) -> Result<()> { api::decrease_allowance(id, spender, value) } - /// 2. PSP-22 Metadata Interface: - /// - token_name - /// - token_symbol - /// - token_decimals - #[ink(message)] - pub fn token_name(&self, id: AssetId) -> Result> { + pub fn token_name(&self, id: TokenId) -> Result> { api::token_name(id) } #[ink(message)] - pub fn token_symbol(&self, id: AssetId) -> Result> { + pub fn token_symbol(&self, id: TokenId) -> Result> { api::token_symbol(id) } #[ink(message)] - pub fn token_decimals(&self, id: AssetId) -> Result { + pub fn token_decimals(&self, id: TokenId) -> Result { api::token_decimals(id) } - - // 3. Asset Management: - // - create - // - start_destroy - // - destroy_accounts - // - destroy_approvals - // - finish_destroy - // - set_metadata - // - clear_metadata - - // #[ink(message)] - // pub fn create(&self, id: AssetId, admin: AccountId, min_balance: Balance) -> Result<()> { - // ink::env::debug_println!( - // "PopApiFungiblesExample::create: id: {:?} admin: {:?} min_balance: {:?}", - // id, - // admin, - // min_balance, - // ); - // let result = api::create(id, admin, min_balance); - // ink::env::debug_println!("Result: {:?}", result); - // result.map_err(|e| e.into()) - // result - // } - - // #[ink(message)] - // pub fn set_metadata( - // &self, - // id: AssetId, - // name: Vec, - // symbol: Vec, - // decimals: u8, - // ) -> Result<()> { - // ink::env::debug_println!( - // "PopApiFungiblesExample::set_metadata: id: {:?} name: {:?} symbol: {:?}, decimals: {:?}", - // id, - // name, - // symbol, - // decimals, - // ); - // let result = api::set_metadata(id, name, symbol, decimals); - // ink::env::debug_println!("Result: {:?}", result); - // // result.map_err(|e| e.into()) - // result - // } - // - // #[ink(message)] - // pub fn asset_exists(&self, id: AssetId) -> Result { - // // api::asset_exists(id).map_err(|e| e.into()) - // api::asset_exists(id) - // } } #[cfg(test)] @@ -178,8 +107,6 @@ mod fungibles { use super::*; #[ink::test] - fn default_works() { - PopApiFungiblesExample::new(); - } + fn default_works() {} } -} \ No newline at end of file +} diff --git a/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml b/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml index c3d2c2fc..e5f80cdf 100755 --- a/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml +++ b/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml @@ -1,21 +1,20 @@ [package] -authors = [ "[your_name] <[your_email]>" ] edition = "2021" name = "create_token_in_constructor" version = "0.1.0" [dependencies] ink = { version = "5.0.0", default-features = false } -pop-api = { path = "../../..", default-features = false, features = [ "fungibles" ] } +pop-api = { path = "../../..", default-features = false, features = ["fungibles"] } [lib] path = "lib.rs" [features] -default = [ "std" ] -e2e-tests = [ ] -ink-as-dependency = [ ] +default = ["std"] +e2e-tests = [] +ink-as-dependency = [] std = [ - "ink/std", - "pop-api/std", + "ink/std", + "pop-api/std", ] diff --git a/pop-api/integration-tests/contracts/fungibles/Cargo.toml b/pop-api/integration-tests/contracts/fungibles/Cargo.toml index 0d0e80d5..c61a3650 100755 --- a/pop-api/integration-tests/contracts/fungibles/Cargo.toml +++ b/pop-api/integration-tests/contracts/fungibles/Cargo.toml @@ -1,21 +1,20 @@ [package] -authors = [ "[your_name] <[your_email]>" ] edition = "2021" name = "fungibles" version = "0.1.0" [dependencies] ink = { version = "5.0.0", default-features = false } -pop-api = { path = "../../../../pop-api", default-features = false, features = [ "fungibles" ] } +pop-api = { path = "../../../../pop-api", default-features = false, features = ["fungibles"] } [lib] path = "lib.rs" [features] -default = [ "std" ] -e2e-tests = [ ] -ink-as-dependency = [ ] +default = ["std"] +e2e-tests = [] +ink-as-dependency = [] std = [ - "ink/std", - "pop-api/std", + "ink/std", + "pop-api/std", ] diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index bfea0b45..18a63705 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,4 +1,4 @@ -use pop_primitives::{ArithmeticError::*, Error::*, TokenError::*, TokenId, *}; +use pop_primitives::{ArithmeticError::*, Error, Error::*, TokenError::*, TokenId}; use utils::*; use super::*; @@ -29,7 +29,7 @@ fn total_supply_works() { assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(0)); // Tokens in circulation. - create_asset_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); + pallet_assets_create_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); assert_eq!(total_supply(addr, TOKEN_ID), Ok(100)); }); @@ -46,7 +46,7 @@ fn balance_of_works() { assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(0)); // Tokens in circulation. - create_asset_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); + pallet_assets_create_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); assert_eq!(balance_of(addr, TOKEN_ID, BOB), Ok(100)); }); @@ -66,7 +66,7 @@ fn allowance_works() { assert_eq!(allowance(addr.clone(), TOKEN_ID, BOB, ALICE), Ok(0)); // Tokens in circulation. - create_asset_mint_and_approve(addr.clone(), TOKEN_ID, BOB, 100, ALICE, 50); + pallet_assets_create_mint_and_approve(addr.clone(), TOKEN_ID, BOB, 100, ALICE, 50); assert_eq!( allowance(addr.clone(), TOKEN_ID, BOB, ALICE), Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) @@ -82,41 +82,41 @@ fn transfer_works() { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; - // Asset does not exist. + // Token does not exist. assert_eq!( transfer(addr.clone(), 1, BOB, amount), Err(Module { index: 52, error: [3, 0] }) ); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); + // Create token with Alice as owner and mint `amount` to contract address. + let token = pallet_assets_create_and_mint_to(ALICE, 1, addr.clone(), amount); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(ALICE, token); assert_eq!( - transfer(addr.clone(), asset, BOB, amount), + transfer(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); - thaw_asset(ALICE, asset); + pallet_assets_thaw(ALICE, token); // Not enough balance. assert_eq!( - transfer(addr.clone(), asset, BOB, amount + 1 * UNIT), + transfer(addr.clone(), token, BOB, amount + 1 * UNIT), Err(Module { index: 52, error: [0, 0] }) ); // Not enough balance due to ED. assert_eq!( - transfer(addr.clone(), asset, BOB, amount), + transfer(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [0, 0] }) ); // Successful transfer. - let balance_before_transfer = Assets::balance(asset, &BOB); - assert_ok!(transfer(addr.clone(), asset, BOB, amount / 2)); - let balance_after_transfer = Assets::balance(asset, &BOB); + let balance_before_transfer = Assets::balance(token, &BOB); + assert_ok!(transfer(addr.clone(), token, BOB, amount / 2)); + let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); - // Transfer asset to account that does not exist. - assert_eq!(transfer(addr.clone(), asset, FERDIE, amount / 4), Err(Token(CannotCreate))); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(ALICE, asset); + // Transfer token to account that does not exist. + assert_eq!(transfer(addr.clone(), token, FERDIE, amount / 4), Err(Token(CannotCreate))); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(ALICE, token); assert_eq!( - transfer(addr.clone(), asset, BOB, amount / 4), + transfer(addr.clone(), token, BOB, amount / 4), Err(Module { index: 52, error: [16, 0] }) ); }); @@ -129,40 +129,40 @@ fn transfer_from_works() { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; - // Asset does not exist. + // Token does not exist. assert_eq!( transfer_from(addr.clone(), 1, ALICE, BOB, amount / 2), Err(Module { index: 52, error: [3, 0] }), ); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, ALICE, amount); + // Create token with Alice as owner and mint `amount` to contract address. + let token = pallet_assets_create_and_mint_to(ALICE, 1, ALICE, amount); // Unapproved transfer. assert_eq!( - transfer_from(addr.clone(), asset, ALICE, BOB, amount / 2), + transfer_from(addr.clone(), token, ALICE, BOB, amount / 2), Err(Module { index: 52, error: [10, 0] }) ); assert_ok!(Assets::approve_transfer( RuntimeOrigin::signed(ALICE.into()), - asset.into(), + token.into(), addr.clone().into(), amount + 1 * UNIT, )); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(ALICE, token); assert_eq!( - transfer_from(addr.clone(), asset, ALICE, BOB, amount), + transfer_from(addr.clone(), token, ALICE, BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); - thaw_asset(ALICE, asset); + pallet_assets_thaw(ALICE, token); // Not enough balance. assert_eq!( - transfer_from(addr.clone(), asset, ALICE, BOB, amount + 1 * UNIT), + transfer_from(addr.clone(), token, ALICE, BOB, amount + 1 * UNIT), Err(Module { index: 52, error: [0, 0] }), ); // Successful transfer. - let balance_before_transfer = Assets::balance(asset, &BOB); - assert_ok!(transfer_from(addr.clone(), asset, ALICE, BOB, amount / 2)); - let balance_after_transfer = Assets::balance(asset, &BOB); + let balance_before_transfer = Assets::balance(token, &BOB); + assert_ok!(transfer_from(addr.clone(), token, ALICE, BOB, amount / 2)); + let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); }); } @@ -174,31 +174,31 @@ fn approve_works() { let addr = instantiate(CONTRACT, 0, vec![]); let amount: Balance = 100 * UNIT; - // Asset does not exist. + // Token does not exist. assert_eq!(approve(addr.clone(), 0, BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount); - assert_eq!(approve(addr.clone(), asset, BOB, amount), Err(ConsumerRemaining)); + let token = pallet_assets_create_and_mint_to(ALICE, 0, addr.clone(), amount); + assert_eq!(approve(addr.clone(), token, BOB, amount), Err(ConsumerRemaining)); let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); + // Create token with Alice as owner and mint `amount` to contract address. + let token = pallet_assets_create_and_mint_to(ALICE, 1, addr.clone(), amount); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(ALICE, token); assert_eq!( - approve(addr.clone(), asset, BOB, amount), + approve(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); - thaw_asset(ALICE, asset); + pallet_assets_thaw(ALICE, token); // Successful approvals: - assert_eq!(0, Assets::allowance(asset, &addr, &BOB)); - assert_ok!(approve(addr.clone(), asset, BOB, amount)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount); + assert_eq!(0, Assets::allowance(token, &addr, &BOB)); + assert_ok!(approve(addr.clone(), token, BOB, amount)); + assert_eq!(Assets::allowance(token, &addr, &BOB), amount); // Non-additive, sets new value. - assert_ok!(approve(addr.clone(), asset, BOB, amount / 2)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount / 2); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(ALICE, asset); + assert_ok!(approve(addr.clone(), token, BOB, amount / 2)); + assert_eq!(Assets::allowance(token, &addr, &BOB), amount / 2); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(ALICE, token); assert_eq!( - approve(addr.clone(), asset, BOB, amount), + approve(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); }); @@ -211,36 +211,36 @@ fn increase_allowance_works() { let amount: Balance = 100 * UNIT; // Instantiate a contract without balance - test `ConsumerRemaining. let addr = instantiate(CONTRACT, 0, vec![]); - // Asset does not exist. + // Token does not exist. assert_eq!( increase_allowance(addr.clone(), 0, BOB, amount), Err(Module { index: 52, error: [3, 0] }) ); - let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount); - assert_eq!(increase_allowance(addr.clone(), asset, BOB, amount), Err(ConsumerRemaining)); + let token = pallet_assets_create_and_mint_to(ALICE, 0, addr.clone(), amount); + assert_eq!(increase_allowance(addr.clone(), token, BOB, amount), Err(ConsumerRemaining)); // Instantiate a contract with balance. let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); + // Create token with Alice as owner and mint `amount` to contract address. + let token = pallet_assets_create_and_mint_to(ALICE, 1, addr.clone(), amount); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(ALICE, token); assert_eq!( - increase_allowance(addr.clone(), asset, BOB, amount), + increase_allowance(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); - thaw_asset(ALICE, asset); + pallet_assets_thaw(ALICE, token); // Successful approvals: - assert_eq!(0, Assets::allowance(asset, &addr, &BOB)); - assert_ok!(increase_allowance(addr.clone(), asset, BOB, amount)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount); + assert_eq!(0, Assets::allowance(token, &addr, &BOB)); + assert_ok!(increase_allowance(addr.clone(), token, BOB, amount)); + assert_eq!(Assets::allowance(token, &addr, &BOB), amount); // Additive. - assert_ok!(increase_allowance(addr.clone(), asset, BOB, amount)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount * 2); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(ALICE, asset); + assert_ok!(increase_allowance(addr.clone(), token, BOB, amount)); + assert_eq!(Assets::allowance(token, &addr, &BOB), amount * 2); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(ALICE, token); assert_eq!( - increase_allowance(addr.clone(), asset, BOB, amount), + increase_allowance(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); }); @@ -253,30 +253,36 @@ fn decrease_allowance_works() { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; - // Asset does not exist. + // Token does not exist. assert_eq!( decrease_allowance(addr.clone(), 0, BOB, amount), Err(Module { index: 52, error: [3, 0] }), ); - // Create asset and mint `amount` to contract address, then approve Bob to spend `amount`. - let asset = - create_asset_mint_and_approve(addr.clone(), 0, addr.clone(), amount, BOB, amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); + // Create token and mint `amount` to contract address, then approve Bob to spend `amount`. + let token = pallet_assets_create_mint_and_approve( + addr.clone(), + 0, + addr.clone(), + amount, + BOB, + amount, + ); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(addr.clone(), token); assert_eq!( - decrease_allowance(addr.clone(), asset, BOB, amount), + decrease_allowance(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); - thaw_asset(addr.clone(), asset); + pallet_assets_thaw(addr.clone(), token); // Successfully decrease allowance. - let allowance_before = Assets::allowance(asset, &addr, &BOB); + let allowance_before = Assets::allowance(token, &addr, &BOB); assert_ok!(decrease_allowance(addr.clone(), 0, BOB, amount / 2 - 1 * UNIT)); - let allowance_after = Assets::allowance(asset, &addr, &BOB); + let allowance_after = Assets::allowance(token, &addr, &BOB); assert_eq!(allowance_before - allowance_after, amount / 2 - 1 * UNIT); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(addr.clone(), token); assert_eq!( - decrease_allowance(addr.clone(), asset, BOB, amount), + decrease_allowance(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); }); @@ -297,30 +303,36 @@ fn token_metadata_works() { let decimals: u8 = 69; // Token does not exist. - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(token_name_asset(TOKEN_ID))); + assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(Vec::::new())); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(token_symbol_asset(TOKEN_ID))); + assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(Vec::::new())); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(token_decimals_asset(TOKEN_ID))); + assert_eq!( + token_decimals(addr.clone(), TOKEN_ID), + Ok(pallet_assets_token_decimals(TOKEN_ID)) + ); assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(0)); // Create Token. - create_asset_and_set_metadata( + pallet_assets_create_and_set_metadata( addr.clone(), TOKEN_ID, name.clone(), symbol.clone(), decimals, ); - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(token_name_asset(TOKEN_ID))); + assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(name)); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(token_symbol_asset(TOKEN_ID))); + assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(symbol)); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(token_decimals_asset(TOKEN_ID))); + assert_eq!( + token_decimals(addr.clone(), TOKEN_ID), + Ok(pallet_assets_token_decimals(TOKEN_ID)) + ); assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(decimals)); }); } -/// 3. Asset Management: +/// 3. Management: /// - create /// - start_destroy /// - set_metadata @@ -353,14 +365,14 @@ fn create_works() { create(addr.clone(), TOKEN_ID, BOB, 0), Err(Module { index: 52, error: [7, 0] }), ); - // The minimal balance for an asset must be non zero. + // The minimal balance for an token must be non zero. assert_eq!( create(addr.clone(), TOKEN_ID, BOB, 0), Err(Module { index: 52, error: [7, 0] }), ); - // Create asset successfully. + // Create token successfully. assert_ok!(create(addr.clone(), TOKEN_ID, BOB, 1)); - // Asset ID is already taken. + // Token ID is already taken. assert_eq!( create(addr.clone(), TOKEN_ID, BOB, 1), Err(Module { index: 52, error: [5, 0] }), @@ -368,20 +380,20 @@ fn create_works() { }); } -// Testing a contract that creates an asset in the constructor. +// Testing a contract that creates an token in the constructor. #[test] fn instantiate_and_create_fungible_works() { new_test_ext().execute_with(|| { let _ = env_logger::try_init(); let contract = "contracts/create_token_in_constructor/target/ink/create_token_in_constructor.wasm"; - // Asset already exists. - create_asset(ALICE, 0, 1); + // Token already exists. + pallet_assets_create(ALICE, 0, 1); assert_eq!( instantiate_and_create_fungible(contract, 0, 1), Err(Module { index: 52, error: [5, 0] }) ); - // Successfully create an asset when instantiating the contract. + // Successfully create an token when instantiating the contract. assert_ok!(instantiate_and_create_fungible(contract, TOKEN_ID, 1)); assert!(Assets::asset_exists(TOKEN_ID)); }); @@ -393,14 +405,14 @@ fn start_destroy_works() { let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); - // Asset does not exist. + // Token does not exist. assert_eq!(start_destroy(addr.clone(), TOKEN_ID), Err(Module { index: 52, error: [3, 0] }),); - // Create assets where contract is not the owner. - let asset = create_asset(ALICE, 0, 1); + // Create tokens where contract is not the owner. + let token = pallet_assets_create(ALICE, 0, 1); // No Permission. - assert_eq!(start_destroy(addr.clone(), asset), Err(Module { index: 52, error: [2, 0] }),); - let asset = create_asset(addr.clone(), TOKEN_ID, 1); - assert_ok!(start_destroy(addr.clone(), asset)); + assert_eq!(start_destroy(addr.clone(), token), Err(Module { index: 52, error: [2, 0] }),); + let token = pallet_assets_create(addr.clone(), TOKEN_ID, 1); + assert_ok!(start_destroy(addr.clone(), token)); }); } @@ -413,26 +425,26 @@ fn set_metadata_works() { let decimals = 42u8; let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - // Asset does not exist. + // Token does not exist. assert_eq!( set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [3, 0] }), ); - // Create assets where contract is not the owner. - let asset = create_asset(ALICE, 0, 1); + // Create token where contract is not the owner. + let token = pallet_assets_create(ALICE, 0, 1); // No Permission. assert_eq!( - set_metadata(addr.clone(), asset, vec![0], vec![0], 0u8), + set_metadata(addr.clone(), token, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [2, 0] }), ); - let asset = create_asset(addr.clone(), TOKEN_ID, 1); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); + let token = pallet_assets_create(addr.clone(), TOKEN_ID, 1); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(addr.clone(), token); assert_eq!( set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [16, 0] }), ); - thaw_asset(addr.clone(), asset); + pallet_assets_thaw(addr.clone(), token); // TODO: calling the below with a vector of length `100_000` errors in pallet contracts // `OutputBufferTooSmall. Added to security analysis issue #131 to revisit. // Set bad metadata - too large values. @@ -442,8 +454,8 @@ fn set_metadata_works() { ); // Set metadata successfully. assert_ok!(set_metadata(addr.clone(), TOKEN_ID, name, symbol, decimals)); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(addr.clone(), token); assert_eq!( set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0), Err(Module { index: 52, error: [16, 0] }), @@ -460,24 +472,24 @@ fn clear_metadata_works() { let decimals = 42u8; let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - // Asset does not exist. + // Token does not exist. assert_eq!(clear_metadata(addr.clone(), 0), Err(Module { index: 52, error: [3, 0] }),); - // Create assets where contract is not the owner. - let asset = create_asset_and_set_metadata(ALICE, 0, vec![0], vec![0], 0); + // Create token where contract is not the owner. + let token = pallet_assets_create_and_set_metadata(ALICE, 0, vec![0], vec![0], 0); // No Permission. - assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [2, 0] }),); - let asset = create_asset(addr.clone(), TOKEN_ID, 1); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); - assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [16, 0] }),); - thaw_asset(addr.clone(), asset); + assert_eq!(clear_metadata(addr.clone(), token), Err(Module { index: 52, error: [2, 0] }),); + let token = pallet_assets_create(addr.clone(), TOKEN_ID, 1); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(addr.clone(), token); + assert_eq!(clear_metadata(addr.clone(), token), Err(Module { index: 52, error: [16, 0] }),); + pallet_assets_thaw(addr.clone(), token); // No metadata set. - assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [3, 0] }),); - set_metadata_asset(addr.clone(), asset, name, symbol, decimals); + assert_eq!(clear_metadata(addr.clone(), token), Err(Module { index: 52, error: [3, 0] }),); + pallet_assets_set_metadata(addr.clone(), token, name, symbol, decimals); // Clear metadata successfully. assert_ok!(clear_metadata(addr.clone(), TOKEN_ID)); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(addr.clone(), token); assert_eq!( set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], decimals), Err(Module { index: 52, error: [16, 0] }), @@ -495,7 +507,7 @@ fn token_exists_works() { assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); // Tokens in circulation. - create_asset(addr.clone(), TOKEN_ID, 1); + pallet_assets_create(addr.clone(), TOKEN_ID, 1); assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); }); } @@ -507,32 +519,32 @@ fn mint_works() { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; - // Asset does not exist. + // Token does not exist. assert_eq!(mint(addr.clone(), 1, BOB, amount), Err(Token(UnknownAsset))); - let asset = create_asset(ALICE, 1, 1); + let token = pallet_assets_create(ALICE, 1, 1); // Minting can only be done by the owner. - assert_eq!(mint(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let asset = create_asset(addr.clone(), 2, 2); - // Minimum balance of an asset can not be zero. - assert_eq!(mint(addr.clone(), asset, BOB, 1), Err(Token(BelowMinimum))); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); - assert_eq!( - mint(addr.clone(), asset, BOB, amount), + assert_eq!(mint(addr.clone(), token, BOB, 1), Err(Module { index: 52, error: [2, 0] })); + let token = pallet_assets_create(addr.clone(), 2, 2); + // Minimum balance of an token can not be zero. + assert_eq!(mint(addr.clone(), token, BOB, 1), Err(Token(BelowMinimum))); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(addr.clone(), token); + assert_eq!( + mint(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); - thaw_asset(addr.clone(), asset); + pallet_assets_thaw(addr.clone(), token); // Successful mint. - let balance_before_mint = Assets::balance(asset, &BOB); - assert_ok!(mint(addr.clone(), asset, BOB, amount)); - let balance_after_mint = Assets::balance(asset, &BOB); + let balance_before_mint = Assets::balance(token, &BOB); + assert_ok!(mint(addr.clone(), token, BOB, amount)); + let balance_after_mint = Assets::balance(token, &BOB); assert_eq!(balance_after_mint, balance_before_mint + amount); // Account can not hold more tokens than Balance::MAX. - assert_eq!(mint(addr.clone(), asset, BOB, Balance::MAX,), Err(Arithmetic(Overflow))); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); + assert_eq!(mint(addr.clone(), token, BOB, Balance::MAX,), Err(Arithmetic(Overflow))); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(addr.clone(), token); assert_eq!( - mint(addr.clone(), asset, BOB, amount), + mint(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); }); @@ -545,31 +557,31 @@ fn burn_works() { let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; - // Asset does not exist. + // Token does not exist. assert_eq!(burn(addr.clone(), 1, BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let asset = create_asset(ALICE, 1, 1); - // Bob has no tokens and thus pallet assets doesn't know the account. - assert_eq!(burn(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [1, 0] })); + let token = pallet_assets_create(ALICE, 1, 1); + // Bob has no tokens and therefore doesn't exist. + assert_eq!(burn(addr.clone(), token, BOB, 1), Err(Module { index: 52, error: [1, 0] })); // Burning can only be done by the manager. - mint_asset(ALICE, asset, BOB, amount); - assert_eq!(burn(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let asset = create_asset_and_mint_to(addr.clone(), 2, BOB, amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); + pallet_assets_mint(ALICE, token, BOB, amount); + assert_eq!(burn(addr.clone(), token, BOB, 1), Err(Module { index: 52, error: [2, 0] })); + let token = pallet_assets_create_and_mint_to(addr.clone(), 2, BOB, amount); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_freeze(addr.clone(), token); assert_eq!( - burn(addr.clone(), asset, BOB, amount), + burn(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); - thaw_asset(addr.clone(), asset); + pallet_assets_thaw(addr.clone(), token); // Successful mint. - let balance_before_burn = Assets::balance(asset, &BOB); - assert_ok!(burn(addr.clone(), asset, BOB, amount)); - let balance_after_burn = Assets::balance(asset, &BOB); + let balance_before_burn = Assets::balance(token, &BOB); + assert_ok!(burn(addr.clone(), token, BOB, amount)); + let balance_after_burn = Assets::balance(token, &BOB); assert_eq!(balance_after_burn, balance_before_burn - amount); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); + // Token is not live, i.e. frozen or being destroyed. + pallet_assets_start_destroy(addr.clone(), token); assert_eq!( - burn(addr.clone(), asset, BOB, amount), + burn(addr.clone(), token, BOB, amount), Err(Module { index: 52, error: [17, 0] }) ); }); diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 35761673..18ebf6e7 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -1,27 +1,30 @@ use super::*; +type AssetId = TokenId; + fn do_bare_call(function: &str, addr: AccountId32, params: Vec) -> ExecReturnValue { let function = function_selector(function); let params = [function, params].concat(); bare_call(addr, params, 0).expect("should work") } +// TODO - issue #263 - why result.data[1..] pub(super) fn decoded(result: ExecReturnValue) -> Result { ::decode(&mut &result.data[1..]).map_err(|_| result) } -pub(super) fn total_supply(addr: AccountId32, asset_id: AssetId) -> Result { - let result = do_bare_call("total_supply", addr, asset_id.encode()); +pub(super) fn total_supply(addr: AccountId32, token_id: TokenId) -> Result { + let result = do_bare_call("total_supply", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } pub(super) fn balance_of( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, owner: AccountId32, ) -> Result { - let params = [asset_id.encode(), owner.encode()].concat(); + let params = [token_id.encode(), owner.encode()].concat(); let result = do_bare_call("balance_of", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -29,47 +32,47 @@ pub(super) fn balance_of( pub(super) fn allowance( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, owner: AccountId32, spender: AccountId32, ) -> Result { - let params = [asset_id.encode(), owner.encode(), spender.encode()].concat(); + let params = [token_id.encode(), owner.encode(), spender.encode()].concat(); let result = do_bare_call("allowance", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_name(addr: AccountId32, asset_id: AssetId) -> Result, Error> { - let result = do_bare_call("token_name", addr, asset_id.encode()); +pub(super) fn token_name(addr: AccountId32, token_id: TokenId) -> Result, Error> { + let result = do_bare_call("token_name", addr, token_id.encode()); decoded::, Error>>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_symbol(addr: AccountId32, asset_id: AssetId) -> Result, Error> { - let result = do_bare_call("token_symbol", addr, asset_id.encode()); +pub(super) fn token_symbol(addr: AccountId32, token_id: TokenId) -> Result, Error> { + let result = do_bare_call("token_symbol", addr, token_id.encode()); decoded::, Error>>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_decimals(addr: AccountId32, asset_id: AssetId) -> Result { - let result = do_bare_call("token_decimals", addr, asset_id.encode()); +pub(super) fn token_decimals(addr: AccountId32, token_id: TokenId) -> Result { + let result = do_bare_call("token_decimals", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_exists(addr: AccountId32, asset_id: AssetId) -> Result { - let result = do_bare_call("token_exists", addr, asset_id.encode()); +pub(super) fn token_exists(addr: AccountId32, token_id: TokenId) -> Result { + let result = do_bare_call("token_exists", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } pub(super) fn transfer( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, to: AccountId32, value: Balance, ) -> Result<(), Error> { - let params = [asset_id.encode(), to.encode(), value.encode()].concat(); + let params = [token_id.encode(), to.encode(), value.encode()].concat(); let result = do_bare_call("transfer", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -77,14 +80,14 @@ pub(super) fn transfer( pub(super) fn transfer_from( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, from: AccountId32, to: AccountId32, value: Balance, ) -> Result<(), Error> { let data: Vec = vec![]; let params = - [asset_id.encode(), from.encode(), to.encode(), value.encode(), data.encode()].concat(); + [token_id.encode(), from.encode(), to.encode(), value.encode(), data.encode()].concat(); let result = do_bare_call("transfer_from", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -92,11 +95,11 @@ pub(super) fn transfer_from( pub(super) fn approve( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, spender: AccountId32, value: Balance, ) -> Result<(), Error> { - let params = [asset_id.encode(), spender.encode(), value.encode()].concat(); + let params = [token_id.encode(), spender.encode(), value.encode()].concat(); let result = do_bare_call("approve", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -104,11 +107,11 @@ pub(super) fn approve( pub(super) fn increase_allowance( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, spender: AccountId32, value: Balance, ) -> Result<(), Error> { - let params = [asset_id.encode(), spender.encode(), value.encode()].concat(); + let params = [token_id.encode(), spender.encode(), value.encode()].concat(); let result = do_bare_call("increase_allowance", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -116,11 +119,11 @@ pub(super) fn increase_allowance( pub(super) fn decrease_allowance( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, spender: AccountId32, value: Balance, ) -> Result<(), Error> { - let params = [asset_id.encode(), spender.encode(), value.encode()].concat(); + let params = [token_id.encode(), spender.encode(), value.encode()].concat(); let result = do_bare_call("decrease_allowance", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -128,18 +131,18 @@ pub(super) fn decrease_allowance( pub(super) fn create( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, admin: AccountId32, min_balance: Balance, ) -> Result<(), Error> { - let params = [asset_id.encode(), admin.encode(), min_balance.encode()].concat(); + let params = [token_id.encode(), admin.encode(), min_balance.encode()].concat(); let result = do_bare_call("create", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn start_destroy(addr: AccountId32, asset_id: AssetId) -> Result<(), Error> { - let result = do_bare_call("start_destroy", addr, asset_id.encode()); +pub(super) fn start_destroy(addr: AccountId32, token_id: TokenId) -> Result<(), Error> { + let result = do_bare_call("start_destroy", addr, token_id.encode()); match decoded::>(result) { Ok(x) => x, Err(result) => panic!("Contract reverted: {:?}", result), @@ -148,30 +151,30 @@ pub(super) fn start_destroy(addr: AccountId32, asset_id: AssetId) -> Result<(), pub(super) fn set_metadata( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, name: Vec, symbol: Vec, decimals: u8, ) -> Result<(), Error> { - let params = [asset_id.encode(), name.encode(), symbol.encode(), decimals.encode()].concat(); + let params = [token_id.encode(), name.encode(), symbol.encode(), decimals.encode()].concat(); let result = do_bare_call("set_metadata", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn clear_metadata(addr: AccountId32, asset_id: AssetId) -> Result<(), Error> { - let result = do_bare_call("clear_metadata", addr, asset_id.encode()); +pub(super) fn clear_metadata(addr: AccountId32, token_id: TokenId) -> Result<(), Error> { + let result = do_bare_call("clear_metadata", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } pub(super) fn mint( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, account: AccountId32, amount: Balance, ) -> Result<(), Error> { - let params = [asset_id.encode(), account.encode(), amount.encode()].concat(); + let params = [token_id.encode(), account.encode(), amount.encode()].concat(); let result = do_bare_call("mint", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) @@ -179,17 +182,21 @@ pub(super) fn mint( pub(super) fn burn( addr: AccountId32, - asset_id: AssetId, + token_id: TokenId, account: AccountId32, amount: Balance, ) -> Result<(), Error> { - let params = [asset_id.encode(), account.encode(), amount.encode()].concat(); + let params = [token_id.encode(), account.encode(), amount.encode()].concat(); let result = do_bare_call("burn", addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn create_asset(owner: AccountId32, asset_id: AssetId, min_balance: Balance) -> AssetId { +pub(super) fn pallet_assets_create( + owner: AccountId32, + asset_id: AssetId, + min_balance: Balance, +) -> AssetId { assert_ok!(Assets::create( RuntimeOrigin::signed(owner.clone()), asset_id.into(), @@ -199,7 +206,7 @@ pub(super) fn create_asset(owner: AccountId32, asset_id: AssetId, min_balance: B asset_id } -pub(super) fn mint_asset( +pub(super) fn pallet_assets_mint( owner: AccountId32, asset_id: AssetId, to: AccountId32, @@ -214,18 +221,18 @@ pub(super) fn mint_asset( asset_id } -pub(super) fn create_asset_and_mint_to( +pub(super) fn pallet_assets_create_and_mint_to( owner: AccountId32, asset_id: AssetId, to: AccountId32, value: Balance, ) -> AssetId { - create_asset(owner.clone(), asset_id, 1); - mint_asset(owner, asset_id, to, value) + pallet_assets_create(owner.clone(), asset_id, 1); + pallet_assets_mint(owner, asset_id, to, value) } // Create an asset, mints to, and approves spender. -pub(super) fn create_asset_mint_and_approve( +pub(super) fn pallet_assets_create_mint_and_approve( owner: AccountId32, asset_id: AssetId, to: AccountId32, @@ -233,7 +240,7 @@ pub(super) fn create_asset_mint_and_approve( spender: AccountId32, approve: Balance, ) -> AssetId { - create_asset_and_mint_to(owner.clone(), asset_id, to.clone(), mint); + pallet_assets_create_and_mint_to(owner.clone(), asset_id, to.clone(), mint); assert_ok!(Assets::approve_transfer( RuntimeOrigin::signed(to.into()), asset_id.into(), @@ -244,22 +251,22 @@ pub(super) fn create_asset_mint_and_approve( } // Freeze an asset. -pub(super) fn freeze_asset(owner: AccountId32, asset_id: AssetId) { +pub(super) fn pallet_assets_freeze(owner: AccountId32, asset_id: AssetId) { assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(owner.into()), asset_id.into())); } // Thaw an asset. -pub(super) fn thaw_asset(owner: AccountId32, asset_id: AssetId) { +pub(super) fn pallet_assets_thaw(owner: AccountId32, asset_id: AssetId) { assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(owner.into()), asset_id.into())); } // Start destroying an asset. -pub(super) fn start_destroy_asset(owner: AccountId32, asset_id: AssetId) { +pub(super) fn pallet_assets_start_destroy(owner: AccountId32, asset_id: AssetId) { assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(owner.into()), asset_id.into())); } // Create an asset and set metadata. -pub(super) fn create_asset_and_set_metadata( +pub(super) fn pallet_assets_create_and_set_metadata( owner: AccountId32, asset_id: AssetId, name: Vec, @@ -272,12 +279,12 @@ pub(super) fn create_asset_and_set_metadata( owner.clone().into(), 100 )); - set_metadata_asset(owner, asset_id, name, symbol, decimals); + pallet_assets_set_metadata(owner, asset_id, name, symbol, decimals); asset_id } // Set metadata of an asset. -pub(super) fn set_metadata_asset( +pub(super) fn pallet_assets_set_metadata( owner: AccountId32, asset_id: AssetId, name: Vec, @@ -293,33 +300,32 @@ pub(super) fn set_metadata_asset( )); } -pub(super) fn token_name_asset(asset_id: AssetId) -> Vec { +pub(super) fn pallet_assets_token_name(asset_id: AssetId) -> Vec { as MetadataInspect>::name( - asset_id, - ) + asset_id, + ) } -pub(super) fn token_symbol_asset(asset_id: AssetId) -> Vec { +pub(super) fn pallet_assets_token_symbol(asset_id: AssetId) -> Vec { as MetadataInspect>::symbol( - asset_id, - ) + asset_id, + ) } -pub(super) fn token_decimals_asset(asset_id: AssetId) -> u8 { +pub(super) fn pallet_assets_token_decimals(asset_id: AssetId) -> u8 { as MetadataInspect>::decimals( - asset_id, - ) + asset_id, + ) } pub(super) fn instantiate_and_create_fungible( contract: &str, - asset_id: AssetId, + token_id: TokenId, min_balance: Balance, ) -> Result<(), Error> { let function = function_selector("new"); - let input = [function, asset_id.encode(), min_balance.encode()].concat(); - let (wasm_binary, _) = - load_wasm_module::(contract).expect("could not read .wasm file"); + let input = [function, token_id.encode(), min_balance.encode()].concat(); + let wasm_binary = load_wasm_module::(contract).expect("could not read .wasm file"); let result = Contracts::bare_instantiate( ALICE, INIT_VALUE, diff --git a/pop-api/integration-tests/src/lib.rs b/pop-api/integration-tests/src/lib.rs index 6499df59..946e0a70 100644 --- a/pop-api/integration-tests/src/lib.rs +++ b/pop-api/integration-tests/src/lib.rs @@ -8,23 +8,20 @@ use frame_support::{ weights::Weight, }; use pallet_contracts::{Code, CollectEvents, Determinism, ExecReturnValue}; -use scale::{Decode, Encode}; -use sp_runtime::{traits::Hash, AccountId32, BuildStorage, DispatchError}; - use pop_runtime_devnet::{ config::assets::TrustBackedAssetsInstance, Assets, Contracts, Runtime, RuntimeOrigin, System, UNIT, }; +use scale::{Decode, Encode}; +use sp_runtime::{AccountId32, BuildStorage, DispatchError}; mod fungibles; -type AssetId = u32; type Balance = u128; const ALICE: AccountId32 = AccountId32::new([1_u8; 32]); const BOB: AccountId32 = AccountId32::new([2_u8; 32]); const DEBUG_OUTPUT: pallet_contracts::DebugInfo = pallet_contracts::DebugInfo::UnsafeDebug; -// FERDIE has no initial balance. const FERDIE: AccountId32 = AccountId32::new([3_u8; 32]); const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024); const INIT_AMOUNT: Balance = 100_000_000 * UNIT; @@ -36,6 +33,7 @@ fn new_test_ext() -> sp_io::TestExternalities { .expect("Frame system builds valid default genesis config"); pallet_balances::GenesisConfig:: { + // FERDIE has no initial balance. balances: vec![(ALICE, INIT_AMOUNT), (BOB, INIT_AMOUNT)], } .assimilate_storage(&mut t) @@ -46,13 +44,12 @@ fn new_test_ext() -> sp_io::TestExternalities { ext } -fn load_wasm_module(path: &str) -> std::io::Result<(Vec, ::Output)> +fn load_wasm_module(path: &str) -> std::io::Result> where T: frame_system::Config, { let wasm_binary = std::fs::read(path)?; - let code_hash = T::Hashing::hash(&wasm_binary); - Ok((wasm_binary, code_hash)) + Ok(wasm_binary) } fn function_selector(name: &str) -> Vec { @@ -82,8 +79,7 @@ fn bare_call( // Deploy, instantiate and return contract address. fn instantiate(contract: &str, init_value: u128, salt: Vec) -> AccountId32 { - let (wasm_binary, _) = - load_wasm_module::(contract).expect("could not read .wasm file"); + let wasm_binary = load_wasm_module::(contract).expect("could not read .wasm file"); let result = Contracts::bare_instantiate( ALICE, init_value, @@ -99,4 +95,4 @@ fn instantiate(contract: &str, init_value: u128, salt: Vec) -> AccountId32 { .unwrap(); assert!(!result.result.did_revert(), "deploying contract reverted {:?}", result); result.account_id -} \ No newline at end of file +} From 9320d26d1d89ed9c35ea57518ba3799efde7596a Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Wed, 11 Sep 2024 17:28:40 +0200 Subject: [PATCH 07/29] taplo fmt --- .../contracts/create_token_in_constructor/Cargo.toml | 12 ++++++------ .../integration-tests/contracts/fungibles/Cargo.toml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml b/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml index e5f80cdf..a1517cdd 100755 --- a/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml +++ b/pop-api/integration-tests/contracts/create_token_in_constructor/Cargo.toml @@ -5,16 +5,16 @@ version = "0.1.0" [dependencies] ink = { version = "5.0.0", default-features = false } -pop-api = { path = "../../..", default-features = false, features = ["fungibles"] } +pop-api = { path = "../../..", default-features = false, features = [ "fungibles" ] } [lib] path = "lib.rs" [features] -default = ["std"] -e2e-tests = [] -ink-as-dependency = [] +default = [ "std" ] +e2e-tests = [ ] +ink-as-dependency = [ ] std = [ - "ink/std", - "pop-api/std", + "ink/std", + "pop-api/std", ] diff --git a/pop-api/integration-tests/contracts/fungibles/Cargo.toml b/pop-api/integration-tests/contracts/fungibles/Cargo.toml index c61a3650..dce9b257 100755 --- a/pop-api/integration-tests/contracts/fungibles/Cargo.toml +++ b/pop-api/integration-tests/contracts/fungibles/Cargo.toml @@ -5,16 +5,16 @@ version = "0.1.0" [dependencies] ink = { version = "5.0.0", default-features = false } -pop-api = { path = "../../../../pop-api", default-features = false, features = ["fungibles"] } +pop-api = { path = "../../../../pop-api", default-features = false, features = [ "fungibles" ] } [lib] path = "lib.rs" [features] -default = ["std"] -e2e-tests = [] -ink-as-dependency = [] +default = [ "std" ] +e2e-tests = [ ] +ink-as-dependency = [ ] std = [ - "ink/std", - "pop-api/std", + "ink/std", + "pop-api/std", ] From 4383ae085c230ea7d1dff8bc7ba71db9bb0c354b Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Wed, 11 Sep 2024 18:28:30 +0200 Subject: [PATCH 08/29] refactor: remove clone --- .../integration-tests/src/fungibles/mod.rs | 351 +++++++----------- .../integration-tests/src/fungibles/utils.rs | 102 ++--- pop-api/integration-tests/src/lib.rs | 2 + 3 files changed, 192 insertions(+), 263 deletions(-) diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 18a63705..3345729f 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -21,102 +21,89 @@ const CONTRACT: &str = "contracts/fungibles/target/ink/fungibles.wasm"; #[test] fn total_supply_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); // No tokens in circulation. - assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); - assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(0)); + assert_eq!(total_supply(&addr, TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); + assert_eq!(total_supply(&addr, TOKEN_ID), Ok(0)); // Tokens in circulation. - pallet_assets_create_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); - assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); - assert_eq!(total_supply(addr, TOKEN_ID), Ok(100)); + pallet_assets_create_and_mint_to(&addr, TOKEN_ID, &BOB, 100); + assert_eq!(total_supply(&addr, TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); + assert_eq!(total_supply(&addr, TOKEN_ID), Ok(100)); }); } #[test] fn balance_of_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); // No tokens in circulation. - assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); - assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(0)); + assert_eq!(balance_of(&addr, TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); + assert_eq!(balance_of(&addr, TOKEN_ID, BOB), Ok(0)); // Tokens in circulation. - pallet_assets_create_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); - assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); - assert_eq!(balance_of(addr, TOKEN_ID, BOB), Ok(100)); + pallet_assets_create_and_mint_to(&addr, TOKEN_ID, &BOB, 100); + assert_eq!(balance_of(&addr, TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); + assert_eq!(balance_of(&addr, TOKEN_ID, BOB), Ok(100)); }); } #[test] fn allowance_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); // No tokens in circulation. assert_eq!( - allowance(addr.clone(), TOKEN_ID, BOB, ALICE), + allowance(&addr, TOKEN_ID, BOB, ALICE), Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) ); - assert_eq!(allowance(addr.clone(), TOKEN_ID, BOB, ALICE), Ok(0)); + assert_eq!(allowance(&addr, TOKEN_ID, BOB, ALICE), Ok(0)); // Tokens in circulation. - pallet_assets_create_mint_and_approve(addr.clone(), TOKEN_ID, BOB, 100, ALICE, 50); + pallet_assets_create_mint_and_approve(&addr, TOKEN_ID, &BOB, 100, &ALICE, 50); assert_eq!( - allowance(addr.clone(), TOKEN_ID, BOB, ALICE), + allowance(&addr, TOKEN_ID, BOB, ALICE), Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) ); - assert_eq!(allowance(addr, TOKEN_ID, BOB, ALICE), Ok(50)); + assert_eq!(allowance(&addr, TOKEN_ID, BOB, ALICE), Ok(50)); }); } #[test] fn transfer_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; // Token does not exist. - assert_eq!( - transfer(addr.clone(), 1, BOB, amount), - Err(Module { index: 52, error: [3, 0] }) - ); + assert_eq!(transfer(&addr, 1, BOB, amount), Err(Module { index: 52, error: [3, 0] })); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(ALICE, 1, addr.clone(), amount); + let token = pallet_assets_create_and_mint_to(&ALICE, 1, &addr, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(ALICE, token); - assert_eq!( - transfer(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - pallet_assets_thaw(ALICE, token); + pallet_assets_freeze(&ALICE, token); + assert_eq!(transfer(&addr, token, BOB, amount), Err(Module { index: 52, error: [16, 0] })); + pallet_assets_thaw(&ALICE, token); // Not enough balance. assert_eq!( - transfer(addr.clone(), token, BOB, amount + 1 * UNIT), + transfer(&addr, token, BOB, amount + 1 * UNIT), Err(Module { index: 52, error: [0, 0] }) ); // Not enough balance due to ED. - assert_eq!( - transfer(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [0, 0] }) - ); + assert_eq!(transfer(&addr, token, BOB, amount), Err(Module { index: 52, error: [0, 0] })); // Successful transfer. let balance_before_transfer = Assets::balance(token, &BOB); - assert_ok!(transfer(addr.clone(), token, BOB, amount / 2)); + assert_ok!(transfer(&addr, token, BOB, amount / 2)); let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); // Transfer token to account that does not exist. - assert_eq!(transfer(addr.clone(), token, FERDIE, amount / 4), Err(Token(CannotCreate))); + assert_eq!(transfer(&addr, token, FERDIE, amount / 4), Err(Token(CannotCreate))); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(ALICE, token); + pallet_assets_start_destroy(&ALICE, token); assert_eq!( - transfer(addr.clone(), token, BOB, amount / 4), + transfer(&addr, token, BOB, amount / 4), Err(Module { index: 52, error: [16, 0] }) ); }); @@ -125,20 +112,19 @@ fn transfer_works() { #[test] fn transfer_from_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; // Token does not exist. assert_eq!( - transfer_from(addr.clone(), 1, ALICE, BOB, amount / 2), + transfer_from(&addr, 1, ALICE, BOB, amount / 2), Err(Module { index: 52, error: [3, 0] }), ); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(ALICE, 1, ALICE, amount); + let token = pallet_assets_create_and_mint_to(&ALICE, 1, &ALICE, amount); // Unapproved transfer. assert_eq!( - transfer_from(addr.clone(), token, ALICE, BOB, amount / 2), + transfer_from(&addr, token, ALICE, BOB, amount / 2), Err(Module { index: 52, error: [10, 0] }) ); assert_ok!(Assets::approve_transfer( @@ -148,20 +134,20 @@ fn transfer_from_works() { amount + 1 * UNIT, )); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(ALICE, token); + pallet_assets_freeze(&ALICE, token); assert_eq!( - transfer_from(addr.clone(), token, ALICE, BOB, amount), + transfer_from(&addr, token, ALICE, BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); - pallet_assets_thaw(ALICE, token); + pallet_assets_thaw(&ALICE, token); // Not enough balance. assert_eq!( - transfer_from(addr.clone(), token, ALICE, BOB, amount + 1 * UNIT), + transfer_from(&addr, token, ALICE, BOB, amount + 1 * UNIT), Err(Module { index: 52, error: [0, 0] }), ); // Successful transfer. let balance_before_transfer = Assets::balance(token, &BOB); - assert_ok!(transfer_from(addr.clone(), token, ALICE, BOB, amount / 2)); + assert_ok!(transfer_from(&addr, token, ALICE, BOB, amount / 2)); let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); }); @@ -170,77 +156,69 @@ fn transfer_from_works() { #[test] fn approve_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, 0, vec![]); let amount: Balance = 100 * UNIT; // Token does not exist. - assert_eq!(approve(addr.clone(), 0, BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let token = pallet_assets_create_and_mint_to(ALICE, 0, addr.clone(), amount); - assert_eq!(approve(addr.clone(), token, BOB, amount), Err(ConsumerRemaining)); + assert_eq!(approve(&addr, 0, &BOB, amount), Err(Module { index: 52, error: [3, 0] })); + let token = pallet_assets_create_and_mint_to(&ALICE, 0, &addr, amount); + assert_eq!(approve(&addr, token, &BOB, amount), Err(ConsumerRemaining)); let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(ALICE, 1, addr.clone(), amount); + let token = pallet_assets_create_and_mint_to(&ALICE, 1, &addr, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(ALICE, token); - assert_eq!( - approve(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - pallet_assets_thaw(ALICE, token); + pallet_assets_freeze(&ALICE, token); + assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); + pallet_assets_thaw(&ALICE, token); // Successful approvals: assert_eq!(0, Assets::allowance(token, &addr, &BOB)); - assert_ok!(approve(addr.clone(), token, BOB, amount)); + assert_ok!(approve(&addr, token, &BOB, amount)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount); // Non-additive, sets new value. - assert_ok!(approve(addr.clone(), token, BOB, amount / 2)); + assert_ok!(approve(&addr, token, &BOB, amount / 2)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount / 2); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(ALICE, token); - assert_eq!( - approve(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); + pallet_assets_start_destroy(&ALICE, token); + assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); }); } #[test] fn increase_allowance_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let amount: Balance = 100 * UNIT; // Instantiate a contract without balance - test `ConsumerRemaining. let addr = instantiate(CONTRACT, 0, vec![]); // Token does not exist. assert_eq!( - increase_allowance(addr.clone(), 0, BOB, amount), + increase_allowance(&addr, 0, &BOB, amount), Err(Module { index: 52, error: [3, 0] }) ); - let token = pallet_assets_create_and_mint_to(ALICE, 0, addr.clone(), amount); - assert_eq!(increase_allowance(addr.clone(), token, BOB, amount), Err(ConsumerRemaining)); + let token = pallet_assets_create_and_mint_to(&ALICE, 0, &addr, amount); + assert_eq!(increase_allowance(&addr, token, &BOB, amount), Err(ConsumerRemaining)); // Instantiate a contract with balance. let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(ALICE, 1, addr.clone(), amount); + let token = pallet_assets_create_and_mint_to(&ALICE, 1, &addr, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(ALICE, token); + pallet_assets_freeze(&ALICE, token); assert_eq!( - increase_allowance(addr.clone(), token, BOB, amount), + increase_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); - pallet_assets_thaw(ALICE, token); + pallet_assets_thaw(&ALICE, token); // Successful approvals: assert_eq!(0, Assets::allowance(token, &addr, &BOB)); - assert_ok!(increase_allowance(addr.clone(), token, BOB, amount)); + assert_ok!(increase_allowance(&addr, token, &BOB, amount)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount); // Additive. - assert_ok!(increase_allowance(addr.clone(), token, BOB, amount)); + assert_ok!(increase_allowance(&addr, token, &BOB, amount)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount * 2); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(ALICE, token); + pallet_assets_start_destroy(&ALICE, token); assert_eq!( - increase_allowance(addr.clone(), token, BOB, amount), + increase_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); }); @@ -249,40 +227,32 @@ fn increase_allowance_works() { #[test] fn decrease_allowance_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; // Token does not exist. assert_eq!( - decrease_allowance(addr.clone(), 0, BOB, amount), + decrease_allowance(&addr, 0, &BOB, amount), Err(Module { index: 52, error: [3, 0] }), ); // Create token and mint `amount` to contract address, then approve Bob to spend `amount`. - let token = pallet_assets_create_mint_and_approve( - addr.clone(), - 0, - addr.clone(), - amount, - BOB, - amount, - ); + let token = pallet_assets_create_mint_and_approve(&addr, 0, &addr, amount, &BOB, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(addr.clone(), token); + pallet_assets_freeze(&addr, token); assert_eq!( - decrease_allowance(addr.clone(), token, BOB, amount), + decrease_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); - pallet_assets_thaw(addr.clone(), token); + pallet_assets_thaw(&addr, token); // Successfully decrease allowance. let allowance_before = Assets::allowance(token, &addr, &BOB); - assert_ok!(decrease_allowance(addr.clone(), 0, BOB, amount / 2 - 1 * UNIT)); + assert_ok!(decrease_allowance(&addr, 0, &BOB, amount / 2 - 1 * UNIT)); let allowance_after = Assets::allowance(token, &addr, &BOB); assert_eq!(allowance_before - allowance_after, amount / 2 - 1 * UNIT); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(addr.clone(), token); + pallet_assets_start_destroy(&addr, token); assert_eq!( - decrease_allowance(addr.clone(), token, BOB, amount), + decrease_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); }); @@ -296,42 +266,34 @@ fn decrease_allowance_works() { #[test] fn token_metadata_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let name: Vec = vec![11, 12, 13]; let symbol: Vec = vec![21, 22, 23]; let decimals: u8 = 69; // Token does not exist. - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(Vec::::new())); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(Vec::::new())); - assert_eq!( - token_decimals(addr.clone(), TOKEN_ID), - Ok(pallet_assets_token_decimals(TOKEN_ID)) - ); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(0)); + assert_eq!(token_name(&addr, TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); + assert_eq!(token_name(&addr, TOKEN_ID), Ok(Vec::::new())); + assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); + assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(Vec::::new())); + assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(pallet_assets_token_decimals(TOKEN_ID))); + assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(0)); // Create Token. pallet_assets_create_and_set_metadata( - addr.clone(), + &addr, TOKEN_ID, name.clone(), symbol.clone(), decimals, ); - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(name)); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(symbol)); - assert_eq!( - token_decimals(addr.clone(), TOKEN_ID), - Ok(pallet_assets_token_decimals(TOKEN_ID)) - ); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(decimals)); + assert_eq!(token_name(&addr, TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); + assert_eq!(token_name(&addr, TOKEN_ID), Ok(name)); + assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); + assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(symbol)); + assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(pallet_assets_token_decimals(TOKEN_ID))); + assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(decimals)); }); } - /// 3. Management: /// - create /// - start_destroy @@ -342,41 +304,25 @@ fn token_metadata_works() { #[test] fn create_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); // Instantiate a contract without balance for fees. let addr = instantiate(CONTRACT, 0, vec![0]); // No balance to pay for fees. - assert_eq!( - create(addr.clone(), TOKEN_ID, addr.clone(), 1), - Err(Module { index: 10, error: [2, 0] }), - ); + assert_eq!(create(&addr, TOKEN_ID, &addr, 1), Err(Module { index: 10, error: [2, 0] }),); // Instantiate a contract without balance for deposit. let addr = instantiate(CONTRACT, 100, vec![1]); // No balance to pay the deposit. - assert_eq!( - create(addr.clone(), TOKEN_ID, addr.clone(), 1), - Err(Module { index: 10, error: [2, 0] }), - ); + assert_eq!(create(&addr, TOKEN_ID, &addr, 1), Err(Module { index: 10, error: [2, 0] }),); // Instantiate a contract with enough balance. let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); - assert_eq!( - create(addr.clone(), TOKEN_ID, BOB, 0), - Err(Module { index: 52, error: [7, 0] }), - ); + assert_eq!(create(&addr, TOKEN_ID, &BOB, 0), Err(Module { index: 52, error: [7, 0] }),); // The minimal balance for an token must be non zero. - assert_eq!( - create(addr.clone(), TOKEN_ID, BOB, 0), - Err(Module { index: 52, error: [7, 0] }), - ); + assert_eq!(create(&addr, TOKEN_ID, &BOB, 0), Err(Module { index: 52, error: [7, 0] }),); // Create token successfully. - assert_ok!(create(addr.clone(), TOKEN_ID, BOB, 1)); + assert_ok!(create(&addr, TOKEN_ID, &BOB, 1)); // Token ID is already taken. - assert_eq!( - create(addr.clone(), TOKEN_ID, BOB, 1), - Err(Module { index: 52, error: [5, 0] }), - ); + assert_eq!(create(&addr, TOKEN_ID, &BOB, 1), Err(Module { index: 52, error: [5, 0] }),); }); } @@ -384,11 +330,10 @@ fn create_works() { #[test] fn instantiate_and_create_fungible_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let contract = "contracts/create_token_in_constructor/target/ink/create_token_in_constructor.wasm"; // Token already exists. - pallet_assets_create(ALICE, 0, 1); + pallet_assets_create(&ALICE, 0, 1); assert_eq!( instantiate_and_create_fungible(contract, 0, 1), Err(Module { index: 52, error: [5, 0] }) @@ -402,24 +347,22 @@ fn instantiate_and_create_fungible_works() { #[test] fn start_destroy_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); // Token does not exist. - assert_eq!(start_destroy(addr.clone(), TOKEN_ID), Err(Module { index: 52, error: [3, 0] }),); + assert_eq!(start_destroy(&addr, TOKEN_ID), Err(Module { index: 52, error: [3, 0] }),); // Create tokens where contract is not the owner. - let token = pallet_assets_create(ALICE, 0, 1); + let token = pallet_assets_create(&ALICE, 0, 1); // No Permission. - assert_eq!(start_destroy(addr.clone(), token), Err(Module { index: 52, error: [2, 0] }),); - let token = pallet_assets_create(addr.clone(), TOKEN_ID, 1); - assert_ok!(start_destroy(addr.clone(), token)); + assert_eq!(start_destroy(&addr, token), Err(Module { index: 52, error: [2, 0] }),); + let token = pallet_assets_create(&addr, TOKEN_ID, 1); + assert_ok!(start_destroy(&addr, token)); }); } #[test] fn set_metadata_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let name = vec![42]; let symbol = vec![42]; let decimals = 42u8; @@ -427,37 +370,37 @@ fn set_metadata_works() { // Token does not exist. assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), + set_metadata(&addr, TOKEN_ID, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [3, 0] }), ); // Create token where contract is not the owner. - let token = pallet_assets_create(ALICE, 0, 1); + let token = pallet_assets_create(&ALICE, 0, 1); // No Permission. assert_eq!( - set_metadata(addr.clone(), token, vec![0], vec![0], 0u8), + set_metadata(&addr, token, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [2, 0] }), ); - let token = pallet_assets_create(addr.clone(), TOKEN_ID, 1); + let token = pallet_assets_create(&addr, TOKEN_ID, 1); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(addr.clone(), token); + pallet_assets_freeze(&addr, token); assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), + set_metadata(&addr, TOKEN_ID, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [16, 0] }), ); - pallet_assets_thaw(addr.clone(), token); + pallet_assets_thaw(&addr, token); // TODO: calling the below with a vector of length `100_000` errors in pallet contracts // `OutputBufferTooSmall. Added to security analysis issue #131 to revisit. // Set bad metadata - too large values. assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0; 1000], vec![0; 1000], 0u8), + set_metadata(&addr, TOKEN_ID, vec![0; 1000], vec![0; 1000], 0u8), Err(Module { index: 52, error: [9, 0] }), ); // Set metadata successfully. - assert_ok!(set_metadata(addr.clone(), TOKEN_ID, name, symbol, decimals)); + assert_ok!(set_metadata(&addr, TOKEN_ID, name, symbol, decimals)); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(addr.clone(), token); + pallet_assets_start_destroy(&addr, token); assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0), + set_metadata(&addr, TOKEN_ID, vec![0], vec![0], 0), Err(Module { index: 52, error: [16, 0] }), ); }); @@ -466,32 +409,31 @@ fn set_metadata_works() { #[test] fn clear_metadata_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let name = vec![42]; let symbol = vec![42]; let decimals = 42u8; let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); // Token does not exist. - assert_eq!(clear_metadata(addr.clone(), 0), Err(Module { index: 52, error: [3, 0] }),); + assert_eq!(clear_metadata(&addr, 0), Err(Module { index: 52, error: [3, 0] }),); // Create token where contract is not the owner. - let token = pallet_assets_create_and_set_metadata(ALICE, 0, vec![0], vec![0], 0); + let token = pallet_assets_create_and_set_metadata(&ALICE, 0, vec![0], vec![0], 0); // No Permission. - assert_eq!(clear_metadata(addr.clone(), token), Err(Module { index: 52, error: [2, 0] }),); - let token = pallet_assets_create(addr.clone(), TOKEN_ID, 1); + assert_eq!(clear_metadata(&addr, token), Err(Module { index: 52, error: [2, 0] }),); + let token = pallet_assets_create(&addr, TOKEN_ID, 1); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(addr.clone(), token); - assert_eq!(clear_metadata(addr.clone(), token), Err(Module { index: 52, error: [16, 0] }),); - pallet_assets_thaw(addr.clone(), token); + pallet_assets_freeze(&addr, token); + assert_eq!(clear_metadata(&addr, token), Err(Module { index: 52, error: [16, 0] }),); + pallet_assets_thaw(&addr, token); // No metadata set. - assert_eq!(clear_metadata(addr.clone(), token), Err(Module { index: 52, error: [3, 0] }),); - pallet_assets_set_metadata(addr.clone(), token, name, symbol, decimals); + assert_eq!(clear_metadata(&addr, token), Err(Module { index: 52, error: [3, 0] }),); + pallet_assets_set_metadata(&addr, token, name, symbol, decimals); // Clear metadata successfully. - assert_ok!(clear_metadata(addr.clone(), TOKEN_ID)); + assert_ok!(clear_metadata(&addr, TOKEN_ID)); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(addr.clone(), token); + pallet_assets_start_destroy(&addr, token); assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], decimals), + set_metadata(&addr, TOKEN_ID, vec![0], vec![0], decimals), Err(Module { index: 52, error: [16, 0] }), ); }); @@ -500,89 +442,74 @@ fn clear_metadata_works() { #[test] fn token_exists_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); // No tokens in circulation. - assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); + assert_eq!(token_exists(&addr, TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); // Tokens in circulation. - pallet_assets_create(addr.clone(), TOKEN_ID, 1); - assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); + pallet_assets_create(&addr, TOKEN_ID, 1); + assert_eq!(token_exists(&addr, TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); }); } #[test] fn mint_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; // Token does not exist. - assert_eq!(mint(addr.clone(), 1, BOB, amount), Err(Token(UnknownAsset))); - let token = pallet_assets_create(ALICE, 1, 1); + assert_eq!(mint(&addr, 1, &BOB, amount), Err(Token(UnknownAsset))); + let token = pallet_assets_create(&ALICE, 1, 1); // Minting can only be done by the owner. - assert_eq!(mint(addr.clone(), token, BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let token = pallet_assets_create(addr.clone(), 2, 2); + assert_eq!(mint(&addr, token, &BOB, 1), Err(Module { index: 52, error: [2, 0] })); + let token = pallet_assets_create(&addr, 2, 2); // Minimum balance of an token can not be zero. - assert_eq!(mint(addr.clone(), token, BOB, 1), Err(Token(BelowMinimum))); + assert_eq!(mint(&addr, token, &BOB, 1), Err(Token(BelowMinimum))); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(addr.clone(), token); - assert_eq!( - mint(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - pallet_assets_thaw(addr.clone(), token); + pallet_assets_freeze(&addr, token); + assert_eq!(mint(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); + pallet_assets_thaw(&addr, token); // Successful mint. let balance_before_mint = Assets::balance(token, &BOB); - assert_ok!(mint(addr.clone(), token, BOB, amount)); + assert_ok!(mint(&addr, token, &BOB, amount)); let balance_after_mint = Assets::balance(token, &BOB); assert_eq!(balance_after_mint, balance_before_mint + amount); // Account can not hold more tokens than Balance::MAX. - assert_eq!(mint(addr.clone(), token, BOB, Balance::MAX,), Err(Arithmetic(Overflow))); + assert_eq!(mint(&addr, token, &BOB, Balance::MAX,), Err(Arithmetic(Overflow))); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(addr.clone(), token); - assert_eq!( - mint(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); + pallet_assets_start_destroy(&addr, token); + assert_eq!(mint(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); }); } #[test] fn burn_works() { new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); let amount: Balance = 100 * UNIT; // Token does not exist. - assert_eq!(burn(addr.clone(), 1, BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let token = pallet_assets_create(ALICE, 1, 1); + assert_eq!(burn(&addr, 1, &BOB, amount), Err(Module { index: 52, error: [3, 0] })); + let token = pallet_assets_create(&ALICE, 1, 1); // Bob has no tokens and therefore doesn't exist. - assert_eq!(burn(addr.clone(), token, BOB, 1), Err(Module { index: 52, error: [1, 0] })); + assert_eq!(burn(&addr, token, &BOB, 1), Err(Module { index: 52, error: [1, 0] })); // Burning can only be done by the manager. - pallet_assets_mint(ALICE, token, BOB, amount); - assert_eq!(burn(addr.clone(), token, BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let token = pallet_assets_create_and_mint_to(addr.clone(), 2, BOB, amount); + pallet_assets_mint(&ALICE, token, &BOB, amount); + assert_eq!(burn(&addr, token, &BOB, 1), Err(Module { index: 52, error: [2, 0] })); + let token = pallet_assets_create_and_mint_to(&addr, 2, &BOB, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(addr.clone(), token); - assert_eq!( - burn(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - pallet_assets_thaw(addr.clone(), token); + pallet_assets_freeze(&addr, token); + assert_eq!(burn(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); + pallet_assets_thaw(&addr, token); // Successful mint. let balance_before_burn = Assets::balance(token, &BOB); - assert_ok!(burn(addr.clone(), token, BOB, amount)); + assert_ok!(burn(&addr, token, &BOB, amount)); let balance_after_burn = Assets::balance(token, &BOB); assert_eq!(balance_after_burn, balance_before_burn - amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(addr.clone(), token); - assert_eq!( - burn(addr.clone(), token, BOB, amount), - Err(Module { index: 52, error: [17, 0] }) - ); + pallet_assets_start_destroy(&addr, token); + assert_eq!(burn(&addr, token, &BOB, amount), Err(Module { index: 52, error: [17, 0] })); }); } diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 18ebf6e7..e0ea3c83 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -2,10 +2,10 @@ use super::*; type AssetId = TokenId; -fn do_bare_call(function: &str, addr: AccountId32, params: Vec) -> ExecReturnValue { +fn do_bare_call(function: &str, addr: &AccountId32, params: Vec) -> ExecReturnValue { let function = function_selector(function); let params = [function, params].concat(); - bare_call(addr, params, 0).expect("should work") + bare_call(addr.clone(), params, 0).expect("should work") } // TODO - issue #263 - why result.data[1..] @@ -13,61 +13,61 @@ pub(super) fn decoded(result: ExecReturnValue) -> Result::decode(&mut &result.data[1..]).map_err(|_| result) } -pub(super) fn total_supply(addr: AccountId32, token_id: TokenId) -> Result { +pub(super) fn total_supply(addr: &AccountId32, token_id: TokenId) -> Result { let result = do_bare_call("total_supply", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } pub(super) fn balance_of( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, owner: AccountId32, ) -> Result { let params = [token_id.encode(), owner.encode()].concat(); - let result = do_bare_call("balance_of", addr, params); + let result = do_bare_call("balance_of", &addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } pub(super) fn allowance( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, owner: AccountId32, spender: AccountId32, ) -> Result { let params = [token_id.encode(), owner.encode(), spender.encode()].concat(); - let result = do_bare_call("allowance", addr, params); + let result = do_bare_call("allowance", &addr, params); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_name(addr: AccountId32, token_id: TokenId) -> Result, Error> { +pub(super) fn token_name(addr: &AccountId32, token_id: TokenId) -> Result, Error> { let result = do_bare_call("token_name", addr, token_id.encode()); decoded::, Error>>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_symbol(addr: AccountId32, token_id: TokenId) -> Result, Error> { +pub(super) fn token_symbol(addr: &AccountId32, token_id: TokenId) -> Result, Error> { let result = do_bare_call("token_symbol", addr, token_id.encode()); decoded::, Error>>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_decimals(addr: AccountId32, token_id: TokenId) -> Result { +pub(super) fn token_decimals(addr: &AccountId32, token_id: TokenId) -> Result { let result = do_bare_call("token_decimals", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn token_exists(addr: AccountId32, token_id: TokenId) -> Result { +pub(super) fn token_exists(addr: &AccountId32, token_id: TokenId) -> Result { let result = do_bare_call("token_exists", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } pub(super) fn transfer( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, to: AccountId32, value: Balance, @@ -79,7 +79,7 @@ pub(super) fn transfer( } pub(super) fn transfer_from( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, from: AccountId32, to: AccountId32, @@ -94,9 +94,9 @@ pub(super) fn transfer_from( } pub(super) fn approve( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, - spender: AccountId32, + spender: &AccountId32, value: Balance, ) -> Result<(), Error> { let params = [token_id.encode(), spender.encode(), value.encode()].concat(); @@ -106,9 +106,9 @@ pub(super) fn approve( } pub(super) fn increase_allowance( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, - spender: AccountId32, + spender: &AccountId32, value: Balance, ) -> Result<(), Error> { let params = [token_id.encode(), spender.encode(), value.encode()].concat(); @@ -118,9 +118,9 @@ pub(super) fn increase_allowance( } pub(super) fn decrease_allowance( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, - spender: AccountId32, + spender: &AccountId32, value: Balance, ) -> Result<(), Error> { let params = [token_id.encode(), spender.encode(), value.encode()].concat(); @@ -130,9 +130,9 @@ pub(super) fn decrease_allowance( } pub(super) fn create( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, - admin: AccountId32, + admin: &AccountId32, min_balance: Balance, ) -> Result<(), Error> { let params = [token_id.encode(), admin.encode(), min_balance.encode()].concat(); @@ -141,7 +141,7 @@ pub(super) fn create( .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn start_destroy(addr: AccountId32, token_id: TokenId) -> Result<(), Error> { +pub(super) fn start_destroy(addr: &AccountId32, token_id: TokenId) -> Result<(), Error> { let result = do_bare_call("start_destroy", addr, token_id.encode()); match decoded::>(result) { Ok(x) => x, @@ -150,7 +150,7 @@ pub(super) fn start_destroy(addr: AccountId32, token_id: TokenId) -> Result<(), } pub(super) fn set_metadata( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, name: Vec, symbol: Vec, @@ -162,16 +162,16 @@ pub(super) fn set_metadata( .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn clear_metadata(addr: AccountId32, token_id: TokenId) -> Result<(), Error> { +pub(super) fn clear_metadata(addr: &AccountId32, token_id: TokenId) -> Result<(), Error> { let result = do_bare_call("clear_metadata", addr, token_id.encode()); decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } pub(super) fn mint( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, - account: AccountId32, + account: &AccountId32, amount: Balance, ) -> Result<(), Error> { let params = [token_id.encode(), account.encode(), amount.encode()].concat(); @@ -181,9 +181,9 @@ pub(super) fn mint( } pub(super) fn burn( - addr: AccountId32, + addr: &AccountId32, token_id: TokenId, - account: AccountId32, + account: &AccountId32, amount: Balance, ) -> Result<(), Error> { let params = [token_id.encode(), account.encode(), amount.encode()].concat(); @@ -193,81 +193,81 @@ pub(super) fn burn( } pub(super) fn pallet_assets_create( - owner: AccountId32, + owner: &AccountId32, asset_id: AssetId, min_balance: Balance, ) -> AssetId { assert_ok!(Assets::create( RuntimeOrigin::signed(owner.clone()), asset_id.into(), - owner.into(), + owner.clone().into(), min_balance )); asset_id } pub(super) fn pallet_assets_mint( - owner: AccountId32, + owner: &AccountId32, asset_id: AssetId, - to: AccountId32, + to: &AccountId32, value: Balance, ) -> AssetId { assert_ok!(Assets::mint( RuntimeOrigin::signed(owner.clone()), asset_id.into(), - to.into(), + to.clone().into(), value )); asset_id } pub(super) fn pallet_assets_create_and_mint_to( - owner: AccountId32, + owner: &AccountId32, asset_id: AssetId, - to: AccountId32, + to: &AccountId32, value: Balance, ) -> AssetId { - pallet_assets_create(owner.clone(), asset_id, 1); + pallet_assets_create(owner, asset_id, 1); pallet_assets_mint(owner, asset_id, to, value) } // Create an asset, mints to, and approves spender. pub(super) fn pallet_assets_create_mint_and_approve( - owner: AccountId32, + owner: &AccountId32, asset_id: AssetId, - to: AccountId32, + to: &AccountId32, mint: Balance, - spender: AccountId32, + spender: &AccountId32, approve: Balance, ) -> AssetId { - pallet_assets_create_and_mint_to(owner.clone(), asset_id, to.clone(), mint); + pallet_assets_create_and_mint_to(owner, asset_id, to, mint); assert_ok!(Assets::approve_transfer( - RuntimeOrigin::signed(to.into()), + RuntimeOrigin::signed(to.clone().into()), asset_id.into(), - spender.into(), + spender.clone().into(), approve, )); asset_id } // Freeze an asset. -pub(super) fn pallet_assets_freeze(owner: AccountId32, asset_id: AssetId) { - assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(owner.into()), asset_id.into())); +pub(super) fn pallet_assets_freeze(owner: &AccountId32, asset_id: AssetId) { + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(owner.clone().into()), asset_id.into())); } // Thaw an asset. -pub(super) fn pallet_assets_thaw(owner: AccountId32, asset_id: AssetId) { - assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(owner.into()), asset_id.into())); +pub(super) fn pallet_assets_thaw(owner: &AccountId32, asset_id: AssetId) { + assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(owner.clone().into()), asset_id.into())); } // Start destroying an asset. -pub(super) fn pallet_assets_start_destroy(owner: AccountId32, asset_id: AssetId) { - assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(owner.into()), asset_id.into())); +pub(super) fn pallet_assets_start_destroy(owner: &AccountId32, asset_id: AssetId) { + assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(owner.clone().into()), asset_id.into())); } // Create an asset and set metadata. pub(super) fn pallet_assets_create_and_set_metadata( - owner: AccountId32, + owner: &AccountId32, asset_id: AssetId, name: Vec, symbol: Vec, @@ -285,14 +285,14 @@ pub(super) fn pallet_assets_create_and_set_metadata( // Set metadata of an asset. pub(super) fn pallet_assets_set_metadata( - owner: AccountId32, + owner: &AccountId32, asset_id: AssetId, name: Vec, symbol: Vec, decimals: u8, ) { assert_ok!(Assets::set_metadata( - RuntimeOrigin::signed(owner.into()), + RuntimeOrigin::signed(owner.clone().into()), asset_id.into(), name, symbol, diff --git a/pop-api/integration-tests/src/lib.rs b/pop-api/integration-tests/src/lib.rs index 946e0a70..3c3dc1e3 100644 --- a/pop-api/integration-tests/src/lib.rs +++ b/pop-api/integration-tests/src/lib.rs @@ -28,6 +28,8 @@ const INIT_AMOUNT: Balance = 100_000_000 * UNIT; const INIT_VALUE: Balance = 100 * UNIT; fn new_test_ext() -> sp_io::TestExternalities { + let _ = env_logger::try_init(); + let mut t = frame_system::GenesisConfig::::default() .build_storage() .expect("Frame system builds valid default genesis config"); From 0f9b166cfdcad2a6d10536e431a438deed9dbc1a Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Wed, 11 Sep 2024 19:33:51 +0200 Subject: [PATCH 09/29] refactor: small refactors --- .../integration-tests/src/fungibles/mod.rs | 13 +-- .../integration-tests/src/fungibles/utils.rs | 8 +- pop-api/integration-tests/src/lib.rs | 3 +- pop-api/src/lib.rs | 84 +++++++++---------- pop-api/src/v0/fungibles.rs | 14 ++-- pop-api/src/v0/mod.rs | 7 +- primitives/src/lib.rs | 8 +- 7 files changed, 70 insertions(+), 67 deletions(-) diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 3345729f..caf4e159 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -317,16 +317,17 @@ fn create_works() { // Instantiate a contract with enough balance. let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); assert_eq!(create(&addr, TOKEN_ID, &BOB, 0), Err(Module { index: 52, error: [7, 0] }),); - // The minimal balance for an token must be non zero. + // The minimal balance for a token must be non zero. assert_eq!(create(&addr, TOKEN_ID, &BOB, 0), Err(Module { index: 52, error: [7, 0] }),); // Create token successfully. assert_ok!(create(&addr, TOKEN_ID, &BOB, 1)); + assert_eq!(Assets::owner(TOKEN_ID), Some(addr.clone())); // Token ID is already taken. assert_eq!(create(&addr, TOKEN_ID, &BOB, 1), Err(Module { index: 52, error: [5, 0] }),); }); } -// Testing a contract that creates an token in the constructor. +// Testing a contract that creates a token in the constructor. #[test] fn instantiate_and_create_fungible_works() { new_test_ext().execute_with(|| { @@ -338,8 +339,10 @@ fn instantiate_and_create_fungible_works() { instantiate_and_create_fungible(contract, 0, 1), Err(Module { index: 52, error: [5, 0] }) ); - // Successfully create an token when instantiating the contract. - assert_ok!(instantiate_and_create_fungible(contract, TOKEN_ID, 1)); + // Successfully create a token when instantiating the contract. + let result_with_address = instantiate_and_create_fungible(contract, TOKEN_ID, 1); + assert_ok!(result_with_address.clone()); + assert_eq!(Assets::owner(TOKEN_ID), result_with_address.ok()); assert!(Assets::asset_exists(TOKEN_ID)); }); } @@ -465,7 +468,7 @@ fn mint_works() { // Minting can only be done by the owner. assert_eq!(mint(&addr, token, &BOB, 1), Err(Module { index: 52, error: [2, 0] })); let token = pallet_assets_create(&addr, 2, 2); - // Minimum balance of an token can not be zero. + // Minimum balance of a token can not be zero. assert_eq!(mint(&addr, token, &BOB, 1), Err(Token(BelowMinimum))); // Token is not live, i.e. frozen or being destroyed. pallet_assets_freeze(&addr, token); diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index e0ea3c83..d37271e5 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -322,7 +322,7 @@ pub(super) fn instantiate_and_create_fungible( contract: &str, token_id: TokenId, min_balance: Balance, -) -> Result<(), Error> { +) -> Result { let function = function_selector("new"); let input = [function, token_id.encode(), min_balance.encode()].concat(); let wasm_binary = load_wasm_module::(contract).expect("could not read .wasm file"); @@ -338,8 +338,10 @@ pub(super) fn instantiate_and_create_fungible( CollectEvents::Skip, ) .result - .expect("should work") - .result; + .expect("should work"); + let address = result.account_id; + let result = result.result; decoded::>(result.clone()) .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) + .map(|_| address) } diff --git a/pop-api/integration-tests/src/lib.rs b/pop-api/integration-tests/src/lib.rs index 3c3dc1e3..2b664b30 100644 --- a/pop-api/integration-tests/src/lib.rs +++ b/pop-api/integration-tests/src/lib.rs @@ -3,7 +3,8 @@ use frame_support::{ assert_ok, traits::fungibles::{ - approvals::Inspect as ApprovalInspect, metadata::Inspect as MetadataInspect, Inspect, + approvals::Inspect as ApprovalInspect, metadata::Inspect as MetadataInspect, + roles::Inspect as RolesInspect, Inspect, }, weights::Weight, }; diff --git a/pop-api/src/lib.rs b/pop-api/src/lib.rs index 0a080c56..011a5e93 100644 --- a/pop-api/src/lib.rs +++ b/pop-api/src/lib.rs @@ -1,9 +1,10 @@ -//! The `pop-api` crate provides an API for smart contracts to interact with the Pop Network runtime. +//! The `pop-api` crate provides an API for smart contracts to interact with the Pop Network +//! runtime. //! -//! This crate abstracts away complexities to deliver a streamlined developer experience while supporting -//! multiple API versions to ensure backward compatibility. It is designed with a focus on stability, -//! future-proofing, and storage efficiency, allowing developers to easily integrate powerful runtime -//! features into their contracts without unnecessary overhead. +//! This crate abstracts away complexities to deliver a streamlined developer experience while +//! supporting multiple API versions to ensure backward compatibility. It is designed with a focus +//! on stability, future-proofing, and storage efficiency, allowing developers to easily integrate +//! powerful runtime features into their contracts without unnecessary overhead. #![cfg_attr(not(feature = "std"), no_std, no_main)] @@ -16,49 +17,16 @@ pub mod primitives; /// The first version of the API. pub mod v0; -/// A result type used by the API, with the `StatusCode` as the error type. +type ChainExtensionMethodApi = ChainExtensionMethod<(), (), (), false>; +/// The result type used by the API, with the `StatusCode` as the error type. pub type Result = core::result::Result; -mod constants { - // Errors: - pub(crate) const DECODING_FAILED: u32 = 255; - // TODO: will be used in the future when the remaining fungibles features will be implemented. - pub(crate) const _MODULE_ERROR: u8 = 3; - - // Function IDs: - pub(crate) const DISPATCH: u8 = 0; - pub(crate) const READ_STATE: u8 = 1; - - // Modules: - pub(crate) const ASSETS: u8 = 52; - pub(crate) const BALANCES: u8 = 10; - pub(crate) const FUNGIBLES: u8 = 150; -} - -// Helper method to build a dispatch call or a call to read state. -// -// Parameters: -// - 'version': The version of the chain extension. -// - 'function': The ID of the function. -// - 'module': The index of the runtime module. -// - 'dispatchable': The index of the module dispatchable functions. -fn build_extension_method( - version: u8, - function: u8, - module: u8, - dispatchable: u8, -) -> ChainExtensionMethod<(), (), (), false> { - ChainExtensionMethod::build(u32::from_le_bytes([version, function, module, dispatchable])) -} - /// Represents a status code returned by the runtime. /// -/// `StatusCode` encapsulates a `u32` value that indicates the status of an operation performed by -/// the runtime. It helps to communicate the success or failure of a Pop API call to the contract, -/// providing a standardized way to handle errors. +/// `StatusCode` encapsulates a `u32` value that indicates the success or failure of a runtime call +/// via Pop API. /// -/// This status code can be used to determine if an operation succeeded or if it encountered an -/// error. A `StatusCode` of `0` typically indicates success, while any other value represents an +/// A `StatusCode` of `0` indicates success, while any other value represents an /// error. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[ink::scale_derive(Encode, Decode, TypeInfo)] @@ -90,3 +58,33 @@ impl From for StatusCode { StatusCode(DECODING_FAILED) } } + +mod constants { + // Error. + pub(crate) const DECODING_FAILED: u32 = 255; + + // Function IDs. + pub(crate) const DISPATCH: u8 = 0; + pub(crate) const READ_STATE: u8 = 1; + + // Modules. + pub(crate) const ASSETS: u8 = 52; + pub(crate) const BALANCES: u8 = 10; + pub(crate) const FUNGIBLES: u8 = 150; +} + +// Helper method to build a dispatch call or a call to read state. +// +// Parameters: +// - 'version': The version of the chain extension. +// - 'function': The ID of the function. +// - 'module': The index of the runtime module. +// - 'dispatchable': The index of the module dispatchable functions. +fn build_extension_method( + version: u8, + function: u8, + module: u8, + dispatchable: u8, +) -> ChainExtensionMethodApi { + ChainExtensionMethod::build(u32::from_le_bytes([version, function, module, dispatchable])) +} diff --git a/pop-api/src/v0/fungibles.rs b/pop-api/src/v0/fungibles.rs index 5c9b9a30..ecd05b76 100644 --- a/pop-api/src/v0/fungibles.rs +++ b/pop-api/src/v0/fungibles.rs @@ -7,21 +7,21 @@ //! 4. PSP-22 Mintable & Burnable use constants::*; -use ink::{env::chain_extension::ChainExtensionMethod, prelude::vec::Vec}; +use ink::prelude::vec::Vec; pub use management::*; pub use metadata::*; use crate::{ constants::{ASSETS, BALANCES, FUNGIBLES}, primitives::{AccountId, Balance, TokenId}, - Result, StatusCode, + ChainExtensionMethodApi, Result, StatusCode, }; // Helper method to build a dispatch call. // // Parameters: // - 'dispatchable': The index of the dispatchable function within the module. -fn build_dispatch(dispatchable: u8) -> ChainExtensionMethod<(), (), (), false> { +fn build_dispatch(dispatchable: u8) -> ChainExtensionMethodApi { crate::v0::build_dispatch(FUNGIBLES, dispatchable) } @@ -29,7 +29,7 @@ fn build_dispatch(dispatchable: u8) -> ChainExtensionMethod<(), (), (), false> { // // Parameters: // - 'state_query': The index of the runtime state query. -fn build_read_state(state_query: u8) -> ChainExtensionMethod<(), (), (), false> { +fn build_read_state(state_query: u8) -> ChainExtensionMethodApi { crate::v0::build_read_state(FUNGIBLES, state_query) } @@ -99,7 +99,7 @@ pub mod events { pub value: u128, } - /// Event emitted when an token is created. + /// Event emitted when a token is created. #[ink::event] pub struct Create { /// The token identifier. @@ -296,7 +296,7 @@ pub fn burn(token: TokenId, account: AccountId, value: Balance) -> Result<()> { .call(&(token, account, value)) } -/// The PSP-22 Metadata interface for querying metadata. +/// The PSP-22 compliant interface for querying metadata. pub mod metadata { use super::*; @@ -526,7 +526,7 @@ mod tests { } #[test] - fn conversion_status_code_into_fungibles_error_works() { + fn converting_status_code_into_fungibles_error_works() { let other_errors = vec![ Other, CannotLookup, diff --git a/pop-api/src/v0/mod.rs b/pop-api/src/v0/mod.rs index 8ed35058..6e5554bc 100644 --- a/pop-api/src/v0/mod.rs +++ b/pop-api/src/v0/mod.rs @@ -2,9 +2,8 @@ use crate::{ build_extension_method, constants::{DISPATCH, READ_STATE}, primitives::Error, - StatusCode, + ChainExtensionMethodApi, StatusCode, }; -use ink::env::chain_extension::ChainExtensionMethod; /// APIs for fungible tokens. #[cfg(feature = "fungibles")] @@ -23,7 +22,7 @@ impl From for Error { // Parameters: // - 'module': The index of the runtime module. // - 'dispatchable': The index of the module dispatchable functions. -fn build_dispatch(module: u8, dispatchable: u8) -> ChainExtensionMethod<(), (), (), false> { +fn build_dispatch(module: u8, dispatchable: u8) -> ChainExtensionMethodApi { build_extension_method(V0, DISPATCH, module, dispatchable) } @@ -32,6 +31,6 @@ fn build_dispatch(module: u8, dispatchable: u8) -> ChainExtensionMethod<(), (), // Parameters: // - 'module': The index of the runtime module. // - 'state_query': The index of the runtime state query. -fn build_read_state(module: u8, state_query: u8) -> ChainExtensionMethod<(), (), (), false> { +fn build_read_state(module: u8, state_query: u8) -> ChainExtensionMethodApi { build_extension_method(V0, READ_STATE, module, state_query) } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index e6942432..1af18af9 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -17,7 +17,7 @@ pub mod v0 { use super::*; /// Reason why a Pop API call failed. - #[derive(Encode, Decode, Debug, Eq, PartialEq)] + #[derive(Encode, Decode, Debug, Eq, PartialEq, Clone)] #[cfg_attr(feature = "std", derive(TypeInfo))] #[repr(u8)] #[allow(clippy::unnecessary_cast)] @@ -102,7 +102,7 @@ pub mod v0 { } /// Description of what went wrong when trying to complete an operation on a token. - #[derive(Encode, Decode, Debug, Eq, PartialEq)] + #[derive(Encode, Decode, Debug, Eq, PartialEq, Clone)] #[cfg_attr(feature = "std", derive(TypeInfo))] pub enum TokenError { /// Funds are unavailable. @@ -129,7 +129,7 @@ pub mod v0 { } /// Arithmetic errors. - #[derive(Encode, Decode, Debug, Eq, PartialEq)] + #[derive(Encode, Decode, Debug, Eq, PartialEq, Clone)] #[cfg_attr(feature = "std", derive(TypeInfo))] pub enum ArithmeticError { /// Underflow. @@ -141,7 +141,7 @@ pub mod v0 { } /// Errors related to transactional storage layers. - #[derive(Encode, Decode, Debug, Eq, PartialEq)] + #[derive(Encode, Decode, Debug, Eq, PartialEq, Clone)] #[cfg_attr(feature = "std", derive(TypeInfo))] pub enum TransactionalError { /// Too many transactional layers have been spawned. From 1d2ca0eeb2795d922a35ede3e5ac0b47a4958395 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 16 Aug 2024 15:56:50 +0200 Subject: [PATCH 10/29] refactor: fungibles pallet --- pallets/api/src/fungibles/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pallets/api/src/fungibles/mod.rs b/pallets/api/src/fungibles/mod.rs index 311b717e..43a8aeab 100644 --- a/pallets/api/src/fungibles/mod.rs +++ b/pallets/api/src/fungibles/mod.rs @@ -503,10 +503,12 @@ pub mod pallet { use Read::*; match request { TotalSupply(token) => ReadResult::TotalSupply(AssetsOf::::total_supply(token)), - BalanceOf { token, owner } => - ReadResult::BalanceOf(AssetsOf::::balance(token, owner)), - Allowance { token, owner, spender } => - ReadResult::Allowance(AssetsOf::::allowance(token, &owner, &spender)), + BalanceOf { token, owner } => { + ReadResult::BalanceOf(AssetsOf::::balance(token, owner)) + }, + Allowance { token, owner, spender } => { + ReadResult::Allowance(AssetsOf::::allowance(token, &owner, &spender)) + }, TokenName(token) => ReadResult::TokenName( as MetadataInspect< AccountIdOf, >>::name(token)), From 1752cd16d8b3271b2052007be5ef82b6cfd5ba6a Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:48:03 +0700 Subject: [PATCH 11/29] fix: invalid imported crates & crate visibility --- pop-api/src/v0/fungibles.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pop-api/src/v0/fungibles.rs b/pop-api/src/v0/fungibles.rs index 5c9b9a30..2f33f01d 100644 --- a/pop-api/src/v0/fungibles.rs +++ b/pop-api/src/v0/fungibles.rs @@ -496,6 +496,8 @@ mod tests { TransactionalError::*, }, StatusCode, + TokenError::*, + TransactionalError::*, }; fn error_into_status_code(error: Error) -> StatusCode { From 6a47735b35dabafe44d60933aaeb83ae53d7ab26 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:06:47 +0700 Subject: [PATCH 12/29] fix: revert primitive error imports --- pop-api/src/v0/fungibles.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/pop-api/src/v0/fungibles.rs b/pop-api/src/v0/fungibles.rs index 2f33f01d..5c9b9a30 100644 --- a/pop-api/src/v0/fungibles.rs +++ b/pop-api/src/v0/fungibles.rs @@ -496,8 +496,6 @@ mod tests { TransactionalError::*, }, StatusCode, - TokenError::*, - TransactionalError::*, }; fn error_into_status_code(error: Error) -> StatusCode { From e4bbe1b491b6b4b140be573ad0263d6b3334321b Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:23:33 +0700 Subject: [PATCH 13/29] test: assert events emitted from contract --- .../contracts/fungibles/lib.rs | 7 +- .../integration-tests/src/fungibles/mod.rs | 1107 ++++++++--------- 2 files changed, 517 insertions(+), 597 deletions(-) diff --git a/pop-api/integration-tests/contracts/fungibles/lib.rs b/pop-api/integration-tests/contracts/fungibles/lib.rs index 1768b687..b9a895da 100755 --- a/pop-api/integration-tests/contracts/fungibles/lib.rs +++ b/pop-api/integration-tests/contracts/fungibles/lib.rs @@ -88,7 +88,12 @@ mod fungibles { } #[ink(message)] - pub fn approve(&mut self, token: AssetId, spender: AccountId, value: Balance) -> Result<()> { + pub fn approve( + &mut self, + token: AssetId, + spender: AccountId, + value: Balance, + ) -> Result<()> { let result = api::approve(token, spender, value); self.env() .emit_event(Approval { owner: self.env().account_id(), spender, value }); diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 288835f7..43a8aeab 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,610 +1,525 @@ -use pop_api::{ - fungibles::events::{ - Approval, ClearMetadata, Create, SetMetadata, StartDestroy, Transfer, - }, - primitives::account_id_from_slice, -}; -use pop_primitives::{ArithmeticError::*, Error::*, TokenError::*, TokenId, *}; - -use utils::*; - -use super::*; - -mod utils; - -const TOKEN_ID: TokenId = 1; -const CONTRACT: &str = "contracts/fungibles/target/ink/fungibles.wasm"; - -/// 1. PSP-22 Interface: -/// - total_supply -/// - balance_of -/// - allowance -/// - transfer -/// - transfer_from -/// - approve -/// - increase_allowance -/// - decrease_allowance - -#[test] -fn total_supply_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - - // No tokens in circulation. - assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); - assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(0)); - - // Tokens in circulation. - create_asset_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); - assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); - assert_eq!(total_supply(addr, TOKEN_ID), Ok(100)); - }); -} - -#[test] -fn balance_of_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - - // No tokens in circulation. - assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); - assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(0)); - - // Tokens in circulation. - create_asset_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); - assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); - assert_eq!(balance_of(addr, TOKEN_ID, BOB), Ok(100)); - }); -} - -#[test] -fn allowance_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - - // No tokens in circulation. - assert_eq!( - allowance(addr.clone(), TOKEN_ID, BOB, ALICE), - Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) - ); - assert_eq!(allowance(addr.clone(), TOKEN_ID, BOB, ALICE), Ok(0)); - - // Tokens in circulation. - create_asset_mint_and_approve(addr.clone(), TOKEN_ID, BOB, 100, ALICE, 50); - assert_eq!( - allowance(addr.clone(), TOKEN_ID, BOB, ALICE), - Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) - ); - assert_eq!(allowance(addr, TOKEN_ID, BOB, ALICE), Ok(50)); - }); -} - -#[test] -fn transfer_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let amount: Balance = 100 * UNIT; - - // Asset does not exist. - assert_eq!( - transfer(addr.clone(), 1, BOB, amount), - Err(Module { index: 52, error: [3, 0] }) - ); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); - assert_eq!( - transfer(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - thaw_asset(ALICE, asset); - // Not enough balance. - assert_eq!( - transfer(addr.clone(), asset, BOB, amount + 1 * UNIT), - Err(Module { index: 52, error: [0, 0] }) - ); - // Not enough balance due to ED. - assert_eq!( - transfer(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [0, 0] }) - ); - // Successful transfer. - let balance_before_transfer = Assets::balance(asset, &BOB); - assert_ok!(transfer(addr.clone(), asset, BOB, amount / 2)); - let balance_after_transfer = Assets::balance(asset, &BOB); - assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); - // Transfer asset to account that does not exist. - assert_eq!(transfer(addr.clone(), asset, FERDIE, amount / 4), Err(Token(CannotCreate))); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(ALICE, asset); - assert_eq!( - transfer(addr.clone(), asset, BOB, amount / 4), - Err(Module { index: 52, error: [16, 0] }) - ); - }); -} - -#[test] -fn transfer_from_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let amount: Balance = 100 * UNIT; - - // Asset does not exist. - assert_eq!( - transfer_from(addr.clone(), 1, ALICE, BOB, amount / 2), - Err(Module { index: 52, error: [3, 0] }), - ); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, ALICE, amount); - // Unapproved transfer. - assert_eq!( - transfer_from(addr.clone(), asset, ALICE, BOB, amount / 2), - Err(Module { index: 52, error: [10, 0] }) - ); - assert_ok!(Assets::approve_transfer( - RuntimeOrigin::signed(ALICE.into()), - asset.into(), - addr.clone().into(), - amount + 1 * UNIT, - )); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); - assert_eq!( - transfer_from(addr.clone(), asset, ALICE, BOB, amount), - Err(Module { index: 52, error: [16, 0] }), - ); - thaw_asset(ALICE, asset); - // Not enough balance. - assert_eq!( - transfer_from(addr.clone(), asset, ALICE, BOB, amount + 1 * UNIT), - Err(Module { index: 52, error: [0, 0] }), - ); - // Successful transfer. - let balance_before_transfer = Assets::balance(asset, &BOB); - assert_ok!(transfer_from(addr.clone(), asset, ALICE, BOB, amount / 2)); - let balance_after_transfer = Assets::balance(asset, &BOB); - assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); - }); -} - -#[test] -fn approve_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, 0, vec![]); - let amount: Balance = 100 * UNIT; - - // Asset does not exist. - assert_eq!(approve(addr.clone(), 0, BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount); - assert_eq!(approve(addr.clone(), asset, BOB, amount), Err(ConsumerRemaining)); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); - assert_eq!( - approve(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - thaw_asset(ALICE, asset); - // Successful approvals: - assert_eq!(0, Assets::allowance(asset, &addr, &BOB)); - assert_ok!(approve(addr.clone(), asset, BOB, amount)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount); - // Successfully emit an event from approving. - let expected = Approval { - owner: account_id_from_slice(addr.clone().as_ref()), - spender: account_id_from_slice(BOB.as_ref()), - value: amount, +//! The fungibles pallet offers a streamlined interface for interacting with fungible tokens. The +//! goal is to provide a simplified, consistent API that adheres to standards in the smart contract +//! space. + +use frame_support::traits::fungibles::{metadata::Inspect as MetadataInspect, Inspect}; +pub use pallet::*; +use pallet_assets::WeightInfo as AssetsWeightInfoTrait; +use weights::WeightInfo; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +#[cfg(test)] +mod tests; +pub mod weights; + +type AccountIdOf = ::AccountId; +type TokenIdOf = > as Inspect< + ::AccountId, +>>::AssetId; +type TokenIdParameterOf = >>::AssetIdParameter; +type AssetsOf = pallet_assets::Pallet>; +type AssetsInstanceOf = ::AssetsInstance; +type AssetsWeightInfoOf = >>::WeightInfo; +type BalanceOf = > as Inspect< + ::AccountId, +>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use core::cmp::Ordering::*; + + use frame_support::{ + dispatch::{DispatchResult, DispatchResultWithPostInfo, WithPostDispatchInfo}, + pallet_prelude::*, + traits::fungibles::approvals::Inspect as ApprovalInspect, + }; + use frame_system::pallet_prelude::*; + use sp_runtime::{ + traits::{StaticLookup, Zero}, + Saturating, + }; + use sp_std::vec::Vec; + + use super::*; + + /// State reads for the fungibles API with required input. + #[derive(Encode, Decode, Debug, MaxEncodedLen)] + #[repr(u8)] + #[allow(clippy::unnecessary_cast)] + pub enum Read { + /// Total token supply for a specified token. + #[codec(index = 0)] + TotalSupply(TokenIdOf), + /// Account balance for a specified `token` and `owner`. + #[codec(index = 1)] + BalanceOf { + /// The token. + token: TokenIdOf, + /// The owner of the token. + owner: AccountIdOf, + }, + /// Allowance for a `spender` approved by an `owner`, for a specified `token`. + #[codec(index = 2)] + Allowance { + /// The token. + token: TokenIdOf, + /// The owner of the token. + owner: AccountIdOf, + /// The spender with an allowance. + spender: AccountIdOf, + }, + /// Name of the specified token. + #[codec(index = 8)] + TokenName(TokenIdOf), + /// Symbol for the specified token. + #[codec(index = 9)] + TokenSymbol(TokenIdOf), + /// Decimals for the specified token. + #[codec(index = 10)] + TokenDecimals(TokenIdOf), + /// Check if a specified token exists. + #[codec(index = 18)] + TokenExists(TokenIdOf), + } + + /// Results of state reads for the fungibles API. + #[derive(Debug)] + pub enum ReadResult { + /// Total token supply for a specified token. + TotalSupply(BalanceOf), + /// Account balance for a specified token and owner. + BalanceOf(BalanceOf), + /// Allowance for a spender approved by an owner, for a specified token. + Allowance(BalanceOf), + /// Name of the specified token. + TokenName(Vec), + /// Symbol for the specified token. + TokenSymbol(Vec), + /// Decimals for the specified token. + TokenDecimals(u8), + /// Whether the specified token exists. + TokenExists(bool), + } + + impl ReadResult { + /// Encodes the result. + pub fn encode(&self) -> Vec { + use ReadResult::*; + match self { + TotalSupply(result) => result.encode(), + BalanceOf(result) => result.encode(), + Allowance(result) => result.encode(), + TokenName(result) => result.encode(), + TokenSymbol(result) => result.encode(), + TokenDecimals(result) => result.encode(), + TokenExists(result) => result.encode(), + } + } + } + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config + pallet_assets::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The instance of pallet assets it is tightly coupled to. + type AssetsInstance; + /// Weight information for dispatchables in this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(_); + + /// The events that can be emitted. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Event emitted when allowance by `owner` to `spender` changes. + Approval { + /// The token. + token: TokenIdOf, + /// The owner providing the allowance. + owner: AccountIdOf, + /// The beneficiary of the allowance. + spender: AccountIdOf, + /// The new allowance amount. + value: BalanceOf, + }, + /// Event emitted when a token transfer occurs. + Transfer { + /// The token. + token: TokenIdOf, + /// The source of the transfer. `None` when minting. + from: Option>, + /// The recipient of the transfer. `None` when burning. + to: Option>, + /// The amount transferred (or minted/burned). + value: BalanceOf, + }, + /// Event emitted when an token is created. + Create { + /// The token identifier. + id: TokenIdOf, + /// The creator of the token. + creator: AccountIdOf, + /// The administrator of the token. + admin: AccountIdOf, + }, + } + + #[pallet::call] + impl Pallet { + /// Transfers `value` amount of tokens from the caller's account to account `to`. + /// + /// # Parameters + /// - `token` - The token to transfer. + /// - `to` - The recipient account. + /// - `value` - The number of tokens to transfer. + #[pallet::call_index(3)] + #[pallet::weight(AssetsWeightInfoOf::::transfer_keep_alive())] + pub fn transfer( + origin: OriginFor, + token: TokenIdOf, + to: AccountIdOf, + value: BalanceOf, + ) -> DispatchResult { + let from = ensure_signed(origin.clone())?; + AssetsOf::::transfer_keep_alive( + origin, + token.clone().into(), + T::Lookup::unlookup(to.clone()), + value, + )?; + Self::deposit_event(Event::Transfer { token, from: Some(from), to: Some(to), value }); + Ok(()) } - .encode(); - assert_eq!(latest_contract_event(), expected.as_slice()); - // Non-additive, sets new value. - assert_ok!(approve(addr.clone(), asset, BOB, amount / 2)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount / 2); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(ALICE, asset); - assert_eq!( - approve(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - }); -} - -#[test] -fn increase_allowance_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let amount: Balance = 100 * UNIT; - // Instantiate a contract without balance - test `ConsumerRemaining. - let addr = instantiate(CONTRACT, 0, vec![]); - // Asset does not exist. - assert_eq!( - increase_allowance(addr.clone(), 0, BOB, amount), - Err(Module { index: 52, error: [3, 0] }) - ); - let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount); - assert_eq!(increase_allowance(addr.clone(), asset, BOB, amount), Err(ConsumerRemaining)); - - // Instantiate a contract with balance. - let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); - // Create asset with Alice as owner and mint `amount` to contract address. - let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(ALICE, asset); - assert_eq!( - increase_allowance(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - thaw_asset(ALICE, asset); - // Successful approvals: - assert_eq!(0, Assets::allowance(asset, &addr, &BOB)); - assert_ok!(increase_allowance(addr.clone(), asset, BOB, amount)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount); - // Additive. - assert_ok!(increase_allowance(addr.clone(), asset, BOB, amount)); - assert_eq!(Assets::allowance(asset, &addr, &BOB), amount * 2); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(ALICE, asset); - assert_eq!( - increase_allowance(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - }); -} - -#[test] -fn decrease_allowance_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let amount: Balance = 100 * UNIT; - - // Asset does not exist. - assert_eq!( - decrease_allowance(addr.clone(), 0, BOB, amount), - Err(Module { index: 52, error: [3, 0] }), - ); - // Create asset and mint `amount` to contract address, then approve Bob to spend `amount`. - let asset = - create_asset_mint_and_approve(addr.clone(), 0, addr.clone(), amount, BOB, amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); - assert_eq!( - decrease_allowance(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }), - ); - thaw_asset(addr.clone(), asset); - // Successfully decrease allowance. - let allowance_before = Assets::allowance(asset, &addr, &BOB); - assert_ok!(decrease_allowance(addr.clone(), 0, BOB, amount / 2 - 1 * UNIT)); - let allowance_after = Assets::allowance(asset, &addr, &BOB); - assert_eq!(allowance_before - allowance_after, amount / 2 - 1 * UNIT); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); - assert_eq!( - decrease_allowance(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }), - ); - }); -} - -/// 2. PSP-22 Metadata Interface: -/// - token_name -/// - token_symbol -/// - token_decimals - -#[test] -fn token_metadata_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let name: Vec = vec![11, 12, 13]; - let symbol: Vec = vec![21, 22, 23]; - let decimals: u8 = 69; - - // Token does not exist. - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(token_name_asset(TOKEN_ID))); - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(Vec::::new())); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(token_symbol_asset(TOKEN_ID))); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(Vec::::new())); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(token_decimals_asset(TOKEN_ID))); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(0)); - // Create Token. - create_asset_and_set_metadata( - addr.clone(), - TOKEN_ID, - name.clone(), - symbol.clone(), - decimals, - ); - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(token_name_asset(TOKEN_ID))); - assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(name)); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(token_symbol_asset(TOKEN_ID))); - assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(symbol)); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(token_decimals_asset(TOKEN_ID))); - assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(decimals)); - }); -} - -/// 3. Asset Management: -/// - create -/// - start_destroy -/// - set_metadata -/// - clear_metadata -/// - token_exists - -#[test] -fn create_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - // Instantiate a contract without balance for fees. - let addr = instantiate(CONTRACT, 0, vec![0]); - // No balance to pay for fees. - assert_eq!( - create(addr.clone(), TOKEN_ID, addr.clone(), 1), - Err(Module { index: 10, error: [2, 0] }), - ); - - // Instantiate a contract without balance for deposit. - let addr = instantiate(CONTRACT, 100, vec![1]); - // No balance to pay the deposit. - assert_eq!( - create(addr.clone(), TOKEN_ID, addr.clone(), 1), - Err(Module { index: 10, error: [2, 0] }), - ); - - // Instantiate a contract with enough balance. - let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); - assert_eq!( - create(addr.clone(), TOKEN_ID, BOB, 0), - Err(Module { index: 52, error: [7, 0] }), - ); - // The minimal balance for an asset must be non zero. - assert_eq!( - create(addr.clone(), TOKEN_ID, BOB, 0), - Err(Module { index: 52, error: [7, 0] }), - ); - // Create asset successfully. - assert_ok!(create(addr.clone(), TOKEN_ID, BOB, 1)); - // Successfully emit an event from creating a new asset class. - let admin = account_id_from_slice(BOB.as_ref()); - let expected = Create { id: TOKEN_ID, creator: admin, admin }.encode(); - assert_eq!(latest_contract_event(), expected.as_slice()); - // Asset ID is already taken. - assert_eq!( - create(addr.clone(), TOKEN_ID, BOB, 1), - Err(Module { index: 52, error: [5, 0] }), - ); - }); -} - -// Testing a contract that creates an asset in the constructor. -#[test] -fn instantiate_and_create_fungible_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let contract = - "contracts/create_token_in_constructor/target/ink/create_token_in_constructor.wasm"; - // Asset already exists. - create_asset(ALICE, 0, 1); - assert_eq!( - instantiate_and_create_fungible(contract, 0, 1), - Err(Module { index: 52, error: [5, 0] }) - ); - // Successfully create an asset when instantiating the contract. - let instantiator = - instantiate_and_create_fungible(contract, TOKEN_ID, 1).expect("Should work"); - assert!(Assets::asset_exists(TOKEN_ID)); - // Successfully emit an event from instantiating a new fungible. - let instantiator = account_id_from_slice(instantiator.as_ref()); - let expected = - Create { id: ASSET_ID, creator: instantiator.clone(), admin: instantiator }.encode(); - assert_eq!(latest_contract_event(), expected.as_slice()); - }); -} - -#[test] -fn start_destroy_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); - // Asset does not exist. - assert_eq!(start_destroy(addr.clone(), TOKEN_ID), Err(Module { index: 52, error: [3, 0] }),); - // Create assets where contract is not the owner. - let asset = create_asset(ALICE, 0, 1); - // No Permission. - assert_eq!(start_destroy(addr.clone(), asset), Err(Module { index: 52, error: [2, 0] }),); - let asset = create_asset(addr.clone(), TOKEN_ID, 1); - assert_ok!(start_destroy(addr.clone(), asset)); - // Successfully emit an event from destroying an asset. - let expected = StartDestroy { id: ASSET_ID }.encode(); - assert_eq!(latest_contract_event(), expected.as_slice()); - }); -} + /// Transfers `value` amount tokens on behalf of `from` to account `to` with additional + /// `data` in unspecified format. + /// + /// # Parameters + /// - `token` - The token to transfer. + /// - `from` - The account from which the token balance will be withdrawn. + /// - `to` - The recipient account. + /// - `value` - The number of tokens to transfer. + #[pallet::call_index(4)] + #[pallet::weight(AssetsWeightInfoOf::::transfer_approved())] + pub fn transfer_from( + origin: OriginFor, + token: TokenIdOf, + from: AccountIdOf, + to: AccountIdOf, + value: BalanceOf, + ) -> DispatchResult { + AssetsOf::::transfer_approved( + origin, + token.clone().into(), + T::Lookup::unlookup(from.clone()), + T::Lookup::unlookup(to.clone()), + value, + )?; + Self::deposit_event(Event::Transfer { token, from: Some(from), to: Some(to), value }); + Ok(()) + } -#[test] -fn set_metadata_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let name = vec![42]; - let symbol = vec![42]; - let decimals = 42u8; - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + /// Approves `spender` to spend `value` amount of tokens on behalf of the caller. + /// + /// # Parameters + /// - `token` - The token to approve. + /// - `spender` - The account that is allowed to spend the tokens. + /// - `value` - The number of tokens to approve. + #[pallet::call_index(5)] + #[pallet::weight(::WeightInfo::approve(1, 1))] + pub fn approve( + origin: OriginFor, + token: TokenIdOf, + spender: AccountIdOf, + value: BalanceOf, + ) -> DispatchResultWithPostInfo { + let owner = ensure_signed(origin.clone()) + .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; + let current_allowance = AssetsOf::::allowance(token.clone(), &owner, &spender); + + let weight = match value.cmp(¤t_allowance) { + // If the new value is equal to the current allowance, do nothing. + Equal => Self::weight_approve(0, 0), + // If the new value is greater than the current allowance, approve the difference + // because `approve_transfer` works additively (see `pallet-assets`). + Greater => { + AssetsOf::::approve_transfer( + origin, + token.clone().into(), + T::Lookup::unlookup(spender.clone()), + value.saturating_sub(current_allowance), + ) + .map_err(|e| e.with_weight(Self::weight_approve(1, 0)))?; + Self::weight_approve(1, 0) + }, + // If the new value is less than the current allowance, cancel the approval and + // set the new value. + Less => { + let token_param: TokenIdParameterOf = token.clone().into(); + let spender_source = T::Lookup::unlookup(spender.clone()); + AssetsOf::::cancel_approval( + origin.clone(), + token_param.clone(), + spender_source.clone(), + ) + .map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?; + if value.is_zero() { + Self::weight_approve(0, 1) + } else { + AssetsOf::::approve_transfer( + origin, + token_param, + spender_source, + value, + )?; + Self::weight_approve(1, 1) + } + }, + }; + Self::deposit_event(Event::Approval { token, owner, spender, value }); + Ok(Some(weight).into()) + } - // Asset does not exist. - assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), - Err(Module { index: 52, error: [3, 0] }), - ); - // Create assets where contract is not the owner. - let asset = create_asset(ALICE, 0, 1); - // No Permission. - assert_eq!( - set_metadata(addr.clone(), asset, vec![0], vec![0], 0u8), - Err(Module { index: 52, error: [2, 0] }), - ); - let asset = create_asset(addr.clone(), TOKEN_ID, 1); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); - assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), - Err(Module { index: 52, error: [16, 0] }), - ); - thaw_asset(addr.clone(), asset); - // TODO: calling the below with a vector of length `100_000` errors in pallet contracts - // `OutputBufferTooSmall. Added to security analysis issue #131 to revisit. - // Set bad metadata - too large values. - assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0; 1000], vec![0; 1000], 0u8), - Err(Module { index: 52, error: [9, 0] }), - ); - // Set metadata successfully. - assert_ok!(set_metadata(addr.clone(), TOKEN_ID, name.clone(), symbol.clone(), decimals)); - // Successfully emit an event from set asset metadata. - let expected = SetMetadata { id: TOKEN_ID, name, symbol, decimals }.encode(); - assert_eq!(latest_contract_event(), expected.as_slice()); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); - assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0), - Err(Module { index: 52, error: [16, 0] }), - ); - }); -} + /// Increases the allowance of `spender` by `value` amount of tokens. + /// + /// # Parameters + /// - `token` - The token to have an allowance increased. + /// - `spender` - The account that is allowed to spend the tokens. + /// - `value` - The number of tokens to increase the allowance by. + #[pallet::call_index(6)] + #[pallet::weight(::WeightInfo::approve(1, 0))] + pub fn increase_allowance( + origin: OriginFor, + token: TokenIdOf, + spender: AccountIdOf, + value: BalanceOf, + ) -> DispatchResultWithPostInfo { + let owner = ensure_signed(origin.clone()) + .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; + AssetsOf::::approve_transfer( + origin, + token.clone().into(), + T::Lookup::unlookup(spender.clone()), + value, + ) + .map_err(|e| e.with_weight(AssetsWeightInfoOf::::approve_transfer()))?; + let value = AssetsOf::::allowance(token.clone(), &owner, &spender); + Self::deposit_event(Event::Approval { token, owner, spender, value }); + Ok(().into()) + } -#[test] -fn clear_metadata_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let name = vec![42]; - let symbol = vec![42]; - let decimals = 42u8; - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + /// Decreases the allowance of `spender` by `value` amount of tokens. + /// + /// # Parameters + /// - `token` - The token to have an allowance decreased. + /// - `spender` - The account that is allowed to spend the tokens. + /// - `value` - The number of tokens to decrease the allowance by. + #[pallet::call_index(7)] + #[pallet::weight(::WeightInfo::approve(1, 1))] + pub fn decrease_allowance( + origin: OriginFor, + token: TokenIdOf, + spender: AccountIdOf, + value: BalanceOf, + ) -> DispatchResultWithPostInfo { + let owner = ensure_signed(origin.clone()) + .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; + if value.is_zero() { + return Ok(Some(Self::weight_approve(0, 0)).into()); + } + let current_allowance = AssetsOf::::allowance(token.clone(), &owner, &spender); + let spender_source = T::Lookup::unlookup(spender.clone()); + let token_param: TokenIdParameterOf = token.clone().into(); + + // Cancel the approval and set the new value if `new_allowance` is more than zero. + AssetsOf::::cancel_approval( + origin.clone(), + token_param.clone(), + spender_source.clone(), + ) + .map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?; + let new_allowance = current_allowance.saturating_sub(value); + let weight = if new_allowance.is_zero() { + Self::weight_approve(0, 1) + } else { + AssetsOf::::approve_transfer( + origin, + token_param, + spender_source, + new_allowance, + )?; + Self::weight_approve(1, 1) + }; + Self::deposit_event(Event::Approval { token, owner, spender, value: new_allowance }); + Ok(Some(weight).into()) + } - // Asset does not exist. - assert_eq!(clear_metadata(addr.clone(), 0), Err(Module { index: 52, error: [3, 0] }),); - // Create assets where contract is not the owner. - let asset = create_asset_and_set_metadata(ALICE, 0, vec![0], vec![0], 0); - // No Permission. - assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [2, 0] }),); - let asset = create_asset(addr.clone(), TOKEN_ID, 1); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); - assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [16, 0] }),); - thaw_asset(addr.clone(), asset); - // No metadata set. - assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [3, 0] }),); - set_metadata_asset(addr.clone(), asset, name, symbol, decimals); - // Clear metadata successfully. - assert_ok!(clear_metadata(addr.clone(), TOKEN_ID)); - // Successfully emit an event from set asset metadata. - let expected = ClearMetadata { id: TOKEN_ID }.encode(); - assert_eq!(latest_contract_event(), expected.as_slice()); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); - assert_eq!( - set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], decimals), - Err(Module { index: 52, error: [16, 0] }), - ); - }); -} + /// Create a new token with a given identifier. + /// + /// # Parameters + /// - `id` - The identifier of the token. + /// - `admin` - The account that will administer the token. + /// - `min_balance` - The minimum balance required for accounts holding this token. + #[pallet::call_index(11)] + #[pallet::weight(AssetsWeightInfoOf::::create())] + pub fn create( + origin: OriginFor, + id: TokenIdOf, + admin: AccountIdOf, + min_balance: BalanceOf, + ) -> DispatchResult { + let creator = ensure_signed(origin.clone())?; + AssetsOf::::create( + origin, + id.clone().into(), + T::Lookup::unlookup(admin.clone()), + min_balance, + )?; + Self::deposit_event(Event::Create { id, creator, admin }); + Ok(()) + } -#[test] -fn token_exists_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + /// Start the process of destroying a token. + /// + /// # Parameters + /// - `token` - The token to be destroyed. + #[pallet::call_index(12)] + #[pallet::weight(AssetsWeightInfoOf::::start_destroy())] + pub fn start_destroy(origin: OriginFor, token: TokenIdOf) -> DispatchResult { + AssetsOf::::start_destroy(origin, token.into()) + } - // No tokens in circulation. - assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); + /// Set the metadata for a token. + /// + /// # Parameters + /// - `token`: The token to update. + /// - `name`: The user friendly name of this token. + /// - `symbol`: The exchange symbol for this token. + /// - `decimals`: The number of decimals this token uses to represent one unit. + #[pallet::call_index(16)] + #[pallet::weight(AssetsWeightInfoOf::::set_metadata(name.len() as u32, symbol.len() as u32))] + pub fn set_metadata( + origin: OriginFor, + token: TokenIdOf, + name: Vec, + symbol: Vec, + decimals: u8, + ) -> DispatchResult { + AssetsOf::::set_metadata(origin, token.into(), name, symbol, decimals) + } - // Tokens in circulation. - create_asset(addr.clone(), TOKEN_ID, 1); - assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); - }); -} + /// Clear the metadata for a token. + /// + /// # Parameters + /// - `token` - The token to update. + #[pallet::call_index(17)] + #[pallet::weight(AssetsWeightInfoOf::::clear_metadata())] + pub fn clear_metadata(origin: OriginFor, token: TokenIdOf) -> DispatchResult { + AssetsOf::::clear_metadata(origin, token.into()) + } -#[test] -fn mint_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let amount: Balance = 100 * UNIT; + /// Creates `value` amount of tokens and assigns them to `account`, increasing the total + /// supply. + /// + /// # Parameters + /// - `token` - The token to mint. + /// - `account` - The account to be credited with the created tokens. + /// - `value` - The number of tokens to mint. + #[pallet::call_index(19)] + #[pallet::weight(AssetsWeightInfoOf::::mint())] + pub fn mint( + origin: OriginFor, + token: TokenIdOf, + account: AccountIdOf, + value: BalanceOf, + ) -> DispatchResult { + AssetsOf::::mint( + origin, + token.clone().into(), + T::Lookup::unlookup(account.clone()), + value, + )?; + Self::deposit_event(Event::Transfer { token, from: None, to: Some(account), value }); + Ok(()) + } - // Asset does not exist. - assert_eq!(mint(addr.clone(), 1, BOB, amount), Err(Token(UnknownAsset))); - let asset = create_asset(ALICE, 1, 1); - // Minting can only be done by the owner. - assert_eq!(mint(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let asset = create_asset(addr.clone(), 2, 2); - // Minimum balance of an asset can not be zero. - assert_eq!(mint(addr.clone(), asset, BOB, 1), Err(Token(BelowMinimum))); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); - assert_eq!( - mint(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - thaw_asset(addr.clone(), asset); - // Successful mint. - let balance_before_mint = Assets::balance(asset, &BOB); - assert_ok!(mint(addr.clone(), asset, BOB, amount)); - let balance_after_mint = Assets::balance(asset, &BOB); - assert_eq!(balance_after_mint, balance_before_mint + amount); - // Account can not hold more tokens than Balance::MAX. - assert_eq!(mint(addr.clone(), asset, BOB, Balance::MAX,), Err(Arithmetic(Overflow))); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); - assert_eq!( - mint(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - }); -} + /// Destroys `value` amount of tokens from `account`, reducing the total supply. + /// + /// # Parameters + /// - `token` - the token to burn. + /// - `account` - The account from which the tokens will be destroyed. + /// - `value` - The number of tokens to destroy. + #[pallet::call_index(20)] + #[pallet::weight(AssetsWeightInfoOf::::burn())] + pub fn burn( + origin: OriginFor, + token: TokenIdOf, + account: AccountIdOf, + value: BalanceOf, + ) -> DispatchResult { + AssetsOf::::burn( + origin, + token.clone().into(), + T::Lookup::unlookup(account.clone()), + value, + )?; + Self::deposit_event(Event::Transfer { token, from: Some(account), to: None, value }); + Ok(()) + } + } -#[test] -fn burn_works() { - new_test_ext().execute_with(|| { - let _ = env_logger::try_init(); - let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); - let amount: Balance = 100 * UNIT; + impl Pallet { + fn weight_approve(approve: u32, cancel: u32) -> Weight { + ::WeightInfo::approve(cancel, approve) + } + } + + impl crate::Read for Pallet { + /// The type of read requested. + type Read = Read; + /// The type or result returned. + type Result = ReadResult; + + /// Determines the weight of the requested read, used to charge the appropriate weight + /// before the read is performed. + /// + /// # Parameters + /// - `request` - The read request. + fn weight(_request: &Self::Read) -> Weight { + // TODO: match on request and return benchmarked weight + T::DbWeight::get().reads(1_u64) + } - // Asset does not exist. - assert_eq!(burn(addr.clone(), 1, BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let asset = create_asset(ALICE, 1, 1); - // Bob has no tokens and thus pallet assets doesn't know the account. - assert_eq!(burn(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [1, 0] })); - // Burning can only be done by the manager. - mint_asset(ALICE, asset, BOB, amount); - assert_eq!(burn(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let asset = create_asset_and_mint_to(addr.clone(), 2, BOB, amount); - // Asset is not live, i.e. frozen or being destroyed. - freeze_asset(addr.clone(), asset); - assert_eq!( - burn(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [16, 0] }) - ); - thaw_asset(addr.clone(), asset); - // Successful mint. - let balance_before_burn = Assets::balance(asset, &BOB); - assert_ok!(burn(addr.clone(), asset, BOB, amount)); - let balance_after_burn = Assets::balance(asset, &BOB); - assert_eq!(balance_after_burn, balance_before_burn - amount); - // Asset is not live, i.e. frozen or being destroyed. - start_destroy_asset(addr.clone(), asset); - assert_eq!( - burn(addr.clone(), asset, BOB, amount), - Err(Module { index: 52, error: [17, 0] }) - ); - }); + /// Performs the requested read and returns the result. + /// + /// # Parameters + /// - `request` - The read request. + fn read(request: Self::Read) -> Self::Result { + use Read::*; + match request { + TotalSupply(token) => ReadResult::TotalSupply(AssetsOf::::total_supply(token)), + BalanceOf { token, owner } => { + ReadResult::BalanceOf(AssetsOf::::balance(token, owner)) + }, + Allowance { token, owner, spender } => { + ReadResult::Allowance(AssetsOf::::allowance(token, &owner, &spender)) + }, + TokenName(token) => ReadResult::TokenName( as MetadataInspect< + AccountIdOf, + >>::name(token)), + TokenSymbol(token) => ReadResult::TokenSymbol( as MetadataInspect< + AccountIdOf, + >>::symbol(token)), + TokenDecimals(token) => ReadResult::TokenDecimals( + as MetadataInspect>>::decimals(token), + ), + TokenExists(token) => ReadResult::TokenExists(AssetsOf::::asset_exists(token)), + } + } + } } From 1157f22d97a215d5f4b87c019f7cf62b2f0101da Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:29:41 +0700 Subject: [PATCH 14/29] fix: resolve conflict --- .../integration-tests/src/fungibles/mod.rs | 576 ++++++++++++++++++ 1 file changed, 576 insertions(+) diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 43a8aeab..c9860e7c 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -12,6 +12,582 @@ mod benchmarking; #[cfg(test)] mod tests; pub mod weights; +use pop_primitives::{ArithmeticError::*, Error::*, TokenError::*, TokenId, *}; +use utils::*; + +use super::*; + +mod utils; + +const TOKEN_ID: TokenId = 1; +const CONTRACT: &str = "contracts/fungibles/target/ink/fungibles.wasm"; + +/// 1. PSP-22 Interface: +/// - total_supply +/// - balance_of +/// - allowance +/// - transfer +/// - transfer_from +/// - approve +/// - increase_allowance +/// - decrease_allowance + +#[test] +fn total_supply_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // No tokens in circulation. + assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); + assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(0)); + + // Tokens in circulation. + create_asset_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); + assert_eq!(total_supply(addr.clone(), TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); + assert_eq!(total_supply(addr, TOKEN_ID), Ok(100)); + }); +} + +#[test] +fn balance_of_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // No tokens in circulation. + assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); + assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(0)); + + // Tokens in circulation. + create_asset_and_mint_to(addr.clone(), TOKEN_ID, BOB, 100); + assert_eq!(balance_of(addr.clone(), TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); + assert_eq!(balance_of(addr, TOKEN_ID, BOB), Ok(100)); + }); +} + +#[test] +fn allowance_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // No tokens in circulation. + assert_eq!( + allowance(addr.clone(), TOKEN_ID, BOB, ALICE), + Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) + ); + assert_eq!(allowance(addr.clone(), TOKEN_ID, BOB, ALICE), Ok(0)); + + // Tokens in circulation. + create_asset_mint_and_approve(addr.clone(), TOKEN_ID, BOB, 100, ALICE, 50); + assert_eq!( + allowance(addr.clone(), TOKEN_ID, BOB, ALICE), + Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) + ); + assert_eq!(allowance(addr, TOKEN_ID, BOB, ALICE), Ok(50)); + }); +} + +#[test] +fn transfer_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let amount: Balance = 100 * UNIT; + + // Asset does not exist. + assert_eq!( + transfer(addr.clone(), 1, BOB, amount), + Err(Module { index: 52, error: [3, 0] }) + ); + // Create asset with Alice as owner and mint `amount` to contract address. + let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(ALICE, asset); + assert_eq!( + transfer(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + thaw_asset(ALICE, asset); + // Not enough balance. + assert_eq!( + transfer(addr.clone(), asset, BOB, amount + 1 * UNIT), + Err(Module { index: 52, error: [0, 0] }) + ); + // Not enough balance due to ED. + assert_eq!( + transfer(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [0, 0] }) + ); + // Successful transfer. + let balance_before_transfer = Assets::balance(asset, &BOB); + assert_ok!(transfer(addr.clone(), asset, BOB, amount / 2)); + let balance_after_transfer = Assets::balance(asset, &BOB); + assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); + // Transfer asset to account that does not exist. + assert_eq!(transfer(addr.clone(), asset, FERDIE, amount / 4), Err(Token(CannotCreate))); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(ALICE, asset); + assert_eq!( + transfer(addr.clone(), asset, BOB, amount / 4), + Err(Module { index: 52, error: [16, 0] }) + ); + }); +} + +#[test] +fn transfer_from_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let amount: Balance = 100 * UNIT; + + // Asset does not exist. + assert_eq!( + transfer_from(addr.clone(), 1, ALICE, BOB, amount / 2), + Err(Module { index: 52, error: [3, 0] }), + ); + // Create asset with Alice as owner and mint `amount` to contract address. + let asset = create_asset_and_mint_to(ALICE, 1, ALICE, amount); + // Unapproved transfer. + assert_eq!( + transfer_from(addr.clone(), asset, ALICE, BOB, amount / 2), + Err(Module { index: 52, error: [10, 0] }) + ); + assert_ok!(Assets::approve_transfer( + RuntimeOrigin::signed(ALICE.into()), + asset.into(), + addr.clone().into(), + amount + 1 * UNIT, + )); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(ALICE, asset); + assert_eq!( + transfer_from(addr.clone(), asset, ALICE, BOB, amount), + Err(Module { index: 52, error: [16, 0] }), + ); + thaw_asset(ALICE, asset); + // Not enough balance. + assert_eq!( + transfer_from(addr.clone(), asset, ALICE, BOB, amount + 1 * UNIT), + Err(Module { index: 52, error: [0, 0] }), + ); + // Successful transfer. + let balance_before_transfer = Assets::balance(asset, &BOB); + assert_ok!(transfer_from(addr.clone(), asset, ALICE, BOB, amount / 2)); + let balance_after_transfer = Assets::balance(asset, &BOB); + assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); + }); +} + +#[test] +fn approve_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, 0, vec![]); + let amount: Balance = 100 * UNIT; + + // Asset does not exist. + assert_eq!(approve(addr.clone(), 0, BOB, amount), Err(Module { index: 52, error: [3, 0] })); + let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount); + assert_eq!(approve(addr.clone(), asset, BOB, amount), Err(ConsumerRemaining)); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); + // Create asset with Alice as owner and mint `amount` to contract address. + let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(ALICE, asset); + assert_eq!( + approve(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + thaw_asset(ALICE, asset); + // Successful approvals: + assert_eq!(0, Assets::allowance(asset, &addr, &BOB)); + assert_ok!(approve(addr.clone(), asset, BOB, amount)); + assert_eq!(Assets::allowance(asset, &addr, &BOB), amount); + // Non-additive, sets new value. + assert_ok!(approve(addr.clone(), asset, BOB, amount / 2)); + assert_eq!(Assets::allowance(asset, &addr, &BOB), amount / 2); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(ALICE, asset); + assert_eq!( + approve(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + }); +} + +#[test] +fn increase_allowance_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let amount: Balance = 100 * UNIT; + // Instantiate a contract without balance - test `ConsumerRemaining. + let addr = instantiate(CONTRACT, 0, vec![]); + // Asset does not exist. + assert_eq!( + increase_allowance(addr.clone(), 0, BOB, amount), + Err(Module { index: 52, error: [3, 0] }) + ); + let asset = create_asset_and_mint_to(ALICE, 0, addr.clone(), amount); + assert_eq!(increase_allowance(addr.clone(), asset, BOB, amount), Err(ConsumerRemaining)); + + // Instantiate a contract with balance. + let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); + // Create asset with Alice as owner and mint `amount` to contract address. + let asset = create_asset_and_mint_to(ALICE, 1, addr.clone(), amount); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(ALICE, asset); + assert_eq!( + increase_allowance(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + thaw_asset(ALICE, asset); + // Successful approvals: + assert_eq!(0, Assets::allowance(asset, &addr, &BOB)); + assert_ok!(increase_allowance(addr.clone(), asset, BOB, amount)); + assert_eq!(Assets::allowance(asset, &addr, &BOB), amount); + // Additive. + assert_ok!(increase_allowance(addr.clone(), asset, BOB, amount)); + assert_eq!(Assets::allowance(asset, &addr, &BOB), amount * 2); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(ALICE, asset); + assert_eq!( + increase_allowance(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + }); +} + +#[test] +fn decrease_allowance_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let amount: Balance = 100 * UNIT; + + // Asset does not exist. + assert_eq!( + decrease_allowance(addr.clone(), 0, BOB, amount), + Err(Module { index: 52, error: [3, 0] }), + ); + // Create asset and mint `amount` to contract address, then approve Bob to spend `amount`. + let asset = + create_asset_mint_and_approve(addr.clone(), 0, addr.clone(), amount, BOB, amount); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(addr.clone(), asset); + assert_eq!( + decrease_allowance(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }), + ); + thaw_asset(addr.clone(), asset); + // Successfully decrease allowance. + let allowance_before = Assets::allowance(asset, &addr, &BOB); + assert_ok!(decrease_allowance(addr.clone(), 0, BOB, amount / 2 - 1 * UNIT)); + let allowance_after = Assets::allowance(asset, &addr, &BOB); + assert_eq!(allowance_before - allowance_after, amount / 2 - 1 * UNIT); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(addr.clone(), asset); + assert_eq!( + decrease_allowance(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }), + ); + }); +} + +/// 2. PSP-22 Metadata Interface: +/// - token_name +/// - token_symbol +/// - token_decimals + +#[test] +fn token_metadata_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let name: Vec = vec![11, 12, 13]; + let symbol: Vec = vec![21, 22, 23]; + let decimals: u8 = 69; + + // Token does not exist. + assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(token_name_asset(TOKEN_ID))); + assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(Vec::::new())); + assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(token_symbol_asset(TOKEN_ID))); + assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(Vec::::new())); + assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(token_decimals_asset(TOKEN_ID))); + assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(0)); + // Create Token. + create_asset_and_set_metadata( + addr.clone(), + TOKEN_ID, + name.clone(), + symbol.clone(), + decimals, + ); + assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(token_name_asset(TOKEN_ID))); + assert_eq!(token_name(addr.clone(), TOKEN_ID), Ok(name)); + assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(token_symbol_asset(TOKEN_ID))); + assert_eq!(token_symbol(addr.clone(), TOKEN_ID), Ok(symbol)); + assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(token_decimals_asset(TOKEN_ID))); + assert_eq!(token_decimals(addr.clone(), TOKEN_ID), Ok(decimals)); + }); +} + +/// 3. Asset Management: +/// - create +/// - start_destroy +/// - set_metadata +/// - clear_metadata +/// - token_exists + +#[test] +fn create_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + // Instantiate a contract without balance for fees. + let addr = instantiate(CONTRACT, 0, vec![0]); + // No balance to pay for fees. + assert_eq!( + create(addr.clone(), TOKEN_ID, addr.clone(), 1), + Err(Module { index: 10, error: [2, 0] }), + ); + + // Instantiate a contract without balance for deposit. + let addr = instantiate(CONTRACT, 100, vec![1]); + // No balance to pay the deposit. + assert_eq!( + create(addr.clone(), TOKEN_ID, addr.clone(), 1), + Err(Module { index: 10, error: [2, 0] }), + ); + + // Instantiate a contract with enough balance. + let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); + assert_eq!( + create(addr.clone(), TOKEN_ID, BOB, 0), + Err(Module { index: 52, error: [7, 0] }), + ); + // The minimal balance for an asset must be non zero. + assert_eq!( + create(addr.clone(), TOKEN_ID, BOB, 0), + Err(Module { index: 52, error: [7, 0] }), + ); + // Create asset successfully. + assert_ok!(create(addr.clone(), TOKEN_ID, BOB, 1)); + // Asset ID is already taken. + assert_eq!( + create(addr.clone(), TOKEN_ID, BOB, 1), + Err(Module { index: 52, error: [5, 0] }), + ); + }); +} + +// Testing a contract that creates an asset in the constructor. +#[test] +fn instantiate_and_create_fungible_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let contract = + "contracts/create_token_in_constructor/target/ink/create_token_in_constructor.wasm"; + // Asset already exists. + create_asset(ALICE, 0, 1); + assert_eq!( + instantiate_and_create_fungible(contract, 0, 1), + Err(Module { index: 52, error: [5, 0] }) + ); + // Successfully create an asset when instantiating the contract. + assert_ok!(instantiate_and_create_fungible(contract, TOKEN_ID, 1)); + assert!(Assets::asset_exists(TOKEN_ID)); + }); +} + +#[test] +fn start_destroy_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![2]); + + // Asset does not exist. + assert_eq!(start_destroy(addr.clone(), TOKEN_ID), Err(Module { index: 52, error: [3, 0] }),); + // Create assets where contract is not the owner. + let asset = create_asset(ALICE, 0, 1); + // No Permission. + assert_eq!(start_destroy(addr.clone(), asset), Err(Module { index: 52, error: [2, 0] }),); + let asset = create_asset(addr.clone(), TOKEN_ID, 1); + assert_ok!(start_destroy(addr.clone(), asset)); + }); +} + +#[test] +fn set_metadata_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let name = vec![42]; + let symbol = vec![42]; + let decimals = 42u8; + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // Asset does not exist. + assert_eq!( + set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), + Err(Module { index: 52, error: [3, 0] }), + ); + // Create assets where contract is not the owner. + let asset = create_asset(ALICE, 0, 1); + // No Permission. + assert_eq!( + set_metadata(addr.clone(), asset, vec![0], vec![0], 0u8), + Err(Module { index: 52, error: [2, 0] }), + ); + let asset = create_asset(addr.clone(), TOKEN_ID, 1); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(addr.clone(), asset); + assert_eq!( + set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0u8), + Err(Module { index: 52, error: [16, 0] }), + ); + thaw_asset(addr.clone(), asset); + // TODO: calling the below with a vector of length `100_000` errors in pallet contracts + // `OutputBufferTooSmall. Added to security analysis issue #131 to revisit. + // Set bad metadata - too large values. + assert_eq!( + set_metadata(addr.clone(), TOKEN_ID, vec![0; 1000], vec![0; 1000], 0u8), + Err(Module { index: 52, error: [9, 0] }), + ); + // Set metadata successfully. + assert_ok!(set_metadata(addr.clone(), TOKEN_ID, name, symbol, decimals)); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(addr.clone(), asset); + assert_eq!( + set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], 0), + Err(Module { index: 52, error: [16, 0] }), + ); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let name = vec![42]; + let symbol = vec![42]; + let decimals = 42u8; + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // Asset does not exist. + assert_eq!(clear_metadata(addr.clone(), 0), Err(Module { index: 52, error: [3, 0] }),); + // Create assets where contract is not the owner. + let asset = create_asset_and_set_metadata(ALICE, 0, vec![0], vec![0], 0); + // No Permission. + assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [2, 0] }),); + let asset = create_asset(addr.clone(), TOKEN_ID, 1); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(addr.clone(), asset); + assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [16, 0] }),); + thaw_asset(addr.clone(), asset); + // No metadata set. + assert_eq!(clear_metadata(addr.clone(), asset), Err(Module { index: 52, error: [3, 0] }),); + set_metadata_asset(addr.clone(), asset, name, symbol, decimals); + // Clear metadata successfully. + assert_ok!(clear_metadata(addr.clone(), TOKEN_ID)); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(addr.clone(), asset); + assert_eq!( + set_metadata(addr.clone(), TOKEN_ID, vec![0], vec![0], decimals), + Err(Module { index: 52, error: [16, 0] }), + ); + }); +} + +#[test] +fn token_exists_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + + // No tokens in circulation. + assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); + + // Tokens in circulation. + create_asset(addr.clone(), TOKEN_ID, 1); + assert_eq!(token_exists(addr.clone(), TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); + }); +} + +#[test] +fn mint_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let amount: Balance = 100 * UNIT; + + // Asset does not exist. + assert_eq!(mint(addr.clone(), 1, BOB, amount), Err(Token(UnknownAsset))); + let asset = create_asset(ALICE, 1, 1); + // Minting can only be done by the owner. + assert_eq!(mint(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [2, 0] })); + let asset = create_asset(addr.clone(), 2, 2); + // Minimum balance of an asset can not be zero. + assert_eq!(mint(addr.clone(), asset, BOB, 1), Err(Token(BelowMinimum))); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(addr.clone(), asset); + assert_eq!( + mint(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + thaw_asset(addr.clone(), asset); + // Successful mint. + let balance_before_mint = Assets::balance(asset, &BOB); + assert_ok!(mint(addr.clone(), asset, BOB, amount)); + let balance_after_mint = Assets::balance(asset, &BOB); + assert_eq!(balance_after_mint, balance_before_mint + amount); + // Account can not hold more tokens than Balance::MAX. + assert_eq!(mint(addr.clone(), asset, BOB, Balance::MAX,), Err(Arithmetic(Overflow))); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(addr.clone(), asset); + assert_eq!( + mint(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + }); +} + +#[test] +fn burn_works() { + new_test_ext().execute_with(|| { + let _ = env_logger::try_init(); + let addr = instantiate(CONTRACT, INIT_VALUE, vec![]); + let amount: Balance = 100 * UNIT; + + // Asset does not exist. + assert_eq!(burn(addr.clone(), 1, BOB, amount), Err(Module { index: 52, error: [3, 0] })); + let asset = create_asset(ALICE, 1, 1); + // Bob has no tokens and thus pallet assets doesn't know the account. + assert_eq!(burn(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [1, 0] })); + // Burning can only be done by the manager. + mint_asset(ALICE, asset, BOB, amount); + assert_eq!(burn(addr.clone(), asset, BOB, 1), Err(Module { index: 52, error: [2, 0] })); + let asset = create_asset_and_mint_to(addr.clone(), 2, BOB, amount); + // Asset is not live, i.e. frozen or being destroyed. + freeze_asset(addr.clone(), asset); + assert_eq!( + burn(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [16, 0] }) + ); + thaw_asset(addr.clone(), asset); + // Successful mint. + let balance_before_burn = Assets::balance(asset, &BOB); + assert_ok!(burn(addr.clone(), asset, BOB, amount)); + let balance_after_burn = Assets::balance(asset, &BOB); + assert_eq!(balance_after_burn, balance_before_burn - amount); + // Asset is not live, i.e. frozen or being destroyed. + start_destroy_asset(addr.clone(), asset); + assert_eq!( + burn(addr.clone(), asset, BOB, amount), + Err(Module { index: 52, error: [17, 0] }) + ); + }); +} type AccountIdOf = ::AccountId; type TokenIdOf = > as Inspect< From 0122ad9dcc6cfbd813a5d1de428550486aa46f01 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 13 Sep 2024 09:22:50 +0200 Subject: [PATCH 15/29] refactor: example contract --- pop-api/examples/fungibles/lib.rs | 60 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/pop-api/examples/fungibles/lib.rs b/pop-api/examples/fungibles/lib.rs index 1f9200f4..11eafe21 100755 --- a/pop-api/examples/fungibles/lib.rs +++ b/pop-api/examples/fungibles/lib.rs @@ -2,7 +2,7 @@ use ink::prelude::vec::Vec; use pop_api::{ - assets::fungibles::{self as api}, + fungibles::{self as api}, primitives::TokenId, StatusCode, }; @@ -20,93 +20,89 @@ mod fungibles { impl Fungibles { #[ink(constructor, payable)] pub fn new() -> Self { - ink::env::debug_println!("PopApiFungiblesExample::new"); Default::default() } #[ink(message)] - pub fn total_supply(&self, id: TokenId) -> Result { - api::total_supply(id) + pub fn total_supply(&self, token: TokenId) -> Result { + api::total_supply(token) } #[ink(message)] - pub fn balance_of(&self, id: TokenId, owner: AccountId) -> Result { - api::balance_of(id, owner) + pub fn balance_of(&self, token: TokenId, owner: AccountId) -> Result { + api::balance_of(token, owner) } #[ink(message)] pub fn allowance( &self, - id: TokenId, + token: TokenId, owner: AccountId, spender: AccountId, ) -> Result { - api::allowance(id, owner, spender) + api::allowance(token, owner, spender) } #[ink(message)] - pub fn transfer(&mut self, id: TokenId, to: AccountId, value: Balance) -> Result<()> { - api::transfer(id, to, value) + pub fn transfer(&mut self, token: TokenId, to: AccountId, value: Balance) -> Result<()> { + api::transfer(token, to, value) } #[ink(message)] pub fn transfer_from( &mut self, - id: TokenId, + token: TokenId, from: AccountId, to: AccountId, value: Balance, _data: Vec, ) -> Result<()> { - api::transfer_from(id, from, to, value) + api::transfer_from(token, from, to, value) } #[ink(message)] - pub fn approve(&mut self, id: TokenId, spender: AccountId, value: Balance) -> Result<()> { - api::approve(id, spender, value) + pub fn approve( + &mut self, + token: TokenId, + spender: AccountId, + value: Balance, + ) -> Result<()> { + api::approve(token, spender, value) } #[ink(message)] pub fn increase_allowance( &mut self, - id: TokenId, + token: TokenId, spender: AccountId, value: Balance, ) -> Result<()> { - api::increase_allowance(id, spender, value) + api::increase_allowance(token, spender, value) } #[ink(message)] pub fn decrease_allowance( &mut self, - id: TokenId, + token: TokenId, spender: AccountId, value: Balance, ) -> Result<()> { - api::decrease_allowance(id, spender, value) + api::decrease_allowance(token, spender, value) } #[ink(message)] - pub fn token_name(&self, id: TokenId) -> Result> { - api::token_name(id) + pub fn token_name(&self, token: TokenId) -> Result> { + api::token_name(token) } #[ink(message)] - pub fn token_symbol(&self, id: TokenId) -> Result> { - api::token_symbol(id) + pub fn token_symbol(&self, token: TokenId) -> Result> { + api::token_symbol(token) } #[ink(message)] - pub fn token_decimals(&self, id: TokenId) -> Result { - api::token_decimals(id) + pub fn token_decimals(&self, token: TokenId) -> Result { + api::token_decimals(token) } } - - #[cfg(test)] - mod tests { - use super::*; - - #[ink::test] - fn default_works() {} - } } From a34a2baebef8d6e1b6a7591fe6412ba20c659a08 Mon Sep 17 00:00:00 2001 From: Daanvdplas Date: Fri, 13 Sep 2024 09:33:19 +0200 Subject: [PATCH 16/29] refactor: use assets module --- .../integration-tests/src/fungibles/mod.rs | 120 +++++---- .../integration-tests/src/fungibles/utils.rs | 235 +++++++++--------- 2 files changed, 179 insertions(+), 176 deletions(-) diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index caf4e159..1fb5ec19 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -28,7 +28,7 @@ fn total_supply_works() { assert_eq!(total_supply(&addr, TOKEN_ID), Ok(0)); // Tokens in circulation. - pallet_assets_create_and_mint_to(&addr, TOKEN_ID, &BOB, 100); + assets::create_and_mint_to(&addr, TOKEN_ID, &BOB, 100); assert_eq!(total_supply(&addr, TOKEN_ID), Ok(Assets::total_supply(TOKEN_ID))); assert_eq!(total_supply(&addr, TOKEN_ID), Ok(100)); }); @@ -44,7 +44,7 @@ fn balance_of_works() { assert_eq!(balance_of(&addr, TOKEN_ID, BOB), Ok(0)); // Tokens in circulation. - pallet_assets_create_and_mint_to(&addr, TOKEN_ID, &BOB, 100); + assets::create_and_mint_to(&addr, TOKEN_ID, &BOB, 100); assert_eq!(balance_of(&addr, TOKEN_ID, BOB), Ok(Assets::balance(TOKEN_ID, BOB))); assert_eq!(balance_of(&addr, TOKEN_ID, BOB), Ok(100)); }); @@ -63,7 +63,7 @@ fn allowance_works() { assert_eq!(allowance(&addr, TOKEN_ID, BOB, ALICE), Ok(0)); // Tokens in circulation. - pallet_assets_create_mint_and_approve(&addr, TOKEN_ID, &BOB, 100, &ALICE, 50); + assets::create_mint_and_approve(&addr, TOKEN_ID, &BOB, 100, &ALICE, 50); assert_eq!( allowance(&addr, TOKEN_ID, BOB, ALICE), Ok(Assets::allowance(TOKEN_ID, &BOB, &ALICE)) @@ -81,11 +81,11 @@ fn transfer_works() { // Token does not exist. assert_eq!(transfer(&addr, 1, BOB, amount), Err(Module { index: 52, error: [3, 0] })); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(&ALICE, 1, &addr, amount); + let token = assets::create_and_mint_to(&ALICE, 1, &addr, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&ALICE, token); + assets::freeze(&ALICE, token); assert_eq!(transfer(&addr, token, BOB, amount), Err(Module { index: 52, error: [16, 0] })); - pallet_assets_thaw(&ALICE, token); + assets::thaw(&ALICE, token); // Not enough balance. assert_eq!( transfer(&addr, token, BOB, amount + 1 * UNIT), @@ -101,7 +101,7 @@ fn transfer_works() { // Transfer token to account that does not exist. assert_eq!(transfer(&addr, token, FERDIE, amount / 4), Err(Token(CannotCreate))); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&ALICE, token); + assets::start_destroy(&ALICE, token); assert_eq!( transfer(&addr, token, BOB, amount / 4), Err(Module { index: 52, error: [16, 0] }) @@ -121,7 +121,7 @@ fn transfer_from_works() { Err(Module { index: 52, error: [3, 0] }), ); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(&ALICE, 1, &ALICE, amount); + let token = assets::create_and_mint_to(&ALICE, 1, &ALICE, amount); // Unapproved transfer. assert_eq!( transfer_from(&addr, token, ALICE, BOB, amount / 2), @@ -134,12 +134,12 @@ fn transfer_from_works() { amount + 1 * UNIT, )); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&ALICE, token); + assets::freeze(&ALICE, token); assert_eq!( transfer_from(&addr, token, ALICE, BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); - pallet_assets_thaw(&ALICE, token); + assets::thaw(&ALICE, token); // Not enough balance. assert_eq!( transfer_from(&addr, token, ALICE, BOB, amount + 1 * UNIT), @@ -161,15 +161,15 @@ fn approve_works() { // Token does not exist. assert_eq!(approve(&addr, 0, &BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let token = pallet_assets_create_and_mint_to(&ALICE, 0, &addr, amount); + let token = assets::create_and_mint_to(&ALICE, 0, &addr, amount); assert_eq!(approve(&addr, token, &BOB, amount), Err(ConsumerRemaining)); let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(&ALICE, 1, &addr, amount); + let token = assets::create_and_mint_to(&ALICE, 1, &addr, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&ALICE, token); + assets::freeze(&ALICE, token); assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); - pallet_assets_thaw(&ALICE, token); + assets::thaw(&ALICE, token); // Successful approvals: assert_eq!(0, Assets::allowance(token, &addr, &BOB)); assert_ok!(approve(&addr, token, &BOB, amount)); @@ -178,7 +178,7 @@ fn approve_works() { assert_ok!(approve(&addr, token, &BOB, amount / 2)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount / 2); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&ALICE, token); + assets::start_destroy(&ALICE, token); assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); }); } @@ -194,20 +194,20 @@ fn increase_allowance_works() { increase_allowance(&addr, 0, &BOB, amount), Err(Module { index: 52, error: [3, 0] }) ); - let token = pallet_assets_create_and_mint_to(&ALICE, 0, &addr, amount); + let token = assets::create_and_mint_to(&ALICE, 0, &addr, amount); assert_eq!(increase_allowance(&addr, token, &BOB, amount), Err(ConsumerRemaining)); // Instantiate a contract with balance. let addr = instantiate(CONTRACT, INIT_VALUE, vec![1]); // Create token with Alice as owner and mint `amount` to contract address. - let token = pallet_assets_create_and_mint_to(&ALICE, 1, &addr, amount); + let token = assets::create_and_mint_to(&ALICE, 1, &addr, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&ALICE, token); + assets::freeze(&ALICE, token); assert_eq!( increase_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }) ); - pallet_assets_thaw(&ALICE, token); + assets::thaw(&ALICE, token); // Successful approvals: assert_eq!(0, Assets::allowance(token, &addr, &BOB)); assert_ok!(increase_allowance(&addr, token, &BOB, amount)); @@ -216,7 +216,7 @@ fn increase_allowance_works() { assert_ok!(increase_allowance(&addr, token, &BOB, amount)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount * 2); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&ALICE, token); + assets::start_destroy(&ALICE, token); assert_eq!( increase_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }) @@ -236,21 +236,21 @@ fn decrease_allowance_works() { Err(Module { index: 52, error: [3, 0] }), ); // Create token and mint `amount` to contract address, then approve Bob to spend `amount`. - let token = pallet_assets_create_mint_and_approve(&addr, 0, &addr, amount, &BOB, amount); + let token = assets::create_mint_and_approve(&addr, 0, &addr, amount, &BOB, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&addr, token); + assets::freeze(&addr, token); assert_eq!( decrease_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }), ); - pallet_assets_thaw(&addr, token); + assets::thaw(&addr, token); // Successfully decrease allowance. let allowance_before = Assets::allowance(token, &addr, &BOB); assert_ok!(decrease_allowance(&addr, 0, &BOB, amount / 2 - 1 * UNIT)); let allowance_after = Assets::allowance(token, &addr, &BOB); assert_eq!(allowance_before - allowance_after, amount / 2 - 1 * UNIT); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&addr, token); + assets::start_destroy(&addr, token); assert_eq!( decrease_allowance(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] }), @@ -272,25 +272,19 @@ fn token_metadata_works() { let decimals: u8 = 69; // Token does not exist. - assert_eq!(token_name(&addr, TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); + assert_eq!(token_name(&addr, TOKEN_ID), Ok(assets::token_name(TOKEN_ID))); assert_eq!(token_name(&addr, TOKEN_ID), Ok(Vec::::new())); - assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); + assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(assets::token_symbol(TOKEN_ID))); assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(Vec::::new())); - assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(pallet_assets_token_decimals(TOKEN_ID))); + assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(assets::token_decimals(TOKEN_ID))); assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(0)); // Create Token. - pallet_assets_create_and_set_metadata( - &addr, - TOKEN_ID, - name.clone(), - symbol.clone(), - decimals, - ); - assert_eq!(token_name(&addr, TOKEN_ID), Ok(pallet_assets_token_name(TOKEN_ID))); + assets::create_and_set_metadata(&addr, TOKEN_ID, name.clone(), symbol.clone(), decimals); + assert_eq!(token_name(&addr, TOKEN_ID), Ok(assets::token_name(TOKEN_ID))); assert_eq!(token_name(&addr, TOKEN_ID), Ok(name)); - assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(pallet_assets_token_symbol(TOKEN_ID))); + assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(assets::token_symbol(TOKEN_ID))); assert_eq!(token_symbol(&addr, TOKEN_ID), Ok(symbol)); - assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(pallet_assets_token_decimals(TOKEN_ID))); + assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(assets::token_decimals(TOKEN_ID))); assert_eq!(token_decimals(&addr, TOKEN_ID), Ok(decimals)); }); } @@ -334,7 +328,7 @@ fn instantiate_and_create_fungible_works() { let contract = "contracts/create_token_in_constructor/target/ink/create_token_in_constructor.wasm"; // Token already exists. - pallet_assets_create(&ALICE, 0, 1); + assets::create(&ALICE, 0, 1); assert_eq!( instantiate_and_create_fungible(contract, 0, 1), Err(Module { index: 52, error: [5, 0] }) @@ -355,10 +349,10 @@ fn start_destroy_works() { // Token does not exist. assert_eq!(start_destroy(&addr, TOKEN_ID), Err(Module { index: 52, error: [3, 0] }),); // Create tokens where contract is not the owner. - let token = pallet_assets_create(&ALICE, 0, 1); + let token = assets::create(&ALICE, 0, 1); // No Permission. assert_eq!(start_destroy(&addr, token), Err(Module { index: 52, error: [2, 0] }),); - let token = pallet_assets_create(&addr, TOKEN_ID, 1); + let token = assets::create(&addr, TOKEN_ID, 1); assert_ok!(start_destroy(&addr, token)); }); } @@ -377,20 +371,20 @@ fn set_metadata_works() { Err(Module { index: 52, error: [3, 0] }), ); // Create token where contract is not the owner. - let token = pallet_assets_create(&ALICE, 0, 1); + let token = assets::create(&ALICE, 0, 1); // No Permission. assert_eq!( set_metadata(&addr, token, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [2, 0] }), ); - let token = pallet_assets_create(&addr, TOKEN_ID, 1); + let token = assets::create(&addr, TOKEN_ID, 1); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&addr, token); + assets::freeze(&addr, token); assert_eq!( set_metadata(&addr, TOKEN_ID, vec![0], vec![0], 0u8), Err(Module { index: 52, error: [16, 0] }), ); - pallet_assets_thaw(&addr, token); + assets::thaw(&addr, token); // TODO: calling the below with a vector of length `100_000` errors in pallet contracts // `OutputBufferTooSmall. Added to security analysis issue #131 to revisit. // Set bad metadata - too large values. @@ -401,7 +395,7 @@ fn set_metadata_works() { // Set metadata successfully. assert_ok!(set_metadata(&addr, TOKEN_ID, name, symbol, decimals)); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&addr, token); + assets::start_destroy(&addr, token); assert_eq!( set_metadata(&addr, TOKEN_ID, vec![0], vec![0], 0), Err(Module { index: 52, error: [16, 0] }), @@ -420,21 +414,21 @@ fn clear_metadata_works() { // Token does not exist. assert_eq!(clear_metadata(&addr, 0), Err(Module { index: 52, error: [3, 0] }),); // Create token where contract is not the owner. - let token = pallet_assets_create_and_set_metadata(&ALICE, 0, vec![0], vec![0], 0); + let token = assets::create_and_set_metadata(&ALICE, 0, vec![0], vec![0], 0); // No Permission. assert_eq!(clear_metadata(&addr, token), Err(Module { index: 52, error: [2, 0] }),); - let token = pallet_assets_create(&addr, TOKEN_ID, 1); + let token = assets::create(&addr, TOKEN_ID, 1); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&addr, token); + assets::freeze(&addr, token); assert_eq!(clear_metadata(&addr, token), Err(Module { index: 52, error: [16, 0] }),); - pallet_assets_thaw(&addr, token); + assets::thaw(&addr, token); // No metadata set. assert_eq!(clear_metadata(&addr, token), Err(Module { index: 52, error: [3, 0] }),); - pallet_assets_set_metadata(&addr, token, name, symbol, decimals); + assets::set_metadata(&addr, token, name, symbol, decimals); // Clear metadata successfully. assert_ok!(clear_metadata(&addr, TOKEN_ID)); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&addr, token); + assets::start_destroy(&addr, token); assert_eq!( set_metadata(&addr, TOKEN_ID, vec![0], vec![0], decimals), Err(Module { index: 52, error: [16, 0] }), @@ -451,7 +445,7 @@ fn token_exists_works() { assert_eq!(token_exists(&addr, TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); // Tokens in circulation. - pallet_assets_create(&addr, TOKEN_ID, 1); + assets::create(&addr, TOKEN_ID, 1); assert_eq!(token_exists(&addr, TOKEN_ID), Ok(Assets::asset_exists(TOKEN_ID))); }); } @@ -464,16 +458,16 @@ fn mint_works() { // Token does not exist. assert_eq!(mint(&addr, 1, &BOB, amount), Err(Token(UnknownAsset))); - let token = pallet_assets_create(&ALICE, 1, 1); + let token = assets::create(&ALICE, 1, 1); // Minting can only be done by the owner. assert_eq!(mint(&addr, token, &BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let token = pallet_assets_create(&addr, 2, 2); + let token = assets::create(&addr, 2, 2); // Minimum balance of a token can not be zero. assert_eq!(mint(&addr, token, &BOB, 1), Err(Token(BelowMinimum))); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&addr, token); + assets::freeze(&addr, token); assert_eq!(mint(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); - pallet_assets_thaw(&addr, token); + assets::thaw(&addr, token); // Successful mint. let balance_before_mint = Assets::balance(token, &BOB); assert_ok!(mint(&addr, token, &BOB, amount)); @@ -482,7 +476,7 @@ fn mint_works() { // Account can not hold more tokens than Balance::MAX. assert_eq!(mint(&addr, token, &BOB, Balance::MAX,), Err(Arithmetic(Overflow))); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&addr, token); + assets::start_destroy(&addr, token); assert_eq!(mint(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); }); } @@ -495,24 +489,24 @@ fn burn_works() { // Token does not exist. assert_eq!(burn(&addr, 1, &BOB, amount), Err(Module { index: 52, error: [3, 0] })); - let token = pallet_assets_create(&ALICE, 1, 1); + let token = assets::create(&ALICE, 1, 1); // Bob has no tokens and therefore doesn't exist. assert_eq!(burn(&addr, token, &BOB, 1), Err(Module { index: 52, error: [1, 0] })); // Burning can only be done by the manager. - pallet_assets_mint(&ALICE, token, &BOB, amount); + assets::mint(&ALICE, token, &BOB, amount); assert_eq!(burn(&addr, token, &BOB, 1), Err(Module { index: 52, error: [2, 0] })); - let token = pallet_assets_create_and_mint_to(&addr, 2, &BOB, amount); + let token = assets::create_and_mint_to(&addr, 2, &BOB, amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_freeze(&addr, token); + assets::freeze(&addr, token); assert_eq!(burn(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); - pallet_assets_thaw(&addr, token); + assets::thaw(&addr, token); // Successful mint. let balance_before_burn = Assets::balance(token, &BOB); assert_ok!(burn(&addr, token, &BOB, amount)); let balance_after_burn = Assets::balance(token, &BOB); assert_eq!(balance_after_burn, balance_before_burn - amount); // Token is not live, i.e. frozen or being destroyed. - pallet_assets_start_destroy(&addr, token); + assets::start_destroy(&addr, token); assert_eq!(burn(&addr, token, &BOB, amount), Err(Module { index: 52, error: [17, 0] })); }); } diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index d37271e5..0b24fe12 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -192,130 +192,139 @@ pub(super) fn burn( .unwrap_or_else(|_| panic!("Contract reverted: {:?}", result)) } -pub(super) fn pallet_assets_create( - owner: &AccountId32, - asset_id: AssetId, - min_balance: Balance, -) -> AssetId { - assert_ok!(Assets::create( - RuntimeOrigin::signed(owner.clone()), - asset_id.into(), - owner.clone().into(), - min_balance - )); - asset_id -} +// Helper functions for interacting with pallet-assets. +pub(super) mod assets { + use super::*; + pub(crate) fn create(owner: &AccountId32, asset_id: AssetId, min_balance: Balance) -> AssetId { + assert_ok!(Assets::create( + RuntimeOrigin::signed(owner.clone()), + asset_id.into(), + owner.clone().into(), + min_balance + )); + asset_id + } -pub(super) fn pallet_assets_mint( - owner: &AccountId32, - asset_id: AssetId, - to: &AccountId32, - value: Balance, -) -> AssetId { - assert_ok!(Assets::mint( - RuntimeOrigin::signed(owner.clone()), - asset_id.into(), - to.clone().into(), - value - )); - asset_id -} + pub(crate) fn mint( + owner: &AccountId32, + asset_id: AssetId, + to: &AccountId32, + value: Balance, + ) -> AssetId { + assert_ok!(Assets::mint( + RuntimeOrigin::signed(owner.clone()), + asset_id.into(), + to.clone().into(), + value + )); + asset_id + } -pub(super) fn pallet_assets_create_and_mint_to( - owner: &AccountId32, - asset_id: AssetId, - to: &AccountId32, - value: Balance, -) -> AssetId { - pallet_assets_create(owner, asset_id, 1); - pallet_assets_mint(owner, asset_id, to, value) -} + pub(crate) fn create_and_mint_to( + owner: &AccountId32, + asset_id: AssetId, + to: &AccountId32, + value: Balance, + ) -> AssetId { + create(owner, asset_id, 1); + mint(owner, asset_id, to, value) + } -// Create an asset, mints to, and approves spender. -pub(super) fn pallet_assets_create_mint_and_approve( - owner: &AccountId32, - asset_id: AssetId, - to: &AccountId32, - mint: Balance, - spender: &AccountId32, - approve: Balance, -) -> AssetId { - pallet_assets_create_and_mint_to(owner, asset_id, to, mint); - assert_ok!(Assets::approve_transfer( - RuntimeOrigin::signed(to.clone().into()), - asset_id.into(), - spender.clone().into(), - approve, - )); - asset_id -} + // Create an asset, mints to, and approves spender. + pub(crate) fn create_mint_and_approve( + owner: &AccountId32, + asset_id: AssetId, + to: &AccountId32, + mint: Balance, + spender: &AccountId32, + approve: Balance, + ) -> AssetId { + create_and_mint_to(owner, asset_id, to, mint); + assert_ok!(Assets::approve_transfer( + RuntimeOrigin::signed(to.clone().into()), + asset_id.into(), + spender.clone().into(), + approve, + )); + asset_id + } -// Freeze an asset. -pub(super) fn pallet_assets_freeze(owner: &AccountId32, asset_id: AssetId) { - assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(owner.clone().into()), asset_id.into())); -} + // Freeze an asset. + pub(crate) fn freeze(owner: &AccountId32, asset_id: AssetId) { + assert_ok!(Assets::freeze_asset( + RuntimeOrigin::signed(owner.clone().into()), + asset_id.into() + )); + } -// Thaw an asset. -pub(super) fn pallet_assets_thaw(owner: &AccountId32, asset_id: AssetId) { - assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(owner.clone().into()), asset_id.into())); -} + // Thaw an asset. + pub(crate) fn thaw(owner: &AccountId32, asset_id: AssetId) { + assert_ok!(Assets::thaw_asset( + RuntimeOrigin::signed(owner.clone().into()), + asset_id.into() + )); + } -// Start destroying an asset. -pub(super) fn pallet_assets_start_destroy(owner: &AccountId32, asset_id: AssetId) { - assert_ok!(Assets::start_destroy(RuntimeOrigin::signed(owner.clone().into()), asset_id.into())); -} + // Start destroying an asset. + pub(crate) fn start_destroy(owner: &AccountId32, asset_id: AssetId) { + assert_ok!(Assets::start_destroy( + RuntimeOrigin::signed(owner.clone().into()), + asset_id.into() + )); + } -// Create an asset and set metadata. -pub(super) fn pallet_assets_create_and_set_metadata( - owner: &AccountId32, - asset_id: AssetId, - name: Vec, - symbol: Vec, - decimals: u8, -) -> AssetId { - assert_ok!(Assets::create( - RuntimeOrigin::signed(owner.clone()), - asset_id.into(), - owner.clone().into(), - 100 - )); - pallet_assets_set_metadata(owner, asset_id, name, symbol, decimals); - asset_id -} + // Create an asset and set metadata. + pub(crate) fn create_and_set_metadata( + owner: &AccountId32, + asset_id: AssetId, + name: Vec, + symbol: Vec, + decimals: u8, + ) -> AssetId { + assert_ok!(Assets::create( + RuntimeOrigin::signed(owner.clone()), + asset_id.into(), + owner.clone().into(), + 100 + )); + set_metadata(owner, asset_id, name, symbol, decimals); + asset_id + } -// Set metadata of an asset. -pub(super) fn pallet_assets_set_metadata( - owner: &AccountId32, - asset_id: AssetId, - name: Vec, - symbol: Vec, - decimals: u8, -) { - assert_ok!(Assets::set_metadata( - RuntimeOrigin::signed(owner.clone().into()), - asset_id.into(), - name, - symbol, - decimals - )); -} + // Set metadata of an asset. + pub(crate) fn set_metadata( + owner: &AccountId32, + asset_id: AssetId, + name: Vec, + symbol: Vec, + decimals: u8, + ) { + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(owner.clone().into()), + asset_id.into(), + name, + symbol, + decimals + )); + } -pub(super) fn pallet_assets_token_name(asset_id: AssetId) -> Vec { - as MetadataInspect>::name( - asset_id, - ) -} + pub(crate) fn token_name(asset_id: AssetId) -> Vec { + as MetadataInspect< + AccountId32, + >>::name(asset_id) + } -pub(super) fn pallet_assets_token_symbol(asset_id: AssetId) -> Vec { - as MetadataInspect>::symbol( - asset_id, - ) -} + pub(crate) fn token_symbol(asset_id: AssetId) -> Vec { + as MetadataInspect< + AccountId32, + >>::symbol(asset_id) + } -pub(super) fn pallet_assets_token_decimals(asset_id: AssetId) -> u8 { - as MetadataInspect>::decimals( - asset_id, - ) + pub(crate) fn token_decimals(asset_id: AssetId) -> u8 { + as MetadataInspect< + AccountId32, + >>::decimals(asset_id) + } } pub(super) fn instantiate_and_create_fungible( From 9accd10d8e317d6b251fe0428a8d7da9ea81ab43 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:41:09 +0700 Subject: [PATCH 17/29] fix: update events --- pop-api/Cargo.toml | 2 +- pop-api/integration-tests/Cargo.toml | 9 +- .../create_token_in_constructor/lib.rs | 12 +- .../contracts/fungibles/lib.rs | 46 +- .../integration-tests/src/fungibles/mod.rs | 511 ------------------ .../integration-tests/src/fungibles/utils.rs | 4 +- pop-api/src/v0/fungibles.rs | 14 +- runtime/devnet/src/config/api/versioning.rs | 6 +- 8 files changed, 45 insertions(+), 559 deletions(-) diff --git a/pop-api/Cargo.toml b/pop-api/Cargo.toml index ae381d08..4caf8eaa 100644 --- a/pop-api/Cargo.toml +++ b/pop-api/Cargo.toml @@ -8,7 +8,7 @@ version = "0.0.0" [dependencies] ink = { version = "5.0.0", default-features = false } pop-primitives = { path = "../primitives", default-features = false } -sp-io = { version = "31.0.0", default-features = false, features = [ +sp-io = { version = "37.0.0", default-features = false, features = [ "disable_allocator", "disable_oom", "disable_panic_handler", diff --git a/pop-api/integration-tests/Cargo.toml b/pop-api/integration-tests/Cargo.toml index d801e8cf..ab739e9d 100644 --- a/pop-api/integration-tests/Cargo.toml +++ b/pop-api/integration-tests/Cargo.toml @@ -10,14 +10,14 @@ contract-build = "4.1.1" [dev-dependencies] env_logger = "0.11.2" frame-support = { version = "36.0.0", default-features = false } -frame-support-procedural = { version = "=30.0.1", default-features = false } +frame-support-procedural = { version = "30.0.1", default-features = false } frame-system = { version = "36.1.0", default-features = false } log = "0.4.22" pallet-assets = { version = "37.0.0", default-features = false } pallet-balances = { version = "37.0.0", default-features = false } pallet-contracts = { version = "35.0.0", default-features = false } pop-api = { path = "../../pop-api", default-features = false, features = [ - "fungibles", + "fungibles", ] } pop-primitives = { path = "../../primitives", default-features = false } pop-runtime-devnet = { path = "../../runtime/devnet", default-features = false } @@ -25,10 +25,7 @@ scale = { package = "parity-scale-codec", version = "3.6.12", default-features = "derive", ] } sp-io = { version = "37.0.0", default-features = false } -sp-runtime = { version = "=38.0.0", default-features = false } - -# TODO -ink = { version = "5.0.0", default-features = false } +sp-runtime = { version = "38.0.0", default-features = false } [features] default = [ "std" ] diff --git a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs index f2d5d369..3c2caac5 100755 --- a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs +++ b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] use pop_api::{ - assets::fungibles::{self as api, events::Create}, + fungibles::{self as api, events::Created}, primitives::TokenId, StatusCode, }; @@ -14,23 +14,23 @@ mod create_token_in_constructor { #[ink(storage)] pub struct Fungible { - id: TokenId, + token: TokenId, } impl Fungible { #[ink(constructor, payable)] - pub fn new(id: TokenId, min_balance: Balance) -> Result { - let contract = Self { id }; + pub fn new(token: TokenId, min_balance: Balance) -> Result { + let contract = Self { token }; // AccountId of the contract which will be set to the owner of the fungible token. let owner = contract.env().account_id(); api::create(id, owner, min_balance)?; - contract.env().emit_event(Create { id, creator: owner, admin: owner }); + contract.env().emit_event(Created { token, creator: owner, admin: owner }); Ok(contract) } #[ink(message)] pub fn token_exists(&self) -> Result { - api::token_exists(self.id) + api::token_exists(self.token) } } } diff --git a/pop-api/integration-tests/contracts/fungibles/lib.rs b/pop-api/integration-tests/contracts/fungibles/lib.rs index b9a895da..1db81eb5 100755 --- a/pop-api/integration-tests/contracts/fungibles/lib.rs +++ b/pop-api/integration-tests/contracts/fungibles/lib.rs @@ -8,7 +8,7 @@ use ink::prelude::vec::Vec; use pop_api::{ fungibles::{ self as api, - events::{Approval, ClearMetadata, Create, SetMetadata, StartDestroy, Transfer}, + events::{Approved, Created, Destroyed, MetadataCleared, MetadataSet, Transferred}, }, primitives::TokenId, StatusCode, @@ -63,13 +63,13 @@ mod fungibles { #[ink(message)] pub fn transfer(&mut self, token: TokenId, to: AccountId, value: Balance) -> Result<()> { - let result = api::transfer(token, to, value); - self.env().emit_event(Transfer { + api::transfer(token, to, value)?; + self.env().emit_event(Transferred { from: Some(self.env().account_id()), to: Some(to), value, }); - result + Ok(()) } #[ink(message)] @@ -82,9 +82,9 @@ mod fungibles { // In the PSP-22 standard a `[u8]`, but the size needs to be known at compile time. _data: Vec, ) -> Result<()> { - let result = api::transfer_from(token, from, to, value); - self.env().emit_event(Transfer { from: Some(from), to: Some(to), value }); - result + api::transfer_from(token, from, to, value)?; + self.env().emit_event(Transferred { from: Some(from), to: Some(to), value }); + Ok(()) } #[ink(message)] @@ -94,10 +94,10 @@ mod fungibles { spender: AccountId, value: Balance, ) -> Result<()> { - let result = api::approve(token, spender, value); + api::approve(token, spender, value)?; self.env() - .emit_event(Approval { owner: self.env().account_id(), spender, value }); - result + .emit_event(Approved { owner: self.env().account_id(), spender, value }); + Ok(()) } #[ink(message)] @@ -150,20 +150,20 @@ mod fungibles { #[ink(message)] pub fn create( &mut self, - id: TokenId, + token: TokenId, admin: AccountId, min_balance: Balance, ) -> Result<()> { - let result = api::create(id, admin, min_balance); - self.env().emit_event(Create { id, creator: admin, admin }); - result + api::create(token, admin, min_balance)?; + self.env().emit_event(Created { token, creator: admin, admin }); + Ok(()) } #[ink(message)] pub fn start_destroy(&mut self, token: AssetId) -> Result<()> { - let result = api::start_destroy(token); - self.env().emit_event(StartDestroy { id: token }); - result + api::start_destroy(token)?; + self.env().emit_event(Destroyed { token }); + Ok(()) } #[ink(message)] @@ -174,16 +174,16 @@ mod fungibles { symbol: Vec, decimals: u8, ) -> Result<()> { - let result = api::set_metadata(token, name.clone(), symbol.clone(), decimals); - self.env().emit_event(SetMetadata { id: token, name, symbol, decimals }); - result + api::set_metadata(token, name.clone(), symbol.clone(), decimals)?; + self.env().emit_event(MetadataSet { token, name, symbol, decimals }); + Ok(()) } #[ink(message)] pub fn clear_metadata(&mut self, token: AssetId) -> Result<()> { - let result = api::clear_metadata(token); - self.env().emit_event(ClearMetadata { id: token }); - result + api::clear_metadata(token)?; + self.env().emit_event(MetadataCleared { token }); + Ok(()) } #[ink(message)] diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index c9860e7c..43f7de8f 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -588,514 +588,3 @@ fn burn_works() { ); }); } - -type AccountIdOf = ::AccountId; -type TokenIdOf = > as Inspect< - ::AccountId, ->>::AssetId; -type TokenIdParameterOf = >>::AssetIdParameter; -type AssetsOf = pallet_assets::Pallet>; -type AssetsInstanceOf = ::AssetsInstance; -type AssetsWeightInfoOf = >>::WeightInfo; -type BalanceOf = > as Inspect< - ::AccountId, ->>::Balance; - -#[frame_support::pallet] -pub mod pallet { - use core::cmp::Ordering::*; - - use frame_support::{ - dispatch::{DispatchResult, DispatchResultWithPostInfo, WithPostDispatchInfo}, - pallet_prelude::*, - traits::fungibles::approvals::Inspect as ApprovalInspect, - }; - use frame_system::pallet_prelude::*; - use sp_runtime::{ - traits::{StaticLookup, Zero}, - Saturating, - }; - use sp_std::vec::Vec; - - use super::*; - - /// State reads for the fungibles API with required input. - #[derive(Encode, Decode, Debug, MaxEncodedLen)] - #[repr(u8)] - #[allow(clippy::unnecessary_cast)] - pub enum Read { - /// Total token supply for a specified token. - #[codec(index = 0)] - TotalSupply(TokenIdOf), - /// Account balance for a specified `token` and `owner`. - #[codec(index = 1)] - BalanceOf { - /// The token. - token: TokenIdOf, - /// The owner of the token. - owner: AccountIdOf, - }, - /// Allowance for a `spender` approved by an `owner`, for a specified `token`. - #[codec(index = 2)] - Allowance { - /// The token. - token: TokenIdOf, - /// The owner of the token. - owner: AccountIdOf, - /// The spender with an allowance. - spender: AccountIdOf, - }, - /// Name of the specified token. - #[codec(index = 8)] - TokenName(TokenIdOf), - /// Symbol for the specified token. - #[codec(index = 9)] - TokenSymbol(TokenIdOf), - /// Decimals for the specified token. - #[codec(index = 10)] - TokenDecimals(TokenIdOf), - /// Check if a specified token exists. - #[codec(index = 18)] - TokenExists(TokenIdOf), - } - - /// Results of state reads for the fungibles API. - #[derive(Debug)] - pub enum ReadResult { - /// Total token supply for a specified token. - TotalSupply(BalanceOf), - /// Account balance for a specified token and owner. - BalanceOf(BalanceOf), - /// Allowance for a spender approved by an owner, for a specified token. - Allowance(BalanceOf), - /// Name of the specified token. - TokenName(Vec), - /// Symbol for the specified token. - TokenSymbol(Vec), - /// Decimals for the specified token. - TokenDecimals(u8), - /// Whether the specified token exists. - TokenExists(bool), - } - - impl ReadResult { - /// Encodes the result. - pub fn encode(&self) -> Vec { - use ReadResult::*; - match self { - TotalSupply(result) => result.encode(), - BalanceOf(result) => result.encode(), - Allowance(result) => result.encode(), - TokenName(result) => result.encode(), - TokenSymbol(result) => result.encode(), - TokenDecimals(result) => result.encode(), - TokenExists(result) => result.encode(), - } - } - } - - /// Configure the pallet by specifying the parameters and types on which it depends. - #[pallet::config] - pub trait Config: frame_system::Config + pallet_assets::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The instance of pallet assets it is tightly coupled to. - type AssetsInstance; - /// Weight information for dispatchables in this pallet. - type WeightInfo: WeightInfo; - } - - #[pallet::pallet] - pub struct Pallet(_); - - /// The events that can be emitted. - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// Event emitted when allowance by `owner` to `spender` changes. - Approval { - /// The token. - token: TokenIdOf, - /// The owner providing the allowance. - owner: AccountIdOf, - /// The beneficiary of the allowance. - spender: AccountIdOf, - /// The new allowance amount. - value: BalanceOf, - }, - /// Event emitted when a token transfer occurs. - Transfer { - /// The token. - token: TokenIdOf, - /// The source of the transfer. `None` when minting. - from: Option>, - /// The recipient of the transfer. `None` when burning. - to: Option>, - /// The amount transferred (or minted/burned). - value: BalanceOf, - }, - /// Event emitted when an token is created. - Create { - /// The token identifier. - id: TokenIdOf, - /// The creator of the token. - creator: AccountIdOf, - /// The administrator of the token. - admin: AccountIdOf, - }, - } - - #[pallet::call] - impl Pallet { - /// Transfers `value` amount of tokens from the caller's account to account `to`. - /// - /// # Parameters - /// - `token` - The token to transfer. - /// - `to` - The recipient account. - /// - `value` - The number of tokens to transfer. - #[pallet::call_index(3)] - #[pallet::weight(AssetsWeightInfoOf::::transfer_keep_alive())] - pub fn transfer( - origin: OriginFor, - token: TokenIdOf, - to: AccountIdOf, - value: BalanceOf, - ) -> DispatchResult { - let from = ensure_signed(origin.clone())?; - AssetsOf::::transfer_keep_alive( - origin, - token.clone().into(), - T::Lookup::unlookup(to.clone()), - value, - )?; - Self::deposit_event(Event::Transfer { token, from: Some(from), to: Some(to), value }); - Ok(()) - } - - /// Transfers `value` amount tokens on behalf of `from` to account `to` with additional - /// `data` in unspecified format. - /// - /// # Parameters - /// - `token` - The token to transfer. - /// - `from` - The account from which the token balance will be withdrawn. - /// - `to` - The recipient account. - /// - `value` - The number of tokens to transfer. - #[pallet::call_index(4)] - #[pallet::weight(AssetsWeightInfoOf::::transfer_approved())] - pub fn transfer_from( - origin: OriginFor, - token: TokenIdOf, - from: AccountIdOf, - to: AccountIdOf, - value: BalanceOf, - ) -> DispatchResult { - AssetsOf::::transfer_approved( - origin, - token.clone().into(), - T::Lookup::unlookup(from.clone()), - T::Lookup::unlookup(to.clone()), - value, - )?; - Self::deposit_event(Event::Transfer { token, from: Some(from), to: Some(to), value }); - Ok(()) - } - - /// Approves `spender` to spend `value` amount of tokens on behalf of the caller. - /// - /// # Parameters - /// - `token` - The token to approve. - /// - `spender` - The account that is allowed to spend the tokens. - /// - `value` - The number of tokens to approve. - #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::approve(1, 1))] - pub fn approve( - origin: OriginFor, - token: TokenIdOf, - spender: AccountIdOf, - value: BalanceOf, - ) -> DispatchResultWithPostInfo { - let owner = ensure_signed(origin.clone()) - .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; - let current_allowance = AssetsOf::::allowance(token.clone(), &owner, &spender); - - let weight = match value.cmp(¤t_allowance) { - // If the new value is equal to the current allowance, do nothing. - Equal => Self::weight_approve(0, 0), - // If the new value is greater than the current allowance, approve the difference - // because `approve_transfer` works additively (see `pallet-assets`). - Greater => { - AssetsOf::::approve_transfer( - origin, - token.clone().into(), - T::Lookup::unlookup(spender.clone()), - value.saturating_sub(current_allowance), - ) - .map_err(|e| e.with_weight(Self::weight_approve(1, 0)))?; - Self::weight_approve(1, 0) - }, - // If the new value is less than the current allowance, cancel the approval and - // set the new value. - Less => { - let token_param: TokenIdParameterOf = token.clone().into(); - let spender_source = T::Lookup::unlookup(spender.clone()); - AssetsOf::::cancel_approval( - origin.clone(), - token_param.clone(), - spender_source.clone(), - ) - .map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?; - if value.is_zero() { - Self::weight_approve(0, 1) - } else { - AssetsOf::::approve_transfer( - origin, - token_param, - spender_source, - value, - )?; - Self::weight_approve(1, 1) - } - }, - }; - Self::deposit_event(Event::Approval { token, owner, spender, value }); - Ok(Some(weight).into()) - } - - /// Increases the allowance of `spender` by `value` amount of tokens. - /// - /// # Parameters - /// - `token` - The token to have an allowance increased. - /// - `spender` - The account that is allowed to spend the tokens. - /// - `value` - The number of tokens to increase the allowance by. - #[pallet::call_index(6)] - #[pallet::weight(::WeightInfo::approve(1, 0))] - pub fn increase_allowance( - origin: OriginFor, - token: TokenIdOf, - spender: AccountIdOf, - value: BalanceOf, - ) -> DispatchResultWithPostInfo { - let owner = ensure_signed(origin.clone()) - .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; - AssetsOf::::approve_transfer( - origin, - token.clone().into(), - T::Lookup::unlookup(spender.clone()), - value, - ) - .map_err(|e| e.with_weight(AssetsWeightInfoOf::::approve_transfer()))?; - let value = AssetsOf::::allowance(token.clone(), &owner, &spender); - Self::deposit_event(Event::Approval { token, owner, spender, value }); - Ok(().into()) - } - - /// Decreases the allowance of `spender` by `value` amount of tokens. - /// - /// # Parameters - /// - `token` - The token to have an allowance decreased. - /// - `spender` - The account that is allowed to spend the tokens. - /// - `value` - The number of tokens to decrease the allowance by. - #[pallet::call_index(7)] - #[pallet::weight(::WeightInfo::approve(1, 1))] - pub fn decrease_allowance( - origin: OriginFor, - token: TokenIdOf, - spender: AccountIdOf, - value: BalanceOf, - ) -> DispatchResultWithPostInfo { - let owner = ensure_signed(origin.clone()) - .map_err(|e| e.with_weight(Self::weight_approve(0, 0)))?; - if value.is_zero() { - return Ok(Some(Self::weight_approve(0, 0)).into()); - } - let current_allowance = AssetsOf::::allowance(token.clone(), &owner, &spender); - let spender_source = T::Lookup::unlookup(spender.clone()); - let token_param: TokenIdParameterOf = token.clone().into(); - - // Cancel the approval and set the new value if `new_allowance` is more than zero. - AssetsOf::::cancel_approval( - origin.clone(), - token_param.clone(), - spender_source.clone(), - ) - .map_err(|e| e.with_weight(Self::weight_approve(0, 1)))?; - let new_allowance = current_allowance.saturating_sub(value); - let weight = if new_allowance.is_zero() { - Self::weight_approve(0, 1) - } else { - AssetsOf::::approve_transfer( - origin, - token_param, - spender_source, - new_allowance, - )?; - Self::weight_approve(1, 1) - }; - Self::deposit_event(Event::Approval { token, owner, spender, value: new_allowance }); - Ok(Some(weight).into()) - } - - /// Create a new token with a given identifier. - /// - /// # Parameters - /// - `id` - The identifier of the token. - /// - `admin` - The account that will administer the token. - /// - `min_balance` - The minimum balance required for accounts holding this token. - #[pallet::call_index(11)] - #[pallet::weight(AssetsWeightInfoOf::::create())] - pub fn create( - origin: OriginFor, - id: TokenIdOf, - admin: AccountIdOf, - min_balance: BalanceOf, - ) -> DispatchResult { - let creator = ensure_signed(origin.clone())?; - AssetsOf::::create( - origin, - id.clone().into(), - T::Lookup::unlookup(admin.clone()), - min_balance, - )?; - Self::deposit_event(Event::Create { id, creator, admin }); - Ok(()) - } - - /// Start the process of destroying a token. - /// - /// # Parameters - /// - `token` - The token to be destroyed. - #[pallet::call_index(12)] - #[pallet::weight(AssetsWeightInfoOf::::start_destroy())] - pub fn start_destroy(origin: OriginFor, token: TokenIdOf) -> DispatchResult { - AssetsOf::::start_destroy(origin, token.into()) - } - - /// Set the metadata for a token. - /// - /// # Parameters - /// - `token`: The token to update. - /// - `name`: The user friendly name of this token. - /// - `symbol`: The exchange symbol for this token. - /// - `decimals`: The number of decimals this token uses to represent one unit. - #[pallet::call_index(16)] - #[pallet::weight(AssetsWeightInfoOf::::set_metadata(name.len() as u32, symbol.len() as u32))] - pub fn set_metadata( - origin: OriginFor, - token: TokenIdOf, - name: Vec, - symbol: Vec, - decimals: u8, - ) -> DispatchResult { - AssetsOf::::set_metadata(origin, token.into(), name, symbol, decimals) - } - - /// Clear the metadata for a token. - /// - /// # Parameters - /// - `token` - The token to update. - #[pallet::call_index(17)] - #[pallet::weight(AssetsWeightInfoOf::::clear_metadata())] - pub fn clear_metadata(origin: OriginFor, token: TokenIdOf) -> DispatchResult { - AssetsOf::::clear_metadata(origin, token.into()) - } - - /// Creates `value` amount of tokens and assigns them to `account`, increasing the total - /// supply. - /// - /// # Parameters - /// - `token` - The token to mint. - /// - `account` - The account to be credited with the created tokens. - /// - `value` - The number of tokens to mint. - #[pallet::call_index(19)] - #[pallet::weight(AssetsWeightInfoOf::::mint())] - pub fn mint( - origin: OriginFor, - token: TokenIdOf, - account: AccountIdOf, - value: BalanceOf, - ) -> DispatchResult { - AssetsOf::::mint( - origin, - token.clone().into(), - T::Lookup::unlookup(account.clone()), - value, - )?; - Self::deposit_event(Event::Transfer { token, from: None, to: Some(account), value }); - Ok(()) - } - - /// Destroys `value` amount of tokens from `account`, reducing the total supply. - /// - /// # Parameters - /// - `token` - the token to burn. - /// - `account` - The account from which the tokens will be destroyed. - /// - `value` - The number of tokens to destroy. - #[pallet::call_index(20)] - #[pallet::weight(AssetsWeightInfoOf::::burn())] - pub fn burn( - origin: OriginFor, - token: TokenIdOf, - account: AccountIdOf, - value: BalanceOf, - ) -> DispatchResult { - AssetsOf::::burn( - origin, - token.clone().into(), - T::Lookup::unlookup(account.clone()), - value, - )?; - Self::deposit_event(Event::Transfer { token, from: Some(account), to: None, value }); - Ok(()) - } - } - - impl Pallet { - fn weight_approve(approve: u32, cancel: u32) -> Weight { - ::WeightInfo::approve(cancel, approve) - } - } - - impl crate::Read for Pallet { - /// The type of read requested. - type Read = Read; - /// The type or result returned. - type Result = ReadResult; - - /// Determines the weight of the requested read, used to charge the appropriate weight - /// before the read is performed. - /// - /// # Parameters - /// - `request` - The read request. - fn weight(_request: &Self::Read) -> Weight { - // TODO: match on request and return benchmarked weight - T::DbWeight::get().reads(1_u64) - } - - /// Performs the requested read and returns the result. - /// - /// # Parameters - /// - `request` - The read request. - fn read(request: Self::Read) -> Self::Result { - use Read::*; - match request { - TotalSupply(token) => ReadResult::TotalSupply(AssetsOf::::total_supply(token)), - BalanceOf { token, owner } => { - ReadResult::BalanceOf(AssetsOf::::balance(token, owner)) - }, - Allowance { token, owner, spender } => { - ReadResult::Allowance(AssetsOf::::allowance(token, &owner, &spender)) - }, - TokenName(token) => ReadResult::TokenName( as MetadataInspect< - AccountIdOf, - >>::name(token)), - TokenSymbol(token) => ReadResult::TokenSymbol( as MetadataInspect< - AccountIdOf, - >>::symbol(token)), - TokenDecimals(token) => ReadResult::TokenDecimals( - as MetadataInspect>>::decimals(token), - ), - TokenExists(token) => ReadResult::TokenExists(AssetsOf::::asset_exists(token)), - } - } - } -} diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 76867e73..665f8f35 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -342,8 +342,8 @@ pub(super) fn instantiate_and_create_fungible( } } -/// Get the latest event from pallet contracts. -pub(super) fn latest_contract_event() -> Vec { +/// Get the last event from pallet contracts. +pub(super) fn last_contract_event() -> Vec { let events = System::read_events_for_pallet::>(); let contract_events = events .iter() diff --git a/pop-api/src/v0/fungibles.rs b/pop-api/src/v0/fungibles.rs index 5c9b9a30..404bf9c8 100644 --- a/pop-api/src/v0/fungibles.rs +++ b/pop-api/src/v0/fungibles.rs @@ -75,7 +75,7 @@ pub mod events { /// Event emitted when allowance by `owner` to `spender` changes. #[ink::event] - pub struct Approval { + pub struct Approved { /// The owner providing the allowance. #[ink(topic)] pub owner: AccountId, @@ -88,7 +88,7 @@ pub mod events { /// Event emitted when transfer of tokens occurs. #[ink::event] - pub struct Transfer { + pub struct Transferred { /// The source of the transfer. `None` when minting. #[ink(topic)] pub from: Option, @@ -101,10 +101,10 @@ pub mod events { /// Event emitted when an token is created. #[ink::event] - pub struct Create { + pub struct Created { /// The token identifier. #[ink(topic)] - pub id: TokenId, + pub token: TokenId, /// The creator of the token. #[ink(topic)] pub creator: AccountId, @@ -115,7 +115,7 @@ pub mod events { /// Event emitted when a token is in the process of being destroyed. #[ink::event] - pub struct StartDestroy { + pub struct Destroyed { /// The token. #[ink(topic)] pub token: TokenId, @@ -123,7 +123,7 @@ pub mod events { /// Event emitted when new metadata is set for a token. #[ink::event] - pub struct SetMetadata { + pub struct MetadataSet { /// The token. #[ink(topic)] pub token: TokenId, @@ -139,7 +139,7 @@ pub mod events { /// Event emitted when metadata is cleared for a token. #[ink::event] - pub struct ClearMetadata { + pub struct MetadataCleared { /// The token. #[ink(topic)] pub token: TokenId, diff --git a/runtime/devnet/src/config/api/versioning.rs b/runtime/devnet/src/config/api/versioning.rs index 2f3d240f..bc2a73e3 100644 --- a/runtime/devnet/src/config/api/versioning.rs +++ b/runtime/devnet/src/config/api/versioning.rs @@ -114,9 +114,9 @@ impl From for V0Error { // Note: message not used let ModuleError { index, error, message: _message } = error; // Map `pallet-contracts::Error::DecodingFailed` to `Error::DecodingFailed` - if index as usize == - ::index() && - error == DECODING_FAILED_ERROR + if index as usize + == ::index() + && error == DECODING_FAILED_ERROR { Error::DecodingFailed } else { From 1b41af8e3fba03fd90731a88e16390809f50982c Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:43:49 +0700 Subject: [PATCH 18/29] refactor: remove imports --- pop-api/integration-tests/src/fungibles/mod.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 43f7de8f..bfea0b45 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,17 +1,3 @@ -//! The fungibles pallet offers a streamlined interface for interacting with fungible tokens. The -//! goal is to provide a simplified, consistent API that adheres to standards in the smart contract -//! space. - -use frame_support::traits::fungibles::{metadata::Inspect as MetadataInspect, Inspect}; -pub use pallet::*; -use pallet_assets::WeightInfo as AssetsWeightInfoTrait; -use weights::WeightInfo; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; -#[cfg(test)] -mod tests; -pub mod weights; use pop_primitives::{ArithmeticError::*, Error::*, TokenError::*, TokenId, *}; use utils::*; From 45bc9d6d18fa5bc556774ed1c813c76f6e340f60 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:25:20 +0700 Subject: [PATCH 19/29] fix: parameter type --- pop-api/integration-tests/contracts/fungibles/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pop-api/integration-tests/contracts/fungibles/lib.rs b/pop-api/integration-tests/contracts/fungibles/lib.rs index 1db81eb5..3e8a9f2b 100755 --- a/pop-api/integration-tests/contracts/fungibles/lib.rs +++ b/pop-api/integration-tests/contracts/fungibles/lib.rs @@ -90,7 +90,7 @@ mod fungibles { #[ink(message)] pub fn approve( &mut self, - token: AssetId, + token: TokenId, spender: AccountId, value: Balance, ) -> Result<()> { @@ -160,7 +160,7 @@ mod fungibles { } #[ink(message)] - pub fn start_destroy(&mut self, token: AssetId) -> Result<()> { + pub fn start_destroy(&mut self, token: TokenId) -> Result<()> { api::start_destroy(token)?; self.env().emit_event(Destroyed { token }); Ok(()) @@ -180,7 +180,7 @@ mod fungibles { } #[ink(message)] - pub fn clear_metadata(&mut self, token: AssetId) -> Result<()> { + pub fn clear_metadata(&mut self, token: TokenId) -> Result<()> { api::clear_metadata(token)?; self.env().emit_event(MetadataCleared { token }); Ok(()) From b431b07143588cc55b8b8808debc8fffab330bf3 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:41:35 +0700 Subject: [PATCH 20/29] feat: add event emitted tests for approved and transferred --- pop-api/integration-tests/Cargo.toml | 1 + .../create_token_in_constructor/lib.rs | 2 +- .../integration-tests/src/fungibles/mod.rs | 53 +++++++++++++++++-- pop-api/src/v0/mod.rs | 2 - 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/pop-api/integration-tests/Cargo.toml b/pop-api/integration-tests/Cargo.toml index ab739e9d..5e5fe698 100644 --- a/pop-api/integration-tests/Cargo.toml +++ b/pop-api/integration-tests/Cargo.toml @@ -35,6 +35,7 @@ std = [ "pallet-assets/std", "pallet-balances/std", "pallet-contracts/std", + "pop-api/std", "pop-primitives/std", "pop-runtime-devnet/std", "scale/std", diff --git a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs index 3c2caac5..84b7290e 100755 --- a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs +++ b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs @@ -23,7 +23,7 @@ mod create_token_in_constructor { let contract = Self { token }; // AccountId of the contract which will be set to the owner of the fungible token. let owner = contract.env().account_id(); - api::create(id, owner, min_balance)?; + api::create(token, owner, min_balance)?; contract.env().emit_event(Created { token, creator: owner, admin: owner }); Ok(contract) } diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 1fb5ec19..53713b04 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,8 +1,11 @@ +use super::*; +use pop_api::{ + fungibles::events::{Approved, Created, Destroyed, MetadataCleared, MetadataSet, Transferred}, + primitives::account_id_from_slice, +}; use pop_primitives::{ArithmeticError::*, Error, Error::*, TokenError::*, TokenId}; use utils::*; -use super::*; - mod utils; const TOKEN_ID: TokenId = 1; @@ -98,6 +101,11 @@ fn transfer_works() { assert_ok!(transfer(&addr, token, BOB, amount / 2)); let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); + // Successfully emit an event when tokens transferred. + let from = account_id_from_slice(addr.as_ref()); + let to = account_id_from_slice(BOB.as_ref()); + let expected = Transferred { from: Some(from), to: Some(to), value: amount / 2 }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); // Transfer token to account that does not exist. assert_eq!(transfer(&addr, token, FERDIE, amount / 4), Err(Token(CannotCreate))); // Token is not live, i.e. frozen or being destroyed. @@ -150,6 +158,11 @@ fn transfer_from_works() { assert_ok!(transfer_from(&addr, token, ALICE, BOB, amount / 2)); let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); + // Successfully emit an event when tokens transferred. + let from = account_id_from_slice(ALICE.as_ref()); + let to = account_id_from_slice(BOB.as_ref()); + let expected = Transferred { from: Some(from), to: Some(to), value: amount / 2 }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); }); } @@ -170,13 +183,23 @@ fn approve_works() { assets::freeze(&ALICE, token); assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); assets::thaw(&ALICE, token); - // Successful approvals: + // Successful approvals. assert_eq!(0, Assets::allowance(token, &addr, &BOB)); assert_ok!(approve(&addr, token, &BOB, amount)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount); + // Successfully emit an event when a new spend allowance approved. + let owner = account_id_from_slice(addr.as_ref()); + let spender = account_id_from_slice(BOB.as_ref()); + let expected = Approved { owner, spender, value: amount }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); // Non-additive, sets new value. assert_ok!(approve(&addr, token, &BOB, amount / 2)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount / 2); + // Successfully emit an event when a new spend allowance approved. + let owner = account_id_from_slice(addr.as_ref()); + let spender = account_id_from_slice(BOB.as_ref()); + let expected = Approved { owner, spender, value: amount / 2 }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); // Token is not live, i.e. frozen or being destroyed. assets::start_destroy(&ALICE, token); assert_eq!(approve(&addr, token, &BOB, amount), Err(Module { index: 52, error: [16, 0] })); @@ -316,6 +339,10 @@ fn create_works() { // Create token successfully. assert_ok!(create(&addr, TOKEN_ID, &BOB, 1)); assert_eq!(Assets::owner(TOKEN_ID), Some(addr.clone())); + // Successfully emit an event when a new token created. + let admin = account_id_from_slice(BOB.as_ref()); + let expected = Created { token: TOKEN_ID, creator: admin, admin }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); // Token ID is already taken. assert_eq!(create(&addr, TOKEN_ID, &BOB, 1), Err(Module { index: 52, error: [5, 0] }),); }); @@ -335,9 +362,16 @@ fn instantiate_and_create_fungible_works() { ); // Successfully create a token when instantiating the contract. let result_with_address = instantiate_and_create_fungible(contract, TOKEN_ID, 1); + let instantiator = result_with_address.clone().ok(); assert_ok!(result_with_address.clone()); - assert_eq!(Assets::owner(TOKEN_ID), result_with_address.ok()); + assert_eq!(Assets::owner(TOKEN_ID), instantiator.clone()); assert!(Assets::asset_exists(TOKEN_ID)); + // Successfully emit an event when a new token created. + let instantiator = account_id_from_slice(instantiator.unwrap().as_ref()); + let expected = + Created { token: TOKEN_ID, creator: instantiator.clone(), admin: instantiator } + .encode(); + assert_eq!(last_contract_event(), expected.as_slice()); }); } @@ -354,6 +388,9 @@ fn start_destroy_works() { assert_eq!(start_destroy(&addr, token), Err(Module { index: 52, error: [2, 0] }),); let token = assets::create(&addr, TOKEN_ID, 1); assert_ok!(start_destroy(&addr, token)); + // Successfully emit an event when a new token destroyed. + let expected = Destroyed { token: TOKEN_ID }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); }); } @@ -393,7 +430,10 @@ fn set_metadata_works() { Err(Module { index: 52, error: [9, 0] }), ); // Set metadata successfully. - assert_ok!(set_metadata(&addr, TOKEN_ID, name, symbol, decimals)); + assert_ok!(set_metadata(&addr, TOKEN_ID, name.clone(), symbol.clone(), decimals)); + // Successfully emit an event when a token metadata set. + let expected = MetadataSet { token: TOKEN_ID, name, symbol, decimals }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); // Token is not live, i.e. frozen or being destroyed. assets::start_destroy(&addr, token); assert_eq!( @@ -427,6 +467,9 @@ fn clear_metadata_works() { assets::set_metadata(&addr, token, name, symbol, decimals); // Clear metadata successfully. assert_ok!(clear_metadata(&addr, TOKEN_ID)); + // Successfully emit an event when a token metadata set. + let expected = MetadataCleared { token: TOKEN_ID }.encode(); + assert_eq!(last_contract_event(), expected.as_slice()); // Token is not live, i.e. frozen or being destroyed. assets::start_destroy(&addr, token); assert_eq!( diff --git a/pop-api/src/v0/mod.rs b/pop-api/src/v0/mod.rs index fdc0fdba..c6153892 100644 --- a/pop-api/src/v0/mod.rs +++ b/pop-api/src/v0/mod.rs @@ -1,5 +1,3 @@ -use ink::env::chain_extension::ChainExtensionMethod; - use crate::{ build_extension_method, constants::{DISPATCH, READ_STATE}, From 1307d52212534a414a2c56627bb915b5bc59d63e Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:43:42 +0700 Subject: [PATCH 21/29] fix: comments --- pop-api/integration-tests/src/fungibles/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 53713b04..575a61a8 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -101,7 +101,7 @@ fn transfer_works() { assert_ok!(transfer(&addr, token, BOB, amount / 2)); let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); - // Successfully emit an event when tokens transferred. + // Successfully emit event. let from = account_id_from_slice(addr.as_ref()); let to = account_id_from_slice(BOB.as_ref()); let expected = Transferred { from: Some(from), to: Some(to), value: amount / 2 }.encode(); @@ -158,7 +158,7 @@ fn transfer_from_works() { assert_ok!(transfer_from(&addr, token, ALICE, BOB, amount / 2)); let balance_after_transfer = Assets::balance(token, &BOB); assert_eq!(balance_after_transfer, balance_before_transfer + amount / 2); - // Successfully emit an event when tokens transferred. + // Successfully emit event. let from = account_id_from_slice(ALICE.as_ref()); let to = account_id_from_slice(BOB.as_ref()); let expected = Transferred { from: Some(from), to: Some(to), value: amount / 2 }.encode(); @@ -187,7 +187,7 @@ fn approve_works() { assert_eq!(0, Assets::allowance(token, &addr, &BOB)); assert_ok!(approve(&addr, token, &BOB, amount)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount); - // Successfully emit an event when a new spend allowance approved. + // Successfully emit event. let owner = account_id_from_slice(addr.as_ref()); let spender = account_id_from_slice(BOB.as_ref()); let expected = Approved { owner, spender, value: amount }.encode(); @@ -195,7 +195,7 @@ fn approve_works() { // Non-additive, sets new value. assert_ok!(approve(&addr, token, &BOB, amount / 2)); assert_eq!(Assets::allowance(token, &addr, &BOB), amount / 2); - // Successfully emit an event when a new spend allowance approved. + // Successfully emit event. let owner = account_id_from_slice(addr.as_ref()); let spender = account_id_from_slice(BOB.as_ref()); let expected = Approved { owner, spender, value: amount / 2 }.encode(); @@ -339,7 +339,7 @@ fn create_works() { // Create token successfully. assert_ok!(create(&addr, TOKEN_ID, &BOB, 1)); assert_eq!(Assets::owner(TOKEN_ID), Some(addr.clone())); - // Successfully emit an event when a new token created. + // Successfully emit event. let admin = account_id_from_slice(BOB.as_ref()); let expected = Created { token: TOKEN_ID, creator: admin, admin }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); @@ -366,7 +366,7 @@ fn instantiate_and_create_fungible_works() { assert_ok!(result_with_address.clone()); assert_eq!(Assets::owner(TOKEN_ID), instantiator.clone()); assert!(Assets::asset_exists(TOKEN_ID)); - // Successfully emit an event when a new token created. + // Successfully emit event. let instantiator = account_id_from_slice(instantiator.unwrap().as_ref()); let expected = Created { token: TOKEN_ID, creator: instantiator.clone(), admin: instantiator } @@ -388,7 +388,7 @@ fn start_destroy_works() { assert_eq!(start_destroy(&addr, token), Err(Module { index: 52, error: [2, 0] }),); let token = assets::create(&addr, TOKEN_ID, 1); assert_ok!(start_destroy(&addr, token)); - // Successfully emit an event when a new token destroyed. + // Successfully emit event. let expected = Destroyed { token: TOKEN_ID }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); }); @@ -431,7 +431,7 @@ fn set_metadata_works() { ); // Set metadata successfully. assert_ok!(set_metadata(&addr, TOKEN_ID, name.clone(), symbol.clone(), decimals)); - // Successfully emit an event when a token metadata set. + // Successfully emit event. let expected = MetadataSet { token: TOKEN_ID, name, symbol, decimals }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Token is not live, i.e. frozen or being destroyed. @@ -467,7 +467,7 @@ fn clear_metadata_works() { assets::set_metadata(&addr, token, name, symbol, decimals); // Clear metadata successfully. assert_ok!(clear_metadata(&addr, TOKEN_ID)); - // Successfully emit an event when a token metadata set. + // Successfully emit event. let expected = MetadataCleared { token: TOKEN_ID }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Token is not live, i.e. frozen or being destroyed. From e233e608864a15998c221984205a3c065acddd84 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:53:03 +0700 Subject: [PATCH 22/29] fix: formatting --- pallets/api/src/fungibles/mod.rs | 10 ++++------ runtime/devnet/src/config/api/versioning.rs | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/pallets/api/src/fungibles/mod.rs b/pallets/api/src/fungibles/mod.rs index 43a8aeab..311b717e 100644 --- a/pallets/api/src/fungibles/mod.rs +++ b/pallets/api/src/fungibles/mod.rs @@ -503,12 +503,10 @@ pub mod pallet { use Read::*; match request { TotalSupply(token) => ReadResult::TotalSupply(AssetsOf::::total_supply(token)), - BalanceOf { token, owner } => { - ReadResult::BalanceOf(AssetsOf::::balance(token, owner)) - }, - Allowance { token, owner, spender } => { - ReadResult::Allowance(AssetsOf::::allowance(token, &owner, &spender)) - }, + BalanceOf { token, owner } => + ReadResult::BalanceOf(AssetsOf::::balance(token, owner)), + Allowance { token, owner, spender } => + ReadResult::Allowance(AssetsOf::::allowance(token, &owner, &spender)), TokenName(token) => ReadResult::TokenName( as MetadataInspect< AccountIdOf, >>::name(token)), diff --git a/runtime/devnet/src/config/api/versioning.rs b/runtime/devnet/src/config/api/versioning.rs index bc2a73e3..2f3d240f 100644 --- a/runtime/devnet/src/config/api/versioning.rs +++ b/runtime/devnet/src/config/api/versioning.rs @@ -114,9 +114,9 @@ impl From for V0Error { // Note: message not used let ModuleError { index, error, message: _message } = error; // Map `pallet-contracts::Error::DecodingFailed` to `Error::DecodingFailed` - if index as usize - == ::index() - && error == DECODING_FAILED_ERROR + if index as usize == + ::index() && + error == DECODING_FAILED_ERROR { Error::DecodingFailed } else { From 79adb97a87c9b39aeead006ea25f310b69b3054b Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 19:43:36 +0700 Subject: [PATCH 23/29] fix: compile error --- pop-api/integration-tests/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pop-api/integration-tests/Cargo.toml b/pop-api/integration-tests/Cargo.toml index 5e5fe698..cad7b4c4 100644 --- a/pop-api/integration-tests/Cargo.toml +++ b/pop-api/integration-tests/Cargo.toml @@ -10,7 +10,7 @@ contract-build = "4.1.1" [dev-dependencies] env_logger = "0.11.2" frame-support = { version = "36.0.0", default-features = false } -frame-support-procedural = { version = "30.0.1", default-features = false } +frame-support-procedural = { version = "=30.0.1", default-features = false } frame-system = { version = "36.1.0", default-features = false } log = "0.4.22" pallet-assets = { version = "37.0.0", default-features = false } @@ -25,7 +25,7 @@ scale = { package = "parity-scale-codec", version = "3.6.12", default-features = "derive", ] } sp-io = { version = "37.0.0", default-features = false } -sp-runtime = { version = "38.0.0", default-features = false } +sp-runtime = { version = "=38.0.0", default-features = false } [features] default = [ "std" ] From c8cd3498ca9d583fbf95d07389c0a49cf340c330 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:36:22 +0700 Subject: [PATCH 24/29] refactor: primitivces --- pop-api/integration-tests/build.rs | 9 +++++---- .../contracts/create_token_in_constructor/lib.rs | 12 ++++++------ .../integration-tests/contracts/fungibles/lib.rs | 6 +++--- pop-api/integration-tests/src/fungibles/mod.rs | 13 ++++++------- pop-api/integration-tests/src/fungibles/utils.rs | 12 +++++++++--- pop-api/src/primitives.rs | 9 ++------- pop-api/src/v0/fungibles.rs | 2 +- 7 files changed, 32 insertions(+), 31 deletions(-) diff --git a/pop-api/integration-tests/build.rs b/pop-api/integration-tests/build.rs index 5b969a9f..21334ac2 100644 --- a/pop-api/integration-tests/build.rs +++ b/pop-api/integration-tests/build.rs @@ -1,13 +1,14 @@ -use contract_build::{ - execute, BuildArtifacts, BuildMode, BuildResult, ExecuteArgs, ManifestPath, OutputType, - Verbosity, -}; use std::{ fs, path::{Path, PathBuf}, process, }; +use contract_build::{ + execute, BuildArtifacts, BuildMode, BuildResult, ExecuteArgs, ManifestPath, OutputType, + Verbosity, +}; + fn main() { let contracts_dir = PathBuf::from("./contracts/"); let contract_dirs = match get_subcontract_directories(&contracts_dir) { diff --git a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs index 84b7290e..9a794183 100755 --- a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs +++ b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs @@ -14,23 +14,23 @@ mod create_token_in_constructor { #[ink(storage)] pub struct Fungible { - token: TokenId, + id: TokenId, } impl Fungible { #[ink(constructor, payable)] - pub fn new(token: TokenId, min_balance: Balance) -> Result { - let contract = Self { token }; + pub fn new(id: TokenId, min_balance: Balance) -> Result { + let contract = Self { id }; // AccountId of the contract which will be set to the owner of the fungible token. let owner = contract.env().account_id(); - api::create(token, owner, min_balance)?; - contract.env().emit_event(Created { token, creator: owner, admin: owner }); + api::create(id, owner, min_balance)?; + contract.env().emit_event(Created { id, creator: owner, admin: owner }); Ok(contract) } #[ink(message)] pub fn token_exists(&self) -> Result { - api::token_exists(self.token) + api::token_exists(self.id) } } } diff --git a/pop-api/integration-tests/contracts/fungibles/lib.rs b/pop-api/integration-tests/contracts/fungibles/lib.rs index 3e8a9f2b..e34e5dab 100755 --- a/pop-api/integration-tests/contracts/fungibles/lib.rs +++ b/pop-api/integration-tests/contracts/fungibles/lib.rs @@ -150,12 +150,12 @@ mod fungibles { #[ink(message)] pub fn create( &mut self, - token: TokenId, + id: TokenId, admin: AccountId, min_balance: Balance, ) -> Result<()> { - api::create(token, admin, min_balance)?; - self.env().emit_event(Created { token, creator: admin, admin }); + api::create(id, admin, min_balance)?; + self.env().emit_event(Created { id, creator: admin, admin }); Ok(()) } diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 575a61a8..8d3a0db3 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,11 +1,11 @@ -use super::*; -use pop_api::{ - fungibles::events::{Approved, Created, Destroyed, MetadataCleared, MetadataSet, Transferred}, - primitives::account_id_from_slice, +use pop_api::fungibles::events::{ + Approved, Created, Destroyed, MetadataCleared, MetadataSet, Transferred, }; use pop_primitives::{ArithmeticError::*, Error, Error::*, TokenError::*, TokenId}; use utils::*; +use super::*; + mod utils; const TOKEN_ID: TokenId = 1; @@ -341,7 +341,7 @@ fn create_works() { assert_eq!(Assets::owner(TOKEN_ID), Some(addr.clone())); // Successfully emit event. let admin = account_id_from_slice(BOB.as_ref()); - let expected = Created { token: TOKEN_ID, creator: admin, admin }.encode(); + let expected = Created { id: TOKEN_ID, creator: admin, admin }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Token ID is already taken. assert_eq!(create(&addr, TOKEN_ID, &BOB, 1), Err(Module { index: 52, error: [5, 0] }),); @@ -369,8 +369,7 @@ fn instantiate_and_create_fungible_works() { // Successfully emit event. let instantiator = account_id_from_slice(instantiator.unwrap().as_ref()); let expected = - Created { token: TOKEN_ID, creator: instantiator.clone(), admin: instantiator } - .encode(); + Created { id: TOKEN_ID, creator: instantiator.clone(), admin: instantiator }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); }); } diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 3e73e729..caa0acfe 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -1,3 +1,5 @@ +use pop_api::primitives::AccountId; + use super::*; type AssetId = TokenId; @@ -361,11 +363,15 @@ pub(super) fn last_contract_event() -> Vec { let contract_events = events .iter() .filter_map(|event| match event { - pallet_contracts::Event::::ContractEmitted { data, .. } => { - Some(data.as_slice()) - }, + pallet_contracts::Event::::ContractEmitted { data, .. } => + Some(data.as_slice()), _ => None, }) .collect::>(); contract_events.last().unwrap().to_vec() } + +/// Decode slice of bytes to environment associated type AccountId. +pub fn account_id_from_slice(s: &[u8; 32]) -> AccountId { + AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") +} diff --git a/pop-api/src/primitives.rs b/pop-api/src/primitives.rs index 9fec4dd3..2fcb8a95 100644 --- a/pop-api/src/primitives.rs +++ b/pop-api/src/primitives.rs @@ -1,11 +1,6 @@ use ink::env::{DefaultEnvironment, Environment}; -use ink::scale::Decode; pub use pop_primitives::*; -pub(crate) type AccountId = ::AccountId; +// Public due to integration tests crate. +pub type AccountId = ::AccountId; pub(crate) type Balance = ::Balance; - -/// Decode slice of bytes to environment associated type AccountId. -pub fn account_id_from_slice(s: &[u8; 32]) -> AccountId { - AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") -} diff --git a/pop-api/src/v0/fungibles.rs b/pop-api/src/v0/fungibles.rs index 1cd0e40c..531cd006 100644 --- a/pop-api/src/v0/fungibles.rs +++ b/pop-api/src/v0/fungibles.rs @@ -104,7 +104,7 @@ pub mod events { pub struct Created { /// The token identifier. #[ink(topic)] - pub token: TokenId, + pub id: TokenId, /// The creator of the token. #[ink(topic)] pub creator: AccountId, From 6f64e6c817ae25cda6de8d3f1efd87caee9f6ff6 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 22:45:36 +0700 Subject: [PATCH 25/29] fix: resolve comments --- .../contracts/create_token_in_constructor/lib.rs | 6 +++--- pop-api/integration-tests/src/fungibles/utils.rs | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs index 9a794183..3ca787be 100755 --- a/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs +++ b/pop-api/integration-tests/contracts/create_token_in_constructor/lib.rs @@ -14,13 +14,13 @@ mod create_token_in_constructor { #[ink(storage)] pub struct Fungible { - id: TokenId, + token: TokenId, } impl Fungible { #[ink(constructor, payable)] pub fn new(id: TokenId, min_balance: Balance) -> Result { - let contract = Self { id }; + let contract = Self { token: id }; // AccountId of the contract which will be set to the owner of the fungible token. let owner = contract.env().account_id(); api::create(id, owner, min_balance)?; @@ -30,7 +30,7 @@ mod create_token_in_constructor { #[ink(message)] pub fn token_exists(&self) -> Result { - api::token_exists(self.id) + api::token_exists(self.token) } } } diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index caa0acfe..18cffc38 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -1,5 +1,3 @@ -use pop_api::primitives::AccountId; - use super::*; type AssetId = TokenId; @@ -363,15 +361,18 @@ pub(super) fn last_contract_event() -> Vec { let contract_events = events .iter() .filter_map(|event| match event { - pallet_contracts::Event::::ContractEmitted { data, .. } => - Some(data.as_slice()), + pallet_contracts::Event::::ContractEmitted { data, .. } => { + Some(data.as_slice()) + }, _ => None, }) .collect::>(); contract_events.last().unwrap().to_vec() } -/// Decode slice of bytes to environment associated type AccountId. -pub fn account_id_from_slice(s: &[u8; 32]) -> AccountId { - AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") +/// Decodes a byte slice into an `AccountId` as defined in `primitives`. +/// +/// This is used to resolve type mismatches between the `AccountId` in the integration tests and the contract environment. +pub fn account_id_from_slice(s: &[u8; 32]) -> pop_api::primitives::AccountId { + pop_api::primitives::AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") } From c25a5bd77364cef7147059e853ac18e044ad282f Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 22:48:42 +0700 Subject: [PATCH 26/29] fix: resolve comments --- pop-api/integration-tests/contracts/fungibles/lib.rs | 8 ++++---- pop-api/integration-tests/src/fungibles/mod.rs | 10 +++++----- pop-api/integration-tests/src/fungibles/utils.rs | 8 ++++---- pop-api/src/v0/fungibles.rs | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pop-api/integration-tests/contracts/fungibles/lib.rs b/pop-api/integration-tests/contracts/fungibles/lib.rs index e34e5dab..7e6f908d 100755 --- a/pop-api/integration-tests/contracts/fungibles/lib.rs +++ b/pop-api/integration-tests/contracts/fungibles/lib.rs @@ -8,7 +8,7 @@ use ink::prelude::vec::Vec; use pop_api::{ fungibles::{ self as api, - events::{Approved, Created, Destroyed, MetadataCleared, MetadataSet, Transferred}, + events::{Approve, Created, Destroyed, MetadataCleared, MetadataSet, Transfer}, }, primitives::TokenId, StatusCode, @@ -64,7 +64,7 @@ mod fungibles { #[ink(message)] pub fn transfer(&mut self, token: TokenId, to: AccountId, value: Balance) -> Result<()> { api::transfer(token, to, value)?; - self.env().emit_event(Transferred { + self.env().emit_event(Transfer { from: Some(self.env().account_id()), to: Some(to), value, @@ -83,7 +83,7 @@ mod fungibles { _data: Vec, ) -> Result<()> { api::transfer_from(token, from, to, value)?; - self.env().emit_event(Transferred { from: Some(from), to: Some(to), value }); + self.env().emit_event(Transfer { from: Some(from), to: Some(to), value }); Ok(()) } @@ -96,7 +96,7 @@ mod fungibles { ) -> Result<()> { api::approve(token, spender, value)?; self.env() - .emit_event(Approved { owner: self.env().account_id(), spender, value }); + .emit_event(Approve { owner: self.env().account_id(), spender, value }); Ok(()) } diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 8d3a0db3..b3c718f5 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,5 +1,5 @@ use pop_api::fungibles::events::{ - Approved, Created, Destroyed, MetadataCleared, MetadataSet, Transferred, + Approve, Created, Destroyed, MetadataCleared, MetadataSet, Transfer, }; use pop_primitives::{ArithmeticError::*, Error, Error::*, TokenError::*, TokenId}; use utils::*; @@ -104,7 +104,7 @@ fn transfer_works() { // Successfully emit event. let from = account_id_from_slice(addr.as_ref()); let to = account_id_from_slice(BOB.as_ref()); - let expected = Transferred { from: Some(from), to: Some(to), value: amount / 2 }.encode(); + let expected = Transfer { from: Some(from), to: Some(to), value: amount / 2 }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Transfer token to account that does not exist. assert_eq!(transfer(&addr, token, FERDIE, amount / 4), Err(Token(CannotCreate))); @@ -161,7 +161,7 @@ fn transfer_from_works() { // Successfully emit event. let from = account_id_from_slice(ALICE.as_ref()); let to = account_id_from_slice(BOB.as_ref()); - let expected = Transferred { from: Some(from), to: Some(to), value: amount / 2 }.encode(); + let expected = Transfer { from: Some(from), to: Some(to), value: amount / 2 }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); }); } @@ -190,7 +190,7 @@ fn approve_works() { // Successfully emit event. let owner = account_id_from_slice(addr.as_ref()); let spender = account_id_from_slice(BOB.as_ref()); - let expected = Approved { owner, spender, value: amount }.encode(); + let expected = Approve { owner, spender, value: amount }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Non-additive, sets new value. assert_ok!(approve(&addr, token, &BOB, amount / 2)); @@ -198,7 +198,7 @@ fn approve_works() { // Successfully emit event. let owner = account_id_from_slice(addr.as_ref()); let spender = account_id_from_slice(BOB.as_ref()); - let expected = Approved { owner, spender, value: amount / 2 }.encode(); + let expected = Approve { owner, spender, value: amount / 2 }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Token is not live, i.e. frozen or being destroyed. assets::start_destroy(&ALICE, token); diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 18cffc38..47fe1a46 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -361,9 +361,8 @@ pub(super) fn last_contract_event() -> Vec { let contract_events = events .iter() .filter_map(|event| match event { - pallet_contracts::Event::::ContractEmitted { data, .. } => { - Some(data.as_slice()) - }, + pallet_contracts::Event::::ContractEmitted { data, .. } => + Some(data.as_slice()), _ => None, }) .collect::>(); @@ -372,7 +371,8 @@ pub(super) fn last_contract_event() -> Vec { /// Decodes a byte slice into an `AccountId` as defined in `primitives`. /// -/// This is used to resolve type mismatches between the `AccountId` in the integration tests and the contract environment. +/// This is used to resolve type mismatches between the `AccountId` in the integration tests and the +/// contract environment. pub fn account_id_from_slice(s: &[u8; 32]) -> pop_api::primitives::AccountId { pop_api::primitives::AccountId::decode(&mut &s[..]).expect("Should be decoded to AccountId") } diff --git a/pop-api/src/v0/fungibles.rs b/pop-api/src/v0/fungibles.rs index 531cd006..9d6ba2b3 100644 --- a/pop-api/src/v0/fungibles.rs +++ b/pop-api/src/v0/fungibles.rs @@ -75,7 +75,7 @@ pub mod events { /// Event emitted when allowance by `owner` to `spender` changes. #[ink::event] - pub struct Approved { + pub struct Approve { /// The owner providing the allowance. #[ink(topic)] pub owner: AccountId, @@ -88,7 +88,7 @@ pub mod events { /// Event emitted when transfer of tokens occurs. #[ink::event] - pub struct Transferred { + pub struct Transfer { /// The source of the transfer. `None` when minting. #[ink(topic)] pub from: Option, From 11508ce66630ae3e07d7756f8fda0bcc71732ae0 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Fri, 13 Sep 2024 23:44:11 +0700 Subject: [PATCH 27/29] fix: resolve comments --- pop-api/integration-tests/src/fungibles/utils.rs | 2 +- pop-api/integration-tests/src/lib.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pop-api/integration-tests/src/fungibles/utils.rs b/pop-api/integration-tests/src/fungibles/utils.rs index 93dea023..85fb3007 100644 --- a/pop-api/integration-tests/src/fungibles/utils.rs +++ b/pop-api/integration-tests/src/fungibles/utils.rs @@ -327,7 +327,7 @@ pub(super) fn instantiate_and_create_fungible( input, vec![], DEBUG_OUTPUT, - CollectEvents::UnsafeCollect, + CollectEvents::Skip, ) .result .expect("should work"); diff --git a/pop-api/integration-tests/src/lib.rs b/pop-api/integration-tests/src/lib.rs index c74701f5..9e6e20fc 100644 --- a/pop-api/integration-tests/src/lib.rs +++ b/pop-api/integration-tests/src/lib.rs @@ -8,10 +8,7 @@ use frame_support::{ weights::Weight, }; use pallet_contracts::{Code, CollectEvents, Determinism, ExecReturnValue}; -use pop_runtime_devnet::{ - config::assets::TrustBackedAssetsInstance, Assets, Contracts, Runtime, RuntimeOrigin, System, - UNIT, -}; +use pop_runtime_devnet::{Assets, Contracts, Runtime, RuntimeOrigin, System, UNIT}; use scale::{Decode, Encode}; use sp_runtime::{AccountId32, BuildStorage, DispatchError}; From 0d50f2c7e3b67c59d58dccffbdfab6100dcefe98 Mon Sep 17 00:00:00 2001 From: Peter White Date: Fri, 13 Sep 2024 11:41:57 -0600 Subject: [PATCH 28/29] refactor(pop-api/fungibles): events Approve -> Approval, Destroyed -> DestroyStarted --- pop-api/integration-tests/contracts/fungibles/lib.rs | 6 +++--- pop-api/integration-tests/src/fungibles/mod.rs | 8 ++++---- pop-api/src/v0/fungibles.rs | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pop-api/integration-tests/contracts/fungibles/lib.rs b/pop-api/integration-tests/contracts/fungibles/lib.rs index 7e6f908d..17dda2af 100755 --- a/pop-api/integration-tests/contracts/fungibles/lib.rs +++ b/pop-api/integration-tests/contracts/fungibles/lib.rs @@ -8,7 +8,7 @@ use ink::prelude::vec::Vec; use pop_api::{ fungibles::{ self as api, - events::{Approve, Created, Destroyed, MetadataCleared, MetadataSet, Transfer}, + events::{Approval, Created, DestroyStarted, MetadataCleared, MetadataSet, Transfer}, }, primitives::TokenId, StatusCode, @@ -96,7 +96,7 @@ mod fungibles { ) -> Result<()> { api::approve(token, spender, value)?; self.env() - .emit_event(Approve { owner: self.env().account_id(), spender, value }); + .emit_event(Approval { owner: self.env().account_id(), spender, value }); Ok(()) } @@ -162,7 +162,7 @@ mod fungibles { #[ink(message)] pub fn start_destroy(&mut self, token: TokenId) -> Result<()> { api::start_destroy(token)?; - self.env().emit_event(Destroyed { token }); + self.env().emit_event(DestroyStarted { token }); Ok(()) } diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index 6613ec24..db9a4fa1 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -1,5 +1,5 @@ use pop_api::fungibles::events::{ - Approve, Created, Destroyed, MetadataCleared, MetadataSet, Transfer, + Approval, Created, DestroyStarted, MetadataCleared, MetadataSet, Transfer, }; use pop_primitives::{ArithmeticError::*, Error, Error::*, TokenError::*, TokenId}; use utils::*; @@ -190,7 +190,7 @@ fn approve_works() { // Successfully emit event. let owner = account_id_from_slice(addr.as_ref()); let spender = account_id_from_slice(BOB.as_ref()); - let expected = Approve { owner, spender, value: amount }.encode(); + let expected = Approval { owner, spender, value: amount }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Non-additive, sets new value. assert_ok!(approve(&addr, token, &BOB, amount / 2)); @@ -198,7 +198,7 @@ fn approve_works() { // Successfully emit event. let owner = account_id_from_slice(addr.as_ref()); let spender = account_id_from_slice(BOB.as_ref()); - let expected = Approve { owner, spender, value: amount / 2 }.encode(); + let expected = Approval { owner, spender, value: amount / 2 }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); // Token is not live, i.e. frozen or being destroyed. assets::start_destroy(&ALICE, token); @@ -388,7 +388,7 @@ fn start_destroy_works() { let token = assets::create(&addr, TOKEN_ID, 1); assert_ok!(start_destroy(&addr, token)); // Successfully emit event. - let expected = Destroyed { token: TOKEN_ID }.encode(); + let expected = DestroyStarted { token: TOKEN_ID }.encode(); assert_eq!(last_contract_event(), expected.as_slice()); }); } diff --git a/pop-api/src/v0/fungibles.rs b/pop-api/src/v0/fungibles.rs index 9d6ba2b3..99c1261a 100644 --- a/pop-api/src/v0/fungibles.rs +++ b/pop-api/src/v0/fungibles.rs @@ -75,7 +75,7 @@ pub mod events { /// Event emitted when allowance by `owner` to `spender` changes. #[ink::event] - pub struct Approve { + pub struct Approval { /// The owner providing the allowance. #[ink(topic)] pub owner: AccountId, @@ -115,7 +115,7 @@ pub mod events { /// Event emitted when a token is in the process of being destroyed. #[ink::event] - pub struct Destroyed { + pub struct DestroyStarted { /// The token. #[ink(topic)] pub token: TokenId, From c6d390db7397dc4446c9bee6cbae791520796eb4 Mon Sep 17 00:00:00 2001 From: Peter White Date: Fri, 13 Sep 2024 11:46:58 -0600 Subject: [PATCH 29/29] refactor: less cloning --- pop-api/integration-tests/src/fungibles/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pop-api/integration-tests/src/fungibles/mod.rs b/pop-api/integration-tests/src/fungibles/mod.rs index db9a4fa1..d2e06285 100644 --- a/pop-api/integration-tests/src/fungibles/mod.rs +++ b/pop-api/integration-tests/src/fungibles/mod.rs @@ -363,8 +363,8 @@ fn instantiate_and_create_fungible_works() { // Successfully create a token when instantiating the contract. let result_with_address = instantiate_and_create_fungible(contract, TOKEN_ID, 1); let instantiator = result_with_address.clone().ok(); - assert_ok!(result_with_address.clone()); - assert_eq!(Assets::owner(TOKEN_ID), instantiator.clone()); + assert_ok!(result_with_address); + assert_eq!(&Assets::owner(TOKEN_ID), &instantiator); assert!(Assets::asset_exists(TOKEN_ID)); // Successfully emit event. let instantiator = account_id_from_slice(instantiator.unwrap().as_ref());