Skip to main content

Overview

The LFG SDK uses a wallet and subaccount system to manage trading accounts. Understanding this architecture is crucial for building trading applications.

Wallet

Your main account identified by an address (e.g., lfg1abc...). Controls access and signs transactions.

Subaccount

Trading accounts under a wallet. Each subaccount has isolated collateral and positions.

Wallet Management

LocalWallet Class

LocalWallet handles cryptographic key management and transaction signing:
import { LocalWallet } from "@oraichain/lfg-client-js";

Creating a Wallet from Mnemonic

The recommended approach for production applications:
const wallet = await LocalWallet.fromMnemonic(
  "your twelve word mnemonic phrase goes here",
  "lfg" // Address prefix
);

console.log("Address:", wallet.address);
console.log("Public Key:", wallet.pubKey?.value);
mnemonic
string
required
A 12 or 24-word BIP39 mnemonic phrase
prefix
string
required
Address prefix. Use "lfg" for LFG DEX networks
Store mnemonics securely in environment variables or secret management systems. Never hardcode them in your source code.

Creating a Wallet from Private Key

Useful for API keys and programmatic access:
const wallet = await LocalWallet.fromPrivateKey(
  "0xYourPrivateKeyHexString",
  "lfg"
);

console.log("Address:", wallet.address);
privateKey
string
required
Private key as hex string (with or without 0x prefix)
prefix
string
required
Address prefix ("lfg" for LFG DEX)
Private keys grant full control over the account. Protect them with the same security as mnemonics.

Generating a New Wallet

Generate a new random wallet:
// Note: The SDK doesn't expose a generate method directly
// You'll typically use external libraries for key generation
import { generateMnemonic } from "bip39";

const mnemonic = generateMnemonic();
const wallet = await LocalWallet.fromMnemonic(mnemonic, "lfg");

console.log("🔐 Save this mnemonic securely:");
console.log(mnemonic);
console.log("\nNew address:", wallet.address);
You’ll need to install bip39 separately: npm install bip39

Subaccount System

What are Subaccounts?

Subaccounts allow you to:
  • Isolate risk by separating different trading strategies
  • Manage multiple positions independently
  • Organize trading activities across different markets
Each subaccount has:
  • Unique subaccount number (0-127)
  • Isolated collateral balance
  • Independent positions and orders

SubaccountInfo Class

SubaccountInfo represents a trading subaccount:
import { SubaccountInfo } from "@oraichain/lfg-client-js";

Creating a Subaccount for Local Wallet

For standard wallet-based trading:
import { LocalWallet, SubaccountInfo } from "@oraichain/lfg-client-js";

const wallet = await LocalWallet.fromMnemonic(mnemonic, "lfg");

// Create subaccount 0 (default)
const subaccount0 = SubaccountInfo.forLocalWallet(wallet, 0);

// Create additional subaccounts
const subaccount1 = SubaccountInfo.forLocalWallet(wallet, 1);
const subaccount2 = SubaccountInfo.forLocalWallet(wallet, 2);

console.log("Subaccount 0:", subaccount0.address, subaccount0.subaccountNumber);
console.log("Subaccount 1:", subaccount1.address, subaccount1.subaccountNumber);
wallet
LocalWallet
required
The LocalWallet instance that controls this subaccount
subaccountNumber
number
required
Subaccount index (0-127). Use 0 for your primary trading account.

Creating a Subaccount with API Key (Permissioned)

For API key-based trading where an API key controls operations on behalf of a main wallet:
import { LocalWallet, SubaccountInfo } from "@oraichain/lfg-client-js";

// API key wallet (signs transactions)
const apiKeyWallet = await LocalWallet.fromPrivateKey(
  process.env.API_KEY_PRIVATE_KEY!,
  "lfg"
);

// Main wallet address (owns the funds)
const mainWalletAddress = "lfg1mainwalletaddress...";

// Authenticator IDs that grant API key permission
const authenticatorIds = [1]; // From getAuthenticators()

// Create permissioned subaccount
const subaccount = SubaccountInfo.forPermissionedWallet(
  apiKeyWallet, // API key signs
  mainWalletAddress, // Main wallet owns funds
  0, // Subaccount number
  authenticatorIds // Permission authenticators
);
wallet
LocalWallet
required
The API key wallet that signs transactions
address
string
required
The main wallet address that owns the subaccount
subaccountNumber
number
required
Subaccount index (0-127)
authenticatorIds
number[]
required
Array of authenticator IDs granting permission to the API key
See the API Key Trading Example below for complete setup.

Querying Subaccount Information

Get Subaccount Balance

const account = await client.indexerClient.account.getParentSubaccount(
  wallet.address,
  0 // parent subaccount number
);

// Access subaccount balances
for (const subaccount of account.subaccount.childSubaccounts) {
  console.log(`Subaccount ${subaccount.subaccountNumber}:`);
  console.log(`  Total Equity: $${subaccount.equity}`);
  console.log(`  Free Collateral: $${subaccount.freeCollateral}`);
  console.log(`  Margin Usage: $${subaccount.marginUsage}`);
}

Get Subaccount Positions

const account = await client.indexerClient.account.getParentSubaccount(
  wallet.address,
  0
);

for (const subaccount of account.subaccount.childSubaccounts) {
  const positions = subaccount.openPerpetualPositions;

  for (const [market, position] of Object.entries(positions)) {
    console.log(`${market}:`);
    console.log(`  Side: ${position.side}`);
    console.log(`  Size: ${position.size}`);
    console.log(`  Entry Price: $${position.entryPrice}`);
    console.log(`  Unrealized PnL: $${position.unrealizedPnl}`);
  }
}

