Skip to main content
This walkthrough uses a local private key from an imported mnemonic so every step is reproducible. In production, you’ll keep the same prepare → sign → broadcast shape, but sign with your existing key-management system (KMS, HSM, custodian) instead of the SDK’s private-key helper. See Bring your own signer below.
1

Initialize

import { WalletSuiteSDK } from "@walletsuite/wallet-sdk";

const sdk = new WalletSuiteSDK({
  apiKey: process.env.WALLETSUITE_API_KEY!,
  env: "prod",
});

await sdk.init();
2

Import wallet and get Ethereum account

const mnemonic = process.env.MNEMONIC as string;
if (!mnemonic) throw new Error("MNEMONIC is required");

const wallet = await sdk.importWallet(mnemonic);

// Default account for Ethereum (m/44'/60'/0'/0/0)
const eth = await wallet.deriveEthereum();
console.log("ETH address:", eth.address);
3

Read USDT balance on Ethereum

const usdtContract = "0xdAC17F958D2ee523a2206206994597C13D831ec7";

const before = await sdk.api.getAssetBalances(eth.address, {
  chain: "ethereum",
  fiat: "USD",
  assetIds: [usdtContract],
  includeNative: false,
});

console.log("USDT balance (before):", before.data);
Response fields
  • amount is human-readable (decimals applied)
  • smallestUnit is the raw token integer balance
4

Prepare USDT transfer (fees, nonce, calldata, simulation)

This stage produces a signing payload that your UI can display and confirm.Server side actions
  • Resolve nonce if not provided
  • Build ERC20 calldata
  • Select fee mode (EIP1559 by default, legacy fallback when required)
  • Run a simulation check
Client side actions
  • Display fee information to the user
  • If user confirms, sign the payload locally using the SDK signer
const to = process.env.TO as string;
if (!to) throw new Error("TO is required");

// Send 1 USDT
const amountSmallest = "1000000"; // 1 * 10^6

const prepared = await sdk.api.prepareTransferSign({
  chain: "ethereum",
  txType: "TRANSFER_TOKEN",
  from: eth.address,
  to,
  tokenContract: usdtContract,
  amountWei: amountSmallest,

  // Optional fee tuning
  // priorityFeeMultiplier: 1.0,
  // maxPriorityFeePerGasWei: "2000000000",

  // Optional explicit nonce (otherwise backend resolves it)
  // nonce: "12",
});
If the simulation fails, prepareTransferSign throws a structured SDK error with backend code SIMULATION_FAILED.
5

Sign transaction

Signing happens entirely on the client.
  • No network requests are made during signing
  • Private keys are provided by the client application at call time
  • WalletSuite SDK does not persist keys
The SDK’s signEvmTransaction / signTronTransaction helpers accept a raw private key — useful for tests and integration spikes. If your signer lives in a KMS, HSM, or custodian, skip these helpers: pass prepared.data to your signer, take the signed hex back, and continue to the broadcast step. sendSignedTransaction accepts any valid signed hex. See Security Best Practices → Key Management for backend key-storage guidance.
// Sign locally — no network requests, private key never leaves the client
const signedTx = sdk.signEvmTransaction(prepared.data, eth.privateKeyHex);

// 0x-prefixed signed raw transaction
console.log("signedTx:", signedTx.slice(0, 20) + "...");
6

Broadcast signed transaction

const sent = await sdk.api.sendSignedTransaction({
  chain: "ethereum",
  signedTx,
});

console.log("tx hash:", sent.data.hash);
7

Check transaction status

The SDK does not provide any waiting or polling helpers.After broadcasting the transaction, the client application is responsible for deciding when and how to check the status. A common approach is to wait ~10 seconds (Ethereum) or few seconds other chains before the first check and then poll periodically until a terminal state is reached.
// Example: single status check after a delay handled by the client
const status = await sdk.api.getTransactionStatus(sent.data.hash, "ethereum");

console.log("status:", status.status);
console.log("success:", status.success);
console.log("block:", status.blockNumber ?? "-");
8

Read USDT balance again

const after = await sdk.api.getAssetBalances(eth.address, {
  chain: "ethereum",
  fiat: "USD",
  assetIds: [usdtContract],
  includeNative: false,
});

console.log("USDT balance (after):", after.data);
Notes
  • Balance updates depend on chain finality and node/indexer freshness.
  • If you transfer the full balance, account level gas costs are paid in ETH and do not affect USDT amount.
Common failure modes — Simulation failed.
  • Typical causes: insufficient token balance, invalid recipient, token restrictions
  • Expected SDK error: a structured error with backend code SIMULATION_FAILED

Bring your own signer

The prepare-sign → broadcast surface of the SDK is signer-agnostic. prepareTransferSign returns a typed unsigned payload and sendSignedTransaction accepts any valid signed hex — how you sign in between is up to you.

Local private key

For tests, integration spikes, or cases where the private key legitimately belongs in your application’s process. sdk.transfer() handles the whole prepare → sign → broadcast flow in one call:
const result = await sdk.transfer({
  chain: "ethereum",
  from: eth.address,
  to: "0xRecipient",
  amount: "1000000",                                          // smallest unit
  privateKey: eth.privateKeyHex,
  txType: "TRANSFER_TOKEN",                                   // optional, auto-detected from tokenContract
  tokenContract: "0xdAC17F958D2ee523a2206206994597C13D831ec7", // omit for native transfers
  priorityFeeMultiplier: 1.0,                                 // optional, default 1.0
});

console.log("tx hash:", result.hash);
Use the step-by-step flow above when you need to display fee details to the user before signing, or when you want to split preparation and signing across processes.

External signer (KMS, HSM, custodian)

The production pattern, equivalent to External Signing in the architecture model. Prepare with sdk.api.prepareTransferSign, hand the payload to your existing signer, broadcast with sdk.api.sendSignedTransaction. The SDK never sees the key.
// 1. Prepare the unsigned payload with the SDK
const prepared = await sdk.api.prepareTransferSign({
  chain: "ethereum",
  txType: "TRANSFER_TOKEN",
  from: fromAddress,
  to: recipient,
  tokenContract: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
  amountWei: "1000000",
});

// 2. Sign with your own infrastructure — shape varies per signer
const signedTx = await yourSigner.signEvmTransaction(prepared.data);

// 3. Broadcast
const sent = await sdk.api.sendSignedTransaction({
  chain: "ethereum",
  signedTx,
});
See Add Wallet Operations to Your Application for a worked backend-integration example.