Skip to main content

Flare Transaction SDK

Flare Transaction SDK (@flarenetwork/flare-tx-sdk) is the official Node.js Software Development Kit for performing common actions on Flare's networks:

  • Retrieving account and balance information
  • Transferring native and wrapped coins
  • Claiming rewards from FlareDrops, staking, and FTSO delegation
  • Delegating to FTSO providers
  • Interacting with the C-chain contracts
  • Staking on the P-chain

This guide will walk you through installation, core concepts, and cookbook for all major features.

Need help?

You can raise an issue on the flare-foundation/flare-tx-sdk GitHub repository.

Prerequisites

Before you start, ensure you have the following:

  • Node.js
  • An EIP-1193 (e.g. MetaMask, WalletConnect), or a hardware wallet like Ledger or Trezor.

Installation

To get started, install the SDK into your Node.js project:

npm install @flarenetwork/flare-tx-sdk

Core concepts

Before you write code, it's helpful to understand two key components of the SDK:

  • Network Object: This is your main entry point for all on-chain actions. It represents the network you want to connect to (FLARE, COSTON2, SONGBIRD or COSTON) and provides all the methods for querying balances, sending transactions, and interacting with contracts.

  • Wallet Object: This object represents the user's account. It's responsible for providing a public key to identify the account and for signing transactions. The SDK doesn't handle private keys directly; instead, it defines a Wallet interface that you can implement using standard wallets like MetaMask, Ledger, or your own custom signer.

Quick start

Here's a simple example of how to use the SDK to connect to Flare Mainnet with a MetaMask wallet and check an account's balance.

import { Network, EIP1193WalletController } from "@flarenetwork/flare-tx-sdk";

async function main() {
console.log("Connecting to the Flare Mainnet...");

// 1. Initialize the Network object for Flare Mainnet
const network = Network.FLARE;

// 2. Connect to the active wallet in MetaMask
const controller = new EIP1193WalletController(window.ethereum);
const wallet = await controller.getActiveWallet();

// 3. Get the public key from the wallet
const publicKey = await wallet.getPublicKey();

// 4. Derive the C-Chain and P-Chain addresses
const cAddress = network.getCAddress(publicKey);
const pAddress = network.getPAddress(publicKey);
console.log(`C-Chain Address: ${cAddress}, P-Chain Address: ${pAddress}`);

// 5. Fetch the account's complete balance overview
console.log("Fetching balance...");
const balance = await network.getBalance(publicKey);
console.log("✅ Balance retrieved successfully!");
// All amounts are returned as wei
console.log(` - Available on C-Chain: ${balance.availableOnC} wei`);
console.log(` - Wrapped on C-Chain: ${balance.wrappedOnC} wei`);
console.log(` - Available on P-Chain: ${balance.availableOnP} wei`);
console.log(` - Staked on P-Chain: ${balance.stakedOnP} wei`);
}

main().catch(console.error);

Cookbook

This section provides practical guides for each major feature of the SDK.

Get account balances

The Flare network uses two chains: the C-Chain (Contract Chain) for EVM smart contracts and the P-Chain (Platform Chain) for staking. Both chains derive their addresses from a single public key.

// Get the public key from your wallet
const publicKey = await wallet.getPublicKey();

// Derive the addresses for each chain
const cAddress = network.getCAddress(publicKey);
const pAddress = network.getPAddress(publicKey);

// Get a full balance overview
const balance = await network.getBalance(publicKey);

// Or, query for specific balances
const cBalance = await network.getBalanceOnC(cAddress);
const cWrappedBalance = await network.getBalanceWrappedOnC(publicKeyOrCAddress);
const pBalance = await network.getBalanceOnP(publicKey);
const stakedBalance = await network.getBalanceStakedOnP(publicKey);

Wrap and transfer

Transfer native FLR and its wrapped equivalent WFLR on the C-Chain.

import { Amount } from "@flarenetwork/flare-tx-sdk";

// Transfer 1 FLR
await network.transferNative(wallet, recipientAddress, Amount.nats(1)); // Amount.nats handles the conversion to wei

// Wrap 1 FLR -> 1 WFLR
await network.wrapNative(wallet, Amount.nats(1));

// Transfer 1 WFLR
await network.transferWrapped(wallet, recipientAddress, Amount.wnats(1));

// Unwrap 1 WFLR -> 1 FLR
await network.unwrapToNative(wallet, Amount.wnats(1));

Claim Flaredrops rewards

// Check claimable FlareDrop rewards
const flareDropAmount = await network.getClaimableFlareDropReward(cAddress);
if (flareDropAmount > 0) {
// Claim the reward and send it to the wallet's C-Chain address
await network.claimFlareDropReward(wallet);
}

You can also pass additional parameters to modify:

  • rewardOwner (address) - C-chain address of the reward owner
  • recipient (address) - C-chain address of where the reward should be transferred
  • wrap (boolean) - transfer reward as native (default) or wrapped.
