For the complete documentation index, see llms.txt. This page is also available as Markdown.

Signing

EIP-712 structured signing for Agent and Master wallet operations.

AFX DEX uses EIP-712 structured signatures for authentication. No API keys or sessions — every Exchange request is signed by an Ethereum wallet.

Agent Signature

Used for most trading operations. The Agent wallet signs a hash derived from the protobuf-serialized action payload.

Domain: Exchange

Operations: placeOrder, replaceOrder, placeBracketOrder, cancelOrder, cancelAll, setLeverage, setMarginMode, assignPosMargin, bindReferral, and vault-context operations when the Agent is explicitly authorized for that vault workflow.

Master Signature

Used for privileged operations. The Master wallet signs the action fields directly as EIP-712 message — no protobuf involved.

Domain: SignTransaction

Operations: approveAgent, revokeAgent, withdraw, faucetClaim.

Permission Boundary

Operation family
Signer
Operational risk

Order placement, replacement, cancellation, leverage, margin mode, and position margin

Agent wallet

Can change trading exposure and liquidation risk. Cannot withdraw account funds to an external address.

Agent approval and revocation

Master wallet

Controls whether an Agent wallet can act for the Master account. Keep revocation available as an emergency runbook step.

Account withdrawal

Master wallet

Moves account funds to an external address. Never place the Master private key in an automated trading runtime.

Vault operations

Agent wallet in vault context

Can affect vault balances, ownership, withdrawal flow, or vault lifecycle depending on the action. Do not treat a vault-authorized Agent as trading-only.

For operational guidance, see Agent Safety.


Agent Signing Process

1

Serialize action to Protobuf

Encode the action fields using the corresponding protobuf message (e.g. MsgPlaceOrders for placeOrder).

  • JSON camelCase fields map to protobuf snake_case

  • Enum values use integers (e.g. LIMIT = 1)

  • Zero values are omitted per proto3 rules

2

Compute connectionId

connectionId = keccak256(
    proto_bytes
    + bytes(vaultAddress)              // strip 0x, decode hex. empty if null
    + little_endian_uint64(nonce)       // 8 bytes, millisecond timestamp
    + little_endian_uint64(expiryAfter) // 8 bytes, Unix timestamp milliseconds; null → 0
)

nonce is a uint64 request nonce. Use the current Unix timestamp in milliseconds (for example Date.now() or int(time.time() * 1000)) and do not reuse the same nonce for another signed request.

expiryAfter is a uint64 Unix timestamp in milliseconds. The request expires after this timestamp. Use null in the request body, and 0 inside the signature payload, when the request should not expire.

3

Sign EIP-712

{
  "types": {
    "EIP712Domain": [
      { "name": "name",              "type": "string"  },
      { "name": "version",           "type": "string"  },
      { "name": "chainId",           "type": "uint256" },
      { "name": "verifyingContract", "type": "address" }
    ],
    "Agent": [
      { "name": "source",       "type": "string"  },
      { "name": "connectionId", "type": "bytes32" }
    ]
  },
  "primaryType": "Agent",
  "domain": {
    "name":              "Exchange",
    "version":           "1",
    "chainId":           421614,
    "verifyingContract": "0x0100000000000000000000000000000000000001"
  },
  "message": {
    "source":       "b",
    "connectionId": "0x<step2_result>"
  }
}
Field
Value

source

"a" = Mainnet, "b" = Testnet

chainId

Mainnet: 42161, Testnet: 421614

verifyingContract

0x0100000000000000000000000000000000000001

For Python applications, use the official afx-python-sdk. The SDK handles protobuf serialization, connectionId calculation, and EIP-712 signing internally.

from afx import AfxClient

client = AfxClient.from_env(testnet=True)

# Agent-signed operations just work -- SDK handles signing internally.
result = client.exchange.place_order(
    symbol_code=1,
    px="40000",
    qty="0.5",
    side="BUY",
)

Master Signing Process

Master wallet signs the action fields directly as an EIP-712 message. No protobuf serialization.

Each action has its own EIP-712 type definition. Common domain:

approveAgent

validitySeconds is the agent authorization duration in seconds. 0 means the authorization is valid for 7 days; maximum 365 days.

revokeAgent

Revocation uses the same approveAgent signing flow with:

The Python SDK exposes this as:

Use revocation when rotating Agent keys, stopping an automated strategy, or responding to suspected key exposure.

withdraw

withdrawSequence is included in both the withdraw action body and the signed EIP-712 message. If omitted in the Python SDK, it defaults to the request nonce.

For withdrawals, use a longer expiryAfter window, such as current Unix time in milliseconds + 3,600,000. This gives the withdrawal enough time to pass signature verification and broadcast.

The minimum mainnet withdrawal amount is 2 USDC.

faucetClaim (Testnet only)

Message: { "dexChain": "Testnet" }, chainId fixed 421614.

Signature r and s values must be zero-padded to exactly 32 bytes (64 hex characters). For example in Python: "0x" + format(signed.r, "064x")

Last updated