Skip to content

Commit

Permalink
[feature]: add store asset transfer instruction
Browse files Browse the repository at this point in the history
Signed-off-by: Asem-Abdelhady <[email protected]>
  • Loading branch information
Asem-Abdelhady committed Feb 6, 2024
1 parent 301b32e commit 62fd223
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 4 deletions.
79 changes: 79 additions & 0 deletions client/tests/integration/transfer_asset.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
use std::str::FromStr;

use iroha_client::{
client::{self, QueryResult},
crypto::KeyPair,
data_model::{isi::Instruction, prelude::*, Registered},
};
use iroha_data_model::{
account::{Account, AccountId},
asset::{Asset, AssetDefinition},
isi::InstructionBox,
metadata::Metadata,
name::Name,
};
use iroha_primitives::fixed::Fixed;
use test_network::*;

Expand Down Expand Up @@ -55,6 +64,10 @@ fn simulate_insufficient_funds() {
10_800,
)
}
#[test]
fn simulate_transfer_store_asset() {
simulate_transfer_store(Transfer::asset_store)
}

fn simulate_transfer<T>(
starting_amount: T,
Expand Down Expand Up @@ -120,3 +133,69 @@ fn simulate_transfer<T>(
)
.expect("Test case failure.");
}

fn simulate_transfer_store(
transfer_ctr: impl FnOnce(AssetId, AccountId) -> Transfer<Asset, Metadata, Account>,
) where
Transfer<Asset, Metadata, Account>: Instruction,
{
let (_rt, _peer, iroha_client) = <PeerBuilder>::new().with_port(10_805).start_with_runtime();
wait_for_genesis_committed(&[iroha_client.clone()], 0);
let (alice_id, mouse_id) = generate_two_ids();
let create_mouse = create_mouse(mouse_id.clone());
let asset_definition_id: AssetDefinitionId = "camomile#wonderland".parse().expect("Valid");
let create_asset =
Register::asset_definition(AssetDefinition::store(asset_definition_id.clone()));
let set_key_value = SetKeyValue::asset(
AssetId::new(asset_definition_id.clone(), alice_id.clone()),
Name::from_str("alicek").unwrap(),
true,
);

let instructions: [InstructionBox; 3] = [
// create_alice.into(), We don't need to register Alice, because she is created in genesis
create_mouse.into(),
create_asset.into(),
set_key_value.into(),
];

iroha_client
.submit_all_blocking(instructions)
.expect("Failed to prepare state.");

let transfer_asset = transfer_ctr(
AssetId::new(asset_definition_id.clone(), alice_id.clone()),
mouse_id.clone(),
);
let transfer_box: InstructionBox = transfer_asset.into();

iroha_client
.submit_till(
transfer_box,
client::asset::by_account_id(mouse_id.clone()),
|result| {
let assets = result.collect::<QueryResult<Vec<_>>>().expect("Valid");
for asset in assets.iter() {
println!("Asset: {}", asset.id().definition_id);
}
assets.iter().any(|asset| {
asset.id().definition_id == asset_definition_id
&& asset.id().account_id == mouse_id
})
},
)
.expect("Test case failure.");
}

fn generate_two_ids() -> (AccountId, AccountId) {
let alice_id: AccountId = "alice@wonderland".parse().expect("Valid");
let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid");
(alice_id, mouse_id)
}

