Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Proof-labs/trading-sdk/llms.txt

Use this file to discover all available pages before exploring further.

An agent wallet is a second Ed25519 keypair whose public key you register against your owner account. Once approved, the agent can sign and submit PlaceOrder, CancelOrder, CancelAllOrders, and any other trading action on your behalf — but the engine enforces a hard separation: agents can never withdraw funds or move balances. This lets you keep your owner private key cold (or in a hardware store) while running an automated trading bot with a hot key that can only affect open positions and orders.

What agents can and cannot do

CapabilityOwnerAgent
Place / cancel orders
Set leverage overrides
Close positions
Submit WithdrawRequest❌ error code 20
Submit Deposit / Withdraw (relayer)❌ error code 20
Approve or revoke other agents❌ error code 19
Error code 19 (AgentNotAuthorized) is returned when the envelope signer is neither the account owner nor an approved agent for that owner. Error code 20 (AgentCannotWithdraw) is returned when an approved agent attempts any withdrawal action.

Action types

Both ApproveAgent and RevokeAgent are signed by the owner key and carry the agent’s 32-byte Ed25519 public key:
// From src/types.ts

/** Approve a delegate keypair ("agent wallet") to trade on the owner's behalf. */
export interface ApproveAgent {
  /** Account address granting the delegation (20 bytes). */
  owner: Address;
  /** Ed25519 public key of the agent wallet (32 bytes). */
  agentPubkey: Uint8Array; // 32 bytes
}

/** Revoke a previously approved agent wallet. */
export interface RevokeAgent {
  /** Account address revoking the delegation (20 bytes). */
  owner: Address;
  /** Ed25519 public key of the agent wallet to revoke (32 bytes). */
  agentPubkey: Uint8Array; // 32 bytes
}

Events

The engine emits these events on successful approval and revocation:
// From src/types.ts

/** Emitted when an agent wallet is approved for delegation. */
export interface AgentApprovedEvent {
  type: "AgentApproved";
  /** Hex-encoded owner address. */
  owner: string;
  /** Hex-encoded agent address (derived from agentPubkey via keccak256(pubkey)[12..32]). */
  agent: string;
  /** Hex-encoded Ed25519 public key of the agent (32 bytes). */
  agentPubkey: string;
}

/** Emitted when an agent wallet delegation is revoked. */
export interface AgentRevokedEvent {
  type: "AgentRevoked";
  /** Hex-encoded owner address. */
  owner: string;
  /** Hex-encoded agent address. */
  agent: string;
  /** Hex-encoded Ed25519 public key of the agent (32 bytes). */
  agentPubkey: string;
}
The agent field in both events is the 20-byte address derived from the agent’s public key using keccak256(pubkey)[12..32] — the same derivation as pubkeyToOwner() in src/crypto.ts.

Full workflow

Step 1 — Generate an agent keypair

import {
  generateKeypair,
  pubkeyToOwner,
  ownerToHex,
} from "@proof/trading-sdk";

const agentKeypair = generateKeypair();
// agentKeypair.privateKey → Uint8Array (32 bytes) — store securely in your bot
// agentKeypair.publicKey  → Uint8Array (32 bytes) — safe to share publicly

Step 2 — Submit ApproveAgent from the owner’s key

import { ExchangeClient } from "@proof/trading-sdk";

// Owner client — signed with the cold owner key
const ownerClient = new ExchangeClient({ chainId: "exchange-devnet-1" });
ownerClient.setPrivateKey(ownerPrivateKey);

const ownerAddress = ownerClient.getAddress(); // Uint8Array (20 bytes)

const approveResult = await ownerClient.submitTx({
  type: "ApproveAgent",
  data: {
    owner: ownerAddress,
    agentPubkey: agentKeypair.publicKey, // 32 bytes
  },
});

if (approveResult.code !== 0) {
  throw new Error(`ApproveAgent failed: code=${approveResult.code} log=${approveResult.log}`);
}
// Engine emits AgentApprovedEvent — the agent is now authorized

Step 3 — Trade with the agent key

Create a separate client loaded with the agent’s private key. Trading actions must specify the owner’s address in the owner field — the agent signs the envelope, but the action targets the owner’s account.
// Agent client — signed with the hot agent key
const agentClient = new ExchangeClient({ chainId: "exchange-devnet-1" });
agentClient.setPrivateKey(agentKeypair.privateKey);

// The action's `owner` field must be the OWNER's address, not the agent's
const orderResult = await agentClient.submitTx({
  type: "PlaceOrder",
  data: {
    market: 1,
    owner: ownerAddress,   // ← owner's address
    side: Side.Buy,
    price: 50000000n,       // $500,000.00 in cents
    quantity: 1n,
  },
});

if (orderResult.code !== 0) {
  throw new Error(`PlaceOrder failed: code=${orderResult.code} log=${orderResult.log}`);
}
The agent signs the transaction envelope (the outer MessagePack wrapper with the public key and Ed25519 signature), but every action’s owner field must carry the owner’s 20-byte address. The engine uses the envelope signer’s derived address to look up the agent authorization list for that owner; if the signer is not on that list, it returns error code 19.

Step 4 — Revoke the agent when done

// Back to the owner client — only the owner can revoke
const revokeResult = await ownerClient.submitTx({
  type: "RevokeAgent",
  data: {
    owner: ownerAddress,
    agentPubkey: agentKeypair.publicKey, // same public key used in ApproveAgent
  },
});

if (revokeResult.code !== 0) {
  throw new Error(`RevokeAgent failed: code=${revokeResult.code} log=${revokeResult.log}`);
}
// Engine emits AgentRevokedEvent — the agent can no longer submit actions

Listening for agent events

You can confirm delegation status by subscribing to block events:
const unsub = ownerClient.subscribeBlocks((event) => {
  if (event.type === "AgentApproved") {
    console.log("Agent authorized:", event.agent, "for owner:", event.owner);
  }
  if (event.type === "AgentRevoked") {
    console.log("Agent revoked:", event.agent);
    unsub();
  }
});

Error reference

CodeNameWhen it occurs
19AgentNotAuthorizedEnvelope signer is not the owner and not an approved agent for the owner field in the action
20AgentCannotWithdrawAn approved agent attempts WithdrawRequest, Withdraw, or any other fund-movement action
17InvalidSignatureThe envelope Ed25519 signature does not verify against the embedded public key

Build docs developers (and LLMs) love