Skip to main content

Institutional Conformance Kit

Use this checklist before giving a bot production credentials. It is designed to catch the integration failures that are expensive in live market making: wrong account id, wrong credential type, nonce replay, stale risk state, mis-derived order ids, and over-trusting fast acknowledgements.

Required gates​

GateRequired evidenceCommand or source
SDK build and vectorsTypeScript SDK compiles and action/HMAC/FIXP vectors passcd sdks/typescript && npm ci && npm run verify
Funded bundle manifestJSON bundle has owner wallet, 32-byte accountIdHex, 20-byte engine account, institutional_agent, HMAC credential, funding minimum, known-good quote, and signed batch pathnode scripts/e2e/institutional-conformance-kit.cjs --bundle-file tmp/institutional-beta-bundle.json
Known-good batch generationBundle knownGoodQuote is signed into orderEntry.signedBatchFile with the live action-signing domainnode sdks/typescript/dist/examples/institutional-known-good-batch.js --bundle-file tmp/institutional-beta-bundle.json
External conformance harnessHMAC vector, live BSL connectivity, fresh bootstrap, optional known-good submitnode scripts/e2e/institutional-conformance-kit.cjs
Python bundle preflightPython SDK reproduces HMAC V2, authenticates, reads connectivity, and verifies fresh bootstrap funding without submitting orderscd sdks/python && python examples/institutional_bundle_preflight.py --bundle-file ../../tmp/institutional-beta-bundle.json
Python signed-batch submitPython SDK sends orderEntry.signedBatchFile bytes over /api/order-entry/binary after funding passescd sdks/python && python examples/institutional_bundle_preflight.py --bundle-file ../../tmp/institutional-beta-bundle.json --submit-signed-batch
Rust bundle preflightRust SDK reproduces HMAC V2, authenticates, reads connectivity, and verifies fresh bootstrap funding without submitting orderscd sdks/rust && cargo run --example institutional_bundle_preflight -- --bundle-file ../../tmp/institutional-beta-bundle.json
Rust signed-batch submitRust SDK sends orderEntry.signedBatchFile bytes over /api/order-entry/binary after funding passescd sdks/rust && cargo run --example institutional_bundle_preflight -- --bundle-file ../../tmp/institutional-beta-bundle.json --submit-signed-batch
Internal docs contract auditLive beta metadata, protected-read boundary, BSL submit, and cleanup are checked by Sentico opsnode scripts/e2e/mm-docs-contract-audit.cjs
OpenAPI institutional contractAccount model, bootstrap, BSL submit, direct order-entry, receipts, and per-action results are typedcargo test -p senticore-sequencing-core openapi_contract --tests
HMAC vectorIndependent client reproduces the documented HMAC signaturesdks/typescript/tests/auth.test.ts
Action hash vectorsIndependent signer reproduces canonical JSON, v1/v2 hashes, and derived order idssdks/typescript/tests/signing.test.ts
Nonce replayDuplicate action nonce is rejected and client re-signs with a fresh in-window noncelocal test or beta account
IdempotencySame key plus same body returns/replays safely; same key plus different body conflictslocal test or beta account
Account mappingClient stores accountIdHex and engineAccountHex separatelylive trading-account list
Funding preflightFresh bootstrap shows funded balances.freeUsdcMicro and matching-engine source when presentGET /api/v1/accounts/:engineAccount/bootstrap?fresh=true
QuoteReplaceOne known-good QuoteReplace produces a derived order id and ackPOST /api/order-entry/binary or BSL compact facade
ReconciliationDerived order id is found in orders/drop-copy/fills or terminal stream eventprivate read/stream/FIX drop-copy
Lane-key compatibilityClient uses X-Senticore-Order-Entry-Key; legacy headers tested only for migrationHTTP order-entry tests
Hotpath latency proofFresh accepted stress report shows local signing, warm connection reuse, no /api/v1/trading/actions/hash hotpath round trip, and exchange ACK p99 within the MM targetnode scripts/e2e/assert-live-order-entry-latency.cjs tmp/live-order-entry-stress-last.json --max-exchange-ack-p99-us=50000
Stream and gap-fill recoveryClient persists seqs[] before strategy mutation, replays from last_contiguous_seq + 1, and dedupes by seq before resuming quote loopsGET /api/v1/bsl/executions and GET /api/v1/bsl/accounts/{account}/executions?fromSeq=...
Quote-family recoveryQuoteReplace returns quoteFamilyScopes[]; lost local order tracking is recovered with scoped cancel-all and operation: "cancel_all_by_market_book_side"POST /api/v1/bsl/orders/cancel-all

