Skip to main content

Step 3: Deposits, withdrawals, and transaction monitoring

Handling deposits, withdrawals, and monitoring transactions are essential components of integrating with Chromia's economy chain. These operations are streamlined using the FT4 library, which provides a comprehensive toolkit for interacting with the Chromia ecosystem.

The FT4 library is designed to help developers build real-world applications within Chromia by offering out-of-the-box functionality for:

  • Account creation and access management: Simplifies user account setup and integrates with familiar external signature solutions.
  • Asset management: Enables issuance, allocation, transfers, and tracing of asset activities, both within a single chain and across chains in the Chromia ecosystem.

Using the FT4 library, you can efficiently manage deposits and withdrawals while monitoring transaction activities within the blockchain network.

Resources

Using the FT4 library example

  1. Setting up the client

Start by configuring the client to interact with the Chromia blockchain. Use the postchain-client library to create a generic client and the @chromia/ft4 library to establish FT4 connections.

import { createClient } from "postchain-client";
import { createConnection } from "@chromia/ft4";

// All IDs are supposed to be 32bytes, or 64-character hex strings - account ID, blockchain RID, asset ID, etc.

// Blockchain connection details
const NODE_URL: string | string[] = ["<node_url>"];
const BLOCKCHAIN_RID: string = "64-character hex string";

// Create a generic client for calling queries and operations
const client = await createClient({
directoryNodeUrlPool: NODE_URL,
blockchainRid: BLOCKCHAIN_RID,
});

// Advanced client for FT4 interaction
const connection = createConnection(client);
  1. Accessing an account

Retrieve an account using its ID to access account-related data. This account remains read-only and can only fetch information, not perform operations like transferring funds.

import { Account } from "@chromia/ft4";

// Access an account by its ID:
const myAccount: Account | null = await connection.getAccountById("account ID");
if (myAccount == null) throw "Account not found";
tip

The getAccountById function helps you verify whether an account exists before you initiate a transfer. By performing this check, you identify if the recipient account already exists or if you need to send a minimum of 10 CHR to create the account.

  1. Retrieving transaction history

Fetch transaction history in batches to handle large datasets efficiently. Use pagination to retrieve a specified number of entries for better control over the data.

import { TransferHistoryType } from "@chromia/ft4";

// Retrieve the latest 200 transactions in which the account participated:
const { data: first200Entries, nextCursor } = await myAccount.getTransferHistory(
200, // Maximum number of entries to fetch (default and cap: 200).
{ transferHistoryType: TransferHistoryType.Received } // Filter for received transactions.
);

// Retrieve 50 more transactions starting from the last fetched entry:
const { data: other50Entries, nextCursor: nextNextCursor } = await myAccount.getTransferHistory(
50, // Number of entries to fetch.
{ transferHistoryType: TransferHistoryType.Received }, // Filter for received transactions.
nextCursor // Cursor to start from the last position in the previous query.
);

// Fetch 200 additional transactions:
const { data: other200Entries, nextCursor: thirdCursor } = await myAccount.getTransferHistory(
200,
{ transferHistoryType: TransferHistoryType.Received },
nextNextCursor // Start from the 250th entry.
);
  1. Retrieving transfer details

Access detailed information about a specific transfer, including participants involved in the transaction.

// Retrieve details about a specific transfer:
const aTransfer = first200Entries[0];

const info = await connection.getTransferDetails(aTransfer.transactionId, aTransfer.opIndex);
  1. Retrieving account balances

Check the balance of an account for all assets or focus on a specific asset to obtain precise information.

// Retrieve account balances (supports pagination):
await myAccount.getBalances();

// Retrieve the balance of a specific token:
await myAccount.getBalanceByAssetId("asset-id-as-hex-string"); // Returns null if balance is zero.
  1. Setting up a key store and transferring funds

Create a key store to handle transaction signing and transfer funds using a read-write account. Utilize utility functions to manage token amounts effectively.

import {
createInMemoryFtKeyStore,
createKeyStoreInteractor,
createAmount,
createAmountFromBalance,
Session,
} from "@chromia/ft4";

// Set up a key store for signing transactions:
const keystore = createInMemoryFtKeyStore({
privKey: Buffer.from("my-privkey-as-hex-string", "hex"),
pubKey: Buffer.from("my-pubkey-as-hex-string", "hex"),
});

// Retrieve accounts accessible by this key pair:
const { getAccounts, getSession } = createKeyStoreInteractor(client, keystore);
const accounts = await getAccounts();

// If you only have one account linked to the keypair, you can access it as:
const readonlyAccount = accounts[0]; // This account is still read-only.

// Access a read-write account:
const session: Session = await getSession("my-account-id-as-hex-string");
const account = session.account;

// Transfer funds to another account:
account.transfer(
"receiver-id-as-hex-string", // Recipient account ID.
"asset-id-as-hex-string", // Asset being transferred.
createAmount(5, 6) // Amount: 5 units with 6 decimals (5000000n).
);

// Use `createAmountFromBalance` if the amount is already a bigint:
createAmountFromBalance(5000000n, 6);
  1. Offline transactions

Prepare a transaction without sending it immediately. This approach is not suitable when the environment lacks blockchain access. It could be useful, however, whenever there should be a delay between the transaction being built and the actual sending. For a completely offline transaction process (except for the sending step), refer to section 8.

import { transactionBuilder } from "@chromia/ft4";

// Build a transaction without sending it:
await transactionBuilder(account.authenticator, client)
.add({
name: "ft4.transfer",
args: [
Buffer.from("receiver-id-as-hex-string", "hex"),
Buffer.from("asset-id-as-hex-string"),
createAmount(5, 6).value, // or 5000000n
],
})
.build();
tip

You can find detailed information about operation names and arguments at: FT4 Rell Documentation

  1. Sending offline transactions

Send a pre-built transaction by specifying transaction details and using a signer for authorization.

import { Transaction } from "postchain-client";

// The following information is required:
// - Blockchain RID
// - Account ID
// - Authentication descriptor ID

const blockchainRid = Buffer.from("id-as-hex", "hex");
const accountId = Buffer.from("id-as-hex", "hex");
const authDescriptorId = Buffer.from("id-as-hex", "hex");

const transaction: Transaction = {
operations: [
{ name: "ft4.ft_auth", args: [accountId, authDescriptorId] },
{
name: "ft4.transfer",
args: [
/* Values for recipient, asset and amount as above. Buffer, Buffer, bigint. */
],
},
],
signers: [
Buffer.from("pubkey-as-hex", "hex"), // The signer for the auth descriptor defined above.
],
};

// To send the transaction on a connected machine:
client.signAndSendUniqueTransaction(transaction, signatureProvider);