Skip to content

Commit

Permalink
Add native token how-tos (iotaledger#541)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
Dr-Electron and Thoralf-M committed Jun 21, 2023
1 parent 6ccea6b commit 61753b8
Show file tree
Hide file tree
Showing 33 changed files with 940 additions and 583 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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();

Expand All @@ -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
Expand All @@ -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`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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();

Expand All @@ -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
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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();

Expand All @@ -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
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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()}`);
Expand Down
Loading

0 comments on commit 61753b8

Please sign in to comment.