External-safe runner​

The customer-facing harness is:

node scripts/e2e/institutional-conformance-kit.cjs --offline

Offline mode verifies the documented HMAC vector and writes a redacted report to tmp/institutional-conformance-last.json. It does not load local secrets, does not SSH to Sentico infrastructure, and does not submit orders.

For live credential preflight:

node scripts/e2e/institutional-conformance-kit.cjs \
--bundle-file tmp/institutional-beta-bundle.json

This checks:

  • HMAC signing string and signature vector
  • funded bundle manifest shape
  • authenticated GET /api/v1/bsl/connectivity
  • testedBetaSubmitPath === "/api/order-entry/binary"
  • fresh GET /api/v1/accounts/:engineAccount/bootstrap?fresh=true
  • freeUsdcMicro against expectedFunding.freeUsdcMicroAtLeast from the bundle

Live submit is opt-in because it requires a known-good signed batch:

cd sdks/typescript
npm install
npm run build
SENTICORE_ACTION_PRIVATE_KEY=0x... \
node dist/examples/institutional-known-good-batch.js \
--bundle-file ../../tmp/institutional-beta-bundle.json
cd ../..
SENTICORE_CONFORMANCE_SUBMIT=1 \
node scripts/e2e/institutional-conformance-kit.cjs \
--bundle-file tmp/institutional-beta-bundle.json

The bundle's orderEntry.signedBatchFile must already contain a fully signed action batch. The harness posts the bytes, verifies HTTP 200, ok: true, and fails when actionResults[] contains a reject. Use the SDK examples on Place Your First Institutional BSL Quote to generate the signed batch for a funded beta account.

To turn on live idempotency and nonce-replay gates, use the same signed batch:

SENTICORE_CONFORMANCE_SUBMIT=1 \
SENTICORE_CONFORMANCE_IDEMPOTENCY=1 \
SENTICORE_CONFORMANCE_REPLAY=1 \
SENTICORE_REPLAY_IDEMPOTENCY_KEY=quote-1-yes-bid-0-replay \
node scripts/e2e/institutional-conformance-kit.cjs \
--bundle-file tmp/institutional-beta-bundle.json

Expected:

  • signed-batch-submit returns HTTP 200, top-level ok: true, and no rejected actionResults[].
  • idempotency-replay-same-key submits identical bytes with the same Idempotency-Key; it should replay or return the same accepted response.
  • nonce-replay-different-key submits identical signed bytes with a different Idempotency-Key; it must reject as a nonce replay/conflict. If this accepts, the client or venue is not enforcing signed action nonce replay protection.

The JSON report records the bundle summary, batch SHA-256, redacted credential metadata, request ids, response status, top-level errors, and per-action reject counts.

Run the language-specific preflights against the same funded bundle before handing credentials to a production strategy:

cd sdks/python
python3 -m pip install -e .
python examples/institutional_bundle_preflight.py \
--bundle-file ../../tmp/institutional-beta-bundle.json
cd ../..
cd sdks/rust
cargo run --example institutional_bundle_preflight -- \
--bundle-file ../../tmp/institutional-beta-bundle.json
cd ../..

Both preflights are read-only. They fail when expectedFunding.freeUsdcMicroAtLeast is not met, because an unfunded account would turn a signing test into a risk-layer failure.

After sdks/typescript/dist/examples/institutional-known-good-batch.js writes orderEntry.signedBatchFile, Python and Rust can submit the same bytes:

cd sdks/python
python examples/institutional_bundle_preflight.py \
--bundle-file ../../tmp/institutional-beta-bundle.json \
--submit-signed-batch
cd ../..
cd sdks/rust
cargo run --example institutional_bundle_preflight -- \
--bundle-file ../../tmp/institutional-beta-bundle.json \
--submit-signed-batch
cd ../..

The submit report includes the batch SHA-256, request id, ok, seqs, derivedOrderIds, acceptedActions, ackMode, and rejectCount.

