Skip to content

Signing

The typed-data domain, action hashing, and the exact payload used for exchange requests.

Updated Nov 4, 2026Builders1 min read
On this page

Nexwest uses typed structured data for signatures. The domain separates mainnet from testnet and prevents a signature from being replayed on another chain.

Domain

FieldValue
nameNexwest
version1
chainId7777 (mainnet), 7778 (testnet)
verifyingContract0x0000000000000000000000000000000000000000

Action

The action is serialized with sorted keys and no whitespace, then hashed with keccak256. The signature is over the typed data:

code
domain      = { name, version, chainId, verifyingContract }
types       = { Action: [{ name: "action", type: "string" }] }
message     = { action: canonicalJson(action) }

Use the SDK

The serialization rules are easy to get subtly wrong. The TypeScript, Python, and Rust SDKs implement them and are tested against the exchange on every release.

Example

code
import { signAction } from "@nexwest/sdk";
 
const signature = await signAction({
  action: {
    type: "order",
    orders: [
      {
        asset: 0,
        isBuy: true,
        limitPx: "104000",
        sz: "0.01",
        reduceOnly: false,
        tif: "Gtc",
      },
    ],
    grouping: "na",
  },
  nonce: Date.now(),
  wallet: apiWallet,
});

The result is { r, s, v } where v is 27 or 28.

Phantom agents

Actions signed for a sub-account or vault use a phantom agent address derived from the master and the target. The SDK handles this when you pass vaultAddress. Do not derive the phantom address manually in production.

Verify a signature

code
from nexwest.signing import recover_signer
 
signer = recover_signer(action, nonce, signature)
assert signer == expected_api_wallet

Was this page helpful?