await network.claimFlareDropReward(wallet, rewardOwner, recipient, wrap);

Claim staking rewards

// Check and claim staking rewards
const stakingRewardAmount = await network.getClaimableStakingReward(cAddress);
if (stakingRewardAmount > 0) {
await network.claimStakingReward(wallet);
}

You can also pass additional parameters to modify:

  • rewardOwner (address) - C-chain address of the reward owner
  • recipient (address) - C-chain address of where the reward should be transferred
  • wrap (boolean) - transfer reward as native (default) or wrapped.
await network.claimStakingReward(wallet, rewardOwner, recipient, wrap);

Claim FTSO delegation rewards

// Check and claim FTSO delegation rewards
const ftsoRewardAmount = await network.getClaimableFtsoReward(cAddress);
if (ftsoRewardAmount > 0) {
await network.claimFtsoReward(wallet);
}

You can also pass additional parameters to modify:

  • rewardOwner (address) - C-chain address of the reward owner
  • recipient (address) - C-chain address of where the reward should be transferred
  • wrap (boolean) - transfer reward as native (default) or wrapped.
await network.claimFtsoReward(wallet, rewardOwner, recipient, wrap);

Detailed rewards

let states = await network.getStateOfFtsoRewards(cAddress);

The method returns an array of reward-epoch arrays. It can be empty or it consists of objects of type FtsoRewardState with properties:

  • rewardEpochId (int) - The reward epoch id.
  • beneficiary (string) - The reward owner (C-chain address or NodeID if claimType is MIRROR).
  • amount (int) - The reward amount in wei.
  • claimType (string) - The type of claim (DIRECT, FEE, WNAT, MIRROR, or CCHAIN).
  • initialised (boolean) - flag indicating if the reward can be claimed without providing proofs.

Claim with proofs

Rewards that are not initialized can be claimed using Merkle proofs available in the flare-foundation/fsp-rewards repository.

await network.claimFtsoReward(wallet, rewardOwner, recipient, wrap, proofs);

where proofs is an array of objects of type FtsoRewardClaimWithProof with properties:

  • merkleProof (array of string) - The Merkle proof in hexadecimal encoding.
  • body (FtsoRewardClaim ) - Same structure as FtsoRewardState without the initialised parameter.

Delegate to FTSO providers

Delegate your wrapped token vote power to one or two FTSO data providers to earn rewards.

import { Amount } from "@flarenetwork/flare-tx-sdk";

// Get current delegations
const delegations = await network.getFtsoDelegatesOf(cAddress);
console.log(delegations);

which returns an array of FtsoDelegate:

  • address - C-chain address of the delegate.
  • shareBP - The delegation share in base points units, a unit corresponds to 0.01%.

Delegate to one provider

const share = Amount.percentages(100);
await network.delegateToFtso(wallet, providerAddress, share);

Delegate to two providers

// Delegate 50% to provider1 and 50% to provider2
const share = Amount.percentages(50);
await network.delegateToFtso(
wallet,
provider1Address,
share,
provider2Address,
share,
);

Undelegate

// Undelegate all vote power
await network.undelegateFromFtso(wallet);

Interact with C-Chain contracts

Interact with any smart contract on the C-Chain by providing its address and ABI.

// Call a read-only contract method
const result = await network.invokeContractCallOnC(contractAddress, abi, "methodName", [param1, param2]);

// Execute a transaction method that changes state
// The `value` parameter is for payable methods
await network.invokeContractMethodOnC(wallet, contractAddress, abi, "methodName", value, [param1, param2]);

// You can also use contract names for official Flare contracts
const contractNames = await network.getFlareContracts(); // See available names
await network.invokeContractMethodOnC(wallet, "FtsoRewardManager", abi, "claimReward", ...);

Stake on P-Chain

Staking requires moving funds from the C-Chain to the P-Chain, delegating them to a validator, and then moving them back. The SDK streamlines this cross-chain process.

  1. Transfer Funds from C-Chain to P-Chain: This operation performs a C-Chain export followed by a P-Chain import automatically.

    // Transfer 100 FLR from C-Chain to P-Chain
    const amountToTransfer = Amount.nats(100);
    await network.transferToP(wallet, amountToTransfer);
  2. Delegate to a Validator: Once funds are on the P-Chain, you can delegate them.

    const amountToDelegate = Amount.nats(50);
    const nodeId = "NodeID-P73B..."; // The ID of the validator
    const startTime = Math.floor(Date.now() / 1000); // Start now
    const endTime = startTime + 14 * 24 * 60 * 60; // End in 14 days

    await network.delegateOnP(
    wallet,
    amountToDelegate,
    nodeId,
    startTime,
    endTime,
    );
  3. Transfer Funds Back to C-Chain: After your delegation period ends, move your funds back to the C-Chain.

    // Transfer all available funds from P-Chain back to C-Chain
    await network.transferToC(wallet);

Wallet controllers