The docs-contract audit and SDK preflight sign actions locally with the chain-bound v2 action hash from GET /api/v1/bsl/connectivity. They must not call POST /api/v1/trading/actions/hash in the order-entry hot path; that server hash endpoint is only for integration debugging and vector comparison. The docs-contract audit submits a one-leg QuoteReplace or SpotQuoteReplace and then reconciles the deterministic child order id, because that is the market-maker primitive the beta contract is meant to protect.

Production latency and recovery gates​

Run the static contract audit before live tests. This catches accidental docs or API drift around the latency, nonce, reconciliation, and recovery contracts:

node scripts/e2e/mm-docs-contract-audit.cjs --static-contract-only

After a fresh accepted order-entry stress run, gate the report:

node scripts/e2e/assert-live-order-entry-latency.cjs \
tmp/live-order-entry-stress-last.json \
--max-exchange-ack-p99-us=50000

The latency gate must show:

  • actionSigning.mode === "local-v2"
  • latencyAttribution.connectionWarmup.ok === true
  • latencyAttribution.removedHotpathRoundtrip.endpoint points at /api/v1/trading/actions/hash with zero measured hotpath time
  • latencyAttribution.exchangeAck.p99Us <= 50000

That is the exchange ACK p99 gate. Public client RTT can be higher on the open internet and is tracked separately; it does not prove or disprove the exchange hotpath by itself.

Before enabling unattended quote size, also verify the recovery contract:

cargo test --manifest-path backend/sequencing/core/Cargo.toml \
"transport::mm::facade::tests::bsl_" -- --nocapture

The DB-backed scoped cancel-all regression needs a local Postgres test runtime:

cargo test --manifest-path backend/sequencing/core/Cargo.toml \
bsl_cancel_all_scopes_by_market_book_side -- --nocapture

Do not ship a strategy that cannot demonstrate stream replay from last_contiguous_seq + 1, quoteFamilyScopes[] reconciliation, and scoped cancel_all_by_market_book_side recovery.

Action signing vectors​

The TypeScript SDK pins the same vectors as the backend. If your client cannot match these, do not send live orders.

Synthetic vectors, not market discovery

Market 7 is fixed here only because these are byte-for-byte golden vectors. It is not currently listed in production. Discover live IDs from GET /api/v1/public/exchange-info; changing the market changes the expected hash and derived order ID.

SpotPlaceOrder​

Canonical JSON:

{"account":"0x1111111111111111111111111111111111111111","nonce":4810,"nonce_reservation_id":null,"ts":1765500000000,"action":{"SpotPlaceOrder":{"market":7,"side":"Bid","price":998400,"qty":1000,"stp_mode":null,"time_in_force":"post_only","is_market":false,"reduce_only":false,"expires_at":null}}}
OutputValue
v1 hash0xc8d02209196c492de5b39c90d7efd356548784ddd464603913b59afab911b42f
v2 hash, chain 8453, contract 0xcccccccccccccccccccccccccccccccccccccccc0x26d8533a5150e7a8bf6537824715562eddb55a0c019a0b23635533a1d4e7e084
derived order id0x52401b1d6de155089120a39ccd8ca52e3b5daaf090f090c5a0705b53b914d57e

QuoteReplace​

Canonical JSON:

{"account":"0x1111111111111111111111111111111111111111","nonce":4812,"nonce_reservation_id":"res-1","ts":1765500000002,"action":{"SpotQuoteReplace":{"market":7,"legs":[{"cancel_order_id":"0x2222222222222222222222222222222222222222222222222222222222222222","side":"Bid","price":998500,"qty":1189,"stp_mode":null,"time_in_force":"post_only","is_market":false,"reduce_only":false,"expires_at":null}]}}}
OutputValue
v1 hash0x0b635be460cf6d9ae3a9fe11c1b5d5176c942e9b6139f88dac142baa1818584c
derived child order id, leg 00xfeac5884704773dd3150bef258b3f5a139dafaba0bba2190fc9d520b8a505e22

For production signatures, fetch the live v2 chain binding from:

GET /api/v1/bsl/connectivity

Then sign with actionSigning.chainId and actionSigning.verifyingContract.

HMAC vector​

Signing string:

SENTICORE-HMAC-V2
sc-key:spk_test
sc-nonce:7
sc-timestamp:123456
method:POST
path:/api/v1/private/account
query:a=1&b=2
body-sha256:08220911bbc1dfd55d93796c4d425a9582f94221975933bb2d98d269ab3c7b95

With secret sps_secret:

0x54ddc2c6f1eef6b75c317de7908c2e5c16a4e38561d75a147085cee9b0e6fb00

