Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(template_lib): improve API for extracting data from NFTs #897

Merged
merged 5 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion dan_layer/engine/src/runtime/impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ use tari_template_lib::{
auth::{ComponentAccessRules, ResourceAccessRules, ResourceAuthAction},
constants::CONFIDENTIAL_TARI_RESOURCE_ADDRESS,
crypto::RistrettoPublicKeyBytes,
models::{Amount, BucketId, ComponentAddress, Metadata, NonFungibleAddress, NotAuthorized, VaultRef},
models::{Amount, BucketId, ComponentAddress, Metadata, NonFungible, NonFungibleAddress, NotAuthorized, VaultRef},
prelude::ResourceType,
template::BuiltinTemplate,
};
Expand Down Expand Up @@ -1086,6 +1086,28 @@ impl<TTemplateProvider: TemplateProvider<Template = LoadedTemplate>> RuntimeInte
})
},
VaultAction::CreateProofByConfidentialResource => todo!("CreateProofByConfidentialResource"),
VaultAction::GetNonFungibles => {
let vault_id = vault_ref.vault_id().ok_or_else(|| RuntimeError::InvalidArgument {
argument: "vault_ref",
reason: "GetNonFungibles vault action requires a vault id".to_string(),
})?;
args.assert_no_args("Vault::GetNonFungibles")?;

self.tracker.write_with(|state| {
let vault_lock = state.lock_substate(&SubstateAddress::Vault(vault_id), LockFlag::Read)?;
let resource_address = state.get_vault(&vault_lock)?.resource_address();
let nft_ids = state.get_vault(&vault_lock)?.get_non_fungible_ids();
let nfts: Vec<NonFungible> = nft_ids
.iter()
.map(|id| NonFungibleAddress::new(*resource_address, id.clone()))
.map(NonFungible::new)
.collect();

let result = InvokeResult::encode(&nfts)?;
state.unlock_substate(vault_lock)?;
Ok(result)
})
},
}
}

Expand Down Expand Up @@ -1246,6 +1268,26 @@ impl<TTemplateProvider: TemplateProvider<Template = LoadedTemplate>> RuntimeInte
Ok(InvokeResult::encode(bucket.non_fungible_ids())?)
})
},
BucketAction::GetNonFungibles => {
let bucket_id = bucket_ref.bucket_id().ok_or_else(|| RuntimeError::InvalidArgument {
argument: "bucket_ref",
reason: "GetNonFungibles bucket action requires a bucket id".to_string(),
})?;
args.assert_no_args("Bucket::GetNonFungibles")?;

self.tracker.write_with(|state| {
let bucket = state.get_bucket(bucket_id)?;
let resource_address = bucket.resource_address();
let nft_ids = bucket.non_fungible_ids();
let nfts: Vec<NonFungible> = nft_ids
.iter()
.map(|id| NonFungibleAddress::new(*resource_address, id.clone()))
.map(NonFungible::new)
.collect();

Ok(InvokeResult::encode(&nfts)?)
})
},
}
}

Expand Down
13 changes: 13 additions & 0 deletions dan_layer/engine/tests/templates/nft/basic_nft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,18 @@ mod sparkle_nft_template {
// native instruction can be used instead
bucket.burn();
}

pub fn get_non_fungibles_from_bucket(&mut self) -> Vec<NonFungible> {
let bucket = self.vault.withdraw_all();
let nfts = bucket.get_non_fungibles();
// deposit the nfts back into the vault
self.vault.deposit(bucket);

nfts
}

