Build an Alias Output
The following code example will:
- Create a
Client
which will connect to the Shimmer Testnet. - Create a
SecretManager
from a mnemonic. - Build an Alias output.
Code Example
- Rust
- Nodejs
- Python
- Java
Dotenv
This example uses dotenv, which is not safe to use in production environments.
// Copyright 2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
//! cargo run --example alias --release
use iota_client::{
block::{
output::{
feature::{IssuerFeature, MetadataFeature, SenderFeature},
unlock_condition::{
GovernorAddressUnlockCondition, StateControllerAddressUnlockCondition, UnlockCondition,
},
AliasId, AliasOutputBuilder, Feature, Output, OutputId,
},
payload::{transaction::TransactionEssence, Payload},
},
request_funds_from_faucet,
secret::{mnemonic::MnemonicSecretManager, SecretManager},
Client, Result,
};
/// In this example we will create an alias output
#[tokio::main]
async fn main() -> Result<()> {
// This example uses dotenv, which is not safe for use in production!
// Configure your own mnemonic in the ".env" file. Since the output amount cannot be zero, the seed must contain
// non-zero balance.
dotenv::dotenv().ok();
let node_url = std::env::var("NODE_URL").unwrap();
let faucet_url = std::env::var("FAUCET_URL").unwrap();
// Create a client instance.
let client = Client::builder().with_node(&node_url)?.finish()?;
let secret_manager = SecretManager::Mnemonic(MnemonicSecretManager::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];
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;
//////////////////////////////////
// create new alias output
//////////////////////////////////
let alias_output_builder = AliasOutputBuilder::new_with_amount(1_000_000, AliasId::null())?
.add_feature(Feature::Sender(SenderFeature::new(address)))
.add_feature(Feature::Metadata(MetadataFeature::new(vec![1, 2, 3])?))
.add_immutable_feature(Feature::Issuer(IssuerFeature::new(address)))
.add_unlock_condition(UnlockCondition::StateControllerAddress(
StateControllerAddressUnlockCondition::new(address),
))
.add_unlock_condition(UnlockCondition::GovernorAddress(GovernorAddressUnlockCondition::new(
address,
)));
let outputs = vec![alias_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 alias output sent: {node_url}/api/core/v2/blocks/{}",
block.id()
);
let _ = client.retry_until_included(&block.id(), None, None).await?;
//////////////////////////////////
// create second transaction with the actual AliasId (BLAKE2b-160 hash of the Output ID that created the alias)
//////////////////////////////////
let alias_output_id = get_alias_output_id(block.payload().unwrap())?;
let alias_id = AliasId::from(&alias_output_id);
let outputs = vec![
alias_output_builder
.with_alias_id(alias_id)
.with_state_index(1)
.finish_output(token_supply)?,
];
let block = client
.block()
.with_secret_manager(&secret_manager)
.with_input(alias_output_id.into())?
.with_outputs(outputs)?
.finish()
.await?;
println!(
"Transaction with alias id set sent: {node_url}/api/core/v2/blocks/{}",
block.id()
);
let _ = client.retry_until_included(&block.id(), None, None).await?;
Ok(())
}
// helper function to get the output id for the first alias output
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"),
}
}
Run the Example
Run the example by running the following command:
cargo run --example alias --release
Dotenv
This example uses dotenv, which is not safe to use in production environments.
// Copyright 2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
import { Client, initLogger } from '@iota/client';
require('dotenv').config({ path: '../.env' });
// Run with command:
// node ./dist/13_build_alias_output.js
// Build a basic output
async function run() {
initLogger();
if (!process.env.NODE_URL) {
throw new Error('.env NODE_URL is undefined, see .env.example');
}
const client = new Client({
nodes: [process.env.NODE_URL],
});
try {
if (!process.env.NON_SECURE_USE_OF_DEVELOPMENT_MNEMONIC_1) {
throw new Error('.env mnemonic is undefined, see .env.example');
}
const secretManager = {
mnemonic: process.env.NON_SECURE_USE_OF_DEVELOPMENT_MNEMONIC_1,
};
const addresses = await client.generateAddresses(secretManager, {
range: {
start: 0,
end: 1,
},
});
const hexAddress = await client.bech32ToHex(addresses[0]);
const aliasOutput = await client.buildAliasOutput({
aliasId:
'0x0000000000000000000000000000000000000000000000000000000000000000',
amount: '1000000',
unlockConditions: [
{
// StateControllerAddressUnlockCondition
type: 4,
address: {
type: 0,
pubKeyHash: hexAddress,
},
},
{
// GovernorAddressUnlockCondition
type: 5,
address: {
type: 0,
pubKeyHash: hexAddress,
},
},
],
});
console.log(aliasOutput);
} catch (error) {
console.error('Error: ', error);
}
}
run();
You can run the example by running the following command from the bindings/node/examples/
folder:
node dist/13_build_alias_output.js
from iota_client import IotaClient, MnemonicSecretManager
# Create an IotaClient instance
client = IotaClient({'nodes': ['https://api.testnet.shimmer.network']})
# Configure alias output
# TODO: replace with your own values
alias_id = "0xa5c28d5baa951de05e375fb19134ea51a918f03acc2d0cee011a42b298d3effa"
unlock_conditions = [
{ 'type': 4, 'address': { 'type': 0, 'pubKeyHash': '0xa7ebd1b1dbe267ab52fadb04fb777fdd1ed9fca72db01de879bf7bb846e0fc7a' } },
{ 'type': 5, 'address': { 'type': 0, 'pubKeyHash': '0xa7ebd1b1dbe267ab52fadb04fb777fdd1ed9fca72db01de879bf7bb846e0fc7a' } },
]
# Build alias output
output = client.build_alias_output(
alias_id,
unlock_conditions,
)
# Print the output
print(output)
import org.iota.Client;
import org.iota.types.ClientConfig;
import org.iota.types.expections.ClientException;
import org.iota.types.Output;
import org.iota.types.UnlockCondition;
import org.iota.types.expections.InitializeClientException;
import org.iota.types.ids.AliasId;
import org.iota.types.output_builder.AliasOutputBuilderParams;
import org.iota.types.secret.GenerateAddressesOptions;
import org.iota.types.secret.MnemonicSecretManager;
import org.iota.types.secret.Range;
public class BuildAliasOutput {
public static void main(String[] args) throws ClientException, InitializeClientException {
// Build the client.
Client client = new Client(new ClientConfig().withNodes(new String[]{"https://api.testnet.shimmer.network"}));
// Configure a simple Alias output.
MnemonicSecretManager secretManager = new MnemonicSecretManager("endorse answer radar about source reunion marriage tag sausage weekend frost daring base attack because joke dream slender leisure group reason prepare broken river");
String hexAddress = client.bech32ToHex(client.generateAddresses(secretManager, new GenerateAddressesOptions().withRange(new Range(0, 1)))[0]);
AliasId aliasId = new AliasId("0xa5c28d5baa951de05e375fb19134ea51a918f03acc2d0cee011a42b298d3effa");
UnlockCondition[] unlockConditions = new UnlockCondition[]{
new UnlockCondition("{ type: 4, address: { type: 0, pubKeyHash: \"" + hexAddress + "\" } }"),
new UnlockCondition("{ type: 5, address: { type: 0, pubKeyHash: \"" + hexAddress + "\" } }")
};
AliasOutputBuilderParams params = new AliasOutputBuilderParams()
.withAliasId(aliasId)
.withUnlockConditions(unlockConditions);
// Build the output.
Output output = client.buildAliasOutput(params);
// Print the output.
System.out.println(output.toString());
}
}
Expected Output
- Rust
- Nodejs
- Python
- Java
Transaction with new alias output sent: https://api.testnet.shimmer.network/api/core/v2/blocks/0xa2fbd2ff5811c6a56d67f1c114d3202fbab9d24bfef7ce5fd1d025025d869b63
Transaction with foundry output sent: https://api.testnet.shimmer.network/api/core/v2/blocks/0x7d5f9c1b7e9eb664f680ff52baf5e1b1b5b48e73431852d3662ef54d16070713
Transaction with native tokens burnt sent: https://api.testnet.shimmer.network/api/core/v2/blocks/0x81da03ffa6bcd77d99780fb040b7f47d8ffe3f0fad54c0b4c73bf4642b72dce7
Transaction with native tokens sent: https://api.testnet.shimmer.network/api/core/v2/blocks/0x438780b57d3db9f01b371806437f1c2a192f9e3de176bcb30d100483b33f8c33
Second transaction with native tokens sent: https://api.testnet.shimmer.network/api/core/v2/blocks/0x04e7fc17e76fe77d6dd58ecbef258a6615bdfb1a7daabf056ffd69b0ad0d78db
Third transaction with native tokens burned sent: https://api.testnet.shimmer.network/api/core/v2/blocks/0x527c93dec602053b86521125d1cc1c376a0274f4b0d5ec4a5f0d97a4034fcffc
{
type: 4,
amount: '1000000',
aliasId: '0x0000000000000000000000000000000000000000000000000000000000000000',
stateIndex: 0,
stateMetadata: '0x',
foundryCounter: 0,
unlockConditions: [ { type: 4, address: [Object] }, { type: 5, address: [Object] } ]
}
{
"type": 4,
"amount": "50300",
"aliasId": "0xa5c28d5baa951de05e375fb19134ea51a918f03acc2d0cee011a42b298d3effa",
"stateIndex": 0,
"stateMetadata": "0x",
"foundryCounter": 0,
"unlockConditions": [
{
"type": 4,
"address": {
"type": 0,
"pubKeyHash": "0x7ffec9e1233204d9c6dce6812b1539ee96af691ca2e4d9065daa85907d33e5d3"
}
},
{
"type": 5,
"address": {
"type": 0,
"pubKeyHash": "0x7ffec9e1233204d9c6dce6812b1539ee96af691ca2e4d9065daa85907d33e5d3"
}
}
]
}
{
"type": 4,
"amount": "50300",
"aliasId": "0xa5c28d5baa951de05e375fb19134ea51a918f03acc2d0cee011a42b298d3effa",
"stateIndex": 0,
"stateMetadata": "0x",
"foundryCounter": 0,
"unlockConditions": [
{
"type": 4,
"address": {
"type": 0,
"pubKeyHash": "0x7ffec9e1233204d9c6dce6812b1539ee96af691ca2e4d9065daa85907d33e5d3"
}
},
{
"type": 5,
"address": {
"type": 0,
"pubKeyHash": "0x7ffec9e1233204d9c6dce6812b1539ee96af691ca2e4d9065daa85907d33e5d3"
}
}
]
}