Action
struct, verified onchain by the Matching contract when the trade settles. markets-service
stores the signature and forwards it — it never signs on your behalf.
An order request therefore carries three related things:
- Flat order fields (
side,limit_price,desired_amount, …) thatmarkets-serviceuses to place you on the book action_json— theActionstruct you signedsignature— your EIP-712 signature over that struct
action_json disagree, so the two must be
built from the same values.
The Action struct
Action is defined in IActionVerifier and hashed with this type string:
uint256
required
The subaccount placing the order.
uint256
required
Unique per
(owner, nonce). The trade module tracks fills against it, so reusing a nonce
reuses its fill state.address
required
The trade module address for your network — see Contract addresses.
bytes
required
ABI-encoded
TradeData. See Encoding data.uint256
required
Unix seconds after which the action can no longer be matched.
address
required
The account that owns the subaccount.
address
required
The address whose key produced the signature. Equal to
owner unless you are using a
session key.EIP-712 domain
The domain is fixed by theMatching contract, which is the verifying contract:
chainId and Matching address for the network you are trading on.
Encoding data
Action.data is the ABI encoding of TradeData, defined in ITradeModule:
Every field is static, so the encoding is exactly seven 32-byte words — 448 hex characters
after the
0x. markets-service rejects any other length with
expected encoded TradeData tuple.
limitPrice and desiredAmount are signed int256, but both must be positive. The
service rejects zero or negative values.Price and amount use two different scales
This is the easiest thing to get wrong, and a mismatch produces an order that is accepted but never matches.action_json.datacarries the raw onchain values in wei — the numbers the contracts settle on.- The order body carries human decimal values.
markets-servicenormalizes them itself: the price is divided by the instrument’s tick size, and the amount by its minimum size.
limit_price: "1605" and desired_amount: "0.1" in the
body, while data holds 1605000000000000000000 and 100000000000000000.
Sign and submit
action_json mirroring the struct you signed:
What the service checks
markets-service validates consistency before the order reaches the book. It does not
verify your signature — that happens onchain at match time, so a well-formed order with a bad
signature is accepted here and fails later.
Metadata must agree with action_json:
action_json.subaccount_idmatchessubaccount_idaction_json.noncematchesnonceaction_json.ownermatchesowner_addressaction_json.signermatchessigner_address
action_json.data must agree with the flat fields:
data.assetmatchesasset_addressdata.subIdmatchessub_iddata.isBidmatchesside—trueforbuy,falseforselldata.limitPriceis a positive whole multiple of the tick-normalizedlimit_pricedata.desiredAmountis a positive whole multiple of the size-normalizeddesired_amount
data to the human values in the body. Derive
one from the other as shown above and they hold automatically.
Session keys
Setsigner to a different address than owner to trade from a hot key without exposing the
owner key. The session key must be registered onchain first:
Matching then accepts that signer for the owner’s subaccounts until expiry. Deregistering
is subject to a 10-minute cooldown (DEREGISTER_KEY_COOLDOWN).
Contract signers are supported too — if signer is a contract, verification falls back to
ERC-1271.
Contract addresses
Quickstart
See the signed order in the context of the full integration flow.

