> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kairos.trade/llms.txt
> Use this file to discover all available pages before exploring further.

# What the wallet signs

> Every signature and transaction the wallet API asks for, per venue: the method, the chain, the typed data, and what to check before you show it.

Every step the wallet API returns carries an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) `request`. You pass it to the wallet as-is. This page lists every request the API can produce, so a wallet can show it clearly and check it before the user approves.

## The four methods

| `request.method` | `params` | Answer with |
| - | - | - |
| `eth_signTypedData_v4` | `[address, typedDataJson]`. The typed data is a **JSON string**, not an object | `{ "signature": "0x…" }` |
| `personal_sign` | `["0x" + hex(utf-8 message), address]` | `{ "signature": "0x…" }` |
| `wallet_sendCalls` | `[{ version: "2.0.0", chainId, from, atomicRequired: false, calls: [{ to, data, value: "0x0" }] }]` ([EIP-5792](https://eips.ethereum.org/EIPS/eip-5792)) | `{ "result": <what the wallet returned> }` |
| `eth_sendTransaction` | `[{ from, to, data, value: "0x0" }]`. Appears only in `fallbackRequests` and Predict.fun fee settlements (which also carry `chainId`) | `{ "result": ["0xhash", …] }` |

Rules for signatures:

* **Exactly 65 bytes** (`r ‖ s ‖ v`), hex with `0x`. Smart-account (ERC-1271) and longer signatures are refused: sign with the wallet's own key.
* **Switch the wallet to the action's `chainId` first** when it is set. `personal_sign` steps have `chainId: null`.
* **Sign before `expiresAtMs`** when the action has it. A later signature fails the action with `SIGNATURE_EXPIRED`; start a new one.
* A signature from another address answers `400 signature is not from this wallet`. The step stays open so the user can try again.

> [!TIP]
>
> Use a library's typed-data signer by parsing `params[1]` with `JSON.parse`. Some libraries (ethers) want `EIP712Domain` removed from `types` first. viem and eth-account accept it as is.

## Before you show a request

A malicious or buggy server could ask for the wrong thing. Before the wallet prompts, check:

1. `params[0]` (or `from`) is the connected address.
2. The typed data's `domain.chainId` matches the action's `chainId`, and both are a chain you expect for its `venue` ([table](#chains)).
3. `domain.name` and `primaryType` are one of the pairs on this page.
4. For orders, the message's price, size and side match what the user asked for. On Polymarket and Predict.fun the price is `makerAmount / takerAmount` (or the inverse for a sell). On Hyperliquid and cancels the terms are plain fields.
5. For transactions (only Predict.fun approvals), every call is an `approve` or `setApprovalForAll` on BNB Chain USDT or one of Predict.fun's outcome-token contracts, and every `value` is `0x0`.

## Chains

| `chainId` | Chain | Used for |
| - | - | - |
| `0x89` | Polygon | Polymarket setup and orders. **Every cancel, on any venue** |
| `0x38` | BNB Chain | Predict.fun approvals and orders |
| `0xa4b1` | Arbitrum One | Hyperliquid approvals, transfers and orders (Hyperliquid signs on Arbitrum's chain id; nothing is sent to Arbitrum) |
| `0x66eee` | Arbitrum Sepolia | Hyperliquid testnet (`hyperliquidChain: "Testnet"`) |

If the wallet doesn't know a chain, add it with `wallet_addEthereumChain` and switch again. The SDK does this for you.

## Polymarket

Nothing here costs gas.

> [accordion] Setup 1: connect to Polymarket
>
> * `eth_signTypedData_v4`, chain `0x89`
> * Domain `{ name: "ClobAuthDomain", version: "1", chainId: 137 }`, no verifying contract
> * `primaryType: "ClobAuth"` with `address`, `timestamp` (unix seconds, as a string), `nonce`, and `message: "This message attests that I control the given wallet"`
> * Shown as *Connect this wallet to Polymarket (no gas)*

> [accordion] Setup 2: approve the trading wallet
>
> Asked only when the trading wallet isn't approved yet.
>
> * `eth_signTypedData_v4`, chain `0x89`
> * Domain `{ name: "DepositWallet", version: "1", chainId: 137, verifyingContract: <trading wallet> }`
> * `primaryType: "Batch"`: `Batch(address wallet, uint256 nonce, uint256 deadline, Call[] calls)` with `Call(address target, uint256 value, bytes data)`
> * The calls approve Polymarket's contracts to use the trading wallet's pUSD and outcome tokens. `deadline` is 10 minutes out
> * Shown as *Approve your trading wallet (no gas)*
>
> The trading wallet is a smart wallet owned by the user's address and controlled only by the user's key.
>
> The batch holds only the approvals the wallet is missing. Every pUSD `approve` is unlimited. Each operator grant is `setApprovalForAll(…, true)`.
>
> | Call | Spender or operator | What it is for |
> | - | - | - |
> | pUSD `approve` | CTF Exchange `0xE111180000d2663C0091e4f400237545B87B996B` | Buying on standard markets |
> | pUSD `approve` | Neg Risk CTF Exchange `0xe2222d279d744050d28e00520010520000310F59` | Buying on neg-risk markets |
> | pUSD `approve` | Neg Risk Collateral Adapter `0xadA2005600Dec949baf300f4C6120000bDB6eAab` | Neg-risk markets, including split and merge |
> | pUSD `approve` | Neg Risk Adapter (CLOB v1) `0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296` | Polymarket's order book still checks this allowance before matching a neg-risk order |
> | Outcome tokens `setApprovalForAll` | The same four contracts | Selling, and the adapter's split, merge and redeem |
> | Outcome tokens `setApprovalForAll` | Auto Redeemer `0xa1200000d0002264C9a1698e001292D00E1b00af` | Polymarket redeeming resolved winners for the wallet. Only for wallets enrolled in auto-redeem |
> | pUSD `approve` | Exchange V3 `0xe3333700cA9d93003F00f0F71f8515005F6c00Aa` | Buying on Protocol V2 markets, including Combos |
> | Position Manager `setApprovalForAll` | Exchange V3 | Selling on Protocol V2 markets, including cashing out a Combo |
> | pUSD `approve` | Router `0x12121212006e4CD160D18e3f00711DA5c3372600` | **Split** on Protocol V2 markets: the Router takes pUSD and mints one YES and one NO share per unit |
> | Position Manager `setApprovalForAll` | Router | **Merge** and **redeem** on Protocol V2 markets, including redeeming a winning Combo. These move shares, not pUSD |
> | Position Manager `setApprovalForAll` | Auto Redeemer | Auto-redeem for Protocol V2 positions. Only for enrolled wallets |
>
> The Exchange V3, Router and Position Manager rows appear while Kairos has Polymarket Protocol V2 trading on.
>
> Outcome tokens are Polymarket's Conditional Tokens `0x4D97DCd97eC945f40cF65F87097ACe5EA0476045`. Position Manager `0x006F54F7f9A22e0000CC2AB60031000000ae9fEF` holds Protocol V2 shares, Combo shares included. pUSD is `0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB`.
>
> The Router appears twice and only the first approval spends pUSD. If you never split Protocol V2 positions, that allowance is never used. A split or merge through [on-chain intents](https://docs.kairos.trade/wallets/onchain.md) carries its own approval, so it works whether or not this batch granted one.

> [accordion] Order
>
> * `eth_signTypedData_v4`, chain `0x89`
> * An [ERC-7739](https://eips.ethereum.org/EIPS/eip-7739) `TypedDataSign` that wraps the Polymarket order, so the trading wallet can validate it:
>   * Domain: `{ name: "Polymarket CTF Exchange", version: "2" | "3", chainId: 137, verifyingContract: <exchange> }`. Version `3` is for markets on Polymarket's newer exchange
>   * `primaryType: "TypedDataSign"`, message `{ contents: <Order>, name: "DepositWallet", version: "1", chainId: 137, verifyingContract: <trading wallet>, salt }`
>   * `Order` carries `salt, maker, signer, tokenId, makerAmount, takerAmount, side, signatureType, timestamp, metadata, builder`. `maker` is the trading wallet
> * Shown as *Confirm this Polymarket order*. Sign within about 60 seconds

A first order on a new wallet can ask for all three in one action.

## Predict.fun

> [accordion] Setup 1: approvals (pays BNB gas)
>
> Asked only for approvals the wallet is missing.
>
> * `wallet_sendCalls`, chain `0x38`, one call per approval (up to 12): an unlimited ERC-20 `approve` of USDT and ERC-1155 `setApprovalForAll` of outcome tokens, both to Predict.fun's exchange contracts
> * `fallbackRequests` holds the same calls as separate `eth_sendTransaction`s, for wallets without `wallet_sendCalls`
> * The user pays BNB gas once (about 70,000 gas per approval). With too little BNB, setup asks for nothing and ends `done` with `next: "fund"` and `venueDetail.reason`; an order fails with `this wallet needs about … BNB …`
> * Shown as *Approve Predict.fun trading on BNB Chain: N approvals in one confirmation (pays BNB gas)*
>
> After you answer, the step is `working` while the approvals confirm, up to about 5 minutes.

> [accordion] Setup 2: sign in to Predict.fun
>
> * `personal_sign` of Predict.fun's own login message, `chainId: null`
> * Shown as *Sign in to Predict.fun (no gas)*
> * The session lasts about a day. An order asks for this again when less than an hour is left

> [accordion] Order
>
> * `eth_signTypedData_v4`, chain `0x38`
> * Predict.fun's own EIP-712 order: domain `{ name: "predict.fun CTF Exchange", version, chainId: 56, verifyingContract: <exchange> }`. The exchange depends on whether the market is neg-risk and yield-bearing
> * `Order` carries `salt, maker, signer, taker, tokenId, makerAmount, takerAmount, expiration, nonce, feeRateBps, side, signatureType`. `maker` and `signer` are the wallet; `feeRateBps` is the market's venue fee
> * Shown as *Confirm this Predict.fun order*. Sign within about 60 seconds

## Hyperliquid

Hyperliquid's user actions are EIP-712 messages on Arbitrum's chain id. Nothing costs gas.

> [accordion] Setup: approve the trading agent
>
> * `eth_signTypedData_v4`, chain `0xa4b1`
> * Domain `{ name: "HyperliquidSignTransaction", version: "1", chainId: 42161, verifyingContract: 0x0000000000000000000000000000000000000000 }`
> * `primaryType: "HyperliquidTransaction:ApproveAgent"` with `hyperliquidChain` (`"Mainnet"`), `agentAddress`, `agentName`, `nonce`
> * Shown as *Allow Kairos to place Hyperliquid trades for you (it cannot withdraw; no gas)*. If Hyperliquid dropped the agent while the account was empty, setup asks again with a note saying so
>
> Hyperliquid agents can place and cancel orders only. They can't withdraw or transfer funds, and the user can revoke the agent on Hyperliquid at any time.

> [accordion] Setup: builder fee approval
>
> Asked right after the agent approval, only where a Hyperliquid builder fee is configured.
>
> * Same domain, `primaryType: "HyperliquidTransaction:ApproveBuilderFee"` with `hyperliquidChain`, `maxFeeRate` (a percent string, for example `"0.01%"`), `builder`, `nonce`
> * Shown as *Approve the Hyperliquid builder fee on your trades (no gas)*
> * See [fees](https://docs.kairos.trade/wallets/fees.md#hyperliquid)

> [accordion] Order: move USDC from perps (only when needed)
>
> Asked when spot USDC is short but the wallet's perps account can cover the gap.
>
> * Same domain, `primaryType: "HyperliquidTransaction:UsdClassTransfer"` with `hyperliquidChain`, `amount` (the shortfall including fees, rounded up to the cent), `toPerp: false`, `nonce`
> * Shown as *Move X USDC from your Hyperliquid perps to spot for this order (no gas)*

> [accordion] Order
>
> * `eth_signTypedData_v4`, chain `0xa4b1`
> * Domain `{ name: "Kairos", version: "1", chainId: 42161 }`, no verifying contract
> * `primaryType: "PlaceOrder"` with `wallet, market, outcome, side, price, size, timeInForce, postOnly, action, expiresAt`. The terms are in plain text, so a wallet can show them directly
> * Kairos then places exactly that order on Hyperliquid with the approved agent
> * Shown as *Confirm this Hyperliquid order*. Sign within 5 minutes

## Cancel (every venue)

* `eth_signTypedData_v4`, chain `0x89` (Polygon), **even when the orders are on Predict.fun or Hyperliquid**
* Domain `{ name: "Kairos", version: "1", chainId: 137 }`, no verifying contract
* `primaryType: "CancelOrders"` with `wallet`, `orders` (`"all"`, or the order ids joined by commas), `action` (the action id), `expiresAt`
* Shown as *Confirm cancelling these orders*. Sign within 5 minutes

One cancel signature covers every venue.

## Sign-in

`personal_sign` of a Sign-In with Ethereum message, `chainId: null`. See [the sign-in token](https://docs.kairos.trade/wallets/authentication.md#the-sign-in-token).

## Preview features

[Trade plans](https://docs.kairos.trade/wallets/trade-plans.md), [fee settlements](https://docs.kairos.trade/wallets/fees.md) and [on-chain intents](https://docs.kairos.trade/wallets/onchain.md) use the same methods. Their documents are listed on those pages:

| Document | Domain | `primaryType` |
| - | - | - |
| Trade plan consent | `{ name: "KairosTradePlan", version: "1", chainId: <the venue's chain> }` | `TradePlan` |
| On-chain intent consent | `{ name: "KairosOnchainIntent", version: "1", chainId: 137 }` | `OnchainIntent` |
| Polymarket fee payment, on-chain intent batch | `{ name: "DepositWallet", version: "1", chainId: 137, verifyingContract: <trading wallet> }` | `Batch` |
| Funding permit 1 (trade plans) | `{ name: "RelayApprovalProxy", version: "3.1", chainId, verifyingContract }` on the source chain | `MulticallAuthorization` |
| Funding permit 2 (trade plans) | `{ name: "USD Coin", version: "2", chainId, verifyingContract: <USDC> }` on the source chain | `ReceiveWithAuthorization` |

Trade plans and on-chain intents check signatures more strictly: 65 bytes, `v` of `0`, `1`, `27` or `28`, and a low `s` value. Standard wallets already sign this way. On-chain intent documents carry `chainId` as a decimal string (`"137"`).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.