Frequently Asked Questions

Common questions and answers about the OpenClawWallet SDK.

Registration

Why can I only launch one token per API key?

Each API key is tied to one agent account to prevent spam and ensure quality token launches. This limit:

  • Prevents bot-driven token spam
  • Ensures creators are invested in their token's success
  • Maintains platform quality

If you need to launch multiple tokens, you'll need separate agent accounts.

How do I get a new API key if I lost mine?

Registration is IP-limited. Your options:

  1. Check your code - Search for agent_ in your codebase or environment files
  2. Check registration response - If you try to register again, you'll see your key prefix
  3. Contact support - Email support@loomlay.io with verification of ownership
// Registration attempt shows your existing key prefix
const result = await OpenClawWallet.register();
if (!result.success) {
  console.log('Already registered. Key prefix:', result.keyPrefix);
  // Use this to help identify your key
}

Can I have multiple API keys?

Yes, you can create additional keys for your existing account:

// Create new key
const newKey = await wallet.auth.createKey();
 
// List all keys
const keys = await wallet.auth.listKeys();
 
// Revoke if needed
await wallet.auth.revokeKey({ keyId: 'key_id' });

Trading

Why is my swap failing?

Common causes:

Insufficient balance

import { InsufficientFundsError } from '@loomlay/openclaw-wallet-sdk';
 
try {
  await wallet.trading.swap({ ... });
} catch (error) {
  if (error instanceof InsufficientFundsError) {
    console.log('Required:', error.required);
    console.log('Available:', error.available);
  }
}

Slippage too low

// Try higher slippage for volatile tokens
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'MEMECOIN',
  amount: '1',
  slippage: 3, // 3% instead of default 0.5%
});

Token not found

// Ensure token exists and use correct symbol or address
await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC address
  amount: '1',
});

Liquidity issues

// Check price impact first
const quote = await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'LOW_LIQ_TOKEN',
  amount: '100',
  quoteOnly: true,
});
 
if (quote.priceImpact > 5) {
  console.warn('High price impact - consider smaller amount');
}

Why is my bridge taking so long?

Bridge times vary by network congestion:

RouteTypical Time
Ethereum to Base1-5 minutes
Ethereum to Arbitrum1-5 minutes
Base to Ethereum5-15 minutes
Arbitrum to Ethereum5-15 minutes

The SDK returns estimated time:

const result = await wallet.trading.bridge({ ... });
console.log('Estimated time:', result.estimatedTime);

What chains are supported for bridges?

EVM chains only. Solana bridges are not yet supported.

FromToSupported
EthereumBase, ArbitrumYes
BaseEthereum, ArbitrumYes
ArbitrumEthereum, BaseYes
SolanaAnyNo
AnySolanaNo

Wallet

How do I check my wallet balance?

Two options depending on what you need:

// Option 1: Basic wallet info
const info = await wallet.wallet.get();
console.log('SOL:', info.balances.solana.native);
console.log('ETH:', info.balances.ethereum.native);
 
// Option 2: Full portfolio with USD values
const portfolio = await wallet.portfolio.get();
console.log('Total value:', portfolio.totalValueUsd);
for (const holding of portfolio.holdings) {
  console.log(`${holding.symbol}: ${holding.balance} ($${holding.valueUsd})`);
}

Can I import an existing wallet?

Yes, in self-custody mode you can import an existing BIP39 seed phrase:

// SDK
const imported = await wallet.wallet.importSeed(
  'your twelve word seed phrase here ...',
  'my-secure-passphrase'
);
// Plugin
const imported = await wallet_import({
  seedPhrase: 'your twelve word seed phrase here ...',
  passphrase: 'my-secure-passphrase'
});

The seed phrase is encrypted locally and public addresses are registered with the API for balance lookups.

Where are my private keys stored?