API Key Trading Example

Complete example of API key-based trading:
import {
  CompositeClient,
  LocalWallet,
  SubaccountInfo,
  Network,
  OrderSide,
  Order_TimeInForce,
} from "@oraichain/lfg-client-js";

async function apiKeyTrading() {
  // 1. Create API key wallet
  const apiKeyWallet = await LocalWallet.fromPrivateKey(
    process.env.API_KEY_PRIVATE_KEY!,
    "lfg"
  );

  const mainWalletAddress = process.env.MAIN_WALLET_ADDRESS!;

  // 2. Connect to network
  const network = Network.staging();
  const client = await CompositeClient.connect(network);

  // 3. Get authenticators for main wallet
  const auths = await client.getAuthenticators(mainWalletAddress);
  const authenticatorId = auths.accountAuthenticators[0].id;

  console.log(`Found authenticator ID: ${authenticatorId}`);

  // 4. Create permissioned subaccount
  const subaccount = SubaccountInfo.forPermissionedWallet(
    apiKeyWallet,
    mainWalletAddress,
    0,
    [authenticatorId]
  );

  // 5. Place order using API key
  const currentBlock = await client.validatorClient.get.latestBlockHeight();
  const goodTilBlock = currentBlock + 20;
  const clientId = Math.floor(Math.random() * 100000000);

  const tx = await client.placeShortTermOrder(
    subaccount,
    "ETH-USD",
    OrderSide.BUY,
    3800,
    0.01,
    clientId,
    goodTilBlock,
    Order_TimeInForce.TIME_IN_FORCE_UNSPECIFIED,
    false
  );

  console.log("✅ Order placed via API key!");
  console.log("TX Hash:", Buffer.from(tx.hash).toString("hex"));
}
API keys must be registered with the main wallet’s authenticators before they can trade. This is typically done through the web interface.

Security Best Practices

Never expose private keys or mnemonics in:
  • Source code
  • Version control
  • Log files
  • Error messages
  • Client-side code
Use instead:
  • Environment variables
  • Secret management services (AWS Secrets Manager, HashiCorp Vault)
  • Hardware security modules (HSM) for production
Create different API keys for different purposes:
  • Trading Bot: Limited to order placement
  • Withdrawal Key: Separate key for withdrawals
  • Read-Only: For monitoring and analytics
This limits damage if a key is compromised.
Separate trading strategies into different subaccounts:
const conservativeBot = SubaccountInfo.forLocalWallet(wallet, 0);
const aggressiveBot = SubaccountInfo.forLocalWallet(wallet, 1);
const hedging = SubaccountInfo.forLocalWallet(wallet, 2);
If one strategy fails, others remain unaffected.
Regularly rotate API keys and update your applications:
  1. Generate new API key
  2. Add to authenticators
  3. Update application configuration
  4. Remove old API key
  5. Monitor for unauthorized access

Advanced Usage

Multiple Subaccounts Example

Organize trading strategies across subaccounts:
// Define subaccount purposes
enum SubaccountPurpose {
  SPOT_HEDGING = 0,
  MOMENTUM_TRADING = 1,
  MARKET_MAKING = 2,
  ARBITRAGE = 3,
}

class MultiSubaccountManager {
  private wallet: LocalWallet;
  private subaccounts: Map<SubaccountPurpose, SubaccountInfo>;

  constructor(wallet: LocalWallet) {
    this.wallet = wallet;
    this.subaccounts = new Map();

    // Initialize subaccounts
    this.subaccounts.set(
      SubaccountPurpose.SPOT_HEDGING,
      SubaccountInfo.forLocalWallet(wallet, 0)
    );
    this.subaccounts.set(
      SubaccountPurpose.MOMENTUM_TRADING,
      SubaccountInfo.forLocalWallet(wallet, 1)
    );
    this.subaccounts.set(
      SubaccountPurpose.MARKET_MAKING,
      SubaccountInfo.forLocalWallet(wallet, 2)
    );
  }

  getSubaccount(purpose: SubaccountPurpose): SubaccountInfo {
    return this.subaccounts.get(purpose)!;
  }

  async getBalances(client: CompositeClient) {
    const balances = new Map();

    for (const [purpose, subaccount] of this.subaccounts) {
      const account = await client.indexerClient.account.getParentSubaccount(
        this.wallet.address,
        subaccount.subaccountNumber
      );
      balances.set(purpose, account.subaccount);
    }

    return balances;
  }
}

Common Patterns

Singleton Wallet Instance

// wallet-manager.ts
let walletInstance: LocalWallet | null = null;

export async function getWallet(): Promise<LocalWallet> {
  if (!walletInstance) {
    walletInstance = await LocalWallet.fromMnemonic(
      process.env.MNEMONIC!,
      "lfg"
    );
  }
  return walletInstance;
}

Wallet Factory

// wallet-factory.ts
export class WalletFactory {
  static async createFromEnv(): Promise<LocalWallet> {
    if (process.env.MNEMONIC) {
      return await LocalWallet.fromMnemonic(process.env.MNEMONIC, "lfg");
    } else if (process.env.PRIVATE_KEY) {
      return await LocalWallet.fromPrivateKey(process.env.PRIVATE_KEY, "lfg");
    } else {
      throw new Error("No wallet credentials found in environment");
    }
  }
}

Next Steps