diff --git a/docs/content/developer/stardust/claiming/address-unlock-condition.mdx b/docs/content/developer/stardust/claiming/address-unlock-condition.mdx index 68371525101..f61a5f737fa 100644 --- a/docs/content/developer/stardust/claiming/address-unlock-condition.mdx +++ b/docs/content/developer/stardust/claiming/address-unlock-condition.mdx @@ -13,7 +13,7 @@ For this example, we're using an `AliasOutput` to extract an `Alias` object that -```rust file=/docs/examples/rust/stardust/address_unlock_condition.rs#L74-L90 +```rust file=/docs/examples/rust/stardust/address-unlock-condition.rs#L70-L88 ``` @@ -27,7 +27,7 @@ For this example, we're using an `AliasOutput` to extract an `Alias` object that -```rust file=/docs/examples/rust/stardust/address_unlock_condition.rs#L95-L105 +```rust file=/docs/examples/rust/stardust/address-unlock-condition.rs#L90-L103 ``` @@ -42,7 +42,7 @@ Applying the filter to get `NftOutput`s owned by the `Alias`. -```rust file=/docs/examples/rust/stardust/address_unlock_condition.rs#L109-L130 +```rust file=/docs/examples/rust/stardust/address-unlock-condition.rs#L105-L128 ``` @@ -56,7 +56,7 @@ Applying the filter to get `NftOutput`s owned by the `Alias`. -```rust file=/docs/examples/rust/stardust/address_unlock_condition.rs#L132-L241 +```rust file=/docs/examples/rust/stardust/address-unlock-condition.rs#L130-L239 ``` diff --git a/docs/content/developer/stardust/claiming/alias.mdx b/docs/content/developer/stardust/claiming/alias.mdx index 7e39ec47db1..16c03a6c89a 100644 --- a/docs/content/developer/stardust/claiming/alias.mdx +++ b/docs/content/developer/stardust/claiming/alias.mdx @@ -15,7 +15,7 @@ A Governor address can claim the `AliasOutput` assets at any time: -```rust file=/docs/examples/rust/stardust/alias-output-claim.rs#L74-L99 +```rust file=/docs/examples/rust/stardust/alias-output-claim.rs#L56-L81 ``` @@ -32,7 +32,7 @@ In the case of the native tokens, the keys are strings representing the [`OTW`]( -```rust file=/docs/examples/rust/stardust/alias-output-claim.rs#L101-L128 +```rust file=/docs/examples/rust/stardust/alias-output-claim.rs#L83-L110 ``` @@ -48,7 +48,7 @@ In fact, the main purpose of claiming is extracting the `Alias` object from the -```rust file=/docs/examples/rust/stardust/alias-output-claim.rs#L130-L198 +```rust file=/docs/examples/rust/stardust/alias-output-claim.rs#L112-L180 ``` @@ -80,9 +80,7 @@ Also, the `nft.move` module was extended with the following function: ``` - - Once the package is prepared, we can extract and use a Stardust `Alias` in a single transaction to create a `CollectionControllerCap`. @@ -91,7 +89,7 @@ This capability is then used in later transactions for managing new collections. -```rust file=/docs/examples/rust/stardust/alias-migration.rs#L122-L247 +```rust file=/docs/examples/rust/stardust/alias-migration.rs#L119-L244 ``` diff --git a/docs/content/developer/stardust/claiming/basic.mdx b/docs/content/developer/stardust/claiming/basic.mdx index 0c75c948d91..f0bdf636bed 100644 --- a/docs/content/developer/stardust/claiming/basic.mdx +++ b/docs/content/developer/stardust/claiming/basic.mdx @@ -26,7 +26,7 @@ Once a Basic Output can be unlocked the claim of its assets can start -```rust file=/docs/examples/rust/stardust/basic-output-claim.rs#L74-L99 +```rust file=/docs/examples/rust/stardust/basic-output-claim.rs#L56-L81 ``` @@ -43,7 +43,7 @@ TODO -```rust file=/docs/examples/rust/stardust/basic-output-claim.rs#L101-L128 +```rust file=/docs/examples/rust/stardust/basic-output-claim.rs#L83-L110 ``` @@ -59,7 +59,7 @@ TODO -```rust file=/docs/examples/rust/stardust/basic-output-claim.rs#L131-L195 +```rust file=/docs/examples/rust/stardust/basic-output-claim.rs#L113-L177 ``` diff --git a/docs/content/developer/stardust/claiming/foundry.mdx b/docs/content/developer/stardust/claiming/foundry.mdx index c65006df758..8826672693b 100644 --- a/docs/content/developer/stardust/claiming/foundry.mdx +++ b/docs/content/developer/stardust/claiming/foundry.mdx @@ -11,7 +11,7 @@ As seen in the [Move Models](../move-models) page, the Foundry Output does not h -```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L147-L159 +```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L60-L74 ``` @@ -26,7 +26,7 @@ As seen in the [Move Models](../move-models) page, the Foundry Output does not h -```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L164-L174 +```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L76-L89 ``` @@ -40,7 +40,7 @@ As seen in the [Move Models](../move-models) page, the Foundry Output does not h -```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L178-L216 +```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L91-L131 ``` @@ -54,7 +54,7 @@ As seen in the [Move Models](../move-models) page, the Foundry Output does not h -```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L220-L227 +```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L133-L142 ``` @@ -69,7 +69,7 @@ As seen in the [Move Models](../move-models) page, the Foundry Output does not h -```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L231-L300 +```rust file=/docs/examples/rust/stardust/foundry-output-claim.rs#L144-L215 ``` diff --git a/docs/content/developer/stardust/claiming/nft.mdx b/docs/content/developer/stardust/claiming/nft.mdx index f4c8128f2c7..875cc5fbbb9 100644 --- a/docs/content/developer/stardust/claiming/nft.mdx +++ b/docs/content/developer/stardust/claiming/nft.mdx @@ -14,7 +14,7 @@ Once an Nft Output can be unlocked the claim of its assets can start -```rust file=/docs/examples/rust/stardust/nft-output-claim.rs#L54-L78 +```rust file=/docs/examples/rust/stardust/nft-output-claim.rs#L56-L80 ``` @@ -29,7 +29,7 @@ Once an Nft Output can be unlocked the claim of its assets can start -```rust file=/docs/examples/rust/stardust/nft-output-claim.rs#L80-L105 +```rust file=/docs/examples/rust/stardust/nft-output-claim.rs#L82-L107 ``` @@ -45,7 +45,7 @@ In fact, the main purpose of claiming is extracting the `Nft` object from the `N -```rust file=/docs/examples/rust/stardust/nft-output-claim.rs#L107-L173 +```rust file=/docs/examples/rust/stardust/nft-output-claim.rs#L109-L175 ``` @@ -67,33 +67,17 @@ The following is an example of a simple module for representing a custom NFT, mi ``` - - -1. Publish a custom Nft package, and retrieve its package ID. - - - - -```rust file=/docs/examples/rust/stardust/nft-migration.rs#L210-L227 -``` - - - - - - - -2. Create a PTB that extracts the Stardust `Nft` from an `NftOutput` and then calls the `custom_nft::nft::convert` method for converting it into a `custom_nft::nft::Nft` of the collection just published. +Create a PTB that extracts the Stardust `Nft` from an `NftOutput` and then converts it into a custom NFT of the collection just published. This conversion method extracts the Stardust `Nft` metadata and uses it for minting a new NFT. -```rust file=/docs/examples/rust/stardust/nft-migration.rs#L84-L141 +```rust file=/docs/examples/rust/stardust/nft-migration.rs#L77-L137 ``` diff --git a/docs/content/developer/stardust/claiming/self-sponsor.mdx b/docs/content/developer/stardust/claiming/self-sponsor.mdx index cbb8921c788..8ecd7374180 100644 --- a/docs/content/developer/stardust/claiming/self-sponsor.mdx +++ b/docs/content/developer/stardust/claiming/self-sponsor.mdx @@ -14,7 +14,7 @@ This is useful for Shimmer assets, because none of the Move objects obtained fro -```rust file=/docs/examples/rust/stardust/shimmer-self-sponsor.rs#L61-L67 +```rust file=/docs/examples/rust/stardust/shimmer-self-sponsor.rs#L44-L50 ``` @@ -31,7 +31,7 @@ TODO -```rust file=/docs/examples/rust/stardust/shimmer-self-sponsor.rs#L103-L152 +```rust file=/docs/examples/rust/stardust/shimmer-self-sponsor.rs#L85-L135 ``` @@ -47,7 +47,7 @@ TODO -```rust file=/docs/examples/rust/stardust/shimmer-self-sponsor.rs#L168-L194 +```rust file=/docs/examples/rust/stardust/shimmer-self-sponsor.rs#L151-L177 ``` diff --git a/docs/examples/rust/Cargo.toml b/docs/examples/rust/Cargo.toml index 4dff5785e23..f4741516b5f 100644 --- a/docs/examples/rust/Cargo.toml +++ b/docs/examples/rust/Cargo.toml @@ -6,22 +6,25 @@ edition = "2021" license = "Apache-2.0" publish = false -[dev-dependencies] +[dependencies] anyhow.workspace = true + +iota-keys.workspace = true +iota-move-build.workspace = true +iota-sdk.workspace = true +shared-crypto.workspace = true + +[dev-dependencies] bcs.workspace = true bip32.workspace = true serde_json.workspace = true tokio.workspace = true -iota-keys.workspace = true -iota-move-build.workspace = true -iota-sdk.workspace = true move-core-types.workspace = true -shared-crypto.workspace = true [[example]] -name = "address_unlock_condition" -path = "stardust/address_unlock_condition.rs" +name = "address-unlock-condition" +path = "stardust/address-unlock-condition.rs" [[example]] name = "nft-output-claim" diff --git a/docs/examples/rust/src/lib.rs b/docs/examples/rust/src/lib.rs new file mode 100644 index 00000000000..0d76a1a1e6e --- /dev/null +++ b/docs/examples/rust/src/lib.rs @@ -0,0 +1,4 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +pub mod utils; diff --git a/docs/examples/rust/src/utils.rs b/docs/examples/rust/src/utils.rs new file mode 100644 index 00000000000..b8eb717c629 --- /dev/null +++ b/docs/examples/rust/src/utils.rs @@ -0,0 +1,194 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! A set of utility functions for the examples. + +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use anyhow::{anyhow, Result}; +use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use iota_move_build::BuildConfig; +use iota_sdk::{ + rpc_types::{IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponseOptions}, + types::{ + base_types::{IotaAddress, ObjectID}, + crypto::SignatureScheme::ED25519, + programmable_transaction_builder::ProgrammableTransactionBuilder, + quorum_driver_types::ExecuteTransactionRequestType, + transaction::{Transaction, TransactionData}, + }, + IotaClient, +}; +use shared_crypto::intent::Intent; + +/// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs +const SPONSOR_ADDRESS_MNEMONIC: &str = "okay pottery arch air egg very cave cash poem gown sorry mind poem crack dawn wet car pink extra crane hen bar boring salt"; + +/// Move Custom NFT example relative path +const CUSTOM_NFT_PACKAGE_PATH: &str = "../move/custom_nft"; + +/// Creates a temporary keystore. +pub fn setup_keystore() -> Result { + let keystore_path = PathBuf::from("iotatempdb"); + if !keystore_path.exists() { + let keystore = FileBasedKeystore::new(&keystore_path)?; + keystore.save()?; + } + // Read iota keystore + FileBasedKeystore::new(&keystore_path) +} + +/// Deletes the temporary keystore. +pub fn clean_keystore() -> Result<(), anyhow::Error> { + // Remove files + fs::remove_file("iotatempdb")?; + fs::remove_file("iotatempdb.aliases")?; + Ok(()) +} + +/// Utility function for funding an address using the transfer of a coin. +pub async fn fund_address( + iota_client: &IotaClient, + keystore: &mut FileBasedKeystore, + recipient: IotaAddress, +) -> Result<(), anyhow::Error> { + // Derive the address of the sponsor. + let sponsor = keystore.import_from_mnemonic(SPONSOR_ADDRESS_MNEMONIC, ED25519, None)?; + + println!("Sponsor address: {sponsor:?}"); + + // Get a gas coin. + let gas_coin = iota_client + .coin_read_api() + .get_coins(sponsor, None, None, None) + .await? + .data + .into_iter() + .next() + .ok_or(anyhow!("No coins found for sponsor"))?; + + let pt = { + // Init a programmable transaction builder. + let mut builder = ProgrammableTransactionBuilder::new(); + // Pay all iotas from the gas object + builder.pay_all_iota(recipient); + builder.finish() + }; + + // Setup a gas budget and a gas price. + let gas_budget = 10_000_000; + let gas_price = iota_client.read_api().get_reference_gas_price().await?; + + // Create a transaction data that will be sent to the network. + let tx_data = TransactionData::new_programmable( + sponsor, + vec![gas_coin.object_ref()], + pt, + gas_budget, + gas_price, + ); + + // Sign the transaction. + let signature = keystore.sign_secure(&sponsor, &tx_data, Intent::iota_transaction())?; + + // Execute the transaction. + let transaction_response = iota_client + .quorum_driver_api() + .execute_transaction_block( + Transaction::from_data(tx_data, vec![signature]), + IotaTransactionBlockResponseOptions::full_content(), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await?; + + println!( + "Funding transaction digest: {}", + transaction_response.digest + ); + + Ok(()) +} + +/// Utility function for publishing a custom NFT package found in the Move +/// examples. +pub async fn publish_custom_nft_package( + sender: IotaAddress, + keystore: &mut FileBasedKeystore, + iota_client: &IotaClient, +) -> Result { + // Get a gas coin + let gas_coin = iota_client + .coin_read_api() + .get_coins(sender, None, None, None) + .await? + .data + .into_iter() + .next() + .ok_or(anyhow!("No coins found"))?; + + // Build custom nft package + let package_path = Path::new(env!("CARGO_MANIFEST_DIR")).join(CUSTOM_NFT_PACKAGE_PATH); + let compiled_package = BuildConfig::default().build(package_path)?; + let modules = compiled_package + .get_modules() + .map(|module| { + let mut buf = Vec::new(); + module.serialize(&mut buf)?; + Ok(buf) + }) + .collect::>>>()?; + let dependencies = compiled_package.get_dependency_original_package_ids(); + + // Publish package + let pt = { + let mut builder = ProgrammableTransactionBuilder::new(); + builder.publish_immutable(modules, dependencies); + builder.finish() + }; + + // Setup gas budget and gas price + let gas_budget = 50_000_000; + let gas_price = iota_client.read_api().get_reference_gas_price().await?; + + // Create the transaction data that will be sent to the network + let tx_data = TransactionData::new_programmable( + sender, + vec![gas_coin.object_ref()], + pt, + gas_budget, + gas_price, + ); + + // Sign the transaction + let signature = keystore.sign_secure(&sender, &tx_data, Intent::iota_transaction())?; + + // Execute transaction + let transaction_response = iota_client + .quorum_driver_api() + .execute_transaction_block( + Transaction::from_data(tx_data, vec![signature]), + IotaTransactionBlockResponseOptions::full_content(), + Some(ExecuteTransactionRequestType::WaitForLocalExecution), + ) + .await?; + + println!( + "Package publishing transaction digest: {}", + transaction_response.digest + ); + + // Extract package id from the transaction effects + let tx_effects = transaction_response + .effects + .expect("Transaction has no effects"); + let package_ref = tx_effects + .created() + .first() + .expect("There are no created objects"); + let package_id = package_ref.reference.object_id; + println!("Package ID: {package_id}"); + Ok(package_id) +} diff --git a/docs/examples/rust/stardust/address_unlock_condition.rs b/docs/examples/rust/stardust/address-unlock-condition.rs similarity index 78% rename from docs/examples/rust/stardust/address_unlock_condition.rs rename to docs/examples/rust/stardust/address-unlock-condition.rs index 914ecf057a5..e3383b79de0 100644 --- a/docs/examples/rust/stardust/address_unlock_condition.rs +++ b/docs/examples/rust/stardust/address-unlock-condition.rs @@ -5,18 +5,19 @@ //! In order to work, it requires a network with test objects //! generated from iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf, str::FromStr}; +use std::str::FromStr; use anyhow::anyhow; use bip32::DerivationPath; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use docs_examples::utils::{clean_keystore, fund_address, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ rpc_types::{ IotaObjectDataFilter, IotaObjectDataOptions, IotaObjectResponseQuery, IotaTransactionBlockResponseOptions, }, types::{ - base_types::{IotaAddress, ObjectID}, + base_types::ObjectID, crypto::SignatureScheme::ED25519, dynamic_field::DynamicFieldName, gas_coin::GAS, @@ -26,14 +27,11 @@ use iota_sdk::{ transaction::{Argument, ObjectArg, Transaction, TransactionData}, TypeTag, IOTA_FRAMEWORK_ADDRESS, STARDUST_ADDRESS, }, - IotaClient, IotaClientBuilder, + IotaClientBuilder, }; use move_core_types::ident_str; use shared_crypto::intent::Intent; -/// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs -const SPONSOR_ADDRESS_MNEMONIC: &str = "okay pottery arch air egg very cave cash poem gown sorry mind poem crack dawn wet car pink extra crane hen bar boring salt"; - /// Got from iota-genesis-builder/src/stardust/test_outputs/alias_ownership.rs const MAIN_ADDRESS_MNEMONIC: &str = "few hood high omit camp keep burger give happy iron evolve draft few dawn pulp jazz box dash load snake gown bag draft car"; @@ -271,83 +269,3 @@ async fn main() -> Result<(), anyhow::Error> { // Finish and clean the temporary keystore file clean_keystore() } - -fn setup_keystore() -> Result { - // Create a temporary keystore - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read iota keystore - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove files - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} - -async fn fund_address( - iota_client: &IotaClient, - keystore: &mut FileBasedKeystore, - recipient: IotaAddress, -) -> Result<(), anyhow::Error> { - // Derive the address of the sponsor. - let sponsor = keystore.import_from_mnemonic(SPONSOR_ADDRESS_MNEMONIC, ED25519, None)?; - - println!("Sponsor address: {sponsor:?}"); - - // Get a gas coin. - let gas_coin = iota_client - .coin_read_api() - .get_coins(sponsor, None, None, None) - .await? - .data - .into_iter() - .next() - .ok_or(anyhow!("No coins found for sponsor"))?; - - let pt = { - // Init a programmable transaction builder. - let mut builder = ProgrammableTransactionBuilder::new(); - // Pay all iotas from the gas object - builder.pay_all_iota(recipient); - builder.finish() - }; - - // Setup a gas budget and a gas price. - let gas_budget = 10_000_000; - let gas_price = iota_client.read_api().get_reference_gas_price().await?; - - // Create a transaction data that will be sent to the network. - let tx_data = TransactionData::new_programmable( - sponsor, - vec![gas_coin.object_ref()], - pt, - gas_budget, - gas_price, - ); - - // Sign the transaction. - let signature = keystore.sign_secure(&sponsor, &tx_data, Intent::iota_transaction())?; - - // Execute the transaction. - let transaction_response = iota_client - .quorum_driver_api() - .execute_transaction_block( - Transaction::from_data(tx_data, vec![signature]), - IotaTransactionBlockResponseOptions::full_content(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - - println!( - "Funding transaction digest: {}", - transaction_response.digest - ); - - Ok(()) -} diff --git a/docs/examples/rust/stardust/alias-migration.rs b/docs/examples/rust/stardust/alias-migration.rs index 562ab20f89b..035c6de6090 100644 --- a/docs/examples/rust/stardust/alias-migration.rs +++ b/docs/examples/rust/stardust/alias-migration.rs @@ -6,18 +6,15 @@ //! with test objects generated from //! iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf, str::FromStr}; +use std::str::FromStr; use anyhow::{anyhow, Result}; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; -use iota_move_build::BuildConfig; +use docs_examples::utils::{clean_keystore, publish_custom_nft_package, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ - rpc_types::{ - IotaData, IotaObjectDataOptions, IotaTransactionBlockEffectsAPI, - IotaTransactionBlockResponseOptions, - }, + rpc_types::{IotaData, IotaObjectDataOptions, IotaTransactionBlockResponseOptions}, types::{ - base_types::{IotaAddress, ObjectID}, + base_types::ObjectID, crypto::SignatureScheme::ED25519, gas_coin::GAS, programmable_transaction_builder::ProgrammableTransactionBuilder, @@ -26,14 +23,13 @@ use iota_sdk::{ transaction::{Argument, CallArg, ObjectArg, Transaction, TransactionData}, TypeTag, IOTA_FRAMEWORK_PACKAGE_ID, STARDUST_PACKAGE_ID, }, - IotaClient, IotaClientBuilder, + IotaClientBuilder, }; use move_core_types::ident_str; use shared_crypto::intent::Intent; /// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs const MAIN_ADDRESS_MNEMONIC: &str = "okay pottery arch air egg very cave cash poem gown sorry mind poem crack dawn wet car pink extra crane hen bar boring salt"; -const CUSTOM_NFT_PACKAGE_PATH: &str = "../move/custom_nft"; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { @@ -49,9 +45,10 @@ async fn main() -> Result<(), anyhow::Error> { println!("{sender:?}"); // Publish the package of a custom NFT collection and then get the package id. + // The custom NFT module is obtained from a Move example in the docs. + // It is the same used in the Nft migration example. let custom_nft_package_id = - publish_custom_nft_package(sender, &mut keystore, &iota_client, CUSTOM_NFT_PACKAGE_PATH) - .await?; + publish_custom_nft_package(sender, &mut keystore, &iota_client).await?; // Get a gas coin let gas_coin = iota_client @@ -277,100 +274,3 @@ async fn main() -> Result<(), anyhow::Error> { // Finish and clean the temporary keystore file clean_keystore() } - -fn setup_keystore() -> Result { - // Create a temporary keystore - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read iota keystore - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove files - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} - -async fn publish_custom_nft_package( - sender: IotaAddress, - keystore: &mut FileBasedKeystore, - iota_client: &IotaClient, - package_path: &str, -) -> Result { - // Get a gas coin - let gas_coin = iota_client - .coin_read_api() - .get_coins(sender, None, None, None) - .await? - .data - .into_iter() - .next() - .ok_or(anyhow!("No coins found"))?; - - // Build custom nft package - let compiled_package = BuildConfig::default().build(package_path.into())?; - let modules = compiled_package - .get_modules() - .map(|module| { - let mut buf = Vec::new(); - module.serialize(&mut buf)?; - Ok(buf) - }) - .collect::>>>()?; - let dependencies = compiled_package.get_dependency_original_package_ids(); - - // Publish package - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder.publish_immutable(modules, dependencies); - builder.finish() - }; - - // Setup gas budget and gas price - let gas_budget = 50_000_000; - let gas_price = iota_client.read_api().get_reference_gas_price().await?; - - // Create the transaction data that will be sent to the network - let tx_data = TransactionData::new_programmable( - sender, - vec![gas_coin.object_ref()], - pt, - gas_budget, - gas_price, - ); - - // Sign the transaction - let signature = keystore.sign_secure(&sender, &tx_data, Intent::iota_transaction())?; - - // Execute transaction - let transaction_response = iota_client - .quorum_driver_api() - .execute_transaction_block( - Transaction::from_data(tx_data, vec![signature]), - IotaTransactionBlockResponseOptions::full_content(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - - println!( - "Package publishing transaction digest: {}", - transaction_response.digest - ); - - // Extract package id from the transaction effects - let tx_effects = transaction_response - .effects - .expect("Transaction has no effects"); - let package_ref = tx_effects - .created() - .first() - .expect("There are no created objects"); - let package_id = package_ref.reference.object_id; - println!("Package ID: {}", package_id); - Ok(package_id) -} diff --git a/docs/examples/rust/stardust/alias-output-claim.rs b/docs/examples/rust/stardust/alias-output-claim.rs index f2a710e797e..d8613caf3c0 100644 --- a/docs/examples/rust/stardust/alias-output-claim.rs +++ b/docs/examples/rust/stardust/alias-output-claim.rs @@ -5,10 +5,11 @@ //! In order to work, it requires a network with test objects //! generated from iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf, str::FromStr}; +use std::str::FromStr; use anyhow::anyhow; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use docs_examples::utils::{clean_keystore, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ rpc_types::{IotaData, IotaObjectDataOptions, IotaTransactionBlockResponseOptions}, types::{ @@ -29,25 +30,6 @@ use shared_crypto::intent::Intent; /// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs const MAIN_ADDRESS_MNEMONIC: &str = "okay pottery arch air egg very cave cash poem gown sorry mind poem crack dawn wet car pink extra crane hen bar boring salt"; -/// Creates a temporary keystore. -fn setup_keystore() -> Result { - // Create a temporary keystore. - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read the iota keystore. - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove the keystore files. - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} - #[tokio::main] async fn main() -> Result<(), anyhow::Error> { // Build an IOTA client for a local network. diff --git a/docs/examples/rust/stardust/basic-output-claim.rs b/docs/examples/rust/stardust/basic-output-claim.rs index 38dd8766965..eaf0aecd916 100644 --- a/docs/examples/rust/stardust/basic-output-claim.rs +++ b/docs/examples/rust/stardust/basic-output-claim.rs @@ -5,10 +5,11 @@ //! In order to work, it requires a network with test objects //! generated from iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf, str::FromStr}; +use std::str::FromStr; use anyhow::anyhow; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use docs_examples::utils::{clean_keystore, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ rpc_types::{IotaData, IotaObjectDataOptions, IotaTransactionBlockResponseOptions}, types::{ @@ -29,25 +30,6 @@ use shared_crypto::intent::Intent; /// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs const MAIN_ADDRESS_MNEMONIC: &str = "rain flip mad lamp owner siren tower buddy wolf shy tray exit glad come dry tent they pond wrist web cliff mixed seek drum"; -/// Creates a temporary keystore -fn setup_keystore() -> Result { - // Create a temporary keystore - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read iota keystore - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove files - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} - #[tokio::main] async fn main() -> Result<(), anyhow::Error> { // Build an iota client for a local network diff --git a/docs/examples/rust/stardust/foundry-output-claim.rs b/docs/examples/rust/stardust/foundry-output-claim.rs index 3c9fc0880c8..826cd6ea46d 100644 --- a/docs/examples/rust/stardust/foundry-output-claim.rs +++ b/docs/examples/rust/stardust/foundry-output-claim.rs @@ -5,16 +5,15 @@ //! foundry output. In order to work, it requires a network with test objects //! generated from iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf}; - use anyhow::anyhow; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use docs_examples::utils::{clean_keystore, fund_address, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ rpc_types::{ IotaObjectDataOptions, IotaObjectResponseQuery, IotaTransactionBlockResponseOptions, }, types::{ - base_types::{IotaAddress, ObjectID}, + base_types::ObjectID, coin_manager::CoinManagerTreasuryCap, crypto::SignatureScheme::ED25519, dynamic_field::DynamicFieldName, @@ -24,7 +23,7 @@ use iota_sdk::{ transaction::{Argument, ObjectArg, Transaction, TransactionData}, TypeTag, IOTA_FRAMEWORK_ADDRESS, STARDUST_ADDRESS, }, - IotaClient, IotaClientBuilder, + IotaClientBuilder, }; use move_core_types::{ident_str, language_storage::StructTag}; use shared_crypto::intent::Intent; @@ -32,90 +31,6 @@ use shared_crypto::intent::Intent; /// Got from iota-genesis-builder/src/stardust/test_outputs/alias_ownership.rs const MAIN_ADDRESS_MNEMONIC: &str = "few hood high omit camp keep burger give happy iron evolve draft few dawn pulp jazz box dash load snake gown bag draft car"; -/// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs -const SPONSOR_ADDRESS_MNEMONIC: &str = "okay pottery arch air egg very cave cash poem gown sorry mind poem crack dawn wet car pink extra crane hen bar boring salt"; - -/// Creates a temporary keystore. -fn setup_keystore() -> Result { - // Create a temporary keystore. - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read the iota keystore. - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove the keystore files. - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} - -async fn fund_address( - iota_client: &IotaClient, - keystore: &mut FileBasedKeystore, - recipient: IotaAddress, -) -> Result<(), anyhow::Error> { - // Derive the address of the sponsor. - let sponsor = keystore.import_from_mnemonic(SPONSOR_ADDRESS_MNEMONIC, ED25519, None)?; - - println!("Sponsor address: {sponsor:?}"); - - // Get a gas coin. - let gas_coin = iota_client - .coin_read_api() - .get_coins(sponsor, None, None, None) - .await? - .data - .into_iter() - .next() - .ok_or(anyhow!("No coins found for sponsor"))?; - - let pt = { - // Init a programmable transaction builder. - let mut builder = ProgrammableTransactionBuilder::new(); - // Pay all iotas from the gas object - builder.pay_all_iota(recipient); - builder.finish() - }; - - // Setup a gas budget and a gas price. - let gas_budget = 10_000_000; - let gas_price = iota_client.read_api().get_reference_gas_price().await?; - - // Create a transaction data that will be sent to the network. - let tx_data = TransactionData::new_programmable( - sponsor, - vec![gas_coin.object_ref()], - pt, - gas_budget, - gas_price, - ); - - // Sign the transaction. - let signature = keystore.sign_secure(&sponsor, &tx_data, Intent::iota_transaction())?; - - // Execute the transaction. - let transaction_response = iota_client - .quorum_driver_api() - .execute_transaction_block( - Transaction::from_data(tx_data, vec![signature]), - IotaTransactionBlockResponseOptions::full_content(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - - println!( - "Funding transaction digest: {}", - transaction_response.digest - ); - - Ok(()) -} - #[tokio::main] async fn main() -> Result<(), anyhow::Error> { // Build an IOTA client for a local network. diff --git a/docs/examples/rust/stardust/nft-migration.rs b/docs/examples/rust/stardust/nft-migration.rs index c220aa6cd1d..f8510281131 100644 --- a/docs/examples/rust/stardust/nft-migration.rs +++ b/docs/examples/rust/stardust/nft-migration.rs @@ -5,17 +5,13 @@ //! NFT. In order to work, it requires a network with test objects //! generated from iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf}; - use anyhow::{anyhow, Result}; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; -use iota_move_build::BuildConfig; +use docs_examples::utils::{clean_keystore, publish_custom_nft_package, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ - rpc_types::{ - IotaObjectDataOptions, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponseOptions, - }, + rpc_types::{IotaObjectDataOptions, IotaTransactionBlockResponseOptions}, types::{ - base_types::{IotaAddress, ObjectID}, + base_types::ObjectID, crypto::SignatureScheme::ED25519, gas_coin::GAS, programmable_transaction_builder::ProgrammableTransactionBuilder, @@ -23,14 +19,13 @@ use iota_sdk::{ transaction::{Argument, ObjectArg, Transaction, TransactionData}, IOTA_FRAMEWORK_ADDRESS, STARDUST_ADDRESS, }, - IotaClient, IotaClientBuilder, + IotaClientBuilder, }; use move_core_types::ident_str; use shared_crypto::intent::Intent; /// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs const MAIN_ADDRESS_MNEMONIC: &str = "okay pottery arch air egg very cave cash poem gown sorry mind poem crack dawn wet car pink extra crane hen bar boring salt"; -const CUSTOM_NFT_PACKAGE_PATH: &str = "../move/custom_nft"; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { @@ -46,9 +41,10 @@ async fn main() -> Result<(), anyhow::Error> { println!("{sender:?}"); // Publish the package of a custom NFT collection and then get the package id. + // The custom NFT module is obtained from a Move example in the docs. + // It is the same used in the Alias migration example. let custom_nft_package_id = - publish_custom_nft_package(sender, &mut keystore, &iota_client, CUSTOM_NFT_PACKAGE_PATH) - .await?; + publish_custom_nft_package(sender, &mut keystore, &iota_client).await?; // Get a gas coin let gas_coin = iota_client @@ -171,100 +167,3 @@ async fn main() -> Result<(), anyhow::Error> { // Finish and clean the temporary keystore file clean_keystore() } - -fn setup_keystore() -> Result { - // Create a temporary keystore - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read iota keystore - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove files - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} - -async fn publish_custom_nft_package( - sender: IotaAddress, - keystore: &mut FileBasedKeystore, - iota_client: &IotaClient, - package_path: &str, -) -> Result { - // Get a gas coin - let gas_coin = iota_client - .coin_read_api() - .get_coins(sender, None, None, None) - .await? - .data - .into_iter() - .next() - .ok_or(anyhow!("No coins found"))?; - - // Build custom nft package - let compiled_package = BuildConfig::default().build(package_path.into())?; - let modules = compiled_package - .get_modules() - .map(|module| { - let mut buf = Vec::new(); - module.serialize(&mut buf)?; - Ok(buf) - }) - .collect::>>>()?; - let dependencies = compiled_package.get_dependency_original_package_ids(); - - // Publish package - let pt = { - let mut builder = ProgrammableTransactionBuilder::new(); - builder.publish_immutable(modules, dependencies); - builder.finish() - }; - - // Setup gas budget and gas price - let gas_budget = 50_000_000; - let gas_price = iota_client.read_api().get_reference_gas_price().await?; - - // Create the transaction data that will be sent to the network - let tx_data = TransactionData::new_programmable( - sender, - vec![gas_coin.object_ref()], - pt, - gas_budget, - gas_price, - ); - - // Sign the transaction - let signature = keystore.sign_secure(&sender, &tx_data, Intent::iota_transaction())?; - - // Execute transaction - let transaction_response = iota_client - .quorum_driver_api() - .execute_transaction_block( - Transaction::from_data(tx_data, vec![signature]), - IotaTransactionBlockResponseOptions::full_content(), - Some(ExecuteTransactionRequestType::WaitForLocalExecution), - ) - .await?; - - println!( - "Package publishing transaction digest: {}", - transaction_response.digest - ); - - // Extract package id from the transaction effects - let tx_effects = transaction_response - .effects - .expect("Transaction has no effects"); - let package_ref = tx_effects - .created() - .first() - .expect("There are no created objects"); - let package_id = package_ref.reference.object_id; - println!("Package ID: {}", package_id); - Ok(package_id) -} diff --git a/docs/examples/rust/stardust/nft-output-claim.rs b/docs/examples/rust/stardust/nft-output-claim.rs index 78e66a31123..3d80afa83f1 100644 --- a/docs/examples/rust/stardust/nft-output-claim.rs +++ b/docs/examples/rust/stardust/nft-output-claim.rs @@ -5,10 +5,11 @@ //! In order to work, it requires a network with test objects //! generated from iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf, str::FromStr}; +use std::str::FromStr; use anyhow::anyhow; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use docs_examples::utils::{clean_keystore, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ rpc_types::{IotaData, IotaObjectDataOptions, IotaTransactionBlockResponseOptions}, types::{ @@ -25,6 +26,7 @@ use iota_sdk::{ }; use move_core_types::ident_str; use shared_crypto::intent::Intent; + /// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs const MAIN_ADDRESS_MNEMONIC: &str = "okay pottery arch air egg very cave cash poem gown sorry mind poem crack dawn wet car pink extra crane hen bar boring salt"; @@ -203,21 +205,3 @@ async fn main() -> Result<(), anyhow::Error> { // Finish and clean the temporary keystore file clean_keystore() } - -fn setup_keystore() -> Result { - // Create a temporary keystore - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read iota keystore - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove files - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} diff --git a/docs/examples/rust/stardust/shimmer-self-sponsor.rs b/docs/examples/rust/stardust/shimmer-self-sponsor.rs index 1c8a8166245..89ddf2af64f 100644 --- a/docs/examples/rust/stardust/shimmer-self-sponsor.rs +++ b/docs/examples/rust/stardust/shimmer-self-sponsor.rs @@ -5,11 +5,12 @@ //! output. In order to work, it requires a network with test objects //! generated from iota-genesis-builder/src/stardust/test_outputs. -use std::{fs, path::PathBuf, str::FromStr}; +use std::str::FromStr; use anyhow::anyhow; use bip32::DerivationPath; -use iota_keys::keystore::{AccountKeystore, FileBasedKeystore}; +use docs_examples::utils::{clean_keystore, setup_keystore}; +use iota_keys::keystore::AccountKeystore; use iota_sdk::{ rpc_types::{IotaObjectDataOptions, IotaTransactionBlockResponseOptions}, types::{ @@ -32,24 +33,6 @@ pub const SHIMMER_COIN_TYPE: u32 = 4219; /// Got from iota-genesis-builder/src/stardust/test_outputs/stardust_mix.rs const MAIN_ADDRESS_MNEMONIC: &str = "crazy drum raw dirt tooth where fee base warm beach trim rule sign silk fee fee dad large creek venue coin steel hub scale"; -/// Creates a temporary keystore -fn setup_keystore() -> Result { - let keystore_path = PathBuf::from("iotatempdb"); - if !keystore_path.exists() { - let keystore = FileBasedKeystore::new(&keystore_path)?; - keystore.save()?; - } - // Read iota keystore - FileBasedKeystore::new(&keystore_path) -} - -fn clean_keystore() -> Result<(), anyhow::Error> { - // Remove files - fs::remove_file("iotatempdb")?; - fs::remove_file("iotatempdb.aliases")?; - Ok(()) -} - #[tokio::main] async fn main() -> Result<(), anyhow::Error> { // Build an iota client for a local network