use iota_sdk::{
client::{request_funds_from_faucet, secret::SecretManager, Client, Result},
types::block::{
address::AliasAddress,
output::{
feature::{IssuerFeature, MetadataFeature, SenderFeature},
unlock_condition::{
AddressUnlockCondition, ExpirationUnlockCondition, GovernorAddressUnlockCondition,
ImmutableAliasAddressUnlockCondition, StateControllerAddressUnlockCondition,
StorageDepositReturnUnlockCondition, TimelockUnlockCondition,
},
AliasId, AliasOutputBuilder, BasicOutputBuilder, FoundryId, FoundryOutputBuilder, NativeToken, NftId,
NftOutputBuilder, Output, OutputId, SimpleTokenScheme, TokenId, TokenScheme,
},
payload::{transaction::TransactionEssence, Payload},
},
};
use primitive_types::U256;
#[tokio::main]
async fn main() -> Result<()> {
dotenvy::dotenv().ok();
let node_url = std::env::var("NODE_URL").unwrap();
let faucet_url = std::env::var("FAUCET_URL").unwrap();
let client = Client::builder().with_node(&node_url)?.finish()?;
let secret_manager =
SecretManager::try_from_mnemonic(&std::env::var("NON_SECURE_USE_OF_DEVELOPMENT_MNEMONIC_1").unwrap())?;
let token_supply = client.get_token_supply().await?;
let address = client.get_addresses(&secret_manager).with_range(0..1).get_raw().await?[0];
println!(
"{}",
request_funds_from_faucet(&faucet_url, &address.to_bech32(client.get_bech32_hrp().await?)).await?
);
tokio::time::sleep(std::time::Duration::from_secs(15)).await;
let alias_output_builder = AliasOutputBuilder::new_with_amount(2_000_000, AliasId::null())?
.add_feature(SenderFeature::new(address))
.add_feature(MetadataFeature::new(vec![1, 2, 3])?)
.add_immutable_feature(IssuerFeature::new(address))
.add_unlock_condition(StateControllerAddressUnlockCondition::new(address))
.add_unlock_condition(GovernorAddressUnlockCondition::new(address));
let nft_output_builder = NftOutputBuilder::new_with_amount(1_000_000, NftId::null())?
.add_unlock_condition(AddressUnlockCondition::new(address));
let outputs = vec![
alias_output_builder.clone().finish_output(token_supply)?,
nft_output_builder
.clone()
.finish_output(token_supply)?,
];
let block = client
.block()
.with_secret_manager(&secret_manager)
.with_outputs(outputs)?
.finish()
.await?;
println!(
"Transaction with new nft and alias output sent: {node_url}/api/core/v2/blocks/{}",
block.id()
);
let _ = client.retry_until_included(&block.id(), None, None).await?;
let alias_output_id_1 = get_alias_output_id(block.payload().unwrap())?;
let alias_id = AliasId::from(&alias_output_id_1);
let nft_output_id = get_nft_output_id(block.payload().unwrap())?;
let nft_id = NftId::from(&nft_output_id);
let token_scheme = TokenScheme::Simple(SimpleTokenScheme::new(U256::from(50), U256::from(0), U256::from(100))?);
let foundry_id = FoundryId::build(
&AliasAddress::from(AliasId::from(&alias_output_id_1)),
1,
token_scheme.kind(),
);
let token_id = TokenId::from(foundry_id);
let foundry_output_builder = FoundryOutputBuilder::new_with_amount(1_000_000, 1, token_scheme)?
.add_unlock_condition(ImmutableAliasAddressUnlockCondition::new(AliasAddress::from(alias_id)));
let outputs = vec![
alias_output_builder
.clone()
.with_amount(1_000_000)?
.with_alias_id(alias_id)
.with_state_index(1)
.with_foundry_counter(1)
.finish_output(token_supply)?,
foundry_output_builder
.clone()
.add_native_token(NativeToken::new(token_id, U256::from(50))?)
.finish_output(token_supply)?,
nft_output_builder
.clone()
.with_nft_id(nft_id)
.finish_output(token_supply)?,
];
let block = client
.block()
.with_secret_manager(&secret_manager)
.with_outputs(outputs)?
.finish()
.await?;
println!(
"Transaction with alias id, foundry output with minted native tokens, and nfts sent: {node_url}/api/core/v2/blocks/{}",
block.id()
);
let _ = client.retry_until_included(&block.id(), None, None).await?;
let basic_output_builder =
BasicOutputBuilder::new_with_amount(1_000_000)?.add_unlock_condition(AddressUnlockCondition::new(address));
let outputs = vec![
alias_output_builder
.with_amount(1_000_000)?
.with_alias_id(alias_id)
.with_state_index(2)
.with_foundry_counter(1)
.finish_output(token_supply)?,
foundry_output_builder.finish_output(token_supply)?,
nft_output_builder.with_nft_id(nft_id).finish_output(token_supply)?,
basic_output_builder
.clone()
.add_native_token(NativeToken::new(token_id, U256::from(50))?)
.finish_output(token_supply)?,
basic_output_builder.clone().finish_output(token_supply)?,
basic_output_builder
.clone()
.add_feature(MetadataFeature::new(vec![13, 37])?)
.finish_output(token_supply)?,
basic_output_builder
.clone()
.with_amount(234_100)?
.add_unlock_condition(StorageDepositReturnUnlockCondition::new(
address,
234_000,
token_supply,
)?)
.finish_output(token_supply)?,
basic_output_builder
.clone()
.add_unlock_condition(ExpirationUnlockCondition::new(address, 1)?)
.finish_output(token_supply)?,
basic_output_builder
.clone()
.add_unlock_condition(TimelockUnlockCondition::new(1)?)
.finish_output(token_supply)?,
];
let block = client
.block()
.with_secret_manager(&secret_manager)
.with_outputs(outputs)?
.finish()
.await?;
println!(
"Transaction with all outputs sent: {node_url}/api/core/v2/blocks/{}",
block.id()
);
let _ = client.retry_until_included(&block.id(), None, None).await?;
Ok(())
}
fn get_alias_output_id(payload: &Payload) -> Result<OutputId> {
match payload {
Payload::Transaction(tx_payload) => {
let TransactionEssence::Regular(regular) = tx_payload.essence();
for (index, output) in regular.outputs().iter().enumerate() {
if let Output::Alias(_alias_output) = output {
return Ok(OutputId::new(tx_payload.id(), index.try_into().unwrap())?);
}
}
panic!("No alias output in transaction essence")
}
_ => panic!("No tx payload"),
}
}
fn get_nft_output_id(payload: &Payload) -> Result<OutputId> {
match payload {
Payload::Transaction(tx_payload) => {
let TransactionEssence::Regular(regular) = tx_payload.essence();
for (index, output) in regular.outputs().iter().enumerate() {
if let Output::Nft(_nft_output) = output {
return Ok(OutputId::new(tx_payload.id(), index.try_into().unwrap())?);
}
}
panic!("No nft output in transaction essence")
}
_ => panic!("No tx payload"),
}
}