From 61753b821a5c2f41bf92a4ac03d9077110f1c0e1 Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Wed, 21 Jun 2023 21:03:30 +0200 Subject: [PATCH] Add native token how-tos (#541) * Move examples * Update python examples * Update Cargo.toml * Rename how-tos * Update imports in nodejs examples * Unify mint how-to * Unify decrease_supply how-to * Unify increase_supply how-to * Unify send how-to * Unify burn how-to * Unify destroy_foundry how-to * Fix mint nodejs example * Add first docs draft * Update docs * Format and clippy * Update python examples * Unify examples * Format and lint * Forgot one * lint * Apply suggestions from code review Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> * Add DestroyFoundry admonition * Add hint to IRC30 * Check for existing alias output before minting * Update sdk/examples/how_tos/native_tokens/mint.rs Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> * Update documentation/sdk/docs/_admonitions/_destroy_foundry.md * Fix typo * Lint and format * Update bindings/nodejs/examples/how_tos/native_tokens/burn.ts * Apply suggestions from code review Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --------- Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> --- .../native_tokens/burn.ts} | 41 +++---- .../native_tokens/decrease_supply.ts} | 45 +++----- .../native_tokens/destroy_foundry.ts} | 8 +- .../native_tokens/increase_supply.ts} | 43 +++---- .../native_tokens/mint.ts} | 46 ++++---- .../native_tokens/send.ts} | 74 ++++-------- .../examples/how_tos/native_tokens/burn.py | 37 ++++++ .../how_tos/native_tokens/decrease_supply.py | 40 +++++++ .../how_tos/native_tokens/destroy_foundry.py | 35 ++++++ .../how_tos/native_tokens/increase_supply.py | 39 +++++++ .../examples/how_tos/native_tokens/mint.py | 55 +++++++++ .../examples/how_tos/native_tokens/send.py | 42 +++++++ .../examples/wallet/5-send-native-tokens.py | 30 ----- .../examples/wallet/7-mint-native-tokens.py | 40 ------- .../examples/wallet/burn_native_tokens.py | 27 ----- .../wallet/decrease-native-tokens-supply.py | 27 ----- .../python/examples/wallet/destroy_foundry.py | 27 ----- .../sdk/docs/_admonitions/_destroy_foundry.md | 5 + .../sdk/docs/how_tos/native_tokens/burn.mdx | 64 +++++++++++ .../how_tos/native_tokens/decrease_supply.mdx | 61 ++++++++++ .../how_tos/native_tokens/destroy_foundry.mdx | 69 ++++++++++++ .../how_tos/native_tokens/increase_supply.mdx | 59 ++++++++++ .../sdk/docs/how_tos/native_tokens/mint.mdx | 68 ++++++++++++ .../sdk/docs/how_tos/native_tokens/send.mdx | 65 +++++++++++ documentation/sdk/sidebars.js | 12 ++ sdk/Cargo.toml | 62 ++++++----- sdk/examples/how_tos/native_tokens/burn.rs | 90 +++++++++++++++ .../native_tokens/decrease_supply.rs} | 39 +++---- .../native_tokens/destroy_foundry.rs} | 19 +--- .../native_tokens/increase_supply.rs} | 51 +++------ .../native_tokens/mint.rs} | 41 +++---- .../native_tokens/send.rs} | 57 +++------- sdk/examples/wallet/13_burn_native_token.rs | 105 ------------------ 33 files changed, 940 insertions(+), 583 deletions(-) rename bindings/nodejs/examples/{wallet/13-burn-native-token.ts => how_tos/native_tokens/burn.ts} (60%) rename bindings/nodejs/examples/{wallet/11-decrease-native-token-supply.ts => how_tos/native_tokens/decrease_supply.ts} (54%) rename bindings/nodejs/examples/{wallet/15-destroy-foundry.ts => how_tos/native_tokens/destroy_foundry.ts} (84%) rename bindings/nodejs/examples/{wallet/12-increase-native-token-supply.ts => how_tos/native_tokens/increase_supply.ts} (56%) rename bindings/nodejs/examples/{wallet/09-mint-native-token.ts => how_tos/native_tokens/mint.ts} (54%) rename bindings/nodejs/examples/{wallet/07-send-native-tokens.ts => how_tos/native_tokens/send.ts} (51%) create mode 100644 bindings/python/examples/how_tos/native_tokens/burn.py create mode 100644 bindings/python/examples/how_tos/native_tokens/decrease_supply.py create mode 100644 bindings/python/examples/how_tos/native_tokens/destroy_foundry.py create mode 100644 bindings/python/examples/how_tos/native_tokens/increase_supply.py create mode 100644 bindings/python/examples/how_tos/native_tokens/mint.py create mode 100644 bindings/python/examples/how_tos/native_tokens/send.py delete mode 100644 bindings/python/examples/wallet/5-send-native-tokens.py delete mode 100644 bindings/python/examples/wallet/7-mint-native-tokens.py delete mode 100644 bindings/python/examples/wallet/burn_native_tokens.py delete mode 100644 bindings/python/examples/wallet/decrease-native-tokens-supply.py delete mode 100644 bindings/python/examples/wallet/destroy_foundry.py create mode 100644 documentation/sdk/docs/_admonitions/_destroy_foundry.md create mode 100644 documentation/sdk/docs/how_tos/native_tokens/burn.mdx create mode 100644 documentation/sdk/docs/how_tos/native_tokens/decrease_supply.mdx create mode 100644 documentation/sdk/docs/how_tos/native_tokens/destroy_foundry.mdx create mode 100644 documentation/sdk/docs/how_tos/native_tokens/increase_supply.mdx create mode 100644 documentation/sdk/docs/how_tos/native_tokens/mint.mdx create mode 100644 documentation/sdk/docs/how_tos/native_tokens/send.mdx create mode 100644 sdk/examples/how_tos/native_tokens/burn.rs rename sdk/examples/{wallet/11_decrease_native_token_supply.rs => how_tos/native_tokens/decrease_supply.rs} (60%) rename sdk/examples/{wallet/15_destroy_foundry.rs => how_tos/native_tokens/destroy_foundry.rs} (76%) rename sdk/examples/{wallet/12_increase_native_token_supply.rs => how_tos/native_tokens/increase_supply.rs} (54%) rename sdk/examples/{wallet/09_mint_native_token.rs => how_tos/native_tokens/mint.rs} (65%) rename sdk/examples/{wallet/07_send_native_tokens.rs => how_tos/native_tokens/send.rs} (59%) delete mode 100644 sdk/examples/wallet/13_burn_native_token.rs diff --git a/bindings/nodejs/examples/wallet/13-burn-native-token.ts b/bindings/nodejs/examples/how_tos/native_tokens/burn.ts similarity index 60% rename from bindings/nodejs/examples/wallet/13-burn-native-token.ts rename to bindings/nodejs/examples/how_tos/native_tokens/burn.ts index 712f126585..0a94e0f90a 100644 --- a/bindings/nodejs/examples/wallet/13-burn-native-token.ts +++ b/bindings/nodejs/examples/how_tos/native_tokens/burn.ts @@ -1,14 +1,8 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getUnlockedWallet } from './common'; +import { getUnlockedWallet } from '../../wallet/common'; -// The native token id. Replace it with a TokenId that is available in the account, the foundry output which minted it, -// also needs to be available. You can check this by running the `get_balance` example. You can mint a new native token -// by running the `mint_native_token` example. -// eslint-disable-next-line prefer-const -let TOKEN_ID = - '0x08dc44610c24f32f26330440f3f0d4afb562a8dfd81afe7c2f79024f8f1b9e21940100000000'; // The minimum available native token amount to search for in the account, 11 hex encoded. const MIN_AVAILABLE_AMOUNT = '0xB'; // The amount of the native token to burn, 1 hex encoded. @@ -25,15 +19,6 @@ const BURN_AMOUNT = '0x1'; // yarn run-example ./wallet/13-burn-native-token.ts async function run() { try { - if ( - TOKEN_ID == - '0x086f7011adb53642e8ed7db230c2307fe980f4aff2685c22f7c84a61ec558f691b0200000000' - ) { - throw new Error( - 'You need to change the TOKEN_ID constant before you can run this example successfully!', - ); - } - // Create the wallet const wallet = await getUnlockedWallet(); @@ -43,21 +28,25 @@ async function run() { // May want to ensure the account is synced before sending a transaction. let balance = await account.sync(); + // Get a token with sufficient balance + const tokenId = balance.nativeTokens.find( + (t) => Number(t.available) >= Number(MIN_AVAILABLE_AMOUNT), + )?.tokenId; + let token = balance.nativeTokens.find( (nativeToken) => - nativeToken.tokenId == TOKEN_ID && + nativeToken.tokenId == tokenId && Number(nativeToken.available) >= Number(MIN_AVAILABLE_AMOUNT), ); if (!token) { throw new Error( - `"Native token '${TOKEN_ID}' doesn't exist or there's not at least '${Number( + `Native token '${tokenId}' doesn't exist or there's not at least '${Number( MIN_AVAILABLE_AMOUNT, - )}' tokens of it in account 'Alice'"`, + )}' tokens of it in account 'Alice'`, ); } - console.log(`Balance BEFORE burning:\n`, token); - console.log(`Sending the burning transaction...`); + console.log(`Balance before burning: ${parseInt(token.available)}`); // Burn a native token const transaction = await account @@ -72,20 +61,16 @@ async function run() { ); console.log( - `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, - ); - console.log( - `Burned ${Number(BURN_AMOUNT)} native token(s) (${token.tokenId})`, + `Block included: ${process.env.EXPLORER_URL}/block/${blockId}`, ); balance = await account.sync(); - console.log(`Balance AFTER burning:`); token = balance.nativeTokens.find( - (nativeToken) => nativeToken.tokenId == TOKEN_ID, + (nativeToken) => nativeToken.tokenId == tokenId, ); if (token) { - console.log(token); + console.log(`Balance after burning: ${parseInt(token.available)}`); } else { console.log(`No remaining tokens`); } diff --git a/bindings/nodejs/examples/wallet/11-decrease-native-token-supply.ts b/bindings/nodejs/examples/how_tos/native_tokens/decrease_supply.ts similarity index 54% rename from bindings/nodejs/examples/wallet/11-decrease-native-token-supply.ts rename to bindings/nodejs/examples/how_tos/native_tokens/decrease_supply.ts index 3ad33da852..2fc824a32f 100644 --- a/bindings/nodejs/examples/wallet/11-decrease-native-token-supply.ts +++ b/bindings/nodejs/examples/how_tos/native_tokens/decrease_supply.ts @@ -1,15 +1,9 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getUnlockedWallet } from './common'; +import { getUnlockedWallet } from '../../wallet/common'; -// The native token id. Replace it with a TokenId that is available in the account, the foundry output which minted it, -// also needs to be available. You can check this by running the `get-balance` example. You can mint a new native token -// by running the `mint-native-token` example. -// eslint-disable-next-line prefer-const -let TOKEN_ID = - '0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000'; -// The amount of native tokens to melt, 10 hex encoded. +// The amount of native tokens to melt, 10 hex encoded. TODO Convert to int const MELT_AMOUNT = '0xA'; // In this example we will melt an existing native token with its foundry. @@ -21,16 +15,6 @@ const MELT_AMOUNT = '0xA'; // yarn run-example ./wallet/11-decrease-native-token-supply.ts async function run() { try { - if ( - TOKEN_ID == - '0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000' - ) { - console.log( - 'You need to change the TOKEN_ID constant before you can run this example successfully!', - ); - return; - } - // Create the wallet const wallet = await getUnlockedWallet(); @@ -40,18 +24,19 @@ async function run() { // May want to ensure the account is synced before sending a transaction. let balance = await account.sync(); + // Find first foundry and corresponding token id + const tokenId = balance.foundries[0]; + let token = balance.nativeTokens.find( - (nativeToken) => nativeToken.tokenId == TOKEN_ID, + (nativeToken) => nativeToken.tokenId == tokenId, ); if (token == null) { throw new Error( - `Couldn't find native token '${TOKEN_ID}' in the account`, + `Couldn't find native token '${tokenId}' in the account`, ); } - console.log(`Balance BEFORE melting:\n`, token); - - console.log('Sending the melting transaction...'); + console.log(`Balance before melting:`, parseInt(token.available)); // Melt some of the circulating supply const transaction = await account @@ -66,17 +51,19 @@ async function run() { ); console.log( - `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, - ); - console.log( - `Melted ${Number(MELT_AMOUNT)} native tokens (${token.tokenId})`, + `Block included: ${process.env.EXPLORER_URL}/block/${blockId}`, ); balance = await account.sync(); token = balance.nativeTokens.find( - (nativeToken) => nativeToken.tokenId == TOKEN_ID, + (nativeToken) => nativeToken.tokenId == tokenId, ); - console.log(`Balance AFTER melting:\n`, token); + if (token == null) { + throw new Error( + `Couldn't find native token '${tokenId}' in the account`, + ); + } + console.log(`Balance after melting:`, parseInt(token.available)); } catch (error) { console.log('Error: ', error); } diff --git a/bindings/nodejs/examples/wallet/15-destroy-foundry.ts b/bindings/nodejs/examples/how_tos/native_tokens/destroy_foundry.ts similarity index 84% rename from bindings/nodejs/examples/wallet/15-destroy-foundry.ts rename to bindings/nodejs/examples/how_tos/native_tokens/destroy_foundry.ts index 539f0dc1c0..d97883a9ca 100644 --- a/bindings/nodejs/examples/wallet/15-destroy-foundry.ts +++ b/bindings/nodejs/examples/how_tos/native_tokens/destroy_foundry.ts @@ -1,7 +1,7 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getUnlockedWallet } from './common'; +import { getUnlockedWallet } from '../../wallet/common'; // In this example we will try to destroy the first foundry there is in the account. This is only possible if its // circulating supply is 0 and no native tokens were burned. @@ -28,8 +28,7 @@ async function run() { // We try to destroy the first foundry in the account const foundry = balance.foundries[0]; - console.log(`Foundries BEFORE destroying:\n`, balance.foundries); - console.log('Sending the destroy-foundry transaction...'); + console.log(`Foundries before destroying: ${balance.foundries.length}`); // Burn a foundry const transaction = await account @@ -45,10 +44,9 @@ async function run() { console.log( `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, ); - console.log(`Destroyed foundry ${foundry}`); balance = await account.sync(); - console.log(`Foundries AFTER destroying:\n`, balance.foundries); + console.log(`Foundries after destroying: ${balance.foundries.length}`); } catch (error) { console.log('Error: ', error); } diff --git a/bindings/nodejs/examples/wallet/12-increase-native-token-supply.ts b/bindings/nodejs/examples/how_tos/native_tokens/increase_supply.ts similarity index 56% rename from bindings/nodejs/examples/wallet/12-increase-native-token-supply.ts rename to bindings/nodejs/examples/how_tos/native_tokens/increase_supply.ts index 5e78bb339f..cc03bb22e2 100644 --- a/bindings/nodejs/examples/wallet/12-increase-native-token-supply.ts +++ b/bindings/nodejs/examples/how_tos/native_tokens/increase_supply.ts @@ -1,14 +1,8 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { getUnlockedWallet } from './common'; +import { getUnlockedWallet } from '../../wallet/common'; -// The native token id. Replace it with a TokenId that is available in the account, the foundry output which minted it, -// also needs to be available. You can check this by running the `get-balance` example. You can mint a new native token -// by running the `mint-native-token` example. -// eslint-disable-next-line prefer-const -let TOKEN_ID = - '0x086a62922fd743b541c987020d2cb2942cf789bcefe41572854119180cb8e037a90100000000'; // The amount of native tokens to mint, 10 hex encoded. const MINT_AMOUNT = '0xA'; @@ -21,16 +15,6 @@ const MINT_AMOUNT = '0xA'; // yarn run-example ./wallet/12-increase-native-token-supply.ts async function run() { try { - if ( - TOKEN_ID == - '0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000' - ) { - console.log( - 'You need to change the TOKEN_ID constant before you can run this example successfully!', - ); - return; - } - // Create the wallet const wallet = await getUnlockedWallet(); @@ -40,18 +24,19 @@ async function run() { // May want to ensure the account is synced before sending a transaction. let balance = await account.sync(); + // Find first foundry and corresponding token id + const tokenId = balance.foundries[0]; + let token = balance.nativeTokens.find( - (nativeToken) => nativeToken.tokenId == TOKEN_ID, + (nativeToken) => nativeToken.tokenId == tokenId, ); if (token == null) { throw new Error( - `Couldn't find native token '${TOKEN_ID}' in the account`, + `Couldn't find native token '${tokenId}' in the account`, ); } - console.log(`Balance BEFORE minting:\n`, token); - - console.log('Sending the minting transaction...'); + console.log(`Balance before minting:`, parseInt(token.available)); // Mint some more native tokens const transaction = await account @@ -66,17 +51,19 @@ async function run() { ); console.log( - `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, - ); - console.log( - `Minted ${Number(MINT_AMOUNT)} native tokens (${token.tokenId})`, + `Block included: ${process.env.EXPLORER_URL}/block/${blockId}`, ); balance = await account.sync(); token = balance.nativeTokens.find( - (nativeToken) => nativeToken.tokenId == TOKEN_ID, + (nativeToken) => nativeToken.tokenId == tokenId, ); - console.log(`Balance AFTER minting:\n`, token); + if (token == null) { + throw new Error( + `Couldn't find native token '${tokenId}' in the account`, + ); + } + console.log(`Balance after minting:`, parseInt(token.available)); } catch (error) { console.log('Error: ', error); } diff --git a/bindings/nodejs/examples/wallet/09-mint-native-token.ts b/bindings/nodejs/examples/how_tos/native_tokens/mint.ts similarity index 54% rename from bindings/nodejs/examples/wallet/09-mint-native-token.ts rename to bindings/nodejs/examples/how_tos/native_tokens/mint.ts index 2071642118..3c98eb443e 100644 --- a/bindings/nodejs/examples/wallet/09-mint-native-token.ts +++ b/bindings/nodejs/examples/how_tos/native_tokens/mint.ts @@ -1,9 +1,9 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { MintNativeTokenParams } from '@iota/sdk'; +import { MintNativeTokenParams, utf8ToHex } from '@iota/sdk'; -import { getUnlockedWallet } from './common'; +import { getUnlockedWallet } from '../../wallet/common'; // The circulating supply of the native token. `100` hex encoded const CIRCULATING_SUPPLY = '0x64'; @@ -25,46 +25,50 @@ async function run() { // Get the account we generated with `01-create-wallet` const account = await wallet.getAccount('Alice'); - console.log('Sending alias output transaction...'); + const balance = await account.sync(); - // First create an alias output, this needs to be done only once, because an alias can have many foundry outputs - let transaction = await account - .prepareCreateAliasOutput() - .then((prepared) => prepared.send()); - console.log(`Transaction sent: ${transaction.transactionId}`); + // We can first check if we already have an alias in our account, because an alias can have many foundry outputs and therefore we can reuse an existing one + if (balance.aliases.length > 0) { + // If we don't have an alias, we need to create one + const transaction = await account + .prepareCreateAliasOutput() + .then((prepared) => prepared.send()); + console.log(`Transaction sent: ${transaction.transactionId}`); - // Wait for transaction to get included - let blockId = await account.retryTransactionUntilIncluded( - transaction.transactionId, - ); + // Wait for transaction to get included + const blockId = await account.retryTransactionUntilIncluded( + transaction.transactionId, + ); - console.log( - `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, - ); + console.log( + `Block included: ${process.env.EXPLORER_URL}/block/${blockId}`, + ); - await account.sync(); - console.log('Account synced'); + await account.sync(); + console.log('Account synced'); + } - console.log('Sending the minting transaction...'); + console.log('Preparing minting transaction...'); // If we omit the AccountAddress field the first address of the account is used by default const params: MintNativeTokenParams = { circulatingSupply: CIRCULATING_SUPPLY, maximumSupply: MAXIMUM_SUPPLY, + foundryMetadata: utf8ToHex('Hello, World!'), }; const prepared = await account.prepareMintNativeToken(params); - transaction = await prepared.send(); + const transaction = await prepared.send(); console.log(`Transaction sent: ${transaction.transactionId}`); // Wait for transaction to get included - blockId = await account.retryTransactionUntilIncluded( + const blockId = await account.retryTransactionUntilIncluded( transaction.transactionId, ); console.log( - `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, + `Block included: ${process.env.EXPLORER_URL}/block/${blockId}`, ); console.log(`Minted token: ${prepared.tokenId()}`); diff --git a/bindings/nodejs/examples/wallet/07-send-native-tokens.ts b/bindings/nodejs/examples/how_tos/native_tokens/send.ts similarity index 51% rename from bindings/nodejs/examples/wallet/07-send-native-tokens.ts rename to bindings/nodejs/examples/how_tos/native_tokens/send.ts index b7988673d9..aba8901708 100644 --- a/bindings/nodejs/examples/wallet/07-send-native-tokens.ts +++ b/bindings/nodejs/examples/how_tos/native_tokens/send.ts @@ -1,14 +1,9 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { - AddressUnlockCondition, - BasicOutputBuilderParams, - Ed25519Address, - SendNativeTokensParams, -} from '@iota/sdk'; +import { SendNativeTokensParams } from '@iota/sdk'; -import { getUnlockedWallet } from './common'; +import { getUnlockedWallet } from '../../wallet/common'; // The native token amount to send, `10` hex encoded const SEND_NATIVE_TOKEN_AMOUNT = '0xA'; @@ -32,7 +27,7 @@ async function run() { const account = await wallet.getAccount('Alice'); // May want to ensure the account is synced before sending a transaction. - const balance = await account.sync(); + let balance = await account.sync(); // Get a token with sufficient balance // TODO: use BigNumber library @@ -48,62 +43,41 @@ async function run() { }, ]; - console.log( - `Sending '${Number( - SEND_NATIVE_TOKEN_AMOUNT, - )}' coin(s) to '${RECV_ADDRESS}'...`, + let token = balance.nativeTokens.find( + (nativeToken) => nativeToken.tokenId == tokenId, ); - - let transaction = await account + if (token == null) { + throw new Error( + `Couldn't find native token '${tokenId}' in the account`, + ); + } + console.log(`Balance before sending:`, parseInt(token.available)); + + const transaction = await account .prepareSendNativeTokens(outputs) .then((prepared) => prepared.send()); console.log(`Transaction sent: ${transaction.transactionId}`); // Wait for transaction to get included - let blockId = await account.retryTransactionUntilIncluded( + const blockId = await account.retryTransactionUntilIncluded( transaction.transactionId, ); console.log( - `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, - ); - - await account.sync(); - console.log('Account synced'); - - console.log('Sending basic output transaction...'); - - // Send native tokens together with the required storage deposit - const client = await wallet.getClient(); - - const basicOutput: BasicOutputBuilderParams = { - unlockConditions: [ - new AddressUnlockCondition( - new Ed25519Address(RECV_ADDRESS), - ), - ], - nativeTokens: [ - { - id: tokenId, - amount: SEND_NATIVE_TOKEN_AMOUNT, - }, - ], - }; - - const output = await client.buildBasicOutput(basicOutput); - transaction = await account.sendOutputs([output]); - - console.log(`Transaction sent: ${transaction.transactionId}`); - - // Wait for transaction to get included - blockId = await account.retryTransactionUntilIncluded( - transaction.transactionId, + `Block included: ${process.env.EXPLORER_URL}/block/${blockId}`, ); - console.log( - `Transaction included: ${process.env.EXPLORER_URL}/block/${blockId}`, + balance = await account.sync(); + token = balance.nativeTokens.find( + (nativeToken) => nativeToken.tokenId == tokenId, ); + if (token == null) { + throw new Error( + `Couldn't find native token '${tokenId}' in the account`, + ); + } + console.log(`Balance after sending:`, parseInt(token.available)); } } catch (error) { console.log('Error: ', error); diff --git a/bindings/python/examples/how_tos/native_tokens/burn.py b/bindings/python/examples/how_tos/native_tokens/burn.py new file mode 100644 index 0000000000..e8b363e7de --- /dev/null +++ b/bindings/python/examples/how_tos/native_tokens/burn.py @@ -0,0 +1,37 @@ +from iota_sdk import Wallet, HexStr +from dotenv import load_dotenv +import os + +load_dotenv() + +# In this example we will burn native tokens + +wallet = Wallet('./alice-database') + +account = wallet.get_account('Alice') + +# Sync account with the node +balance = account.sync() + +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"]) + +# Find native token with enough balance +token = [native_balance for native_balance in balance['nativeTokens'] if int(native_balance['available'], 0) >= 10][0] +print(f'Balance before burning: {int(token["available"], 0)}') + +burn_amount = 1 + +# Send transaction. +transaction = account.prepare_burn_native_token(token["tokenId"], burn_amount).send() +print(f'Transaction sent: {transaction["transactionId"]}') + +# Wait for transaction to get included +blockId = account.retry_transaction_until_included(transaction['transactionId']) +print(f'Block included: {os.environ["EXPLORER_URL"]}/block/{blockId}') + +balance = account.sync() +available_balance = int([native_balance for native_balance in balance['nativeTokens'] if native_balance['tokenId'] == token["tokenId"]][0]['available'], 0) +print(f'Balance after burning: {available_balance}') diff --git a/bindings/python/examples/how_tos/native_tokens/decrease_supply.py b/bindings/python/examples/how_tos/native_tokens/decrease_supply.py new file mode 100644 index 0000000000..95a51093a1 --- /dev/null +++ b/bindings/python/examples/how_tos/native_tokens/decrease_supply.py @@ -0,0 +1,40 @@ +from iota_sdk import Wallet, HexStr +from dotenv import load_dotenv +import os +import json + +load_dotenv() + +# In this example we will decrease the native token supply + +wallet = Wallet('./alice-database') + +account = wallet.get_account('Alice') + +# Sync account with the node +balance = account.sync() + +# Find first foundry and corresponding token id +token_id = balance['foundries'][0] + +available_balance = int([native_balance for native_balance in balance['nativeTokens'] if native_balance['tokenId'] == token_id][0]['available'], 0) +print(f'Balance before melting: {available_balance}') + +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"]) + +melt_amount = 10 + +# Send transaction. +transaction = account.prepare_decrease_native_token_supply(token_id, melt_amount).send() +print(f'Transaction sent: {transaction["transactionId"]}') + +# Wait for transaction to get included +blockId = account.retry_transaction_until_included(transaction['transactionId']) +print(f'Block included: {os.environ["EXPLORER_URL"]}/block/{blockId}') + +balance = account.sync() +available_balance = int([native_balance for native_balance in balance['nativeTokens'] if native_balance['tokenId'] == token_id][0]['available'], 0) +print(f'Balance after melting: {available_balance}') diff --git a/bindings/python/examples/how_tos/native_tokens/destroy_foundry.py b/bindings/python/examples/how_tos/native_tokens/destroy_foundry.py new file mode 100644 index 0000000000..cc047edad8 --- /dev/null +++ b/bindings/python/examples/how_tos/native_tokens/destroy_foundry.py @@ -0,0 +1,35 @@ +from iota_sdk import Wallet, HexStr +from dotenv import load_dotenv +import os +import json + +load_dotenv() + +# In this example we will destroy a foundry + +wallet = Wallet('./alice-database') + +account = wallet.get_account('Alice') + +# Sync account with the node +balance = account.sync() +print(f'Foundries before destroying: {len(balance["foundries"])}') + +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"]) + +# We try to destroy the first foundry in the account +foundry_id = balance['foundries'][0] + +# Send transaction. +transaction = account.prepare_destroy_foundry(foundry_id).send() +print(f'Transaction sent: {transaction["transactionId"]}') + +# Wait for transaction to get included +blockId = account.retry_transaction_until_included(transaction['transactionId']) +print(f'Block included: {os.environ["EXPLORER_URL"]}/block/{blockId}') + +balance = account.sync() +print(f'Foundries after destroying: {len(balance["foundries"])}') diff --git a/bindings/python/examples/how_tos/native_tokens/increase_supply.py b/bindings/python/examples/how_tos/native_tokens/increase_supply.py new file mode 100644 index 0000000000..4fb6b43af4 --- /dev/null +++ b/bindings/python/examples/how_tos/native_tokens/increase_supply.py @@ -0,0 +1,39 @@ +from iota_sdk import Wallet +from dotenv import load_dotenv +import os + +load_dotenv() + +# In this example we will decrease the native token supply + +wallet = Wallet('./alice-database') + +account = wallet.get_account('Alice') + +# Sync account with the node +balance = account.sync() + +# Find first foundry and corresponding token id +token_id = balance['foundries'][0] + +available_balance = int([native_balance for native_balance in balance['nativeTokens'] if native_balance['tokenId'] == token_id][0]['available'], 0) +print(f'Balance before minting: {available_balance}') + +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"]) + +mint_amount = 10 + +# Prepare and send transaction. +transaction = account.prepare_increase_native_token_supply(token_id, mint_amount).send() +print(f'Transaction sent: {transaction["transactionId"]}') + +# Wait for transaction to get included +blockId = account.retry_transaction_until_included(transaction['transactionId']) +print(f'Block included: {os.environ["EXPLORER_URL"]}/block/{blockId}') + +balance = account.sync() +available_balance = int([native_balance for native_balance in balance['nativeTokens'] if native_balance['tokenId'] == token_id][0]['available'], 0) +print(f'Balance after minting: {available_balance}') diff --git a/bindings/python/examples/how_tos/native_tokens/mint.py b/bindings/python/examples/how_tos/native_tokens/mint.py new file mode 100644 index 0000000000..1a5fab69c3 --- /dev/null +++ b/bindings/python/examples/how_tos/native_tokens/mint.py @@ -0,0 +1,55 @@ +from iota_sdk import Wallet, utf8_to_hex +from dotenv import load_dotenv +import time +import os + +load_dotenv() + +# In this example we will mint native tokens + +wallet = Wallet('./alice-database') + +account = wallet.get_account('Alice') + +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"]) + +# Sync account with the node +response = account.sync() + +# We can first check if we already have an alias in our account, because an alias can have many foundry outputs and therefore we can reuse an existing one +if len(account.aliases) == 0: + # If we don't have an alias, we need to create one + transaction = account.prepare_create_alias_output(None, None).send() + print(f'Transaction sent: {transaction["transactionId"]}') + + # Wait for transaction to get included + blockId = account.retry_transaction_until_included(transaction['transactionId']) + print(f'Block included: {os.environ["EXPLORER_URL"]}/block/{blockId}') + + account.sync() + print("Account synced") + +print('Preparing minting transaction...') + +params = { + "circulatingSupply": hex(100), + "maximumSupply": hex(100), + "foundryMetadata": utf8_to_hex('Hello, World!'), +} + +prepared_transaction = account.prepare_mint_native_token(params, None) +transaction = prepared_transaction.send() +print(f'Transaction sent: {transaction["transactionId"]}') + +# Wait for transaction to get included +blockId = account.retry_transaction_until_included(transaction['transactionId']) +print(f'Block included: {os.environ["EXPLORER_URL"]}/block/{blockId}') + +print(f'Minted token: {prepared_transaction.token_id()}') + +# Ensure the account is synced after minting. +account.sync() +print('Account synced') diff --git a/bindings/python/examples/how_tos/native_tokens/send.py b/bindings/python/examples/how_tos/native_tokens/send.py new file mode 100644 index 0000000000..2402233c6f --- /dev/null +++ b/bindings/python/examples/how_tos/native_tokens/send.py @@ -0,0 +1,42 @@ +from iota_sdk import Wallet +from dotenv import load_dotenv +import os +import json + +load_dotenv() + +# In this example we will send native tokens + +wallet = Wallet('./alice-database') + +account = wallet.get_account('Alice') + +# Sync account with the node +balance = account.sync() + +token = [native_balance for native_balance in balance['nativeTokens'] if int(native_balance['available'], 0) >= 10][0] +print(f'Balance before sending: {int(token["available"], 0)}') + +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"]) + +outputs = [{ + "address": "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu", + "nativeTokens": [( + token["tokenId"], + hex(10) + )], +}] + +transaction = account.prepare_send_native_tokens(outputs, None).send() +print(f'Transaction sent: {transaction["transactionId"]}') + +# Wait for transaction to get included +blockId = account.retry_transaction_until_included(transaction['transactionId']) +print(f'Block included: {os.environ["EXPLORER_URL"]}/block/{blockId}') + +balance = account.sync() +available_balance = int([native_balance for native_balance in balance['nativeTokens'] if native_balance['tokenId'] == token["tokenId"]][0]['available'], 0) +print(f'Balance after sending: {available_balance}') diff --git a/bindings/python/examples/wallet/5-send-native-tokens.py b/bindings/python/examples/wallet/5-send-native-tokens.py deleted file mode 100644 index 3fb7109fb6..0000000000 --- a/bindings/python/examples/wallet/5-send-native-tokens.py +++ /dev/null @@ -1,30 +0,0 @@ -from iota_sdk import Wallet -from dotenv import load_dotenv -import os - -load_dotenv() - -# In this example we will send native tokens - -wallet = Wallet('./alice-database') - -account = wallet.get_account('Alice') - -# Sync account with the node -response = account.sync() - -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"]) - -outputs = [{ - "address": "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu", - "nativeTokens": [( - "0x08a5526c4a15558b709340822edf00cb348d8606a27e2e59b00432a0afe8afb74d0100000000", - hex(10) - )], -}]; - -transaction = account.prepare_send_native_tokens(outputs, None).send() -print(f'Block sent: {os.environ["EXPLORER_URL"]}/block/{transaction["blockId"]}') diff --git a/bindings/python/examples/wallet/7-mint-native-tokens.py b/bindings/python/examples/wallet/7-mint-native-tokens.py deleted file mode 100644 index 5d9a14538a..0000000000 --- a/bindings/python/examples/wallet/7-mint-native-tokens.py +++ /dev/null @@ -1,40 +0,0 @@ -from iota_sdk import Wallet -from dotenv import load_dotenv -import time -import os - -load_dotenv() - -# In this example we will mint native tokens - -wallet = Wallet('./alice-database') - -account = wallet.get_account('Alice') - -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"]) - -# Sync account with the node -response = account.sync() - -transaction = account.prepare_create_alias_output(None, None).send() - -# Wait a few seconds for the transaction to get confirmed -time.sleep(7) - -account.sync() - -params = { - # 1000 hex encoded - "circulatingSupply": "0x3e8", - "maximumSupply": "0x3e8", - "foundryMetadata": "0xab", -} - -transaction = account.prepare_mint_native_token(params, None) -print(f'Token id: {transaction.token_id()}') - -transaction = transaction.send() -print(f'Block sent: {os.environ["EXPLORER_URL"]}/block/{transaction["blockId"]}') diff --git a/bindings/python/examples/wallet/burn_native_tokens.py b/bindings/python/examples/wallet/burn_native_tokens.py deleted file mode 100644 index 05ba03fcaf..0000000000 --- a/bindings/python/examples/wallet/burn_native_tokens.py +++ /dev/null @@ -1,27 +0,0 @@ -from iota_sdk import Wallet -from dotenv import load_dotenv -import os - -load_dotenv() - -# In this example we will burn native tokens - -wallet = Wallet('./alice-database') - -account = wallet.get_account('Alice') - -# Sync account with the node -response = account.sync() - -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"]) - -# TODO: replace with your own values. -token_id = "0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0300000000" -burn_amount = "0x5" - -# Send transaction. -transaction = account.prepare_burn_native_token(token_id, burn_amount).send() -print(f'Block sent: {os.environ["EXPLORER_URL"]}/block/{transaction["blockId"]}') diff --git a/bindings/python/examples/wallet/decrease-native-tokens-supply.py b/bindings/python/examples/wallet/decrease-native-tokens-supply.py deleted file mode 100644 index 6313b04e0d..0000000000 --- a/bindings/python/examples/wallet/decrease-native-tokens-supply.py +++ /dev/null @@ -1,27 +0,0 @@ -from iota_sdk import Wallet -from dotenv import load_dotenv -import os - -load_dotenv() - -# In this example we will decrease the native token supply - -wallet = Wallet('./alice-database') - -account = wallet.get_account('Alice') - -# Sync account with the node -account.sync() - -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"]) - -# TODO: replace with your own values. -token_id = "0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0500000000" -melt_amount = 32 - -# Send transaction. -transaction = account.prepare_decrease_native_token_supply(token_id, melt_amount).send() -print(f'Block sent: {os.environ["EXPLORER_URL"]}/block/{transaction["blockId"]}') diff --git a/bindings/python/examples/wallet/destroy_foundry.py b/bindings/python/examples/wallet/destroy_foundry.py deleted file mode 100644 index 1b9aab3ae8..0000000000 --- a/bindings/python/examples/wallet/destroy_foundry.py +++ /dev/null @@ -1,27 +0,0 @@ -from iota_sdk import Wallet -from dotenv import load_dotenv -import os - -load_dotenv() - -# In this example we will destroy a foundry - -wallet = Wallet('./alice-database') - -account = wallet.get_account('Alice') - -# Sync account with the node -response = account.sync() - -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"]) - -# TODO: replace with your own values. -foundry_id = "0x08429fe5864378ce70699fc2d22bb144cb86a3c4833d136e3b95c5dadfd6ba0cef0500000000" - -# Send transaction. -transaction = account.prepare_destroy_foundry(foundry_id).send() -print( - f'Block sent: {os.environ["EXPLORER_URL"]}/block/{transaction["blockId"]}') diff --git a/documentation/sdk/docs/_admonitions/_destroy_foundry.md b/documentation/sdk/docs/_admonitions/_destroy_foundry.md new file mode 100644 index 0000000000..fb95df9f4c --- /dev/null +++ b/documentation/sdk/docs/_admonitions/_destroy_foundry.md @@ -0,0 +1,5 @@ +:::warning Destroying Foundry + +A foundry can only be destroyed (and its storage deposit be claimed) if the circulating supply is zero. Therefore if you control the foundry and want to destroy it in the future, you should consider [melting your native tokens](../how_tos/native_tokens/decrease_supply.mdx) instead of [burning](../how_tos/native_tokens/burn.mdx) them. + +::: \ No newline at end of file diff --git a/documentation/sdk/docs/how_tos/native_tokens/burn.mdx b/documentation/sdk/docs/how_tos/native_tokens/burn.mdx new file mode 100644 index 0000000000..4b9f7290ea --- /dev/null +++ b/documentation/sdk/docs/how_tos/native_tokens/burn.mdx @@ -0,0 +1,64 @@ +--- +title: Burn Native Tokens +sidebar_label: Burn +description: 'How to burn native tokens' +image: /img/logo/iota_mark_light.png +keywords: +- how to +- burn +- burn native token +- foundry +- nodejs +- python +- rust +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import NodejsCode from '!!raw-loader!../../../../../bindings/nodejs/examples/how_tos/native_tokens/burn.ts'; +import PythonCode from '!!raw-loader!../../../../../bindings/python/examples/how_tos/native_tokens/burn.py'; +import RustCode from '!!raw-loader!../../../../../sdk/examples/how_tos/native_tokens/burn.rs'; +import DestroyFoundry from '../../_admonitions/_destroy_foundry.md'; + +You may want to burn some native tokens. To do so, you will need to call the +`Account.burn(burn, options)` function. + + + +## Code Example + +The following example will: + +1. Create a wallet. +2. Get Alice's account which was [created in the first guide](../accounts_and_addresses/create_account.mdx). +3. [Get the account's balance](../accounts_and_addresses/check_balance.mdx). +4. Burn 1 native token of the first ID with enough funds. + + + + + + {RustCode} + + + + + {NodejsCode} + + + + + {PythonCode} + + + + +## Expected Output + +```plaintext +Balance before burning: 30 +Transaction sent: 0x8c93b86b003b0476266f1d4d0c486dfcbbb72d4991eb5d63d5466a6cad93e9f2 +Block included: https://explorer.shimmer.network/testnet/block/0x49e2ec7ac5a88b1b0ffcde20bff437b53ef74f38368c28af402435f45dd5b138 +Balance after burning: 29 +``` diff --git a/documentation/sdk/docs/how_tos/native_tokens/decrease_supply.mdx b/documentation/sdk/docs/how_tos/native_tokens/decrease_supply.mdx new file mode 100644 index 0000000000..59564ad87d --- /dev/null +++ b/documentation/sdk/docs/how_tos/native_tokens/decrease_supply.mdx @@ -0,0 +1,61 @@ +--- +title: Melt Native Tokens +sidebar_label: Decrease Circulating Supply +description: 'How to melt native tokens' +image: /img/logo/iota_mark_light.png +keywords: +- how to +- melt native token +- foundry +- nodejs +- python +- rust +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import NodejsCode from '!!raw-loader!../../../../../bindings/nodejs/examples/how_tos/native_tokens/decrease_supply.ts'; +import PythonCode from '!!raw-loader!../../../../../bindings/python/examples/how_tos/native_tokens/decrease_supply.py'; +import RustCode from '!!raw-loader!../../../../../sdk/examples/how_tos/native_tokens/decrease_supply.rs'; + +You may want to melt some of your circulating native tokens. To do so, you will need to call the +`Account.decrease_native_token_supply(token_id, melt_amount, options)` function. + +If you melt your native tokens, you can still destroy the foundry that created them. + +## Code Example + +The following example will: + +1. Create a wallet. +2. Get Alice's account which was [created in the first guide](../accounts_and_addresses/create_account.mdx). +3. Get the account's balance. +4. Melt 10 native tokens of the first ID. + + + + + {RustCode} + + + + + {NodejsCode} + + + + + {PythonCode} + + + + +## Expected Output + +```plaintext +Balance before melting: 100 +Transaction sent: 0x7b3b152127d3cf2921891ad1ea279ae484d559e4040a0d3ca8940c89cb64b34e +Block included: https://explorer.shimmer.network/testnet/block/0x70d34d37e9a30d19b641ac24529c2fc512f8c9169ffa3521be4b05b7fefe8933 +Balance after melting: 90 +``` diff --git a/documentation/sdk/docs/how_tos/native_tokens/destroy_foundry.mdx b/documentation/sdk/docs/how_tos/native_tokens/destroy_foundry.mdx new file mode 100644 index 0000000000..bcc63de221 --- /dev/null +++ b/documentation/sdk/docs/how_tos/native_tokens/destroy_foundry.mdx @@ -0,0 +1,69 @@ +--- +title: Destroy a Foundry +sidebar_label: Destroy a Foundry +description: 'How to destroy a foundry using iota-sdk' +image: /img/logo/iota_mark_light.png +keywords: +- how to +- destroy +- destroy foundry +- foundry +- nodejs +- python +- rust +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import NodejsCode from '!!raw-loader!../../../../../bindings/nodejs/examples/how_tos/native_tokens/destroy_foundry.ts'; +import PythonCode from '!!raw-loader!../../../../../bindings/python/examples/how_tos/native_tokens/destroy_foundry.py'; +import RustCode from '!!raw-loader!../../../../../sdk/examples/how_tos/native_tokens/destroy_foundry.rs'; +import DestroyFoundry from '../../_admonitions/_destroy_foundry.md'; + +You can destroy a foundry by calling the `Account.burn(burn, options)` function. The function will +destroy a foundry output as long as its circulating +[native token](https://wiki.iota.org/shimmer/introduction/explanations/ledger/foundry) supply is zero. + + + +## Code Example + +Before you run the example you should make sure the first foundy on your account has zero circulating supply. If you have no available +foundries, you can create one by [minting a native token](mint.mdx). If you've already minted your +tokens but need to empty the foundry, you can decrease your native token supply by [melting them](decrease_supply.mdx). + +The following example will: + +1. Create a wallet. +2. Get Alice's account which was [created in the first guide](../accounts_and_addresses/create_account.mdx). +3. [Get the account's balance](./../accounts_and_addresses/check_balance.mdx) and show the amount of foundries. +4. Try to destroy the first [foundry](https://wiki.iota.org/shimmer/introduction/explanations/ledger/foundry) output. +5. Get the account's foundry count again to show the difference after step 4. + + + + + {RustCode} + + + + + {NodejsCode} + + + + + {PythonCode} + + + + +## Expected Output + +```plaintext +Foundries before destroying: 51 +Transaction sent: 0xe0930e445aa9e78f59e3979744102bb0980fe6332950c7bb4785700dcb24fe8e +Block included: https://explorer.shimmer.network/testnet/block/0x31d08663ae1d175d798d0f2925f41fa97f0eee8f9e233a4f5dacedb1398ed544 +Foundries after destroying: 50 +``` \ No newline at end of file diff --git a/documentation/sdk/docs/how_tos/native_tokens/increase_supply.mdx b/documentation/sdk/docs/how_tos/native_tokens/increase_supply.mdx new file mode 100644 index 0000000000..1d27d75a5f --- /dev/null +++ b/documentation/sdk/docs/how_tos/native_tokens/increase_supply.mdx @@ -0,0 +1,59 @@ +--- +title: Increase Native Token Circulating Supply +sidebar_label: Increase Circulating Supply +description: 'How to increase the circulating supply of native tokens' +image: /img/logo/iota_mark_light.png +keywords: +- how to +- increase native token circulating supply +- foundry +- nodejs +- python +- rust +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import NodejsCode from '!!raw-loader!../../../../../bindings/nodejs/examples/how_tos/native_tokens/increase_supply.ts'; +import PythonCode from '!!raw-loader!../../../../../bindings/python/examples/how_tos/native_tokens/increase_supply.py'; +import RustCode from '!!raw-loader!../../../../../sdk/examples/how_tos/native_tokens/increase_supply.rs'; + +You may want to increase the circulating native token supply. To do so, you will need to call the +`Account.increase_native_token_supply(token_id, mint_amount, options)` function. + +## Code Example + +The following example will: + +1. Create a wallet. +2. Get Alice's account which was [created in the first guide](../accounts_and_addresses/create_account.mdx). +3. Get the account's balance. +4. Mint 10 native tokens of the first ID. + + + + + {RustCode} + + + + + {NodejsCode} + + + + + {PythonCode} + + + + +## Expected Output + +``` +Balance before minting: 90 +Transaction sent: 0x6dbec7c73ef511c3945eda6265d3de29a4f572a3bd95e39221cff18135e18ca6 +Block included: https://explorer.shimmer.network/testnet/block/0x7b677c0562d8b2a7fdc1fd6182bb6364af517d41ec38a9dab9b29a1c7422f574 +Balance after minting: 100 +``` diff --git a/documentation/sdk/docs/how_tos/native_tokens/mint.mdx b/documentation/sdk/docs/how_tos/native_tokens/mint.mdx new file mode 100644 index 0000000000..c2887df7bd --- /dev/null +++ b/documentation/sdk/docs/how_tos/native_tokens/mint.mdx @@ -0,0 +1,68 @@ +--- +title: Mint Native Tokens +sidebar_label: Mint +description: 'How to mint native tokens using wallet.rs.' +image: /img/logo/iota_mark_light.png +keywords: +- how to +- mint native tokens +- mint +- nodejs +- python +- java +- rust +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import NodejsCode from '!!raw-loader!../../../../../bindings/nodejs/examples/how_tos/native_tokens/mint.ts'; +import PythonCode from '!!raw-loader!../../../../../bindings/python/examples/how_tos/native_tokens/mint.py'; +import RustCode from '!!raw-loader!../../../../../sdk/examples/how_tos/native_tokens/mint.rs'; +import TipFaucet from '../../_admonitions/_tip_faucet.md'; + +The stardust update allows you to create your own [native tokens](https://wiki.iota.org/shimmer/introduction/explanations/what_is_stardust/tokenization#native-tokens) +Native tokens are minted by a so-called Foundry. The Foundry allows you to specify a max supply once and change the circulating supply. You can also specify some custom metadata in the foundry output or follow a standard like [IRC30](https://wiki.iota.org/tips/tips/TIP-0030/). +To create a Foundry you need an Alias Output which owns it. This Alias Output only needs to be generated once and can own multiple foundries. + + + +## Code Example + +The following example will: + +1. Create a wallet. +2. Get Alice's which was [created in the first guide](../accounts_and_addresses/create_a_wallet_account.mdx). +3. Create the `MintNativeTokenParams`. +4. Mint the native token by calling the `Account.mint_native_token(params, options)` function. + + + + + {RustCode} + + + + + {NodejsCode} + + + + + {PythonCode} + + + + +## Expected Output + +```plaintext +Transaction sent: 0x3e7fe86a2b01a7006fe037249be51852d298d32df69507140d3b41c1a6d7fb90 +Block included: https://explorer.shimmer.network/testnet/block/0xca4f8150014bc548214be6b02bed3b7d43041adef8838965815a367f73c7272d +Account synced +Preparing minting transaction... +Transaction sent: 0xcfc5ffae0c7be8cfb7c334d6f6bb39a2ddff612c9a9048c88e3d9158f7cc4832 +Block included: https://explorer.shimmer.network/testnet/block/0x558c0dcede60609bbb641e9f1d9a7802b48a3c3d5827328a054385140d447436 +Minted token: 0x089dc1b964591b15819ef1912fab48c001fed4558b37766dfa5daa512495d5b25a0100000000 +Account synced +``` diff --git a/documentation/sdk/docs/how_tos/native_tokens/send.mdx b/documentation/sdk/docs/how_tos/native_tokens/send.mdx new file mode 100644 index 0000000000..99801dd6ed --- /dev/null +++ b/documentation/sdk/docs/how_tos/native_tokens/send.mdx @@ -0,0 +1,65 @@ +--- +title: Send Native Tokens +sidebar_label: Send +description: 'How to send native tokens' +image: /img/logo/iota_mark_light.png +keywords: +- how to +- send native token +- send +- native token +- nodejs +- python +- rust +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import NodejsCode from '!!raw-loader!../../../../../bindings/nodejs/examples/how_tos/native_tokens/send.ts'; +import PythonCode from '!!raw-loader!../../../../../bindings/python/examples/how_tos/native_tokens/send.py'; +import RustCode from '!!raw-loader!../../../../../sdk/examples/how_tos/native_tokens/send.rs'; + +After you have [minted](mint.mdx) a +[native token](https://wiki.iota.org/shimmer/introduction/explanations/what_is_stardust/tokenization#native-tokens), +you can easily send it by calling the `Account.send_native_tokens(params, options)` function. + +As with any output, you can set [output unlock conditions](https://wiki.iota.org/shimmer/introduction/explanations/what_is_stardust/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 + +The following example will: + +1. Create an account manager. +2. Get Alice's account which was [created in the first guide](../accounts_and_addresses/create_account.mdx). +3. Define the type of native token and amount to send. +4. Send the native tokens calling the `Account.send_native_tokens(params, options)` function. + + + + + {RustCode} + + + + + {NodejsCode} + + + + + {PythonCode} + + + + +## Expected Output + +```plaintext +Balance before sending: 50 +Transaction sent: 0x9a1ea93962b5d4ba3a27053f4727dcc95b29ee35dc85c43d9d6be4635ab10463 +Block included: https://explorer.shimmer.network/testnet/block/0xb22cba455a3176ef62352f907b0fc5e5e49b4797563826141f8057cfa960a640 +Balance after sending: 40 +``` diff --git a/documentation/sdk/sidebars.js b/documentation/sdk/sidebars.js index 90696a8ee5..d4a7f8153c 100644 --- a/documentation/sdk/sidebars.js +++ b/documentation/sdk/sidebars.js @@ -104,6 +104,18 @@ module.exports = { } ] }, + { + type: "category", + label: 'Native Tokens', + items: [ + 'how_tos/native_tokens/mint', + 'how_tos/native_tokens/decrease_supply', + 'how_tos/native_tokens/increase_supply', + 'how_tos/native_tokens/send', + 'how_tos/native_tokens/burn', + 'how_tos/native_tokens/destroy_foundry', + ] + }, { type: "category", label: 'Sign And Verify Ed25519', diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index b62a9898e7..d940e73ae2 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -179,6 +179,38 @@ name = "claim_transaction" path = "examples/how_tos/advanced_transactions/claim_transaction.rs" required-features = [ "rocksdb", "stronghold" ] +# Native Tokens Examples + +[[example]] +name = "mint_native_token" +path = "examples/how_tos/native_tokens/mint.rs" +required-features = [ "rocksdb", "stronghold" ] + +[[example]] +name = "destroy_foundry" +path = "examples/how_tos/native_tokens/destroy_foundry.rs" +required-features = [ "rocksdb", "stronghold" ] + +[[example]] +name = "burn_native_token" +path = "examples/how_tos/native_tokens/burn.rs" +required-features = [ "rocksdb", "stronghold" ] + +[[example]] +name = "decrease_native_token_supply" +path = "examples/how_tos/native_tokens/decrease_supply.rs" +required-features = [ "rocksdb", "stronghold" ] + +[[example]] +name = "increase_native_token_supply" +path = "examples/how_tos/native_tokens/increase_supply.rs" +required-features = [ "rocksdb", "stronghold" ] + +[[example]] +name = "send_native_tokens" +path = "examples/how_tos/native_tokens/send.rs" +required-features = [ "rocksdb", "stronghold" ] + # Alias wallet example [[example]] @@ -561,51 +593,21 @@ name = "3_send_transaction" path = "examples/wallet/offline_signing/3_send_transaction.rs" required-features = [ "wallet", "storage" ] -[[example]] -name = "send_native_tokens" -path = "examples/wallet/07_send_native_tokens.rs" -required-features = [ "wallet", "stronghold" ] - [[example]] name = "send_nft" path = "examples/wallet/08_send_nft.rs" required-features = [ "wallet", "stronghold" ] -[[example]] -name = "mint_native_token" -path = "examples/wallet/09_mint_native_token.rs" -required-features = [ "wallet", "stronghold" ] - [[example]] name = "mint_nft" path = "examples/wallet/10_mint_nft.rs" required-features = [ "wallet", "stronghold" ] -[[example]] -name = "decrease_native_token_supply" -path = "examples/wallet/11_decrease_native_token_supply.rs" -required-features = [ "wallet", "stronghold" ] - -[[example]] -name = "increase_native_token_supply" -path = "examples/wallet/12_increase_native_token_supply.rs" -required-features = [ "wallet", "stronghold" ] - -[[example]] -name = "burn_native_token" -path = "examples/wallet/13_burn_native_token.rs" -required-features = [ "wallet", "stronghold" ] - [[example]] name = "burn_nft" path = "examples/wallet/14_burn_nft.rs" required-features = [ "wallet", "stronghold" ] -[[example]] -name = "destroy_foundry" -path = "examples/wallet/15_destroy_foundry.rs" -required-features = [ "wallet", "stronghold" ] - [[example]] name = "create_alias" path = "examples/wallet/create_alias.rs" diff --git a/sdk/examples/how_tos/native_tokens/burn.rs b/sdk/examples/how_tos/native_tokens/burn.rs new file mode 100644 index 0000000000..961f7e88b1 --- /dev/null +++ b/sdk/examples/how_tos/native_tokens/burn.rs @@ -0,0 +1,90 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! In this example we will burn an existing native token, this will not increase the melted supply in the foundry, +//! therefore the foundry output is also not required. But this will also make it impossible to destroy the foundry +//! output that minted it. +//! +//! Make sure that `example.stronghold` and `example.walletdb` already exist by +//! running the `create_account` example! +//! +//! Rename `.env.example` to `.env` first, then run the command: +//! ```sh +//! cargo run --release --all-features --example burn_native_token +//! ``` + +use std::env::var; + +use iota_sdk::{types::block::output::NativeToken, wallet::Result, Wallet, U256}; + +// The minimum available native token amount to search for in the account +const MIN_AVAILABLE_AMOUNT: u64 = 11; +// The amount of the native token to burn +const BURN_AMOUNT: u64 = 1; + +#[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(); + + let wallet = Wallet::builder() + .with_storage_path(&var("WALLET_DB_PATH").unwrap()) + .finish() + .await?; + let alias = "Alice"; + let account = wallet.get_account(alias.to_string()).await?; + + // May want to ensure the account is synced before sending a transaction. + let balance = account.sync(None).await?; + + // Get a token with sufficient balance + if let Some(token_id) = balance + .native_tokens() + .iter() + .find(|t| t.available() >= U256::from(MIN_AVAILABLE_AMOUNT)) + .map(|t| t.token_id()) + { + let available_balance = balance + .native_tokens() + .iter() + .find(|t| t.token_id() == token_id) + .unwrap() + .available(); + println!("Balance before burning: {available_balance:?}"); + + // Set the stronghold password + wallet + .set_stronghold_password(var("STRONGHOLD_PASSWORD").unwrap()) + .await?; + + // Burn a native token + let burn_amount = U256::from(BURN_AMOUNT); + let transaction = account.burn(NativeToken::new(*token_id, burn_amount)?, 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/{}", var("EXPLORER_URL").unwrap(), block_id); + + let balance = account.sync(None).await?; + + print!("Balance after burning: "); + if let Some(native_token_balance) = balance + .native_tokens() + .iter() + .find(|native_token| native_token.token_id() == token_id) + { + let available_balance = native_token_balance.available(); + println!("{available_balance}"); + } else { + println!("No remaining tokens"); + } + } else { + println!( + "No native token exist or there's not at least '{MIN_AVAILABLE_AMOUNT}' tokens of it in account '{alias}'" + ); + } + + Ok(()) +} diff --git a/sdk/examples/wallet/11_decrease_native_token_supply.rs b/sdk/examples/how_tos/native_tokens/decrease_supply.rs similarity index 60% rename from sdk/examples/wallet/11_decrease_native_token_supply.rs rename to sdk/examples/how_tos/native_tokens/decrease_supply.rs index 99ba66201d..ca0069847a 100644 --- a/sdk/examples/wallet/11_decrease_native_token_supply.rs +++ b/sdk/examples/how_tos/native_tokens/decrease_supply.rs @@ -11,24 +11,15 @@ //! cargo run --release --all-features --example decrease_native_token_supply //! ``` -use std::{env::var, str::FromStr}; +use std::env::var; use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet, U256}; -// The native token id. Replace it with a TokenId that is available in the account, the foundry output which minted it, -// also needs to be available. You can check this by running the `get_balance` example. You can mint a new native token -// by running the `mint_native_token` example. -const TOKEN_ID: &str = "0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000"; // The amount of native tokens to melt const MELT_AMOUNT: u64 = 10; #[tokio::main] async fn main() -> Result<()> { - if TOKEN_ID == "0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000" { - println!("You need to change the TOKEN_ID constant before you can run this example successfully!"); - return Ok(()); - } - // This example uses secrets in environment variables for simplicity which should not be done in production. dotenvy::dotenv().ok(); @@ -38,21 +29,23 @@ async fn main() -> Result<()> { .await?; let account = wallet.get_account("Alice").await?; - let token_id = TokenId::from_str(TOKEN_ID)?; - // May want to ensure the account is synced before sending a transaction. account.sync(None).await?; let balance = account.balance().await?; + // Find first foundry and corresponding token id + let token_id = TokenId::from(*balance.foundries().first().unwrap()); + if let Some(native_token_balance) = balance .native_tokens() .iter() .find(|native_token| native_token.token_id() == &token_id) { - println!("Balance BEFORE melting:\n{native_token_balance:#?}"); + let available_balance = native_token_balance.available(); + println!("Balance before melting: {available_balance}"); } else { - println!("Couldn't find native token '{TOKEN_ID}' in the account"); + println!("Couldn't find native token '{token_id}' in the account"); return Ok(()); } @@ -61,8 +54,6 @@ async fn main() -> Result<()> { .set_stronghold_password(var("STRONGHOLD_PASSWORD").unwrap()) .await?; - println!("Sending the melting transaction..."); - // Melt some of the circulating supply let melt_amount = U256::from(MELT_AMOUNT); let transaction = account @@ -74,20 +65,16 @@ async fn main() -> Result<()> { .retry_transaction_until_included(&transaction.transaction_id, None, None) .await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); - println!("Melted {} native tokens ({})", melt_amount, token_id); + println!("Block included: {}/block/{}", var("EXPLORER_URL").unwrap(), block_id); let balance = account.sync(None).await?; - let native_token_balance = balance + let available_balance = balance .native_tokens() .iter() - .find(|native_token| native_token.token_id() == &token_id) - .unwrap(); - println!("Balance AFTER melting:\n{native_token_balance:#?}"); + .find(|t| t.token_id() == &token_id) + .unwrap() + .available(); + println!("Balance after melting: {available_balance}",); Ok(()) } diff --git a/sdk/examples/wallet/15_destroy_foundry.rs b/sdk/examples/how_tos/native_tokens/destroy_foundry.rs similarity index 76% rename from sdk/examples/wallet/15_destroy_foundry.rs rename to sdk/examples/how_tos/native_tokens/destroy_foundry.rs index da291ee480..e53438db12 100644 --- a/sdk/examples/wallet/15_destroy_foundry.rs +++ b/sdk/examples/how_tos/native_tokens/destroy_foundry.rs @@ -33,33 +33,24 @@ async fn main() -> Result<()> { // We try to destroy the first foundry in the account if let Some(foundry_id) = balance.foundries().first() { - let foundries_before = balance.foundries(); - println!("Foundries BEFORE destroying:\n{foundries_before:#?}",); + let foundry_count = balance.foundries().len(); + println!("Foundries before destroying: {foundry_count}"); // Set the stronghold password wallet .set_stronghold_password(var("STRONGHOLD_PASSWORD").unwrap()) .await?; - println!("Sending foundry burn transaction..."); - let transaction = account.burn(*foundry_id, None).await?; println!("Transaction sent: {}", transaction.transaction_id); let block_id = account .retry_transaction_until_included(&transaction.transaction_id, None, None) .await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); - - println!("Burned Foundry '{}'", foundry_id); + println!("Block included: {}/block/{}", var("EXPLORER_URL").unwrap(), block_id); - let balance = account.sync(None).await?; - let foundries_after = balance.foundries(); - println!("Foundries AFTER destroying:\n{foundries_after:#?}",); + let foundry_count = balance.foundries().len(); + println!("Foundries after destroying: {foundry_count}"); } else { println!("No Foundry available in account '{alias}'"); } diff --git a/sdk/examples/wallet/12_increase_native_token_supply.rs b/sdk/examples/how_tos/native_tokens/increase_supply.rs similarity index 54% rename from sdk/examples/wallet/12_increase_native_token_supply.rs rename to sdk/examples/how_tos/native_tokens/increase_supply.rs index 1c326f3bbf..ac97f323f9 100644 --- a/sdk/examples/wallet/12_increase_native_token_supply.rs +++ b/sdk/examples/how_tos/native_tokens/increase_supply.rs @@ -11,24 +11,15 @@ //! cargo run --release --all-features --example increase_native_token_supply //! ``` -use std::{env::var, str::FromStr}; +use std::env::var; use iota_sdk::{types::block::output::TokenId, wallet::Result, Wallet, U256}; -// The native token id. Replace it with a TokenId that is available in the account, the foundry output which minted it, -// also needs to be available. You can check this by running the `get_balance` example. You can mint a new native token -// by running the `mint_native_token` example. -const TOKEN_ID: &str = "0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000"; // The amount of native tokens to mint const MINT_AMOUNT: u64 = 10; #[tokio::main] async fn main() -> Result<()> { - if TOKEN_ID == "0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000" { - println!("You need to change the TOKEN_ID constant before you can run this example successfully!"); - return Ok(()); - } - // This example uses secrets in environment variables for simplicity which should not be done in production. dotenvy::dotenv().ok(); @@ -38,28 +29,24 @@ async fn main() -> Result<()> { .await?; let account = wallet.get_account("Alice").await?; - let token_id = TokenId::from_str(TOKEN_ID)?; - // May want to ensure the account is synced before sending a transaction. let balance = account.sync(None).await?; - if let Some(native_token_balance) = balance - .native_tokens() - .iter() - .find(|native_token| native_token.token_id() == &token_id) - { - println!("Balance BEFORE minting:\n{native_token_balance:#?}"); - } else { - println!("Couldn't find native token '{TOKEN_ID}' in the account"); - return Ok(()); - } - // Set the stronghold password wallet .set_stronghold_password(var("STRONGHOLD_PASSWORD").unwrap()) .await?; - println!("Sending the minting transaction..."); + // Find first foundry and corresponding token id + let token_id = TokenId::from(*balance.foundries().first().unwrap()); + + let available_balance = balance + .native_tokens() + .iter() + .find(|t| t.token_id() == &token_id) + .unwrap() + .available(); + println!("Balance before minting: {available_balance}",); // Mint some more native tokens let mint_amount = U256::from(MINT_AMOUNT); @@ -71,20 +58,16 @@ async fn main() -> Result<()> { let block_id = account .retry_transaction_until_included(&transaction.transaction.transaction_id, None, None) .await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); - println!("Minted {} native tokens ({})", mint_amount, transaction.token_id); + println!("Block included: {}/block/{}", var("EXPLORER_URL").unwrap(), block_id); let balance = account.sync(None).await?; - let native_token_balance = balance + let available_balance = balance .native_tokens() .iter() - .find(|native_token| native_token.token_id() == &token_id) - .unwrap(); - println!("Balance AFTER minting:\n{native_token_balance:#?}"); + .find(|t| t.token_id() == &token_id) + .unwrap() + .available(); + println!("Balance after minting: {available_balance:?}",); Ok(()) } diff --git a/sdk/examples/wallet/09_mint_native_token.rs b/sdk/examples/how_tos/native_tokens/mint.rs similarity index 65% rename from sdk/examples/wallet/09_mint_native_token.rs rename to sdk/examples/how_tos/native_tokens/mint.rs index 9a2b8a8f3f..acca70093e 100644 --- a/sdk/examples/wallet/09_mint_native_token.rs +++ b/sdk/examples/how_tos/native_tokens/mint.rs @@ -33,32 +33,31 @@ async fn main() -> Result<()> { .finish() .await?; let account = wallet.get_account("Alice").await?; + let balance = account.sync(None).await?; // Set the stronghold password wallet .set_stronghold_password(var("STRONGHOLD_PASSWORD").unwrap()) .await?; - println!("Sending alias output transaction..."); + // We can first check if we already have an alias in our account, because an alias can have many foundry outputs and + // therefore we can reuse an existing one + if balance.aliases().is_empty() { + // If we don't have an alias, we need to create one + let transaction = account.create_alias_output(None, None).await?; + println!("Transaction sent: {}", transaction.transaction_id); - // First create an alias output, this needs to be done only once, because an alias can have many foundry outputs - let transaction = account.create_alias_output(None, None).await?; - println!("Transaction sent: {}", transaction.transaction_id); + // Wait for transaction to get included + let block_id = account + .retry_transaction_until_included(&transaction.transaction_id, None, None) + .await?; + println!("Block included: {}/block/{}", var("EXPLORER_URL").unwrap(), block_id); - // Wait for transaction to get included - let block_id = account - .retry_transaction_until_included(&transaction.transaction_id, None, None) - .await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); - - account.sync(None).await?; - println!("Account synced"); + account.sync(None).await?; + println!("Account synced"); + } - println!("Sending the minting transaction..."); + println!("Preparing minting transaction..."); let params = MintNativeTokenParams { alias_id: None, @@ -74,12 +73,8 @@ async fn main() -> Result<()> { let block_id = account .retry_transaction_until_included(&transaction.transaction.transaction_id, None, None) .await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); - println!("Minted token: {} ", transaction.token_id); + println!("Block included: {}/block/{}", var("EXPLORER_URL").unwrap(), block_id); + println!("Minted token: {}", transaction.token_id); // Ensure the account is synced after minting. account.sync(None).await?; diff --git a/sdk/examples/wallet/07_send_native_tokens.rs b/sdk/examples/how_tos/native_tokens/send.rs similarity index 59% rename from sdk/examples/wallet/07_send_native_tokens.rs rename to sdk/examples/how_tos/native_tokens/send.rs index cbbf50de63..5218fafbea 100644 --- a/sdk/examples/wallet/07_send_native_tokens.rs +++ b/sdk/examples/how_tos/native_tokens/send.rs @@ -14,10 +14,7 @@ use std::env::var; use iota_sdk::{ - types::block::{ - address::Bech32Address, - output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, NativeToken}, - }, + types::block::address::Bech32Address, wallet::{Result, SendNativeTokensParams}, Wallet, }; @@ -49,6 +46,14 @@ async fn main() -> Result<()> { .find(|t| t.available() >= U256::from(SEND_NATIVE_TOKEN_AMOUNT)) .map(|t| t.token_id()) { + let available_balance = balance + .native_tokens() + .iter() + .find(|t| t.token_id() == token_id) + .unwrap() + .available(); + println!("Balance before sending: {available_balance}"); + // Set the stronghold password wallet .set_stronghold_password(var("STRONGHOLD_PASSWORD").unwrap()) @@ -61,11 +66,6 @@ async fn main() -> Result<()> { [(*token_id, U256::from(SEND_NATIVE_TOKEN_AMOUNT))], )?]; - println!( - "Sending '{}' native tokens to '{}'...", - SEND_NATIVE_TOKEN_AMOUNT, bech32_address - ); - let transaction = account.send_native_tokens(outputs, None).await?; println!("Transaction sent: {}", transaction.transaction_id); @@ -73,38 +73,17 @@ async fn main() -> Result<()> { let block_id = account .retry_transaction_until_included(&transaction.transaction_id, None, None) .await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); - - account.sync(None).await?; - println!("Account synced"); - - println!("Sending basic output transaction..."); - - // Send native tokens together with the required storage deposit - let rent_structure = account.client().get_rent_structure().await?; - - let outputs = [BasicOutputBuilder::new_with_minimum_storage_deposit(rent_structure) - .add_unlock_condition(AddressUnlockCondition::new(bech32_address)) - .with_native_tokens([NativeToken::new(*token_id, U256::from(SEND_NATIVE_TOKEN_AMOUNT))?]) - .finish_output(account.client().get_token_supply().await?)?]; + println!("Block included: {}/block/{}", var("EXPLORER_URL").unwrap(), block_id); - let transaction = account.send(outputs, None).await?; - println!("Transaction sent: {}", transaction.transaction_id); - - // Wait for transaction to get included - let block_id = account - .retry_transaction_until_included(&transaction.transaction_id, None, None) - .await?; + let balance = account.sync(None).await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); + let available_balance = balance + .native_tokens() + .iter() + .find(|t| t.token_id() == token_id) + .unwrap() + .available(); + println!("Balance after sending: {available_balance}",); } else { println!("Insufficient native token funds"); } diff --git a/sdk/examples/wallet/13_burn_native_token.rs b/sdk/examples/wallet/13_burn_native_token.rs deleted file mode 100644 index 4d3143be5d..0000000000 --- a/sdk/examples/wallet/13_burn_native_token.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2022 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -//! In this example we will burn a native token. This will not increase the melted supply in the foundry, -//! therefore the foundry output is also not required. But this will also make it impossible to destroy the foundry -//! output that minted it. -//! -//! Make sure that `example.stronghold` and `example.walletdb` already exist by -//! running the `create_account` example! -//! -//! Rename `.env.example` to `.env` first, then run the command: -//! ```sh -//! cargo run --release --all-features --example burn_native_token -//! ``` - -use std::{env::var, str::FromStr}; - -use iota_sdk::{ - types::block::output::{NativeToken, TokenId}, - wallet::Result, - Wallet, U256, -}; - -// The native token id. Replace it with a TokenId that is available in the account, the foundry output which minted it, -// also needs to be available. You can check this by running the `get_balance` example. You can mint a new native token -// by running the `mint_native_token` example. -const TOKEN_ID: &str = "0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000"; -// The minimum available native token amount to search for in the account -const MIN_AVAILABLE_AMOUNT: u64 = 11; -// The amount of the native token to burn -const BURN_AMOUNT: u64 = 1; - -#[tokio::main] -async fn main() -> Result<()> { - if TOKEN_ID == "0x08847bd287c912fadedb6bf38900bda9f2d377b75b2a0bece8738699f56ebca4130100000000" { - println!("You need to change the TOKEN_ID constant before you can run this example successfully!"); - return Ok(()); - } - - // This example uses secrets in environment variables for simplicity which should not be done in production. - dotenvy::dotenv().ok(); - - let wallet = Wallet::builder() - .with_storage_path(&var("WALLET_DB_PATH").unwrap()) - .finish() - .await?; - let alias = "Alice"; - let account = wallet.get_account(alias.to_string()).await?; - - let token_id = TokenId::from_str(TOKEN_ID)?; - - // May want to ensure the account is synced before sending a transaction. - let balance = account.sync(None).await?; - - if let Some(native_token_balance) = balance.native_tokens().iter().find(|native_token| { - native_token.token_id() == &token_id && native_token.available() >= U256::from(MIN_AVAILABLE_AMOUNT) - }) { - println!("Balance BEFORE burning:\n{native_token_balance:#?}",); - - // Set the stronghold password - wallet - .set_stronghold_password(var("STRONGHOLD_PASSWORD").unwrap()) - .await?; - - println!("Sending the burning transaction..."); - - // Burn a native token - let burn_amount = U256::from(BURN_AMOUNT); - let transaction = account.burn(NativeToken::new(token_id, burn_amount)?, None).await?; - println!("Transaction sent: {}", transaction.transaction_id); - - let block_id = account - .retry_transaction_until_included(&transaction.transaction_id, None, None) - .await?; - println!( - "Transaction included: {}/block/{}", - var("EXPLORER_URL").unwrap(), - block_id - ); - println!( - "Burned {} native token(s) ({})", - burn_amount, - native_token_balance.token_id() - ); - - let balance = account.sync(None).await?; - - println!("Balance AFTER burning:"); - if let Some(native_token_balance) = balance - .native_tokens() - .iter() - .find(|native_token| native_token.token_id() == native_token_balance.token_id()) - { - println!("{native_token_balance:#?}"); - } else { - println!("No remaining tokens"); - } - } else { - println!( - "Native token '{TOKEN_ID}' doesn't exist or there's not at least '{MIN_AVAILABLE_AMOUNT}' tokens of it in account '{alias}'" - ); - } - - Ok(()) -}