A controller is a helper class that wraps a standard wallet library (like EIP-1193 for MetaMask or Zondax for Ledger) and produces SDK-compatible Wallet objects. The SDK includes controllers for popular wallet standards to make this easy.

EIP-1193 Wallets

Use the EIP1193WalletController for any browser-based wallet that exposes an EIP-1193 provider (window.ethereum) such as MetaMask or WalletConnect.

import { EIP1193WalletController } from "@flarenetwork/flare-tx-sdk";

// `provider` is the object from your Web3 wallet (e.g., window.ethereum)
const controller = new EIP1193WalletController(provider);

// Get a wallet for the currently active account in MetaMask
const wallet = await controller.getActiveWallet();

// Listen for account changes
controller.onWalletChange((newWallet) => {
console.log("Wallet account changed to:", await newWallet.getCAddress());
// Update your application state with the new wallet
});

Ledger

Use the LedgerWalletController with either @zondax/ledger-flare or @ledgerHQ/hw-app-eth libraries to sign with a Ledger device.

import { LedgerWalletController } from "@flarenetwork/flare-tx-sdk";

// Option 1: Setup with Zondax
import { FlareApp } from "@zondax/ledger-flare"
flrApp = FlareApp(...)
const controller = new LedgerWalletController(flrApp, null);

// Option 2: Setup with LedgerHQ
// import { Eth } from "@ledgerHQ/hw-app-eth"
// ethApp = Eth(...)
// const controller = new LedgerWalletController(null, ethApp);

// Get a wallet for a specific BIP-44 path
const wallet = await controller.getWallet("m/44'/60'/0'/0/0");

Trezor

Use the TrezorWalletController to integrate with a Trezor device via the Trezor Connect SDK.

import { TrezorConnect } from '@trezor/connect';
import { TrezorWalletController } from "@flarenetwork/flare-tx-sdk";

TrezorConnect.init(...)
const controller = new TrezorWalletController(TrezorConnect);

// Get a wallet for a specific BIP-44 path
const wallet = await controller.getWallet("m/44'/60'/0'/0/0");

Advanced

Transaction tracking

For fine-grained control and monitoring, you can register callbacks that fire at different stages of a transaction's lifecycle. All This is useful for UI updates, logging, or offline signing workflows.

// The transaction lifecycle looks like:
// [Unsigned] → [Before Signature] → [Signed] → [Before Submission] → [Submitted] → [After Submission] → [Confirmed]

// 1. Before Signing: Inspect the unsigned transaction.
// Returning `false` will cancel the signing request.
network.setBeforeTxSignatureCallback(async (data) => {
console.log("Transaction to be signed:", data.unsignedTxHex);
console.log("Transaction ID:", data.txType); // https://github.com/flare-foundation/flare-tx-sdk/blob/main/src/network/txtype.ts
return true; // Allow signing
});

// 2. Before Submission: Inspect the signed transaction.
// Returning `false` will prevent it from being sent to the network.
network.setBeforeTxSubmissionCallback(async (data) => {
console.log("Transaction to be submitted:", data.signedTxHex);
console.log("Transaction ID:", data.txId);
console.log("Transaction type:", data.txType); // https://github.com/flare-foundation/flare-tx-sdk/blob/main/src/network/txtype.ts
return true; // Allow submission
});

// 3. After Submission: Get the transaction ID immediately after sending.
network.setAfterTxSubmissionCallback(async (data) => {
console.log(`Transaction ${data.txId} submitted. Awaiting confirmation...`);
console.log("Transaction type:", data.txType); // https://github.com/flare-foundation/flare-tx-sdk/blob/main/src/network/txtype.ts
return true; // Wait for confirmation
});

// 4. After Confirmation: Get the final status of the transaction.
network.setAfterTxConfirmationCallback(async (data) => {
console.log(
`Transaction ${data.txId} confirmed with status: ${data.txStatus}`,
);
});

Change network RPC

When creating the Network object, the SDK utilizes Flare's public RPCs by default. To specify a custom RPC endpoint:

// Initialize the Network object for Flare Mainnet
const network = Network.FLARE;
// Change the RPC endpoint to a custom one
// You can use any public or private RPC, or your own node
network.setRpc(
"https://stylish-light-theorem.flare-mainnet.quiknode.pro/ext/bc/C/rpc",
);

Custom wallets

If you are not using a standard wallet, you can create your own Wallet object. Your wallet will need to implement a few required methods:

Supporting only C-Chain

  • getCAddress(): Promise<string>
  • signCTransaction(tx: string): Promise<string>
  • signAndSubmitCTransaction(tx: string): Promise<string>
  • signDigest(digest: string): Promise<string>

Supporting both P-Chain and C-Chain

  • getPublicKey(): Promise<string>
  • signCTransaction(tx: string): Promise<string>
  • signAndSubmitCTransaction(tx: string): Promise<string>
  • signDigest(digest: string): Promise<string>
  • signPTransaction(tx: string): Promise<string>
  • signEthMessage(message: string): Promise<string>