@olive-so/solana-sdk
v0.1.1
Published
Client and maker SDK for the Olive Solana options program: maker WebSocket transport, V4 quote signing, canonical PDAs, and IDL-backed transaction construction.
Maintainers
Readme
@olive-so/solana-sdk
This is the publishable client, maker WebSocket client, and operational runner for the Olive Solana program. The Solana backend uses the same public digest, PDA, and maker-client exports as external integrations.
The client uses the generated Anchor IDL as the instruction/account authority.
It does not contain handwritten instruction discriminators or account layouts.
Its public helpers cover canonical PDAs, market identity hashes, V4 entry/exit
quote digests, JSON-to-IDL coercion, transaction construction, and decoded
account assertions. MakerWsClient implements the exact /maker/v1/ws
transport. ManagedMaker is the recommended maker-facing API: typed validated
callbacks, safe V4 quote builders, durable quote/nonces/events, signer/HSM
abstraction, reconnect/recovery, and finalized lifecycle routing.
Managed maker
Install the published version or Olive's integrity-pinned onboarding tarball,
then construct ManagedMaker with the exact deployment identity supplied by
Olive, a MakerSigner, and a PostgresMakerStore. Use
LocalKeypairMakerSigner for a local key or CallbackMakerSigner to keep HSM/
remote private keys outside the process. Entry callbacks return
rfq.quote({ premiumUsdc }); exit callbacks return
rfq.quote({ exitAmountUsdc, usdcSource }). The SDK copies every request-bound
field, manages separate entry/exit nonce namespaces, computes safe quote
lifetimes, signs and durably persists before submission, and retries only the
same signed quote. InMemoryMakerStore is explicitly test-only.
Production database roles can run without DDL permission. Apply the packaged
schemas/postgres-maker-store-v1.sql through the maker's migration system, then
construct PostgresMakerStore(pool, { schemaMode: "verify" }). The default
migrate mode remains convenient for development and performs the same
versioned schema initialization transactionally.
Typed lifecycle handlers distinguish selection from execution. Treat
onEntrySelected/onExitSelected as feedback and only finalized
onEntryFilled/onExitFilled as hedge and reconciliation triggers. Durable
events are persisted before server acknowledgement and local handler completion
is itself durable.
RFQ callbacks use a bounded concurrent dispatcher so one slow pricing or HSM
request does not block later two-second auctions. The default concurrency is
eight and can be set with connection.rfqConcurrency; size it together with the
maker's pricing, signer, database, and risk-engine capacity.
runMakerDoctor provides a non-subscribing, no-takeover preflight with both JSON
and human-readable output. It checks deployment identity, signer/maker state,
authorization, finalized capacity freshness, exit-source eligibility, clock
skew, latency, and lifetime feasibility without submitting a quote.
MakerWsClient remains the low-level escape hatch. Its RFQ and lifecycle
callbacks are also runtime-validated discriminated types rather than generic
JSON records. Typed helpers cover subscribe/unsubscribe, open RFQs, decline,
entry/exit submission, capacity, paginated positions, acknowledgement, and
dead-letter recovery. Structured status events expose authentication,
reconnection, RFQ recovery, dead-letter recovery, and rate-limit retries.
Language-neutral integration assets ship in schemas/: the combined v1 JSON
Schema catalog, a self-contained valid fixture for every known notification and
request result, and the cross-language auth/entry/exit digest golden fixture.
The SDK test suite runtime-validates every message fixture and recomputes every
published digest before packaging.
runMakerConformanceSuite provides the versioned, machine-readable report
required by the protocol release gate. It fails closed: every required sandbox
scenario must have a check and pass; omitted checks are reported as skip and
make the report unhealthy. The release-environment harness supplies the actual
checks through the public managed SDK.
The normative wire contract is the published Maker WebSocket API v1, with a complete integration example in the docs-site maker quickstart. The SDK contains no legacy route, EVM quote type, protocol negotiation, or compatibility translator.
Operational safety
- The CLI never reads an admin, maker, guardian, or upgrade secret.
- Every configured plan binds the exact deployment-manifest and IDL SHA-256 hashes.
- Every transaction is generated as an unsigned v0 artifact containing the message bytes, instruction bytes/metas, required signers, packet size and headroom, static and ALT-loaded account counts, recent blockhash, and expected finalized state.
- Admin/maker transactions can be imported into a wallet or multisig proposal. A multisig PDA is not falsely treated as a locally signable key.
- Signed entry and exit steps recompute the canonical Rust digest and cryptographically verify the Ed25519 signature before construction. The Ed25519 instruction is immediately before the Olive instruction, as required on chain.
- Broadcasting is a separate explicit command that reloads the hashed plan/IDL/manifest, reconstructs the original-blockhash message, accepts only byte-identical signed bytes, and locally verifies every required signature.
simulate-signedapplies those same byte-identity, signature, genesis, and blockhash checks without sending the transaction. It records compute units, loaded account-data size, logs, return data, and the serialized resource envelope for target-cluster capacity evidence.- A transaction signature is not completion.
verify-stepdecodes every declared account atfinalizedcommitment and compares selected fields to the approved plan. - Expected-failure canaries pass only when the observed error contains the committed error marker. Unexpected success fails the run.
Tests
From the repository root:
npm run check:solana-sdk
npm run test:solana-sdkThe SDK golden tests share the Rust fixtures for PDAs and the signed V4 entry and exit digests. They also build a real initializer from the generated IDL and prove Ed25519 verification/adjacency for maker quotes.
The SDK pins @solana/[email protected] as its single Solana client runtime.
Anchor, Pyth, and SPL Token integrations currently expose web3.js v1 objects,
so keeping one representation avoids conversion boundaries and duplicate
transaction systems. A future Kit migration should be atomic and gated on
those integrations offering compatible Kit-native APIs.
Plan workflow
The non-deployable templates are:
solana/deployments/initialization-plan.example.jsonsolana/deployments/devnet-canary.example.json
Copy them to ignored operational files, expand repeated assets/markets/makers, and replace every placeholder. Instruction arguments and account names use the generated IDL's camelCase client names. Integer values of 64 bits or larger should be decimal strings; 32-byte hashes may be hexadecimal strings.
Record the exact input hashes:
sha256sum solana/deployments/devnet.json solana/target/idl/olive_options.jsonValidate and render authority phases:
npm run olive:solana -- validate-plan \
--plan solana/deployments/initialization-plan.json \
--idl solana/target/idl/olive_options.json \
--deployment-manifest solana/deployments/devnet.json
npm run olive:solana -- render-plan \
--plan solana/deployments/initialization-plan.jsonBuild one fresh-blockhash transaction at a time:
npm run olive:solana -- build-step \
--plan solana/deployments/initialization-plan.json \
--idl solana/target/idl/olive_options.json \
--deployment-manifest solana/deployments/devnet.json \
--step protocol \
--output solana/evidence/devnet/protocol-unsigned.jsonHave the required wallet/multisig sign the exact messageBase64 transaction.
Run the exact signed serialization through the no-send simulation first:
npm run olive:solana -- simulate-signed \
--artifact solana/evidence/devnet/protocol-unsigned.json \
--signed /path/to/protocol-signed.txt \
--plan solana/deployments/initialization-plan.json \
--idl solana/target/idl/olive_options.json \
--deployment-manifest solana/deployments/devnet.json \
--output solana/evidence/devnet/protocol-simulation.jsonSimulation never counts as completion and may become stale if cluster state changes. Once reviewed, explicitly broadcast those same signed bytes:
npm run olive:solana -- broadcast-signed \
--artifact solana/evidence/devnet/protocol-unsigned.json \
--signed /path/to/protocol-signed.txt \
--plan solana/deployments/initialization-plan.json \
--idl solana/target/idl/olive_options.json \
--deployment-manifest solana/deployments/devnet.json \
--output solana/evidence/devnet/protocol-receipt.jsonFinally verify decoded state before releasing the next authority phase:
npm run olive:solana -- verify-step \
--plan solana/deployments/initialization-plan.json \
--idl solana/target/idl/olive_options.json \
--deployment-manifest solana/deployments/devnet.json \
--step protocol \
--output solana/evidence/devnet/protocol-state.jsonAfter a canary batch has one artifact and no-send simulation per transaction, aggregate its resource and writable-lock evidence:
npm run olive:solana -- summarize-run \
--evidence-dir solana/evidence/devnet/canary-run \
--output solana/evidence/devnet/canary-summary.jsonThe summary reports maximum wire bytes, total accounts, compute, loaded account data, missing simulations, and every writable account shared across two or more transactions. Use the hot-account list to design the clustered-expiry load test; it is measurement evidence, not a claim about public throughput by itself.
Unsigned artifacts use recent blockhashes and therefore expire. Rebuild rather than modifying or reusing an expired message. Any change to the deployment manifest, IDL, instruction, account list, or expected state requires review and a new artifact.
Remaining external inputs
The CLI is executable and the checked-in SDK identity is devnet-only. The templates cannot be configured until operations provide authority/multisig addresses, asset-policy records, maker keys, facility evidence, calendars, Pyth Benchmark API/archive access, fee payer, and funded RPC access. Mainnet must replace the devnet identity and republish its generated client.
