Skip to content

Client

The KaizenClient is the main entry point for interacting with Kaizen Core.

Creating a Client

import { createClient, KaizenClient } from "@kaizen-core/sdk";
 
const client = createClient({
  rpcUrl: "http://localhost:8546", // Required: JSON-RPC endpoint
  wsUrl: "ws://localhost:8546/ws", // Optional: WebSocket endpoint
  chainId: 1, // Optional: Chain ID (default: 1)
});

:::tip Unified Proxy Endpoint When using Docker Compose, connect to the proxy at localhost:8546 for both RPC and WebSocket. The proxy automatically routes:

  • Writes (sendTransaction) → write-node
  • Reads (getAccount, simulateTransaction, etc.) → read-node-aggressive
  • WebSocket subscriptions → read-node-aggressive :::

Signer Management

Connecting as Owner

When you connect directly with your own private key, sender and signer are the same:

// Connect as owner (sender == signer)
client.connectSigner(
  "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
);
 
// Check connection
if (client.hasSigner) {
  console.log(`Connected as: ${client.signerAddress}`);
  console.log(`Account: ${client.accountAddress}`); // Same as signerAddress
}

Connecting as API Wallet

When acting on behalf of an owner via an API wallet, the signer (API wallet) differs from the effective account (owner):

Important: API wallets have restricted permissions. They can only perform trading operations (RFQ submit/settle) and API wallet management. Transfer and Withdraw operations are not allowed for API wallets - these must be performed by the owner directly.

// Connect as API wallet acting on behalf of owner
client.connectAsApiWallet(
  "0x...", // API wallet private key
  "0xOwnerAddress..." // Owner address
);
 
// Check addresses
console.log(`Signer: ${client.signerAddress}`);   // API wallet address
console.log(`Account: ${client.accountAddress}`); // Owner address
console.log(`Is API Wallet: ${client.isApiWallet}`); // true
 
// All "getMy..." methods now return owner's data
const balance = await client.getMyBalance(); // Owner's balance
const theses = await client.getMyTheses();   // Owner's theses
 
// ⚠️ API wallets cannot transfer or withdraw
// await client.transfer(...);  // Will fail!
// await client.withdraw(...);  // Will fail!
 
// ✅ API wallets can perform trading operations
await client.submitRfq(...);  // OK
await client.settleRfq(...);  // OK

Disconnecting

client.disconnectSigner();

Account Methods

Get Account Information

// Get any account
const account = await client.getAccount("0x...");
console.log({
  address: account.address,
  balance: account.balance,
  apiWallets: account.apiWallets,
});
 
// Get connected signer's account
const myAccount = await client.getMyAccount();

Get Balance

import { formatUSDC } from "@kaizen-core/sdk";
 
const balance = await client.getBalance("0x...");
console.log(`Balance: ${formatUSDC(balance.balance)} USDC`);
 
// Or get your balance
const myBalance = await client.getMyBalance();

Thesis Methods

Get Thesis by ID

const thesis = await client.getThesis(1n);
if (thesis) {
  console.log({
    id: thesis.id,
    user: thesis.user,
    solver: thesis.solver,
    status: thesis.status,
    betAmount: thesis.betAmount,
    payout: thesis.payout,
  });
}

Get Theses by User

// Get all theses for a user
const theses = await client.getThesesByUser(
  "0x...",
  100, // limit
  0 // offset
);
 
// Get my theses (requires connected signer)
const myTheses = await client.getMyTheses();

Get Theses by Solver

const solverTheses = await client.getThesesBySolver("0x...");

Oracle Methods

Get Current Price

const BTC_ADDRESS = "0x0000000000000000000000000000000000000001";
const USDC_ADDRESS = "0x0000000000000000000000000000000000000002";
 
const price = await client.getOraclePrice(BTC_ADDRESS, USDC_ADDRESS);
console.log({
  price: price.price,
  timestamp: new Date(price.timestamp),
});

Get Price History

const history = await client.getOraclePriceHistory(
  BTC_ADDRESS,
  USDC_ADDRESS,
  Date.now() - 3600000, // from: 1 hour ago
  Date.now(), // to: now
  100 // limit
);
 
for (const point of history.prices) {
  console.log(`${new Date(point.timestamp)}: ${point.price}`);
}

Block Methods

Get Block by Height

const block = await client.getBlock(100n);
if (block) {
  console.log({
    height: block.height,
    timestamp: block.timestamp,
    stateRoot: block.stateRoot,
    txCount: block.txCount,
  });
}

Get Current Block Height

const height = await client.getBlockHeight();
console.log(`Current height: ${height}`);

Get State Root

const stateRoot = await client.getStateRoot();
console.log(`State root: ${stateRoot}`);

Transaction Methods

Sign and Send Transaction

import { transfer, parseUSDC } from "@kaizen-core/sdk";
 
// Create payload and send in one call
const receipt = await client.sendTransaction(
  transfer("0x...", parseUSDC("100.00")),
  {
    waitForConfirmation: true, // Wait for confirmation
    confirmationTimeout: 30000, // Timeout in ms
  }
);
 
console.log(`Transaction ${receipt.hash}: ${receipt.status}`);

Manual Sign and Send

// Step 1: Sign transaction (timestamp is used for replay protection)
const signedTx = await client.signTransaction(
  transfer("0x...", parseUSDC("100.00")),
  { timestamp: BigInt(Date.now()) } // Optional: auto-set if not provided
);
 
