Send Native Tokens
After you have minted a
native tokens,
you can easily send it by calling the Account.send_native_tokens(addresses_native_tokens, options)
function.
As with any output, you can set a storage deposit and output unlock conditions. Keep in mind that if you set unlock conditions, whoever you send the native tokens to may need to claim them.
Code Example
Before you run the code example, make sure to update the token ID with one which is available in your account. If you haven't done so already, you can follow the how to mint a native token guide. If you don't know the token ID you can check your accounts balance to retrieve the available native tokens in your account.
The following example will:
- Create an account manager.
- Get Alice's account which was created in the first guide.
- Define the type of native token and amount to send.
- Send the native tokens calling the
Account.send_native_tokens(addresses_native_tokens, options)
function.
- Rust
- Nodejs
- Python
- Java
This example uses dotenv, which is not safe for use in production environments.
// Copyright 2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
//! cargo run --example send_native_tokens --release
// In this example we will send native tokens
// Rename `.env.example` to `.env` first
use std::{env, str::FromStr};
use dotenv::dotenv;
use iota_wallet::{
account_manager::AccountManager,
iota_client::block::{
address::Address,
output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, NativeToken, TokenId, UnlockCondition},
},
AddressNativeTokens, Result,
};
use primitive_types::U256;
#[tokio::main]
async fn main() -> Result<()> {
// This example uses dotenv, which is not safe for use in production
dotenv().ok();
// Create the account manager
let manager = AccountManager::builder().finish().await?;
// Get the account we generated with `01_create_wallet`
let account = manager.get_account("Alice").await?;
// Set the stronghold password
manager
.set_stronghold_password(&env::var("STRONGHOLD_PASSWORD").unwrap())
.await?;
let bech32_address = "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu".to_string();
// Replace with a TokenId that is available in the account
let token_id = TokenId::from_str("0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000")?;
let outputs = vec![AddressNativeTokens {
address: bech32_address.clone(),
native_tokens: vec![(token_id, U256::from(10))],
..Default::default()
}];
let transaction = account.send_native_tokens(outputs, None).await?;
println!(
"Transaction: {} Block sent: {}/api/core/v2/blocks/{}",
transaction.transaction_id,
&env::var("NODE_URL").unwrap(),
transaction.block_id.expect("no block created yet")
);
// Send native tokens together with the required storage deposit
let rent_structure = account.client().get_rent_structure().await?;
let outputs = vec![
BasicOutputBuilder::new_with_minimum_storage_deposit(rent_structure)?
.add_unlock_condition(UnlockCondition::Address(AddressUnlockCondition::new(
Address::try_from_bech32(bech32_address)?.1,
)))
.with_native_tokens(vec![NativeToken::new(token_id, U256::from(10))?])
.finish_output(account.client().get_token_supply().await?)?,
];
let transaction = account.send(outputs, None).await?;
println!(
"Transaction: {} Block sent: {}/api/core/v2/blocks/{}",
transaction.transaction_id,
&env::var("NODE_URL").unwrap(),
transaction.block_id.expect("no block created yet")
);
Ok(())
}
Run the example by running the following command:
cargo run --example send_native_tokens --release
/**
* This example will send native tokens
*/
const getUnlockedManager = require('./account-manager');
async function run() {
try {
const manager = await getUnlockedManager();
const account = await manager.getAccount('0');
await account.sync();
// Get a tokenId from your account balance after running example
// 22-mint-native-tokens.js
let tokenId =
'0x087ec7c0a543e60cfc92850ed053d3b323c0d7181e63b24c6ef24dd591814006950100000000';
// `100` hex encoded
let tokenAmount = "0x64"
// Send native tokens with a storage deposit return and an expiraiton of one day
// This means that the receiver has to claim the output in time (can be done with 21-claim-outputs.js),
// where the storage deposit of the output is returned, or if not, the sender gets full control back after one day passed.
const response = await account.sendNativeTokens([
{
//TODO: Replace with the address of your choice!
address: 'rms1qrrv7flg6lz5cssvzv2lsdt8c673khad060l4quev6q09tkm9mgtupgf0h0',
nativeTokens: [[tokenId, tokenAmount]],
}
]);
console.log(response);
console.log(
`Check your block on ${process.env.NODE_URL}/api/core/v2/blocks/${response.blockId}`,
);
} catch (error) {
console.log('Error: ', error);
}
process.exit(0);
}
run();
You can run the example by running the following command from the wallet/bindings/nodejs/examples/
folder:
node 24-send-native-tokens.js
from iota_wallet import IotaWallet
# In this example we will send native tokens
wallet = IotaWallet('./alice-database')
account = wallet.get_account('Alice')
# Sync account with the node
response = account.sync()
print(f'Synced: {response}')
wallet.set_stronghold_password("some_hopefully_secure_password")
outputs = [{
"address": "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu",
"nativeTokens": [(
"0x08a5526c4a15558b709340822edf00cb348d8606a27e2e59b00432a0afe8afb74d0100000000",
# 10 hex encoded
"0xA"
)],
}];
transaction = account.send_native_tokens(outputs, None)
print(f'Sent transaction: {transaction}')
You can run the example by running the following command from the binding/python/examples
folder:
python3 5-send-native-tokens.py
// Copyright 2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
import org.iota.Wallet;
import org.iota.types.*;
import org.iota.types.account_methods.SendNativeTokens;
import org.iota.types.account_methods.SyncAccount;
import org.iota.types.exceptions.InitializeWalletException;
import org.iota.types.exceptions.WalletException;
import org.iota.types.ids.TokenId;
import org.iota.types.ids.account.AccountAlias;
import org.iota.types.secret.StrongholdSecretManager;
public class SendNativeToken {
public static void main(String[] args) throws WalletException, InterruptedException, InitializeWalletException {
// This example assumes that a wallet has already been created using the ´SetupWallet.java´ example.
// If you haven't run the ´SetupWallet.java´ example yet, you must run it first to be able to load the wallet as shown below:
Wallet wallet = new Wallet(new WalletConfig()
.withClientOptions(new ClientConfig().withNodes(Env.NODE))
.withSecretManager(new StrongholdSecretManager(Env.STRONGHOLD_PASSWORD, null, Env.STRONGHOLD_VAULT_PATH))
.withCoinType(CoinType.Shimmer)
.withStoragePath(Env.STORAGE_PATH)
);
// Get account and sync it with the registered node to ensure that its balances are up-to-date.
AccountHandle a = wallet.getAccount(new AccountAlias(Env.ACCOUNT_NAME));
a.syncAccount(new SyncAccount().withOptions(new SyncOptions()));
// TODO: replace with your own values.
String receiverAddress = a.getPublicAddresses()[0].getAddress();
TokenId tokenId = new TokenId("0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0300000000");
String tokenAmount = "0x17"; // `100` hex encoded
// Send transaction.
Transaction t = a.sendNativeTokens(new SendNativeTokens().withAddressesNativeTokens(new AddressNativeTokens[]{ new AddressNativeTokens()
.withAddress(receiverAddress)
.withNativeTokens(new AddressNativeTokens.NativeTokenTuple[] {
new AddressNativeTokens.NativeTokenTuple(tokenId, tokenAmount)
})
}));
// Print transaction.
System.out.println(t);
// In case you are done and don't need the wallet instance anymore you can destroy the instance to clean up memory.
// For this, check out the ´DestroyWallet.java´ example.
}
}
Expected Output
- Rust
- Nodejs
- Python
- Java
Transaction: 0x649987dd056ac5ad87adb5dbfa2648262856f2dfcd0ac7039e520fc6ccbc2b1f
Block sent: http://localhost:14265/api/core/v2/blocks/0x1e2126e848f10cf2c77d122f3bd003454267c1f46c20f4a3458b74f5639ce818
{
payload: {
type: 6,
essence: {
type: 1,
networkId: '1856588631910923207',
inputs: [Array],
inputsCommitment: '0xaf866f45f6418098b2bb3b8359f39ca55ecb57c666c65c40c4f982af365f37d6',
outputs: [Array]
},
unlocks: [ [Object] ]
},
blockId: '0x1630e8423fe5eb11f7c6ad9afcb2198ac731fb2b10efa7e903f30fd79ddd5c14',
inclusionState: 'Pending',
timestamp: '1662659637387',
transactionId: '0xd4a81db105132dfa0c51a29eaecff1d796bf66d4be91be15a9864c88ee8f2c67',
networkId: '1856588631910923207',
incoming: false,
note: null
}
Check your block on http://localhost:14265/api/core/v2/blocks/0x1630e8423fe5eb11f7c6ad9afcb2198ac731fb2b10efa7e903f30fd79ddd5c14
Synced:{
'baseCoin':{
'total':'3302230302',
'available':'3302230302'
},
'requiredStorageDeposit':'910252700',
'nativeTokens':[
{
'tokenId':'0x08a5526c4a15558b709340822edf00cb348d8606a27e2e59b00432a0afe8afb74d0100000000',
'total':'0x3e8',
'available':'0x3e8'
},
{
'tokenId':'0x08b83d49922e341d2cb45159707cfafdc9dc8fdb9d119543480dbaa5773eed8c4a0100000000',
'total':'0x64',
'available':'0x64'
}
],
'nfts':[
'0x17f97185f80fa56eab974de6b7bbb80fa812d4e8e37090d166a0a41da129cebc',
'0xdc8be91d779aac048aa9001ab99ecf12cf62a4701185a95f6206a1a201bfbe7c',
'0xceae643ff7c112a3adce8f55f7953ba0707ade21256a7a09068c0b47f7c62c5b',
'0x1b670afba8d59a445cbaf167f1fda05879362e3ea034f5c4a0979fbeb5a3964b',
'0x1e808b7c6e603aaeb5f718881a74fedae72981ac7d5f0294eb561cad0e653566',
'0x3f0e11e9d9f48a57d0fba43d7d1158ee673cb8055f80a5ce45ad174c962c0d8a',
'0x77133189021f50d8d66e0678e553af9f46a832a24239653d3555edb8dc859e1f'
],
'aliases':[
'0x97eb7a447cd62e1c373ff8188ba422f5c1b0687707d38e10e8366a1c20d33fea',
'0xf9c702ffe50c35d331b2df02295c2cc6d92f883530ff231bd76d1f6a72cb1d95',
'0xa5526c4a15558b709340822edf00cb348d8606a27e2e59b00432a0afe8afb74d',
'0x96717e6d19c13b1c5b120d60b23217f541b5b779e51212e01d72e7fa1f7090cf'
],
'foundries':[
'0x08a5526c4a15558b709340822edf00cb348d8606a27e2e59b00432a0afe8afb74d0100000000'
],
'potentiallyLockedOutputs':{
'0x850c1e43dff1a28a42d71edc6d4ad0b9f251c03993f9b0684a34f645514ffe270000':False
}
}
Sent transaction:{
'payload':{
'type':6,
'essence':{
'type':1,
'networkId':'1856588631910923207',
'inputs':[
{
'type':0,
'transactionId':'0x9d1e61384fc78777c8db475a3d6eaec6465c136dc3ce586ee46a9453aa3dfdc4',
'transactionOutputIndex':2
},
{
'type':0,
'transactionId':'0x0220b5247654d05529f40b3d8cdb7ca6f89627038f47a68aa578b9e675ddc937',
'transactionOutputIndex':32
}
],
'inputsCommitment':'0xff484e025ea72e4ae90d556b645c01f8f763235caac2d128359f1a6410a65c86',
'outputs':[
{
'type':3,
'amount':'57600',
'nativeTokens':[
{
'id':'0x08a5526c4a15558b709340822edf00cb348d8606a27e2e59b00432a0afe8afb74d0100000000',
'amount':'0xa'
}
],
'unlockConditions':[
{
'type':0,
'address':{
'type':0,
'pubKeyHash':'0x60200bad8137a704216e84f8f9acfe65b972d9f4155becb4815282b03cef99fe'
}
},
{
'type':1,
'returnAddress':{
'type':0,
'pubKeyHash':'0x8297ac4149c80cca8225e5f2da36df89a93cd2998d7f6d488c97250a881e65af'
},
'amount':'57600'
},
{
'type':3,
'returnAddress':{
'type':0,
'pubKeyHash':'0x8297ac4149c80cca8225e5f2da36df89a93cd2998d7f6d488c97250a881e65af'
},
'unixTime':1666004529
}
]
},
{
'type':3,
'amount':'91600',
'nativeTokens':[
{
'id':'0x08a5526c4a15558b709340822edf00cb348d8606a27e2e59b00432a0afe8afb74d0100000000',
'amount':'0x3de'
}
],
'unlockConditions':[
{
'type':0,
'address':{
'type':0,
'pubKeyHash':'0x8297ac4149c80cca8225e5f2da36df89a93cd2998d7f6d488c97250a881e65af'
}
}
]
}
]
},
'unlocks':[
{
'type':0,
'signature':{
'type':0,
'publicKey':'0xe62838fda7e8b77bf80e49967f0f089ae2a7230547d5231649732952f6336fae',
'signature':'0x1c90f0d05b6b3902ebc1e8ad489432bdc16e0810179671ad091c5d93b920dc4151eb38f13a4a9b3018d2132e8ca3e8a79788478f5d5b6826b262ca0c3658eb09'
}
},
{
'type':1,
'reference':0
}
]
},
'blockId':'0xabddf4905e86ed11ea2ab2784fdf5a79a1176ef2f353dc0f2db80537d17d59b0',
'inclusionState':'Pending',
'timestamp':'1665918129925',
'transactionId':'0x9a5869b61b29f17326e04b6161d9cd169687e79476c556bd0c3cbbc3648d4ff6',
'networkId':'1856588631910923207',
'incoming':False,
'note':None
}
{
"payload":{
"type":6,
"essence":{
"type":1,
"networkId":"1856588631910923207",
"inputs":[
{
"type":0,
"transactionId":"0x8f83b8c88e396be189d8456a462f67c9806d3acb773fb027bce9027485f6b74d",
"transactionOutputIndex":1
}
],
"inputsCommitment":"0x45643c2e9481d7d8645881f976280e414239691fe562ad56823867c4dd25d5d6",
"outputs":[
{
"type":3,
"amount":"57600",
"nativeTokens":[
{
"id":"0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0300000000",
"amount":"0x17"
}
],
"unlockConditions":[
{
"type":0,
"address":{
"type":0,
"pubKeyHash":"0x4cfde0600797ae07d19d67d78910e70950bfdaf716f0035e9a30b97828aaf6a2"
}
},
{
"type":1,
"returnAddress":{
"type":0,
"pubKeyHash":"0x4cfde0600797ae07d19d67d78910e70950bfdaf716f0035e9a30b97828aaf6a2"
},
"amount":"57600"
},
{
"type":3,
"returnAddress":{
"type":0,
"pubKeyHash":"0x4cfde0600797ae07d19d67d78910e70950bfdaf716f0035e9a30b97828aaf6a2"
},
"unixTime":1664884308
}
]
},
{
"type":3,
"amount":"2096368900",
"nativeTokens":[
{
"id":"0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0100000000",
"amount":"0x3233"
},
{
"id":"0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0200000000",
"amount":"0x3233"
},
{
"id":"0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0400000000",
"amount":"0x17"
}
],
"unlockConditions":[
{
"type":0,
"address":{
"type":0,
"pubKeyHash":"0x4cfde0600797ae07d19d67d78910e70950bfdaf716f0035e9a30b97828aaf6a2"
}
}
]
}
]
},
"unlocks":[
{
"type":0,
"signature":{
"type":0,
"publicKey":"0xde3152ce9d67415b9c5a042ea01caccc3f73ff1c0c77036874cb8badf9798d56",
"signature":"0x136ebfea089a7cfd3b5fdae595a53acb54b19a2483eb3dcf76b852169a2d4e16d4331e1c95f6654488150beacbd7bef033be605207139b33c385822fd09a2a03"
}
}
]
},
"blockId":"0x5227e054723e38dcc86df357cfd1b4715fd622fb7a2a3702931295a4b432bc46",
"inclusionState":"Pending",
"timestamp":"1664884309679",
"transactionId":"0x68454a9dbf31790aa072910a1caa0d3b32cc9ab89c476219a7d184a6dffbcc5c",
"networkId":"1856588631910923207",
"incoming":false
}