TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Proof-labs/trading-sdk/llms.txt
Use this file to discover all available pages before exploring further.
proof-trading-sdk crate is the audited foundation that backs every Proof Exchange SDK surface. The Python PyO3 bindings call into it directly; the TypeScript SDK uses the same wire format enforced by its codec. Internal tools, custom market-making bots, and Rust services that want direct access to the same signing and encoding logic — without an HTTP gateway in between — should depend on this crate.
Most external developers should use the TypeScript SDK or Python SDK. Reach for the Rust crate when you are building a Rust service, writing a custom relayer, or need to embed signing logic in a binary without a language runtime.
Crate location
trading-sdk Cargo workspace. Add it to your project’s Cargo.toml as a path or git dependency:
Workspace layout
The workspace (Cargo.toml at the repository root) contains four crates:
| Crate | Purpose |
|---|---|
proof-trading-sdk | Core signing, codec, and wire types — the crate documented here |
proof-trading-sdk-derive | Proc-macro helpers used internally by the core crate |
proof-trading-sdk-pyo3 | PyO3 extension module (_native) that wraps the core for Python |
spec | Golden-vector fixtures and cross-binding compatibility tests |
Public modules
Fromsrc/lib.rs:
| Module | Contents |
|---|---|
codec | Action enum, encode_signed_tx, sign_and_encode_with_chain, decode_tx, peek_action_type, get_action_types, envelope constants |
crypto | signing_message, verify_signature, pubkey_to_owner, chain_id_from_string, UNBOUND_CHAIN_ID |
signer | Signer trait, LocalSigner, SignerError |
types | All action payload structs (PlaceOrder, CancelOrder, OracleUpdate, …) and domain types |
wire | Address, Pubkey, and other fixed-length byte-array newtypes with length-checked decoding |
Signer trait
The signer module provides an open trait for pluggable key custody. The codec path accepts any impl Signer, so you can swap in an HSM, a cloud KMS, or a remote signer without touching the encoding logic.
Send + Sync is required so handles can be shared across threads; backends that wrap non-thread-safe device sessions should use a Mutex internally.
SignerError
LocalSigner
The built-in in-process signer. The private key lives in Rust-owned memory and is zeroized on drop (ed25519_dalek::SigningKey is ZeroizeOnDrop).
LocalSigner when the key is loaded from a file descriptor or environment at startup. For keys that must never reside in process memory, implement Signer against your HSM or KMS client.
Codec
Wire envelope
Every transaction is a 6-element MessagePack fixarray:versionis always2(the only accepted value today).payload_bytesis a msgpackbinblob (not an array).pubkeyis 32 bytes;signatureis 64 bytes.seqis au64millisecond Unix timestamp used as a replay-protection nonce.
Signing message
Signatures bind to a specific chain via theProofExchange-v3 domain prefix:
v3) is independent of the envelope version (2). The chain-ID binding closes the cross-chain replay vector — an UNBOUND signature (all-zero chain ID) is accepted only on deployments that have not set a real chain ID.
Key codec functions
Action type bytes
Theimpl_action_encoding! macro is the single source of truth for all action-type discriminants:
| Action | Byte |
|---|---|
PlaceOrder | 0x01 |
CancelOrder | 0x02 |
OracleUpdate | 0x03 |
MarketOrder | 0x04 |
Deposit | 0x05 |
Withdraw | 0x06 |
CreateMarket | 0x07 |
WithdrawRequest | 0x08 |
ConfirmDeposit | 0x09 |
ConfirmWithdrawal | 0x0A |
FailWithdrawal | 0x0B |
ApproveAgent | 0x0C |
RevokeAgent | 0x0D |
CreateImpactMarket | 0x0E |
ResolveEvent | 0x0F |
UpdateMarketFees | 0x10 |
SetUserMarketLeverage | 0x16 |
ClosePosition | 0x17 |
CancelClientOrder | 0x18 |
CancelAllOrders | 0x19 |
CancelReplaceOrder | 0x1A |
AmendOrder | 0x1B |
AtomicBasketOrder | 0x1C |
Integer encoding and TypeScript parity
The Rust codec usesrmp-serde with minimal-int encoding: every integer is packed into the smallest msgpack integer type that fits its value. A u64 field holding 100 is encoded as a 1-byte positive fixint, not as a full 8-byte uint64. This is intentional and matches the TypeScript SDK’s minimizeBigInts logic in codec.ts. If you construct envelopes with a different encoder and use fixed-width integers, the bytes will not match the golden vectors in crates/spec/.
Building and testing
crates/spec/ crate contains golden-vector hex fixtures (place_order.hex, cancel_order.hex, oracle_update.hex) that the codec tests verify against. Any change to the wire format that causes a golden-vector mismatch is a breaking change.
Implementing a custom Signer
impl Signer, build the signing message yourself with crypto::signing_message and pass the resulting signature bytes to codec::encode_signed_tx: