Signing contract
| Element | Requirement |
|---|---|
| Signature scheme | EIP-712 typed-data signing |
| Signing domain | Domain includes chain_id and verifying_contract |
| Signer identity | Recovered signer must match trader identity |
| Replay boundary | Replay-window timing checks and duplicate-nonce detection are enforced; lower nonces can still be admitted when they are fresh and non-duplicate |
| Replay-window pairing | client_timestamp_ms and recv_window_ms must be supplied as one complete pair; zero/default or partial population is rejected by the live gateway |
| Failure on mismatch | SignatureRecoveryMismatch safety failure |
Request families
ClientRequestApiSchema currently includes these request variants in the checked source:
| Variant | Note |
|---|---|
Order | Always present in the checked schema surface |
ModifyOrder | Always present in the checked schema surface |
CancelOrder | Always present in the checked schema surface |
CancelAll | Always present in the checked schema surface |
Withdraw | Always present in the checked schema surface |
WithdrawDDX | Always present in the checked schema surface |
InsuranceFundWithdraw | Present only when the insurance_fund_client_req feature is enabled |
ProfileUpdate | Always present in the checked schema surface |
Required signing inputs
| Input | Role |
|---|---|
| trader identity | Determines recovered signer match |
| strategy identifier | Binds request to the correct strategy where applicable |
| request payload | Exact action details that are hashed and signed |
nonce | Duplicate detection key within replay-window policy and retained-idempotency behavior |
chain_id | EIP-712 domain separator input |
verifying_contract | EIP-712 domain separator input |
session_key_signature | Optional delegated session payload bytes when session keys are used |
Replay-window field states
| Field state | Serialized shape | Public gateway behavior |
|---|---|---|
| Missing | client_timestamp_ms = 0 and recv_window_ms = 0 | Rejected as 400 InvalidRequestPayload with missing replay-window detail |
| Incomplete | one replay-window field set while the other remains zero | Rejected as 400 InvalidRequestPayload with malformed replay-window detail |
| Complete | both replay-window fields populated | Continues to replay-window freshness and duplicate-state validation |
Replay-window nuance
DerivaDEX live sequencing is not modeled as one globally increasing nonce stream for every request family.| Rule | Notes |
|---|---|
| Freshness gate | Live signed requests must present a complete replay-window pair and then satisfy timestamp and recvWindow validation |
| Duplicate handling | Retained duplicates can return stored outcomes; pending duplicates can be rejected |
| Lower-nonce edge case | Regression tests explicitly cover fresh lower-nonce CancelOrder and CancelAll requests remaining admissible when they are non-duplicate and still inside the replay window |
| Client guidance | Generate unique increasing nonces anyway because they simplify reconciliation, logging, and cross-family replay avoidance |
Failure classes tied to signing and replay
| Error reason | Status | Meaning |
|---|---|---|
InvalidRequestPayload | 400 | Request body is malformed, including missing or partially populated replay-window fields |
SignerNotFound | 401 | Recovered signer does not exist in verified state |
SessionUnauthorized | 401 | Delegated session proof failed policy checks |
IllegalNonce | 412 | Nonce conflicts with replay/duplicate-state policy for the request family |
ExpiredTimestamp | 412 | Request timestamp is too old |
FutureTimestamp | 412 | Request timestamp is too far in the future |
SignatureRecoveryMismatch | 422 | Signature and trader identity do not match |