Skip to main content

Transfer assets

Before transferring, you need to mint tokens to one of the previously created accounts. Let's use an example where we mint 100 TST tokens to the account with the ID 5E24-EAD2. Since the TST asset has six decimal points, we must pass 100,000,000 to the mint operation.

chr tx ft4.admin.mint \
5E2488889F72939DD4D0A034FB91893ACBF14C7EDBCEF2A9F5C621A07169EAD2 \
85506832C77AFDDB17DE1D175BAEE949C9248578E06CAC3EC7B59AA69C7C69B0 \
100000000L \
--await --secret ft4-admin.keypair
note

Please remember to replace 5E24-EAD2 with the ID of the account you registered in the last step and 8550-69B0 with the ID of the asset you want to use for the whole duration of this guide.

To verify the details of the asset, you can use the following query:

chr query ft4.get_asset_by_id -- '{asset_id=x"85506832C77AFDDB17DE1D175BAEE949C9248578E06CAC3EC7B59AA69C7C69B0"}'

The query'll display information about the asset, including the supply that has been minted.

To check the account balances, use the following command:

chr query ft4.get_asset_balances -- '{ account_id = x"5E2488889F72939DD4D0A034FB91893ACBF14C7EDBCEF2A9F5C621A07169EAD2", page_size = 10, page_cursor = null }'

This command'll return a list of balances for all the assets in the account. In this case, there is only one asset, and the output will show the amount of that asset held by the account.

If you want to check the balance of a specific token, you can use the following query:

chr query ft4.get_asset_balance -- '{ account_id = x"5E2488889F72939DD4D0A034FB91893ACBF14C7EDBCEF2A9F5C621A071", asset_id = x"85506832C77AFDDB17DE1D175BAEE949C9248578E06CAC3EC7B59AA69C7C69B0" }

Now that you have an account with assets, you can start experimenting with asset transfers. Since authorizations work differently in the FT library, performing transfers from the command line would be challenging. Instead, you can use the FT4 client for asset transfers.

Setup the client code

You have already seen how to set up a connection, register an asset and an account.

In your Typescript code, you can use this knowledge to transfer an asset from one account to another. First, you need to retrieve the account 5E24-EAD2, which now holds 100 TST tokens. You'll need to log into that account, using the private key we've stored in user.keypair:

import { encryption } from "postchain-client";

const keyPair = encryption.makeKeyPair(
"9F11AB5B146A928519114E8104825D67E95474BD60F0A1ED60332669E232918D"
);

const accountId =
"5E2488889F72939DD4D0A034FB91893ACBF14C7EDBCEF2A9F5C621A07169EAD2";
caution

Be careful whenever you're using private keys for tests. Always use a fresh keypair every time you release something for production, and rotate the keys as soon as you discover that they might have been exposed.

You can now log into your account:

const { getSession } = createKeyStoreInteractor(
client,
createInMemoryFtKeyStore(keyPair)
);

const session = await getSession(accountId);

It's time to define the details of this transfer:

const recipientId =
"79C71AF3C9C951BED380F8ADAB2E407C15CC4A9EB942AA222D870136C45801CE";
const assetId =
"85506832C77AFDDB17DE1D175BAEE949C9248578E06CAC3EC7B59AA69C7C69B0";
const amountToSend = createAmount(10, 6); // it will send 10 tokens, but it has 6 decimals!

You can safely transfer the assets.

await session.account.transfer(recipientId, assetId, amountToSend);

After running this code, you should have 90 TST tokens in the account. You can check it like we already did at the start of this guide, or you can have the script do that for you:

console.log(await session.account.getBalanceByAssetId(assetId));

Complete example

For this example to work out of the box, you must follow the guides here. Putting the right private key in the marked code would be best.

import {
GtvAuthDescriptor,
authDescriptor,
createAmount,
createInMemoryFtKeyStore,
createKeyStoreInteractor,
op,
} from "@chromia/ft4";
import { AssetResponse } from "@chromia/ft4/dist/client/lib/ft4/asset/types";
import { createClient, encryption } from "postchain-client";

const url = "http://localhost:7740";
const client = await createClient({
nodeURLPool: url,
blockchainIID: 0,
});

//## EDIT HERE ##//
// Taken from ft4-admin.keypair:
const adminKeyPair = encryption.makeKeyPair(
"2AC313A8384F319058C578F0E46A9871EACE285EA9144166D80FACE635713D39"
);

// we can also create a new keypair:
const senderKeyPair = encryption.makeKeyPair();

/**
* In the docs, we used the chromia CLI to create assets and accounts.
* Here, we'll use the equivalent functions from the `postchain-client` library
*
*/

// Create an asset (the admin defined in chromia.yaml must sign)
await client.signAndSendUniqueTransaction(
op(
"ft4.admin.register_asset",
"TestAsset4",
"TST4",
6,
"http://url-to-asset-4-icon"
),
adminKeyPair
);

// we need the asset ID
const assetId = (
await client.query<{ symbol: string }, AssetResponse>(
"ft4.get_asset_by_symbol",
{ symbol: "TST4" }
)
).id;

// Create an auth descriptor for the sender account
const authDesc =
// toGtv makes it possible to send it to postchain
authDescriptor.toGtv(
authDescriptor.create.singleSig.withArgs(
// Can modify the account and transfer
["A", "T"],
// who's the signer
senderKeyPair.pubKey
// No limitations for this signer
).andNoRules
);

/**
* This is equivalent to what we had in the docs
* https://docs.chromia.com/ft4/ft4-register-accounts#registering-with-ft4-admin-operation
*
* [
* 0, // single sig
* [
* ["A","T"], // can modify the account and transfer
* senderKeyPair.pubKey // who's the signer
* ],
* null // we don't want restrictions for this signer
* ]
*/

// The ID of the account can be calculated from the
// Auth descriptor even before account creation
const senderId = authDescriptor.deriveAccountId(authDesc);

// Create the sender account
await client.signAndSendUniqueTransaction(
op("ft4.admin.register_account", authDesc),
adminKeyPair
);

// Mint 100 TST tokens to our account (sender)
// 100 with 6 decimal digits is 100.000000. remove the
// Decimal point and use that as amount
await client.signAndSendUniqueTransaction(
op("ft4.admin.mint", senderId, assetId, 100000000n),
adminKeyPair
);

/**
* This will only work if you followed steps 4 and 5 of
* docs.chromia.com/ft4/ft4-register-accounts#registering-with-ft4-admin-operation
*
const allAccounts = await client.query("get_all_accounts")
*
* If we have only one account on chain, then we can retrieve it
const senderId = allAccounts![0].id;
*/

// Let's create a receiver account too.
// You can also create the auth descriptor as it was in the docs.
const recipientAd: GtvAuthDescriptor = [
0,
[
["A", "T"],
encryption.makeKeyPair().pubKey, // random key
],
null,
];

await client.signAndSendUniqueTransaction(
op("ft4.admin.register_account", recipientAd),
adminKeyPair
);

const recipientId = authDescriptor.deriveAccountId(recipientAd);
const amountToSend = createAmount(10, 6); // it will send 10 tokens, but it has 6 decimals!

// we can now start the login process
const { getSession } = createKeyStoreInteractor(
client,
createInMemoryFtKeyStore(senderKeyPair)
);

const session = await getSession(senderId);

await session.account.transfer(recipientId, assetId, amountToSend);

console.log(await session.account.getBalanceByAssetId(assetId));