Skip to content

Place and cancel orders

After onboarding, the secondary trading EOA signs KuruTradingWallet intents. The relay pays gas and sends the signed action to that delegated EOA.

Shared intent header

Both immediate trading methods use this header:

{
  "accountId": "123",
  "market": "0x2222222222222222222222222222222222222222",
  "authNonce": "1",
  "nonce": "1720000000123",
  "deadline": "1720000030",
  "clientOrderId": "0x0000000000000000000000000000000000000000000000000000000000000001",
  "builder": "0x0000000000000000000000000000000000000000",
  "builderFeePps": "0"
}
Field How to set it
accountId AccountCore account whose balances and positions the trading EOA may use.
market Verified Spot orderbook address.
authNonce Current accountSignerAuthorizationNonces(account), after onboarding.
nonce Strictly increasing uint64 for this secondary EOA's immediate orders. Millisecond timestamps are convenient but not required.
deadline Near-future Unix timestamp in seconds.
clientOrderId Your unique 32-byte correlation value.
builder Zero address when no builder fee is charged.
builderFeePps 0 with the zero builder; otherwise subject to configured policy.

The signing domain is always:

name: KuruTradingWallet
version: 1
chainId: <live chain ID>
verifyingContract: <secondary trading EOA>

Do not use the shared KuruTradingWallet implementation as verifyingContract.

wallet.execute_batch

Use this method for normal integrations. It accepts readable native order objects and can place orders, cancel slots, or do both atomically.

Native order

{
  "side": "BUY",
  "quantity": "1000000",
  "price": "123400",
  "tif": "GTC",
  "executionInstruction": "POST_ONLY",
  "minSizeAfterBlock": "0"
}
  • side: BUY or SELL.
  • tif: GTC, IOC, or FOK.
  • executionInstruction: NONE or POST_ONLY; POST_ONLY requires GTC.
  • quantity and price use the market's contract units, not UI-formatted decimals.
  • minSizeAfterBlock is normally 0; it can protect resting-size assumptions for supported GTC orders.

Place an order

{
  "requestId": "018f5ef2-88a1-7b41-a826-4b679010f87f",
  "method": "wallet.execute_batch",
  "wallet": "0x1111111111111111111111111111111111111111",
  "payload": {
    "header": {
      "accountId": "123",
      "market": "0x2222222222222222222222222222222222222222",
      "authNonce": "1",
      "nonce": "1720000000123",
      "deadline": "1720000030",
      "clientOrderId": "0x0000000000000000000000000000000000000000000000000000000000000001",
      "builder": "0x0000000000000000000000000000000000000000",
      "builderFeePps": "0"
    },
    "orders": [
      {
        "side": "BUY",
        "quantity": "1000000",
        "price": "123400",
        "tif": "GTC",
        "executionInstruction": "POST_ONLY",
        "minSizeAfterBlock": "0"
      }
    ],
    "cancelSlotIdxs": [],
    "expectedOrderIds": [],
    "signature": "0x..."
  },
  "authorization7702": null
}

The EIP-712 BatchIntent signs hashes of orders, cancelSlotIdxs, and expectedOrderIds. These are Solidity ABI hashes—not JSON hashes and not generic EIP-712 array hashing. Use the signing and intent codecs for the exact construction.

Cancel an order slot

Set orders to an empty array and provide parallel cancelSlotIdxs and expectedOrderIds arrays:

{
  "orders": [],
  "cancelSlotIdxs": ["3"],
  "expectedOrderIds": ["31"]
}

Use the current order ID whenever possible. Slot numbers are reused, so binding a cancellation to order 31 prevents it from canceling a newer order that later occupies slot 3.

expectedOrderIds meanings:

Value Meaning
0 The slot must be empty.
Current order ID That exact order must occupy the slot. Recommended for cancellation.
18446744073709551615 Accept any order in the slot. Use only when intentionally accepting the race.

The combined number of orders and cancellations must be nonzero. Cancel slots must be unique.

wallet.execute_replace_by_slot_packed

Use this method when the client already implements Kuru's compact slot operation codec and calldata size matters. Each operation is exactly 32 bytes and targets one maker slot.

{
  "requestId": "018f5ef2-88a1-7b41-a826-4b679010f87f",
  "method": "wallet.execute_replace_by_slot_packed",
  "wallet": "0x1111111111111111111111111111111111111111",
  "payload": {
    "header": {
      "accountId": "123",
      "market": "0x2222222222222222222222222222222222222222",
      "authNonce": "1",
      "nonce": "1720000000124",
      "deadline": "1720000030",
      "clientOrderId": "0x0000000000000000000000000000000000000000000000000000000000000002",
      "builder": "0x0000000000000000000000000000000000000000",
      "builderFeePps": "0"
    },
    "packedOps": "0x...one-or-more-32-byte-words...",
    "expectedOrderIds": ["0"],
    "signature": "0x..."
  },
  "authorization7702": null
}

expectedOrderIds must contain one value for every packed word. Slots must be unique within one request. A strict packed cancellation sets price, size, flags, and minSizeAfterBlock to zero and retains only the slot index.

The EIP-712 ReplaceBySlotIntent signs keccak256(packedOps) and the ABI hash of expectedOrderIds. See orderbook internals for the exact word layout.

Successful execution

For both methods:

  1. the relay returns BROADCAST and a transaction hash;
  2. wait for a successful receipt;
  3. verify IntentExecuted for the expected wallet, account, market, nonce, and client order ID; and
  4. reconcile the resulting orderbook state.

A reverted transaction does not consume the immediate wallet nonce. A successful transaction does. The same immediate nonce sequence is shared by batch and packed methods for that secondary EOA across all accounts and markets.