For the complete documentation index, see llms.txt. This page is also available as Markdown.

Delegate a trading key

This guide shows how a master account authorizes a secondary delegate key with one off-chain signature, and how the delegate then submits orderbook calls on the master's behalf using the delegated envelope. For background on ownership, expiry, and the security model, see Key Delegation; for the envelope's ABI and constraints, see Delegation envelope in the Orderbook precompile reference.

The master signs a single EIP-712 DelegationAuth { delegate, validUntil } message — never a Pod transaction. The resulting 65-byte signature is the delegation certificate: the delegate attaches it to every delegated transaction and it stays valid until validUntil. A delegated intent is accepted only while validUntil >= deadline of the wrapped intent (both in microseconds).

Steps

  1. The master signs the DelegationAuth typed-data message authorizing the delegate (once, off-chain).

  2. The delegate ABI-encodes the orderbook call it wants to perform, wraps it in delegated(master, validUntil, signature, inner), and signs the transaction with its own key.

The example authorizes a fresh delegate key for one week, then has the delegate place a 5 NVDA long at $140 owned by the master. The order rests under the master and draws on the master's orderbook balance; the master can cancel it directly with its own key at any time. Delegated calls are gas-exempt, so the delegate key needs no funds.

import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const master = new ethers.Wallet(MASTER_PRIVATE_KEY);
const delegate = new ethers.Wallet(DELEGATE_PRIVATE_KEY, provider); // fresh app-generated key
const { chainId } = await provider.getNetwork();

const now = BigInt(Date.now()) * 1000n; // microseconds

// 1. Master signs the delegation certificate (once, off-chain) — valid for one week.
const validUntil = now + 7n * 24n * 3600n * 1_000_000n;
const signature = await master.signTypedData(
  { name: "pod delegation", version: "1", chainId },
  {
    DelegationAuth: [
      { name: "delegate", type: "address" },
      { name: "validUntil", type: "uint64" },
    ],
  },
  { delegate: delegate.address, validUntil },
);

// 2. Delegate wraps an order in delegated(...) and submits it with its own key.
const ORDERBOOK = "0x50d0000000000000000000000000000000000002";
const abi = [
  "function submitOrder(bytes32 orderbookId, int256 size, uint256 price, uint8 orderType, uint128 deadline, uint128 ttl, bool reduceOnly, bool ioc)",
  "function delegated(address master, uint64 validUntil, bytes signature, bytes inner)",
];
const orderbook = new ethers.Contract(ORDERBOOK, abi, delegate);

const nvdaPerpId = "0x0000000000000000000000000000000000000000000000000000000000000007"; // NVDA-USD perp
const deadline = now + 10_000_000n; // must be <= validUntil
const ttl = 60n * 1_000_000n;

// 5 NVDA long at $140 limit, owned by the master
const inner = orderbook.interface.encodeFunctionData("submitOrder", [
  nvdaPerpId, ethers.parseEther("5"), ethers.parseEther("140"),
  0 /* Limit */, deadline, ttl, false, false,
]);

const tx = await orderbook.delegated(master.address, validUntil, signature, inner);
console.log("Delegated order tx:", tx.hash);

Notes

  • Reuse the certificate. Step 1 runs once; the delegate reuses the same signature and validUntil on every delegated call until expiry. Any single-intent call (submitOrder, cancel, update, triggers, deposit, withdraw) or a whole submitBatch can be wrapped the same way — see What can be delegated.

  • Deadlines. The usual orderbook rules apply to the inner call unchanged (microsecond timestamps, deadline aligned to the market's auction_interval — see the Orderbook precompile reference), plus one more: the certificate must satisfy validUntil >= deadline.

  • Funds stay with the master. A delegated deposit or withdraw has its recipient overridden to the master, so the delegate can never direct funds elsewhere.

  • Rotation. There is no on-chain revocation — to replace a delegate, stop using the old key and sign a new DelegationAuth for a new one. Keep validUntil short.

Last updated