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
- How to set up the FT4 library: Client setup guide
- Detailed documentation: FT4 library overview
- Repository: FT4 library GitLab
- Memo integration guide: Memo integration guide
Using the FT4 library example
- 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);
- 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";
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.
- 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.
);
- 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);
- 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.
- 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);
- 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();
You can find detailed information about operation names and arguments at: FT4 Rell Documentation
- 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);