pub fn get_non_fungibles_from_vault(&self) -> Vec<NonFungible> {
self.vault.get_non_fungibles()
}
}
}
41 changes: 41 additions & 0 deletions dan_layer/engine/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ mod fungible {

mod basic_nft {
use serde::{Deserialize, Serialize};
use tari_template_lib::models::NonFungible;

use super::*;

Expand Down Expand Up @@ -840,6 +841,46 @@ mod basic_nft {
)
.unwrap_err();
}

#[test]
fn get_non_fungibles_from_containers() {
let (mut template_test, (account_address, account_owner), nft_component, nft_resx) = setup();

let vars = vec![
("account", account_address.into()),
("nft", nft_component.into()),
("nft_resx", nft_resx.into()),
];

let total_supply: Amount = template_test.call_method(nft_component, "total_supply", args![], vec![]);
assert_eq!(total_supply, Amount(4));

let result = template_test
.execute_and_commit_manifest(
r#"
let sparkle_nft = var!["nft"];
sparkle_nft.get_non_fungibles_from_bucket();
sparkle_nft.get_non_fungibles_from_vault();
"#,
vars.clone(),
vec![account_owner],
)
.unwrap();

result.finalize.result.expect("execution failed");

// sparkle_nft.get_non_fungibles_from_bucket()
let nfts_from_bucket = result.finalize.execution_results[0]
.decode::<Vec<NonFungible>>()
.unwrap();
assert_eq!(nfts_from_bucket.len(), 4);

// sparkle_nft.get_non_fungibles_from_vault()
let nfts_from_bucket = result.finalize.execution_results[1]
.decode::<Vec<NonFungible>>()
.unwrap();
assert_eq!(nfts_from_bucket.len(), 4);
}
}

mod emoji_id {
Expand Down
2 changes: 2 additions & 0 deletions dan_layer/template_lib/src/args/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ pub enum VaultAction {
CreateProofByFungibleAmount,
CreateProofByNonFungibles,
CreateProofByConfidentialResource,
GetNonFungibles,
}

/// A vault withdraw operation argument
Expand Down Expand Up @@ -397,6 +398,7 @@ pub enum BucketAction {
Burn,
CreateProof,
GetNonFungibleIds,
GetNonFungibles,
}

/// A bucket burn operation argument
Expand Down
13 changes: 12 additions & 1 deletion dan_layer/template_lib/src/models/bucket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize};
use tari_bor::BorTag;
use tari_template_abi::{call_engine, rust::fmt, EngineOp};

use super::NonFungibleId;
use super::{NonFungible, NonFungibleId};
use crate::{
args::{BucketAction, BucketInvokeArg, BucketRef, InvokeResult},
models::{Amount, BinaryTag, ConfidentialWithdrawProof, Proof, ResourceAddress},
Expand Down Expand Up @@ -188,4 +188,15 @@ impl Bucket {
resp.decode()
.expect("get_non_fungible_ids returned invalid non fungible ids")
}

/// Returns all the non-fungibles in this bucket
pub fn get_non_fungibles(&self) -> Vec<NonFungible> {
let resp: InvokeResult = call_engine(EngineOp::BucketInvoke, &BucketInvokeArg {
bucket_ref: BucketRef::Ref(self.id),
action: BucketAction::GetNonFungibles,
args: invoke_args![],
});

resp.decode().expect("get_non_fungibles returned invalid non fungibles")
}
}
13 changes: 12 additions & 1 deletion dan_layer/template_lib/src/models/vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use tari_template_abi::{
EngineOp,
};

use super::{BinaryTag, Proof, ProofAuth};
use super::{BinaryTag, NonFungible, Proof, ProofAuth};
use crate::{
args::{
ConfidentialRevealArg,
Expand Down Expand Up @@ -273,6 +273,17 @@ impl Vault {
.expect("get_non_fungible_ids returned invalid non fungible ids")
}

/// Returns all the non-fungibles in this vault
pub fn get_non_fungibles(&self) -> Vec<NonFungible> {
let resp: InvokeResult = call_engine(EngineOp::VaultInvoke, &VaultInvokeArg {
vault_ref: self.vault_ref(),
action: VaultAction::GetNonFungibles,
args: invoke_args![],
});

resp.decode().expect("get_non_fungibles returned invalid non fungibles")
}

/// Returns the resource address of the tokens that this vault holds
pub fn resource_address(&self) -> ResourceAddress {
let resp: InvokeResult = call_engine(EngineOp::VaultInvoke, &VaultInvokeArg {
Expand Down
Loading