fn create_mouse(mouse_id: AccountId) -> Register<Account> {
let (bob_public_key, _) = KeyPair::generate()
.expect("Failed to generate KeyPair")
.into();
Register::account(Account::new(mouse_id, [bob_public_key]))
}
41 changes: 40 additions & 1 deletion core/src/smartcontracts/isi/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Registrable for NewAssetDefinition {
/// - update metadata
/// - transfer, etc.
pub mod isi {
use iroha_data_model::isi::error::MintabilityError;
use iroha_data_model::{isi::error::MintabilityError, metadata::Metadata};

use super::*;
use crate::smartcontracts::account::isi::forbid_minting;
Expand Down Expand Up @@ -103,6 +103,45 @@ pub mod isi {
}
}

impl Execute for Transfer<Asset, Metadata, Account> {
#[metrics(+"transfer_store")]
fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> {
let asset_id = self.source_id;
assert_asset_type(&asset_id.definition_id, wsv, AssetValueType::Store)?;

let (original_owner_metadata, destination_id) = {
let original_store_owner: &Account = wsv.account(&asset_id.account_id)?;
let metadata: Metadata = original_store_owner.metadata().clone();
let destination_id =
AssetId::new(asset_id.definition_id.clone(), self.destination_id.clone());
(metadata, destination_id)
};

let asset_metadata_limits = wsv.config.asset_metadata_limits;
let destination_store_asset =
wsv.asset_or_insert(destination_id.clone(), Metadata::new())?;
let store: &mut Metadata = destination_store_asset
.try_as_mut()
.map_err(eyre::Error::from)
.map_err(|e| Error::Conversion(e.to_string()))?;

for pair in original_owner_metadata.iter() {
let key: &Name = pair.0;
let value: &Value = pair.1;
store.insert_with_limits(key.clone(), value.clone(), asset_metadata_limits)?;
}

{
let original_store_owner = wsv.account_mut(&asset_id.account_id)?;
assert!(original_store_owner.remove_asset(&asset_id).is_some());
}

wsv.emit_events([AssetEvent::Deleted(asset_id)]);

Ok(())
}
}

macro_rules! impl_mint {
($ty:ty, $metrics:literal) => {
impl InnerMint for $ty {}
Expand Down
1 change: 1 addition & 0 deletions core/src/smartcontracts/isi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl Execute for AssetTransferBox {
Self::Quantity(isi) => isi.execute(authority, wsv),
Self::BigQuantity(isi) => isi.execute(authority, wsv),
Self::Fixed(isi) => isi.execute(authority, wsv),
Self::Store(isi) => isi.execute(authority, wsv),
}
}
}
Expand Down
18 changes: 17 additions & 1 deletion data_model/src/isi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ pub mod model {
impl Instruction for Transfer<Asset, u32, Account> {}
impl Instruction for Transfer<Asset, u128, Account> {}
impl Instruction for Transfer<Asset, Fixed, Account> {}
impl Instruction for Transfer<Asset, Metadata, Account> {}

impl Instruction for Grant<PermissionToken> {}
impl Instruction for Grant<RoleId> {}
Expand All @@ -166,7 +167,7 @@ pub mod model {

mod transparent {
use super::*;
use crate::{account::NewAccount, domain::NewDomain};
use crate::{account::NewAccount, domain::NewDomain, metadata::Metadata};

macro_rules! isi {
($($meta:meta)* $item:item) => {
Expand Down Expand Up @@ -847,6 +848,17 @@ mod transparent {
}
}

impl Transfer<Asset, Metadata, Account> {
/// Constructs a new [`Transfer`] for an [`Asset`] of [`Store`] type.
pub fn asset_store(asset_id: AssetId, to: AccountId) -> Self {
Self {
source_id: asset_id,
object: Metadata::new(),
destination_id: to,
}
}
}

impl_display! {
Transfer<S, O, D>
where
Expand All @@ -865,6 +877,7 @@ mod transparent {
impl_into_box! {
Transfer<Asset, u32, Account> |
Transfer<Asset, u128, Account> |
Transfer<Asset, Metadata, Account> |
Transfer<Asset, Fixed, Account> => AssetTransferBox ==> TransferBox::Asset
}

Expand All @@ -873,6 +886,7 @@ mod transparent {
Transfer<Account, AssetDefinitionId, Account> |
Transfer<Asset, u32, Account> |
Transfer<Asset, u128, Account> |
Transfer<Asset, Metadata, Account> |
Transfer<Asset, Fixed, Account> => TransferBox ==> InstructionBox::Transfer
}

Expand Down Expand Up @@ -1194,6 +1208,8 @@ isi_box! {
BigQuantity(Transfer<Asset, u128, Account>),
/// Transfer [`Asset`] of [`Fixed`] type.
Fixed(Transfer<Asset, Fixed, Account>),
/// Transfer [`Asset`] of [`Store`] type.
Store(Transfer<Asset, Metadata, Account>),
}
}

Expand Down
2 changes: 2 additions & 0 deletions data_model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ mod seal {
Transfer<Asset, u32, Account>,
Transfer<Asset, u128, Account>,
Transfer<Asset, Fixed, Account>,
Transfer<Asset, Metadata, Account>,


Grant<PermissionToken>,
Grant<RoleId>,
Expand Down
3 changes: 3 additions & 0 deletions data_model/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ pub trait Visit {
visit_transfer_asset_quantity(&Transfer<Asset, u32, Account>),
visit_transfer_asset_big_quantity(&Transfer<Asset, u128, Account>),
visit_transfer_asset_fixed(&Transfer<Asset, Fixed, Account>),
visit_transfer_asset_store(&Transfer<Asset, Metadata, Account>),
visit_transfer_domain(&Transfer<Account, DomainId, Account>),

// Visit SetKeyValueBox
Expand Down Expand Up @@ -349,6 +350,7 @@ pub fn visit_transfer<V: Visit + ?Sized>(
visitor.visit_transfer_asset_big_quantity(authority, obj)
}
AssetTransferBox::Fixed(obj) => visitor.visit_transfer_asset_fixed(authority, obj),
AssetTransferBox::Store(obj) => visitor.visit_transfer_asset_store(authority, obj),
},
}
}
Expand Down Expand Up @@ -425,6 +427,7 @@ leaf_visitors! {
visit_transfer_asset_quantity(&Transfer<Asset, u32, Account>),
visit_transfer_asset_big_quantity(&Transfer<Asset, u128, Account>),
visit_transfer_asset_fixed(&Transfer<Asset, Fixed, Account>),
visit_transfer_asset_store(&Transfer<Asset, Metadata, Account>),
visit_set_asset_key_value(&SetKeyValue<Asset>),
visit_remove_asset_key_value(&RemoveKeyValue<Asset>),
visit_register_asset_definition(&Register<AssetDefinition>),
Expand Down
1 change: 1 addition & 0 deletions smart_contract/executor/derive/src/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub fn impl_derive_visit(emitter: &mut Emitter, input: &syn2::DeriveInput) -> To
"fn visit_transfer_asset_quantity(operation: &Transfer<Asset, u32, Account>)",
"fn visit_transfer_asset_big_quantity(operation: &Transfer<Asset, u128, Account>)",
"fn visit_transfer_asset_fixed(operation: &Transfer<Asset, Fixed, Account>)",
"fn visit_transfer_asset_store(operation: &Transfer<Asset, Metadata, Account>)",
"fn visit_set_asset_key_value(operation: &SetKeyValue<Asset>)",
"fn visit_remove_asset_key_value(operation: &RemoveKeyValue<Asset>)",
"fn visit_register_asset_definition(operation: &Register<AssetDefinition>)",
Expand Down
12 changes: 10 additions & 2 deletions smart_contract/executor/src/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub use asset::{
visit_mint_asset_big_quantity, visit_mint_asset_fixed, visit_mint_asset_quantity,
visit_register_asset, visit_remove_asset_key_value, visit_set_asset_key_value,
visit_transfer_asset_big_quantity, visit_transfer_asset_fixed, visit_transfer_asset_quantity,
visit_unregister_asset,
visit_transfer_asset_store, visit_unregister_asset,
};
pub use asset_definition::{
visit_register_asset_definition, visit_remove_asset_definition_key_value,
Expand Down Expand Up @@ -581,7 +581,7 @@ pub mod asset_definition {
}

pub mod asset {
use iroha_smart_contract::data_model::isi::Instruction;
use iroha_smart_contract::data_model::{isi::Instruction, metadata::Metadata};
use iroha_smart_contract_utils::Encode;
use permission::{asset::is_asset_owner, asset_definition::is_asset_definition_owner};

Expand Down Expand Up @@ -829,6 +829,14 @@ pub mod asset {
validate_transfer_asset(executor, authority, isi);
}

pub fn visit_transfer_asset_store<V: Validate + ?Sized>(
executor: &mut V,
authority: &AccountId,
isi: &Transfer<Asset, Metadata, Account>,
) {
validate_transfer_asset(executor, authority, isi);
}

pub fn visit_set_asset_key_value<V: Validate + ?Sized>(
executor: &mut V,
authority: &AccountId,
Expand Down

0 comments on commit 62fd223

Please sign in to comment.