Stardust Exchange Integration Guide
This guide explains how to integrate the IOTA SDK into your exchange, custody solution, or product.
Features of the IOTA SDK:
- Secure seed management.
- Account management with multiple accounts and multiple addresses.
- Confirmation monitoring.
- Deposit address monitoring.
- Backup and restore functionality.
The Stardust update is a set of protocol changes that were first deployed to the Shimmer network.
See What is Stardust?
for an overview of its features or TIPs
flagged Stardust
for a deeper understanding of the protocol changes.
How Does It Work?
The IOTA SDK is a stateful library which provides an API for developers to build value transaction applications. It offers abstractions to handle payments, and can optionally interact with Stronghold for seed handling, seed storage, and state backup.
You can use the following examples as a guide to implement the multi-account model.
If you were already supporting Shimmer with wallet.rs
1. Set Up the IOTA SDK
Install the IOTA SDK
First, you should install the components needed to use the IOTA SDK and the binding of your choice; it may vary a bit from language to language.
You can read more about backup and security in this guide.
- Rust
- Typescript (Node.js)
- Python
Check out our Getting Started with Rust guide for more detailed instructions.
- Cargo add
- Cargo.toml
To start using the IOTA SDK in your Rust project, you can include it as a dependencies in your project's
Cargo.toml
by running:
cargo add iota-sdk
To start using the IOTA SDK in your Rust project, you can include the following line under
dependencies
in your Cargo.toml
:
[dependencies]
iota-sdk = "1.0.0"
Check out our Getting Started with Node.js guide for more detailed instructions.
- npm
- Yarn
- pnpm
npm i @iota/sdk dotenv
yarn add @iota/sdk dotenv
pnpm add @iota/sdk dotenv
Check out our Getting Started with Python guide for more detailed instructions.
pip install iota-sdk
Set Up you .env
File
This guide uses dotenv
to share user-defined constants, like database paths, node URLs, and wallet credentials across
the code examples.
This is for convenience only and shouldn't be done in production.
You can create a .env
by running the following command:
touch .env
The following examples will need these variables to exist, here are some default values you can use but also change:
WALLET_DB_PATH="./wallet-database"
NODE_URL="https://api.testnet.shimmer.network"
STRONGHOLD_SNAPSHOT_PATH="./wallet.stronghold"
STRONGHOLD_PASSWORD="*K6%79#yeFn7AMQhMQ"
EXPLORER_URL="https://explorer.shimmer.network/testnet"
2. Generate a Mnemonic
After you have created the .env
file, you can initialize the Wallet
instance with a secret manager
(Stronghold
by default) and client options.
By default, the Stronghold file will be called wallet.stronghold
.
It will store the seed (derived from the mnemonic) that serves as a cryptographic key from which all accounts and
related addresses are generated.
One of the key principles behind Stronghold
is that is impossible to extract a mnemonic from it ever again, that is,
recover it from the .stronghold
file.
That's why you should always back up your 24-word mnemonic and have it stored in
a safe place.
You deal with accounts using the Wallet
instance exclusively, which abstracts away all internal
complexities and makes transacting in a network very easy and convenient.
It is best practice to keep the stronghold
password and the stronghold
database on separate devices.
- Rust
- Typescript (Node.js)
- Python
use iota_sdk::client::{Client, Result};
#[tokio::main]
async fn main() -> Result<()> {
let mnemonic = Client::generate_mnemonic()?;
println!("Generated mnemonic:\n{}", mnemonic.as_ref());
Ok(())
}
import { Utils } from '@iota/sdk';
// Run with command:
// yarn run-example ./how_tos/accounts_and_addresses/create-mnemonic.ts
// In this example we will generate a random BIP39 mnemonic
async function run() {
try {
const mnemonic = Utils.generateMnemonic();
console.log('Mnemonic: ' + mnemonic);
} catch (error) {
console.error('Error: ', error);
}
}
run().then(() => process.exit());
from iota_sdk import Utils
# Generate a random BIP39 mnemonic
mnemonic = Utils.generate_mnemonic()
print(f'Mnemonic: {mnemonic}')
3. Create an Account for Each User
You can import the IOTA SDK and create a wallet using the following example:
- Rust
- Typescript (Node.js)
- Python
use iota_sdk::{
client::{
constants::SHIMMER_COIN_TYPE,
secret::{SecretManager, stronghold::StrongholdSecretManager},
},
crypto::keys::bip39::Mnemonic,
wallet::{ClientOptions, Result, Wallet},
};
#[tokio::main]
async fn main() -> Result<()> {
// This example uses secrets in environment variables for simplicity which should not be done in production.
dotenvy::dotenv().ok();
for var in [
"STRONGHOLD_PASSWORD",
"STRONGHOLD_SNAPSHOT_PATH",
"MNEMONIC",
"NODE_URL",
"WALLET_DB_PATH",
] {
std::env::var(var).expect(&format!(".env variable '{var}' is undefined, see .env.example"));
}
// Setup Stronghold secret_manager
let secret_manager = StrongholdSecretManager::builder()
.password(std::env::var("STRONGHOLD_PASSWORD").unwrap())
.build(std::env::var("STRONGHOLD_SNAPSHOT_PATH").unwrap())?;
// Only required the first time, can also be generated with `manager.generate_mnemonic()?`
let mnemonic = Mnemonic::from(std::env::var("MNEMONIC").unwrap());
// The mnemonic only needs to be stored the first time
secret_manager.store_mnemonic(mnemonic).await?;
let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?;
// Create the wallet
let wallet = Wallet::builder()
.with_secret_manager(SecretManager::Stronghold(secret_manager))
.with_storage_path(std::env::var("WALLET_DB_PATH").unwrap())
.with_client_options(client_options)
.with_coin_type(SHIMMER_COIN_TYPE)
.finish()
.await?;
// Create a new account
let account = wallet.create_account().with_alias("Alice").finish().await?;
println!("Generated new account: '{}'", account.alias().await);
Ok(())
}
import { Wallet, CoinType, initLogger, WalletOptions } from '@iota/sdk';
// This example uses secrets in environment variables for simplicity which should not be done in production.
require('dotenv').config({ path: '.env' });
// Run with command:
// yarn run-example ./how_tos/accounts_and_addresses/create-account.ts
// This example creates a new database and account.
async function run() {
initLogger();
for (const envVar of [
'NODE_URL',
'STRONGHOLD_PASSWORD',
'STRONGHOLD_SNAPSHOT_PATH',
'MNEMONIC',
'WALLET_DB_PATH',
])
if (!(envVar in process.env)) {
throw new Error(`.env ${envVar} is undefined, see .env.example`);
}
try {
const walletOptions: WalletOptions = {
storagePath: process.env.WALLET_DB_PATH,
clientOptions: {
nodes: [process.env.NODE_URL as string],
},
coinType: CoinType.Shimmer,
secretManager: {
stronghold: {
snapshotPath: process.env.STRONGHOLD_SNAPSHOT_PATH,
password: process.env.STRONGHOLD_PASSWORD,
},
},
};
const wallet = new Wallet(walletOptions);
// A mnemonic can be generated with `Utils.generateMnemonic()`.
// Store the mnemonic in the Stronghold snapshot, this needs to be done only the first time.
// The mnemonic can't be retrieved from the Stronghold file, so make a backup in a secure place!
await wallet.storeMnemonic(process.env.MNEMONIC as string);
// Create a new account
const account = await wallet.createAccount({
alias: 'Alice',
});
console.log('Generated new account:', account.getMetadata().alias);
} catch (error) {
console.error('Error: ', error);
}
}
run().then(() => process.exit());
import os
from dotenv import load_dotenv
from iota_sdk import ClientOptions, CoinType, StrongholdSecretManager, Wallet
load_dotenv()
# This example creates a new database and account
node_url = os.environ.get('NODE_URL', 'https://api.testnet.shimmer.network')
client_options = ClientOptions(nodes=[node_url])
# Shimmer coin type
coin_type = CoinType.SHIMMER
for env_var in ['STRONGHOLD_PASSWORD', 'MNEMONIC']:
if env_var not in os.environ:
raise Exception(f".env {env_var} is undefined, see .env.example")
secret_manager = StrongholdSecretManager(
os.environ['STRONGHOLD_SNAPSHOT_PATH'], os.environ['STRONGHOLD_PASSWORD'])
wallet = Wallet(
os.environ['WALLET_DB_PATH'],
client_options,
coin_type,
secret_manager)
# Store the mnemonic in the Stronghold snapshot, this only needs to be
# done once.
wallet.store_mnemonic(os.environ['MNEMONIC'])
account = wallet.create_account('Alice')
print("Account created:", account.get_metadata())
The Alias
must be unique and can be whatever fits your use case.
The Alias
is typically used to identify an account later on.
Each account is also represented by an index
, which is incremented by one every time a new account is
created.
You can refer to any account via its index
or its alias
.
- Rust
- Typescript (Node.js)
- Python
You get an instance of any created account using
Wallet.get_account(accountId|alias)
or get all accounts with
Wallet.get_accounts()
.
Common methods of an Account
instance include:
account.addresses()
: Returns a list of addresses related to the account.account.generate_ed25519_addresses()
: Generates one or more new address(es) for the address index incremented by 1.account.balance()
: Returns the balance for the given account.account.sync()
: Sync the account information with the Tangle.
You get an instance of any created account using
Wallet.getAccount(accountId|alias)
or get all accounts with
Wallet.getAccounts()
.
Common methods of an Account
instance include:
account.addresses()
: Returns a list of addresses related to the account.account.generateEd25519Addresses()
: Generates one or more new address(es) for the address index incremented by 1.account.getBalance()
: Returns the balance for the given account.account.sync()
: Sync the account information with the Tangle.
You get an instance of any created account using
wallet.get_account(accountId|alias)
or get all accounts with
wallet.get_accounts()
.
Common methods of an
Account
instance include:
account.addresses()
: Returns a list of addresses related to the account.account.generate_ed25519_addresses()
: Generates one or more new address(es) for the address index incremented by 1.account.get_balance()
: Returns the balance for the given account.account.sync()
: Sync the account information with the Tangle.
4. Generate a User Address to Deposit Funds
The wallet
module of the IOTA SDK is a stateful library.
This means it caches all relevant information in storage to provide performance benefits while dealing with,
potentially, many accounts and addresses.
- Rust
- Typescript (Node.js)
- Python
use iota_sdk::{Wallet, wallet::Result};
// The number of addresses to generate
const NUM_ADDRESSES_TO_GENERATE: u32 = 5;
#[tokio::main]
async fn main() -> Result<()> {
// This example uses secrets in environment variables for simplicity which should not be done in production.
dotenvy::dotenv().ok();
for var in ["WALLET_DB_PATH", "EXPLORER_URL", "STRONGHOLD_PASSWORD"] {
std::env::var(var).expect(&format!(".env variable '{var}' is undefined, see .env.example"));
}
let wallet = Wallet::builder()
.with_storage_path(std::env::var("WALLET_DB_PATH").unwrap())
.finish()
.await?;
let account = wallet.get_account("Alice").await?;
// Provide the stronghold password
wallet
.set_stronghold_password(std::env::var("STRONGHOLD_PASSWORD").unwrap())
.await?;
let explorer_url = std::env::var("EXPLORER_URL").ok();
let address_url = explorer_url.map(|url| format!("{url}/addr/")).unwrap_or_default();
println!("Current addresses:");
for address in account.addresses().await? {
println!(" - {address_url}{}", address.address());
}
// Generate some addresses
let new_addresses = account
.generate_ed25519_addresses(NUM_ADDRESSES_TO_GENERATE, None)
.await?;
println!("Generated {} new addresses:", new_addresses.len());
let account_addresses = account.addresses().await?;
for new_address in new_addresses.iter() {
assert!(account_addresses.contains(new_address));
println!(" - {address_url}{}", new_address.address());
}
Ok(())
}
import { Wallet, initLogger } from '@iota/sdk';
require('dotenv').config({ path: '.env' });
// Run with command:
// yarn run-example ./how_tos/accounts_and_addresses/create-address.ts
// This example creates an address
async function run() {
initLogger();
for (const envVar of ['WALLET_DB_PATH', 'STRONGHOLD_PASSWORD'])
if (!(envVar in process.env)) {
throw new Error(`.env ${envVar} is undefined, see .env.example`);
}
try {
const wallet = new Wallet({
storagePath: process.env.WALLET_DB_PATH,
});
const account = await wallet.getAccount('Alice');
// To create an address we need to unlock stronghold.
await wallet.setStrongholdPassword(
process.env.STRONGHOLD_PASSWORD as string,
);
const address = (await account.generateEd25519Addresses(1))[0];
console.log(`Generated address:`, address.address);
} catch (error) {
console.error('Error: ', error);
}
}
run().then(() => process.exit());
import os
from dotenv import load_dotenv
from iota_sdk import Wallet
load_dotenv()
# This example generates a new address.
wallet = Wallet(os.environ['WALLET_DB_PATH'])
if 'STRONGHOLD_PASSWORD' not in os.environ:
raise Exception(".env STRONGHOLD_PASSWORD is undefined, see .env.example")
wallet.set_stronghold_password(os.environ["STRONGHOLD_PASSWORD"])
account = wallet.get_account('Alice')
address = account.generate_ed25519_addresses(1)
print('Generated address:', address[0].address)
Every account can have multiple addresses.
Addresses are represented by an index
which is incremented by one every time a new address is created.
You can access the addresses using the account.addresses()
method:
- Rust
- Typescript (Node.js)
- Python
for address in account.addresses().await? {
println!("{}", address.address());
}
const addresses = await account.addresses();
for (const address of addresses) console.log(address.address);
addresses = account.addresses()
for address in addresses:
print(address.address)
You can use the Faucet to request test tokens and test your account.
There are two types of addresses, internal
and public
(external). This approach is known as a BIP32 Hierarchical Deterministic wallet (HD Wallet).
- Each set of addresses is independent of each other and has an independent
index
id. - Addresses that are created by
account.generateEd25519Addresses()
are indicated asinternal=false
(public). - Internal addresses (
internal=true
) are calledchange
addresses and are used to send the excess funds to them.
5. Check the Account Balance
Outputs may have multiple UnlockConditions, which may require returning some or all of the transferred amount. The outputs could also expire if not claimed in time, or may not be unlockable for a predefined period.
To get outputs with only the AddressUnlockCondition
, you should synchronize with the option syncOnlyMostBasicOutputs: true
.
If you are synchronizing outputs with other unlock conditions, you should check the unlock conditions carefully before crediting users any balance.
You can find an example illustrating how to check if an output has only the address unlock condition, where the address belongs to the account in the Check Unlock Conditions how-to guide.
You can get the available account balance across all addresses of the given account using the following example:
- Rust
- Typescript (Node.js)
- Python
use iota_sdk::{Wallet, wallet::Result};
#[tokio::main]
async fn main() -> Result<()> {
// This example uses secrets in environment variables for simplicity which should not be done in production.
dotenvy::dotenv().ok();
for var in ["WALLET_DB_PATH", "EXPLORER_URL"] {
std::env::var(var).expect(&format!(".env variable '{var}' is undefined, see .env.example"));
}
let wallet = Wallet::builder()
.with_storage_path(std::env::var("WALLET_DB_PATH").unwrap())
.finish()
.await?;
let account = wallet.get_account("Alice").await?;
// Sync and get the balance
let balance = account.sync(None).await?;
println!("{balance:#?}");
println!("ADDRESSES:");
let explorer_url = std::env::var("EXPLORER_URL").ok();
let prepended = explorer_url.map(|url| format!("{url}/addr/")).unwrap_or_default();
for address in account.addresses().await? {
println!(" - {prepended}{}", address.address());
}
Ok(())
}
import { Wallet, initLogger } from '@iota/sdk';
// This example uses secrets in environment variables for simplicity which should not be done in production.
require('dotenv').config({ path: '.env' });
// Run with command:
// yarn run-example ./how_tos/accounts_and_addresses/check-balance.ts
// This example syncs the account and prints the balance.
async function run() {
initLogger();
for (const envVar of ['WALLET_DB_PATH']) {
if (!(envVar in process.env)) {
throw new Error(`.env ${envVar} is undefined, see .env.example`);
}
}
try {
const wallet = new Wallet({
storagePath: process.env.WALLET_DB_PATH,
});
const account = await wallet.getAccount('Alice');
// Sync new outputs from the node.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _syncBalance = await account.sync();
// After syncing the balance can also be computed with the local data
const balance = await account.getBalance();
console.log('Balance', balance);
} catch (error) {
console.error('Error: ', error);
}
}
import json
import os
from dotenv import load_dotenv
from iota_sdk import Wallet
# This example checks the balance of an account.
# This example uses secrets in environment variables for simplicity which
# should not be done in production.
load_dotenv()
wallet = Wallet(os.environ['WALLET_DB_PATH'])
account = wallet.get_account('Alice')
# Sync account with the node
_balance = account.sync()
# Just calculate the balance with the known state
balance = account.get_balance()
print(f'Balance {json.dumps(balance.as_dict(), indent=4)}')
6. Listen to Events
The IOTA SDK supports several events for listening. A provided callback is triggered as soon as an event occurs (which usually happens during syncingA process when a node downloads and verifies the entire history of the Tangle corresponding to a slot commitment chain. This allows to ensure that it has an up-to-date and accurate copy of the ledger.).
You can use the following example to listen to new output events:
- Rust
- Typescript (Node.js)
- Python
use iota_sdk::{
client::{
constants::SHIMMER_COIN_TYPE,
secret::{SecretManager, mnemonic::MnemonicSecretManager},
},
types::block::{
address::Address,
output::{BasicOutputBuilder, unlock_condition::AddressUnlockCondition},
},
wallet::{ClientOptions, Result, Wallet},
};
// The amount of base coins we'll send
const SEND_AMOUNT: u64 = 1_000_000;
// The address we'll be sending coins to
const RECV_ADDRESS: &str = "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu";
#[tokio::main]
async fn main() -> Result<()> {
// This example uses secrets in environment variables for simplicity which should not be done in production.
dotenvy::dotenv().ok();
for var in ["NODE_URL", "MNEMONIC", "WALLET_DB_PATH", "EXPLORER_URL"] {
std::env::var(var).expect(&format!(".env variable '{var}' is undefined, see .env.example"));
}
let client_options = ClientOptions::new().with_node(&std::env::var("NODE_URL").unwrap())?;
let secret_manager = MnemonicSecretManager::try_from_mnemonic(std::env::var("MNEMONIC").unwrap())?;
let wallet = Wallet::builder()
.with_secret_manager(SecretManager::Mnemonic(secret_manager))
.with_storage_path(std::env::var("WALLET_DB_PATH").unwrap())
.with_client_options(client_options)
.with_coin_type(SHIMMER_COIN_TYPE)
.finish()
.await?;
wallet
.listen([], move |event| {
println!("RECEIVED AN EVENT:\n{:?}", event.event);
})
.await;
// Get or create an account
let account = wallet.get_or_create_account("Alice").await?;
let balance = account.sync(None).await?;
println!("Balance BEFORE:\n{:#?}", balance.base_coin());
// send transaction
let outputs = [BasicOutputBuilder::new_with_amount(SEND_AMOUNT)
.add_unlock_condition(AddressUnlockCondition::new(Address::try_from_bech32(RECV_ADDRESS)?))
.finish_output(account.client().get_token_supply().await?)?];
let transaction = account.send_outputs(outputs, None).await?;
println!("Transaction sent: {}", transaction.transaction_id);
let block_id = account
.retry_transaction_until_included(&transaction.transaction_id, None, None)
.await?;
println!(
"Block included: {}/block/{}",
std::env::var("EXPLORER_URL").unwrap(),
block_id
);
let balance = account.sync(None).await?;
println!("Balance AFTER:\n{:#?}", balance.base_coin());
Ok(())
}
import { Wallet, Event, WalletEventType } from '@iota/sdk';
// This example uses secrets in environment variables for simplicity which should not be done in production.
require('dotenv').config({ path: '.env' });
async function run() {
try {
for (const envVar of ['WALLET_DB_PATH']) {
if (!(envVar in process.env)) {
throw new Error(
`.env ${envVar} is undefined, see .env.example`,
);
}
}
const wallet = new Wallet({
storagePath: process.env.WALLET_DB_PATH,
});
const callback = function (err: any, event: Event) {
console.log('AccountIndex:', event.accountIndex);
console.log('Event:', event.event);
// Exit after receiving an event.
process.exit(0);
};
// Only interested in new outputs here.
await wallet.listen([WalletEventType.NewOutput], callback);
const account = await wallet.getAccount('Alice');
// Use the faucet to send testnet tokens to your address.
console.log(
'Fill your address with the faucet: https://faucet.testnet.shimmer.network/',
);
const addresses = await account.addresses();
console.log('Send funds to:', addresses[0].address);
// Sync every 5 seconds until the faucet transaction gets confirmed.
for (let i = 0; i < 100; i++) {
await new Promise((resolve) => setTimeout(resolve, 5000));
// Sync to detect new outputs
// Set syncOnlyMostBasicOutputs to true if not interested in outputs that are timelocked,
// have a storage deposit return, expiration or are nft/alias/foundry outputs.
await account.sync({ syncOnlyMostBasicOutputs: true });
}
} catch (error) {
console.error(error);
}
}
import json
import os
import sys
import time
from dotenv import load_dotenv
from iota_sdk import SyncOptions, Wallet, WalletEventType
# This example uses secrets in environment variables for simplicity which
# should not be done in production.
load_dotenv()
if 'WALLET_DB_PATH' not in os.environ:
raise Exception(".env WALLET_DB_PATH is undefined, see .env.example")
wallet = Wallet(os.environ.get('WALLET_DB_PATH'))
account = wallet.get_account('Alice')
received_event = False
def callback(event):
"""Callback function for the event listener"""
event_dict = json.loads(event)
print('AccountIndex:', event_dict["accountIndex"])
print('Event:', event_dict["event"])
# Exit after receiving an event.
# pylint: disable=global-statement
global received_event
received_event = True
# Only interested in new outputs here.
wallet.listen(callback, [WalletEventType.NewOutput])
account = wallet.get_account('Alice')
# Use the faucet to send testnet tokens to your address.
print('Fill your address with the faucet: https://faucet.testnet.shimmer.network/')
addresses = account.addresses()
print('Send funds to:', addresses[0].address)
# Sync every 5 seconds until the faucet transaction gets confirmed.
for _ in range(100):
if received_event:
sys.exit()
time.sleep(5)
# Sync to detect new outputs
# Set sync_only_most_basic_outputs to True if not interested in outputs that are timelocked,
# have a storage deposit return , expiration or are nft/alias/foundry
# outputs.
account.sync(SyncOptions(sync_only_most_basic_outputs=True))
Example output:
NewOutput: {
output: {
outputId: '0x2df0120a5e0ff2b941ec72dff3464a5b2c3ad8a0c96fe4c87243e4425b9a3fe30000',
metadata: [Object],
output: [Object],
isSpent: false,
address: [Object],
networkId: '1862946857608115868',
remainder: false,
chain: [Array]
},
transaction: null,
transactionInputs: null
}
- Rust
- Typescript (Node.js)
- Python
Alternatively you can use
account.outputs()
to get all the outputs that are stored in the account, or
account.unspent_outputs()
, to get the unspent outputs only.
Alternatively you can use account.outputs()
to get all the outputs
that are stored in the account, or account.unspentOutputs()
,
to get the unspent outputs only.
Alternatively you can use
account.outputs()
to get all the outputs that are stored in
the account, or account.unspent_outputs()
,
to get the unspent outputs only.
7. Enable Withdrawals
You can use the following example to send tokens to an address.
When sending tokens, you should consider a dust protection mechanism.
- Rust
- Typescript (Node.js)
- Python
loading...
The full function signature is
Account.send(&self, amount: u64, address: impl ConvertTo<Bech32Address>,options: impl Into<Option <TransactionOptions>>)
.
The default
TransactionOptions
are fine and successful. However, you can provide additional options, such as
RemainderValueStrategy
,
which can have the following values:
ChangeAddress
: Send the remainder value to an internal address.ReuseAddress
: Send the remainder value back to its original address.CustomAddress
: Send the remainder value back to a provided account address.
The account.send()
function returns a
Transaction
with its id. You can use the blockId
to check the confirmation status. You can obtain individual
transactions related to the given account using the
account.transactions()
function.
You can use the
account.send_with_params()
to send to multiple addresses in a single transaction.
loading...
The full function signature is
Account.send(amount, address,
transactionOptions?)
.
The default
TransactionOptions
are fine and successful. However, you can provide additional options, such as
remainderValueStrategy
,
which can have the following values:
changeAddress
: Send the remainder value to an internal address.reuseAddress
: Send the remainder value back to its original address.customAddress
: Send the remainder value back to a provided account address.
The account.send()
function returns a
Transaction
with its id. You can use the blockId
to check the confirmation status. You can obtain individual
transactions related to the given account using the
account.transactions()
function.
You can use the
account.sendWithParams()
to send to multiple addresses in a single transaction.
loading...
The full function signature is
Account.send(send(amount: str, address: str, options: Optional[TransactionOptions] =
None)
.
The default
TransactionOptions
are fine and successful. However, you can provide additional options, such as
remainderValueStrategy
,
which can have the following values:
changeAddress
: Send the remainder value to an internal address.reuseAddress
: Send the remainder value back to its original address.customAddress
: Send the remainder value back to a provided account address.
The account.send()
function returns a
Transaction
with its id. You can use the blockId
to check the confirmation status. You can obtain individual
transactions related to the given account using the
account.transactions()
function.
You can use the
account.send_with_params()
to send to multiple addresses in a single transaction.