Rules:

  • method is uppercase
  • path excludes query string
  • query is split on &, empty parts are dropped, then sorted and rejoined
  • body hash is lowercase SHA-256 hex of the raw request body, or SHA-256 of empty bytes for GET
  • SC-Nonce is decimal and single-use for that credential
  • SC-Timestamp is Unix milliseconds with a 30 second skew tolerance

Nonce replay tests​

Run these against a funded beta account with tiny post-only quantities.

TestExpected
Submit action nonce N onceaccepted or valid strategy/risk reject
Submit exact same signed body again with same idempotency keyidempotency replay or same stored response
Submit exact same signed body with different idempotency keynonce_replayed or equivalent nonce conflict
Submit nonce below nonceFloorcode: nonce_below_floor, nonceFloor present
Submit nonce above nonceFloor + nonceWindowcode: nonce_outside_window, client must not blind retry
Submit nonce 0 on a fresh funded accountaccepted when no earlier nonce was used

Retry rule: if the nonce must change, rebuild and re-sign the action payload. Changing only Idempotency-Key cannot fix an action nonce failure.

Idempotency tests​

For BSL compact submit:

  1. Build one encoded batch and compute its SHA-256 locally.
  2. Submit with Idempotency-Key: idem-1.
  3. Repeat the exact same bytes with idem-1.
  4. Submit different bytes with idem-1.

Expected:

  • step 2 returns accepted or a deterministic reject
  • step 3 returns the same stored response where idempotency is enabled
  • step 4 returns conflict

The client should persist idempotencyKey, request hash, action nonces, and derived order ids together.

Risk and funding fixture​

Every beta bundle should include a known-good order and minimum funding.

{
"engineAccount": "0x2222222222222222222222222222222222222222",
"minimumFreeUsdcMicro": "100000000",
"quote": {
"kind": "QuoteReplace",
"market": 1,
"book": "YES",
"side": "Bid",
"price": 100000,
"qty": 100000,
"timeInForce": "post_only"
}
}

Before submitting, calculate:

requiredUsdcMicro = floor(priceMicro * qtyMicro / 1_000_000)

For price=100000 and qty=100000, required notional is 10000 micro USDC. The bundle's minimumFreeUsdcMicro should exceed this by enough margin for fees, open-order holds, and any account risk config.

QuoteReplace fixture rules​

For outcome markets use QuoteReplace; for spot markets use SpotQuoteReplace.

{
"QuoteReplace": {
"market": 1,
"legs": [
{
"cancel_order_id": null,
"book": "YES",
"side": "Bid",
"price": 100000,
"qty": 100000,
"stp_mode": "skip_self",
"time_in_force": "post_only",
"is_market": false,
"reduce_only": false,
"expires_at": null
},
{
"cancel_order_id": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"book": "YES",
"side": "Bid",
"price": 0,
"qty": 0,
"stp_mode": null,
"time_in_force": "post_only",
"is_market": false,
"reduce_only": false,
"expires_at": null
}
]
}
}

The first leg places a deterministic child order. The second leg is cancel-only because qty is 0. Conformance should assert local derived child ids match the response derivedOrderIds[].

Live beta audit​

From the repository root:

node scripts/e2e/mm-docs-contract-audit.cjs

For BSL compact facade verification:

MM_DOCS_SUBMIT_ROUTE=/api/v1/bsl/orders/compact \
MM_DOCS_RESULT_MODE=ack \
MM_DOCS_RESPONSE_MODE=detailed \
node scripts/e2e/mm-docs-contract-audit.cjs

The audit should produce a redacted JSON artifact under tmp/ and should never print HMAC secrets or private keys.

Ship/no-ship criteria​

Ship the integration only when all are true:

  • Account mapping is explicit: owner wallet, accountIdHex, and engine account are separately stored and logged.
  • HMAC and action-signing vectors pass in the client language.
  • Fresh bootstrap reports a funded account.
  • One QuoteReplace is accepted and reconciled to an order/drop-copy/fill state.
  • Nonce replay and idempotency behavior are tested.
  • Strategy code treats ack as admission, not terminal truth.
  • Per-action rejects in actionResults[] and receipt/drop-copy rejects are handled as real terminal state, not ignored because HTTP was 200.
  • Risk rejects are logged with account, market, book, asset, free, locked, required, nonce, and idempotency key.