Private keys are derived from your seed phrase using:

  • Solana: SLIP-0010 derivation (m/44'/501'/0'/0')
  • EVM: BIP32 derivation (m/44'/60'/0'/0/0)

Storage depends on your wallet mode:

ModeWhere Keys LiveEncryption
Self-custody (local)~/.loomlay/wallet.json on your devicePBKDF2-SHA512 + AES-256-GCM
CustodialServer-side (PostgreSQL)AES-256-GCM with server key

In self-custody mode, private keys never leave your device. Only public addresses and signed transactions are sent to the API.

How do I unlock my wallet for signing?

In self-custody mode, you need to provide your passphrase before signing transactions. Three options:

  1. Environment variable (recommended): export LOOMLAY_WALLET_PASSPHRASE=your-passphrase
  2. Plugin tool: Call wallet_unlock({ passphrase: 'your-passphrase' })
  3. SDK callback: Pass getPassphrase when creating the client

Token Launch

Why did my token launch fail?

Common issues:

Insufficient SOL

// Need SOL for: liquidity + transaction fees
// Example: 10 SOL liquidity + ~0.1 SOL fees
const info = await wallet.wallet.get();
console.log('SOL balance:', info.balances.solana.native);

Invalid image

// Image requirements:
// - Valid URL (https://)
// - PNG, JPG, or GIF format
// - Minimum 200x200 pixels
// - Accessible publicly

Symbol already used

// Each symbol must be unique on LoomLay
// Try a different symbol if yours is taken

How do I claim fees from my token?

// Check pending fees
const fees = await wallet.fees.getPending();
console.log('Pending:', fees.pendingAmount, 'SOL');
 
// Claim fees (rate limited to 1 per hour)
if (parseFloat(fees.pendingAmount) > 0) {
  const claim = await wallet.fees.claim();
  console.log('Claimed:', claim.claimedAmount, 'SOL');
}

Fee claims are rate limited to 1 per hour. The platform pays gas, so this prevents abuse.

WebSockets

Why am I getting disconnected?

Common causes:

Inactivity timeout

// Send heartbeats to stay connected
const dexWs = wallet.createDexWebSocket();
 
// SDK handles heartbeats automatically, but you can listen:
dexWs.on('heartbeat', () => {
  console.log('Connection alive');
});

Too many subscriptions

// Maximum 10 subscriptions per connection
// Create multiple connections if needed

Network issues

dexWs.on('disconnect', (reason) => {
  console.log('Disconnected:', reason);
  // SDK auto-reconnects with exponential backoff
});

How do I subscribe to multiple pairs?

const dexWs = wallet.createDexWebSocket();
 
// Subscribe to multiple pairs (max 10)
const pairs = ['SOL/USDC', 'ETH/USDC', 'BONK/SOL'];
 
for (const pair of pairs) {
  dexWs.subscribePair(pair);
}
 
dexWs.on('update', (data) => {
  console.log(`${data.pair}: $${data.price}`);
});

General

Is the SDK browser-compatible?

No. The SDK is designed for server-side use only:

  • API keys should never be exposed to browsers
  • Seed phrases must stay server-side
  • Use a backend API to proxy requests if needed

What's the difference between quote and execute?

// Quote: Get price without executing (no funds needed)
const quote = await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '100',
  quoteOnly: true,  // Just get the price
});
 
// Execute: Actually perform the swap (needs funds)
const result = await wallet.trading.swap({
  inputToken: 'SOL',
  outputToken: 'USDC',
  amount: '100',
  // quoteOnly defaults to false
});

How do I handle errors?

import {
  OpenClawWalletError,
  AuthenticationError,
  RateLimitError,
  InsufficientFundsError,
  ValidationError,
} from '@loomlay/openclaw-wallet-sdk';
 
try {
  await wallet.trading.swap({ ... });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Invalid or revoked API key
  } else if (error instanceof RateLimitError) {
    // Wait and retry
    await sleep(error.retryAfter * 1000);
  } else if (error instanceof InsufficientFundsError) {
    // Not enough balance
  } else if (error instanceof ValidationError) {
    // Invalid parameters
  } else if (error instanceof OpenClawWalletError) {
    // Other SDK error
    console.log('Error code:', error.code);
  } else {
    throw error;
  }
}

See Error Handling for more details.