// Step 2: Send signed transaction
const receipt = await client.sendSignedTransaction(signedTx, {
  waitForConfirmation: true,
});

Simulate Transaction

const simulation = await client.simulateTransaction(
  transfer("0x...", parseUSDC("100.00"))
);
 
if (simulation.success) {
  console.log(`Gas used: ${simulation.gasUsed}`);
} else {
  console.log(`Would fail: ${simulation.error}`);
}

Get Transaction Status

const receipt = await client.getTransactionStatus("0x...");
if (receipt) {
  console.log(`Status: ${receipt.status}`);
  // "pending" | "confirmed" | "failed"
}

Wait for Confirmation

try {
  const receipt = await client.waitForConfirmation(
    "0x...", // transaction hash
    30000 // timeout in ms
  );
  console.log("Transaction confirmed!");
} catch (error) {
  console.log("Transaction failed or timed out");
}

High-Level Transaction APIs

The client provides convenient methods for common operations. These methods automatically handle payload creation, signing, and sending.

Transfer

// Simple transfer
const receipt = await client.transfer(
  "0xRecipient...",
  parseUSDC("100.00"),
  { waitForConfirmation: true }
);

Withdraw

// Withdraw to external chain
const receipt = await client.withdraw(
  parseUSDC("500.00"),
  "0xExternalAddress...",
  84532, // Base Sepolia chain ID
  { waitForConfirmation: true }
);

Nominate API Wallet

// Authorize an API wallet for 24 hours
const receipt = await client.nominateApiWallet(
  "0xApiWallet...",
  Date.now() + 86400000, // 24 hours, 0 = no expiry
  { waitForConfirmation: true }
);

Revoke API Wallet

// Remove API wallet authorization
const receipt = await client.revokeApiWallet(
  "0xApiWallet...",
  { waitForConfirmation: true }
);

Submit RFQ

The submitRfq method handles quote signing automatically:

// Get quote from solver
const quote = await client.requestQuote(solverUrl, { ... });
 
// Submit - quote signing is handled automatically
const receipt = await client.submitRfq(quote, {
  waitForConfirmation: true
});

Settle RFQ

// Settle a thesis (usually done by Settler service)
const receipt = await client.settleRfq(
  1n, // thesisId
  { waitForConfirmation: true }
);

:::tip High-Level vs Low-Level Use high-level methods for simplicity. Use sendTransaction() with payload builders when you need more control (e.g., custom timestamps). :::

Solver API Helper

Request Quote from Solver

const quote = await client.requestQuote(
  "http://localhost:4000", // Solver API URL
  {
    user: client.signerAddress!,
    thesisType: "box",
    base: BTC_ADDRESS,
    quote: USDC_ADDRESS,
    lowerPrice: parsePrice("94000.00"),
    upperPrice: parsePrice("96000.00"),
    betAmount: parseUSDC("100.00"),
    startTime: Date.now() + 5000,
    endTime: Date.now() + 65000,
    deadline: Date.now() + 30000,
  }
);
 
console.log(`Quote payout: ${formatUSDC(quote.payout)}`);

Sign Quote for Execution

Sign the solver quote hash to authorize an RFQ thesis. This signature is required for POST /execute on the solver API.

// Get quote from solver
const quote = await client.requestQuote("http://localhost:4000", { ... });
 
// Sign the quote hash (user authorizing the thesis)
const userSignature = await client.signQuote(quote);
 
// Execute via solver
const response = await fetch("http://localhost:4000/execute", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    quote: {
      user: quote.user,
      orderType: quote.orderType,
      oraclePair: quote.oraclePair,
      priceRange: {
        lower: quote.priceRange.lower.toString(),
        upper: quote.priceRange.upper.toString(),
      },
      betAmount: quote.betAmount.toString(),
      payout: quote.payout.toString(),
      startTime: quote.startTime,
      endTime: quote.endTime,
      deadline: quote.deadline,
      signature: quote.signature,
    },
    userSignature,
  }),
});
 
const result = await response.json();
console.log(`Tx Hash: ${result.result.txHash}`);

Note: The quote hash is computed as keccak256(borsh_serialize(solverQuote)), matching the Rust implementation.

Error Handling

import { RpcError } from "@kaizen-core/sdk";
 
try {
  await client.sendTransaction(transfer("0x...", parseUSDC("100.00")));
} catch (error) {
  if (error instanceof RpcError) {
    console.log(`RPC Error ${error.code}: ${error.message}`);
    console.log(`Data: ${error.data}`);
  } else {
    throw error;
  }
}

Full Example

import { createClient, parseUSDC, formatUSDC } from "@kaizen-core/sdk";
 
async function main() {
  // Setup
  const client = createClient({ rpcUrl: "http://localhost:8546" });
  client.connectSigner("0x...");
 
  // Check balance
  const balance = await client.getMyBalance();
  console.log(`Balance: ${formatUSDC(balance.balance)} USDC`);
 
  // Transfer funds (high-level API)
  await client.transfer("0xRecipient...", parseUSDC("50.00"), {
    waitForConfirmation: true,
  });
 
  // Nominate API wallet for trading
  // API wallets can do everything EXCEPT withdraw and transfer
  await client.nominateApiWallet(
    "0xApiWallet...",
    Date.now() + 86400000, // 24 hours, 0 = no expiry
    { waitForConfirmation: true }
  );
 
  // Withdraw to external address
  await client.withdraw(
    parseUSDC("25.00"),
    "0xExternalAddress...",
    84532, // Base Sepolia
    { waitForConfirmation: true }
  );
}
 
main();