Skip to main content

Olive Solana Python SDK

Olive's Long Calls and Long Puts are cash-settled: both pay intrinsic value in USDC, and holders never supply an exercise payment.

This SDK implements the V12 program and the native /maker/v3/ws protocol (protocolVersion 3.0) and nothing else. There is no translation or compatibility layer: 0.x clients are refused by the server, and quotes signed for earlier programs cannot be carried forward.

How V12 margining works

  • One entry route. Every entry quote is signed under the single domain OLIVE_ENTRY_QUOTE_V12. There is no JIT route, no collateralMode, no entry_collateral_modes subscription preference and no signing.routes.
  • Margin requirement, not maximum payout. Each bucket holds a price-driven requirement (risk.bucket_requirement): every strike slot's time-value add-on (addon) plus the worse of the bucket's intrinsic payout at a shocked-up and a shocked-down price. That is netting: calls and puts in the same bucket offset, because only one side of a strangle can pay at expiry. Credit from your facility covers the unfunded part (required - locked); a maker with a zero credit limit simply prefunds buckets and every fill is covered by that prefunding.
  • Up to 8 buckets per expiry. A maker can hold up to MAX_BUCKETS_PER_EXPIRY (8) buckets for one market and maturity, each with 32 strike slots. Buckets are numbered by index (0 to 7): it is part of the bucket address (bucket_address(program, maker, market, maturity, index)) and appears on every bucket object in maker.capacity and on bucket events. Olive routes each fill to the bucket that already holds its strike, else to the open bucket where it adds the least unfunded exposure (so a bucket holding the opposite side is preferred), and opens the next bucket before the open ones fill up. Netting, deadlines and funding are per bucket; credit is shared across all of them through your facility.
  • 24h funding deadline. Credit stops backing a bucket 24 hours before maturity (funding_deadline(maturity)); by then locked must reach required. Fills inside the lead are prefund-only.
  • Warnings at the deadline, default only at the cutoff (1.2.0). A bucket found short after the deadline starts a shortfall clock (bucket.shortfall) and warnings, not a default. On chain it becomes default-eligible (reportable; the maker is deactivated on every market) at max(maturity - 3600, shortfallSince + 14400): the hard cutoff is one hour before maturity (DEFAULT_CUTOFF_LEAD_SECONDS, default_cutoff(maturity)) and the shortfall must be at least 4 hours old (default_eligible_at, is_default_eligible, seconds_until_default_cutoff, bucket_timings). A shortfall that first opens in the last 4 hours before maturity is never eligible before maturity (settlement handles it); one that opens between 5 h and 4 h before maturity becomes eligible between the cutoff and maturity. At the deadline, credit is denied, locked collateral only grows and the prefunding withdrawal rule applies. The cutoff is a backstop: keep funding before the 24h deadline.
  • Repeated warnings and the routing gate. Olive sends bucket.prefunding_required from six hours before the deadline, then bucket.funding_required at the deadline and 12 h, 6 h, 3 h, 2 h and 90 min before expiry while the bucket is short, plus one extra notice when the deficit has grown since the last one by at least the larger of 5% of the requirement and 100 USDC (the baseline only moves down), one per deposit that leaves the bucket short (with what is left), and one when the routing pause begins; each carries the current deficit, secondsUntilCutoff (negative after the cutoff) and defaultEligibleAt. A maker receives no new entry requests while any of its buckets is short for 4 hours past its deadline (funding_shortfall), Pending with a gap (settlement_shortfall) or in an open incident or unfinalized Haircut (incident); a position that gets worse does not end the pause, and it resumes only when none qualifies. maker.capacity reports routing: {paused, reason?, since?} on both scopes (reason and since absent, not null, when not paused) and maker.routing_paused / maker.routing_resumed (on_routing_paused / on_routing_resumed) announce it. Exits, funding, true-up and settlement continue. The notifications are sent to every session (the SDK always declares maker.routing_notifications; there is no opt-out and no fallback). These events are durable but are not money-at-risk and need no handler. ManagedMaker reports funding_warning, routing_paused and routing_resumed through on_status without any handler, and does not fund buckets itself (neither SDK's managed maker does): funding is your own code. React to on_prefunding_required, on_funding_required and on_routing_paused by building a fund_bucket_instruction for the notice's deficit, signing it with the funding authority and sending it (bucket_timings gives the deadline and cutoff). The fields added in 1.2.0 are optional when decoding, so the SDK reads a gateway that predates them.
  • 4h true-up. A bucket that settles short enters pending with a 4-hour true-up window (bucket.true_up_pending, true_up_deadline). Fund remaining before it lapses; afterwards insurance is drawn (insurance.drawn) and holders are paid pro rata (haircut).
  • Headroom. maker.capacity (scope all) returns your facility (creditLimit, unfundedExposure, availableCredit, breached), each market's risk parameters and price, and every bucket's required, locked, prefunded, index, slots (product, strikeE8, qty, addon) and deadlines. capacity_entry_route(capacity, ...) tells you which bucket Olive would route a fill to, or why none can take it (bucket_slots_full, insufficient_credit, funding_bucket_unavailable). capacity_max_size(capacity, ...) runs the program's entry credit check through the risk mirror over every open bucket to give the largest size you can still fill for one strike. credit.breached reports a facility whose unfunded exposure exceeds its limit after a price move; only fills that add unfunded exposure are refused.

olive_solana.lifecycle builds the bucket instructions (initialize_bucket_instruction, fund_bucket_instruction, withdraw_bucket_funds_instruction, refresh_bucket_instruction, settle_bucket_instruction, record_pyth_settlement_instruction, redeem_position_instruction, report_bucket_incident_instruction, fund_insurance_instruction, finalize_defaulted_bucket_instruction, and the close instructions); olive_solana.pdas derives the canonical facility, bucket, bucket token account and insurance addresses. Sign and send them with your own custody.

Which Pyth feeds Olive supports is registered on chain (1.1.0): olive_solana.feeds decodes the FeedConfig account and the FeedRegistered / FeedClosed events (decode_feed_config, decode_feed_registered_event, decode_feed_closed_event), encodes and validates the 12-byte symbol (encode_feed_symbol, decode_feed_symbol) and builds the admin register_feed_instruction and close_feed_instruction; feed_config_address derives the account. Makers that only trade are unaffected.

ManagedMaker is the recommended API. Maker code supplies entry premium or exit amount and funding source; the SDK validates requests, binds canonical quote fields, allocates durable quote IDs and entry nonces, signs through a local/HSM callback, persists before submission, reconnects, and durably routes lifecycle events.

Install

# From this repository:
pip install -e "packages/python-sdk[postgres]"

# After the distribution is published:
pip install "olive-solana-sdk[postgres]"

Python 3.11 or newer is required. Create a new store once by constructing PostgresMakerStore(database_url, schema_mode="migrate") with a DDL-capable role and awaiting store.initialize(), then store.close(), or apply the packaged schemas/postgres-maker-store-v2.sql. Use schema_mode="verify" for production starts. The SDK reads schema version 2 stores only. InMemoryMakerStore is test-only.

The new-store schema is also available programmatically with postgres_maker_store_schema() so deployment tooling does not need to locate the installed wheel's data directory.

Managed maker quickstart

import asyncio
import os
import time

from olive_solana import (
    DeploymentIdentity,
    LocalKeypairMakerSigner,
    ManagedMaker,
    ManagedMakerEventHandlers,
    ManagedMakerOptions,
    PostgresMakerStore,
    capacity_entry_route,
    entry_strike_grid_warning,
)


async def main() -> None:
    signer = LocalKeypairMakerSigner.from_json_file(
        os.environ["OLIVE_QUOTE_SIGNER_KEYPAIR"]
    )
    store = PostgresMakerStore(
        os.environ["DATABASE_URL"], schema_mode="verify"
    )

    async def entry(rfq):
        request = rfq.request
        # Olive only sends on-grid strikes; this is a cheap defensive check.
        if entry_strike_grid_warning(request) is not None:
            return rfq.decline("strike_off_grid")
        capacity = await maker.client.capacity("all")
        route = capacity_entry_route(
            capacity,
            market_config=request["marketConfig"],
            maturity=int(request["maturity"]),
            product=request["product"],
            strike_e8=int(request["strikeE8"]),
            size=int(request["size"]),
            now_seconds=int(time.time()),
        )
        if route.bucket is None:
            # RFQs are all-or-nothing: no bucket can back the full size.
            return rfq.decline(route.reason or "insufficient_credit")
        premium = await price_entry(request)
        return (
            rfq.decline("outside_risk_limits")
            if premium is None
            else rfq.quote(premium_usdc=premium)
        )

    async def exit_(rfq):
        amount = await price_exit(rfq.request)
        return (
            rfq.decline("outside_risk_limits")
            if amount is None
            else rfq.quote(
                exit_amount_usdc=amount,
                usdc_source=os.environ["OLIVE_EXIT_USDC_SOURCE"],
            )
        )

    maker = ManagedMaker(
        ManagedMakerOptions(
            url=os.environ["OLIVE_MAKER_WS_URL"],
            maker_config=os.environ["OLIVE_MAKER_CONFIG"],
            expected_deployment=DeploymentIdentity(
                program_id=os.environ["OLIVE_PROGRAM_ID"],
                genesis_hash=os.environ["OLIVE_GENESIS_HASH"],
                chain_tag=os.environ["OLIVE_CHAIN_TAG"],
            ),
            signer=signer,
            store=store,
            assets=("btc", "sol"),  # the topics this session owns
            topics=("btc", "sol"),
            products=(0, 1),
            on_entry_rfq=entry,
            on_exit_rfq=exit_,
            events=ManagedMakerEventHandlers(
                # Selection is feedback, not execution.
                on_entry_selected=record_selection,
                # Only finalized fills trigger hedging/reconciliation.
                on_entry_filled=hedge_finalized_entry,
                on_exit_filled=reconcile_finalized_exit,
                # Money-at-risk margin events need a handler (or on_event).
                on_prefunding_required=fund_before_deadline,
                on_funding_required=fund_before_deadline,
                on_shortfall=top_up_within_grace,
                on_true_up_pending=true_up_before_deadline,
                on_default=page_risk,
                on_incident=page_risk,
                on_credit_breached=alert_credit_breach,
                on_settlement=record_settlement,
            ),
        )
    )
    try:
        await maker.run()
    finally:
        await store.close()


asyncio.run(main())

capacity_entry_route answers for the whole size: before the 24h deadline it counts facility credit plus the bucket's prefunding; inside it, prefunding only. The quickstart leaves price_entry, price_exit and the event handlers to you.

Lifecycle delivery is at least once. Make every external side effect idempotent by eventId; a process can stop after performing the side effect but before the SDK records local handler completion. Prefunding, funding, shortfall, true-up, default and incident events (on_prefunding_required, on_funding_required, on_shortfall, on_true_up_pending, on_default, on_incident) must have explicit handlers unless the generic on_event handler covers them; otherwise the event is never acknowledged, and Olive refuses the maker new entries while one is unacknowledged. The other margin events (bucket.refreshed, bucket.funded, bucket.settled, insurance.drawn, credit.breached) have optional handlers.

Two off-chain events report the routing gate:

Event Handler Gates entries Meaning
maker.routing_paused on_routing_paused no (the pause itself stops new entry requests) A bucket is short for 4h past its funding deadline (reason "funding_shortfall"), Pending with a gap ("settlement_shortfall") in an incident ("incident") or held after a cure while the maker is still deactivated ("maker_inactive"); an open set, treat an unknown reason as paused, with bucket, marketConfig, maturity, shortfallSince, deficit and pausedAt. Sent again if the reason changes. Fund it now (your code does that).
maker.routing_resumed on_routing_resumed no None of the buckets qualifies any more: covered, settled Solvent, or the incident cured or finalized (resumedAt). Never sent for a pause whose paused notification you did not receive.

Their typed payloads are RoutingPaused and RoutingResumed.

Six finalized chain events report custody incidents and parameter changes:

Event Handler Gates entries Meaning
bucket.incident on_incident (required) yes, until acknowledged The bucket's token account is frozen, or its live balance (available) is below its accounted obligation (obligation, equal to required). defaulted is always False; a default arrives as bucket.defaulted. The program deactivates the maker until the bucket is whole and a report cures it (bucket.cured).
bucket.default_finalized on_default_finalized no A Haircut bucket was fully redeemed and finalized (dustReturned, insuranceDrawn); any open incident on it is cleared.
facility.changed on_facility_changed no The facility's active flag or creditLimit changed; refresh cached credit headroom.
maker.status_changed on_maker_status_changed no The maker's on-chain active flag changed (previousActive to active).
market.risk_changed on_market_risk_changed no A market's margin parameters (risk) changed; refresh cached maker.capacity.
market.controls_changed on_market_controls_changed no A market's active flag, term bounds (minTermSeconds, maxTermSeconds) or notional limits changed.

All six carry transactionSignature, slot and occurredAtMs; the two bucket events also carry the bucket state fields. Their typed payloads are BucketIncident, BucketDefaultFinalized, FacilityChanged, MakerStatusChanged, MarketRiskChanged and MarketControlsChanged.

The local keypair in this quickstart is for laptop tests or a tightly controlled key-file deployment. Production remote/HSM integrations use CallbackMakerSigner and never pass private-key bytes to the maker process:

from olive_solana import CallbackMakerSigner, SignerContext


async def sign_with_remote_provider(
    digest: bytes,
    context: SignerContext,
) -> bytes:
    if len(digest) != 32:
        raise ValueError("expected a 32-byte Olive digest")
    signature = await remote_provider.sign_ed25519(
        key_id="olive-quote-signer",
        message=digest,
        audit_context={"purpose": context.purpose},
    )
    if len(signature) != 64:
        raise ValueError("expected a 64-byte Ed25519 signature")
    return signature


signer = CallbackMakerSigner(
    public_key="<remote Ed25519 public key in canonical base58>",
    callback=sign_with_remote_provider,
)

The callback signs the supplied raw 32-byte SHA-256(preimage) digest with ordinary Ed25519 and returns the raw 64-byte signature. Do not hash again, sign encoded text/the full preimage, or use Ed25519ph. The remote public key may be the finalized on-chain MakerConfig.quoteSigner.

An empty topic or product collection subscribes to everything authorized by maker.hello. Keep takeover_existing_session=False for ordinary starts; enable it only for an intentional failover.

After a silent network drop the gateway keeps your session until its lease lapses (about 90 seconds), so an immediate reconnect gets SESSION_ACTIVE. Since 1.2.1 a client that had a session of its own reports session_release_wait through on_status and retries for the lease plus 30 seconds from the moment it lost the connection; refusals past that, or on a first connect, still raise.

One session per asset

Since 1.3.0 every session owns an explicit set of assets: assets (1-32 unique lowercase topics) is required on ManagedMakerOptions, MakerWsClientOptions and MakerDoctorOptions (--assets / OLIVE_ASSETS on the CLI), and topics must be a subset. List every asset to quote them all in one session. There is no all-assets mode. The gateway fixes the claim for the session's whole life: maker.hello.assets lists it, and the client fails terminally if it differs from the request.

  • Run one process per asset, each with its own store. The assets are always part of the store scope, so replay and pending submissions are separate per asset set. 1.3.0 stores are not compatible with earlier ones: drain or discard an older store before upgrading.
  • SESSION_ACTIVE names the sessions in the way in conflicting_assets on the MakerWsRpcFailure (the terminal error's __cause__) and in the session_release_wait status. takeover_existing_session=True replaces every overlapping session (close 4001), only for the assets you claim. The restart wait of 1.2.1 works per asset session.
  • Credit, funding and the routing pause stay maker-wide: maker.capacity shows facility.reservedCredit across all sessions, while its other rows and maker.positions are filtered to the session's assets.
  • Stagger process starts by about one second. FORBIDDEN with session_limit reports maxSessionsPerMaker; asset_not_claimed means the session does not own the topic it used.

Onboard from a server

If your signing key lives on a server, one command takes a maker from Olive's invitation to a passing readiness check. Ask Olive's console for a server token (olv_onb_...), then:

export OLIVE_ONBOARDING_TOKEN=olv_onb_...   # or --token; the env var keeps it out of shell history
olive-maker-onboard --keypair ./maker.json --assets btc,sol

It proves the key is yours (it signs the plain-text ownership message Olive writes, with --keypair as the maker authority; nothing is a transaction), waits for Olive's approval, claims devnet test funds, approves an exit allowance (default: your USDC balance, or --exit-allowance <usdc>), writes olive.env (0600, in --out, default the current directory), runs the doctor and sends its report to Olive. Olive registers the maker with a temporary maker authority; 24 hours later rerun the same command with the maker authority's key and it takes the account over (accept_maker_authority, signed and paid by your key alone). Quoting works in between. Rerun it at any time: it reads the current state and continues; with only the 24 hour wait left it prints the time and exits 0. Before signing anything it checks the message text binds exactly your values (environment, program, maker config and id, the four roles, assets, not expired), and it checks every transaction semantically: exactly one SPL ApproveChecked from your USDC account to Olive's exit delegate, or exactly Olive's accept_maker_authority for your maker, your key the only signer and fee payer. Compute Budget instructions and a different blockhash are fine; anything else is refused and named. Other flags: --api-url, --products 0,1, --yes (skip the confirmation prompts, not the checks), --no-faucet, --rpc-url, --wait-timeout <seconds>, --json (one JSON object per line).

By default one key does everything. Two options change where money and quoting authority sit:

  • --premium-receiver-owner <wallet> pays premiums to that wallet's USDC account (any address, including an off-curve vault or multisig address). Olive creates the account when it registers the maker, the wallet never signs, and the message you sign names that wallet. Left out, premiums go to the funding authority.
  • Separate keys: --keypair stays the maker authority and signs the registration. Name the others with --quote-signer <pubkey> (the hot key on the quoting server) and --funding-authority <pubkey> (the custody wallet that holds the funds); the command checks the message names exactly those (with --quote-signer-keypair / --funding-keypair it also adds their signatures as extra proof). It cannot sign for keys it does not hold, so in separate mode:
    • the exit allowance is skipped with a pointer to the console's "Sign with another tool" panel, unless you pass --funding-keypair <path> (it must match the funding authority; refused otherwise);
    • the readiness check runs only with --quote-signer-keypair <path> (it must match the quote signer); otherwise the command prints what to run on the quoting server;
    • olive.env names --quote-signer-keypair as OLIVE_QUOTE_SIGNER_KEYPAIR when given; otherwise it keeps Olive's placeholder, which you point at the hot key file. It never names the maker authority key in separate mode;
    • the test faucet pays the funding authority, so it still works without its key.
olive-maker-onboard --keypair ./authority.json --assets btc,sol \
  --quote-signer <HOT_PUBKEY> --funding-authority <VAULT_PUBKEY> --premium-receiver-owner <VAULT_PUBKEY>

Rerunning a separate-key maker needs the same --quote-signer / --funding-authority flags.

Operational preflight

The doctor authenticates without subscribing, taking over a live maker, or submitting quotes. Its convenience CLI intentionally uses a local test keypair:

olive-maker-doctor --topics btc,sol --products 0,1 \
  --exit-sources "$OLIVE_EXIT_USDC_SOURCE"

olive-maker-doctor --json > maker-doctor.json

Connection and deployment values default from OLIVE_MAKER_WS_URL, OLIVE_MAKER_CONFIG, OLIVE_PROGRAM_ID, OLIVE_GENESIS_HASH, OLIVE_CHAIN_TAG, and OLIVE_QUOTE_SIGNER_KEYPAIR.

By default the doctor reads maker.capacity with scope all and reports credit_facility (limit, unfunded exposure and available credit; fail when breached, warning with no active credit), bucket_margin (requirement versus locked and prefunded per open bucket; fail with the default-eligible time when a shortfall is running, warning when a bucket still needs funding before its deadline), routing (fail while Olive has paused new entry requests) and true_up (fail while a settled bucket owes a true-up). The same checks are available as margin_checks(capacity, now_seconds). Pass --exit-only (exit_only=True) to read only the exit-payment scope.

Remote/HSM deployments MUST NOT export their private key to use the CLI. Call run_maker_doctor(MakerDoctorOptions(..., signer=signer, assets=["btc"])) programmatically with the same CallbackMakerSigner used by the managed maker, and retain report.to_dict() as the machine-readable preflight record.

Strike grid

Entry strikes sit on a fixed grid of round levels per market. The step depends on how far the strike is from the request's reference price (referencePriceE8):

Market within 5% 5% to 15% beyond 15%
BTC $1,000 $2,000 $5,000
SOL $1 $2 $5
GOLD / PAXG $25 $50 $100
SP500 / SPYX $5 $10 $10 (one tier beyond 5%)
  • Symbols are case-insensitive, and both the app names (GOLD, SP500) and the on-chain names (PAXG, SPYX) work.
  • Re-striking. If the price falls so far that the finest step is wider than 5% of spot, every step is divided by ten until it fits: SOL at $15 strikes on $0.10 / $0.20 / $0.50, BTC at $15,000 on $100 / $200 / $500.
  • Boundary tolerance. Near a tier boundary the API accepts a strike that is a multiple of either neighbouring tier's step, within 1 percentage point (STRIKE_GRID_SLACK_PCT). With BTC at $98,000, $103,000 is 5.1% out, where the step is $2,000, but it is accepted because it is within 1 point of the $1,000 tier.
  • A market without a configured grid gets one tier with a 1-2-5 step near 0.1% of spot.

The API rejects an off-grid entry RFQ (INVALID_STRIKE, reason strike_off_grid), so a maker should never receive one. The SDK lets you check anyway, with exact decimal arithmetic (no binary floats):

from olive_solana import (
    STRIKE_GRID_SLACK_PCT, entry_strike_grid_warning, grid_levels, grid_step,
    nearest_strike, on_grid, strike_grid_for,
)

grid = strike_grid_for("BTC", "112480")          # tuple of StrikeTier(within_pct, step)
on_grid(grid, "112480", "113000", STRIKE_GRID_SLACK_PCT)   # True
grid_step(grid, "112480", "130000")              # Decimal('5000')
nearest_strike(grid, 0, "112480")                # Decimal('113000'), call side
nearest_strike(grid, 1, "112480")                # Decimal('112000'), put side
grid_levels(grid, "112480", "100000", "125000")  # every level in the range

entry_strike_grid_warning(rfq.request)           # None when on grid, else a message

Prices can be Decimal, int, str, Fraction or (converted through their decimal text) float. entry_strike_grid_warning reads underlyingSymbol, strikeE8 and referencePriceE8 and judges the strike exactly as the API does. The grid matches the TypeScript SDK; schemas/strike-grid.golden.json holds the shared test vectors.

Conformance runs can pass the entry requests they received as run_maker_conformance_suite(..., observed_entry_requests=[...]). Any off-grid request is listed as a [WARN] line under entry_quoting; it does not fail the report, because it points at a gateway or fixture problem, not at the maker.

Wire types and schema

The complete required/optional DTO catalog is published at maker-websocket-v2.schema.json and included in the wheel at olive_solana/schemas/maker-websocket-v2.schema.json. Python exports typed RFQ, quote, selected, filled, decline, and error/result shapes from olive_solana. Missing required fields fail before maker callbacks run; unknown additive server fields are preserved, while outbound quotes remain strict. The normative semantics and signing preimages are in the Maker WebSocket API v2.

Reliability contract

  • Wire integers remain canonical decimal strings.
  • Entry nonces are durable; V6 exit quotes have no wire nonce and are replay-safe because a successful exit closes the bound position.
  • Complete quote, digest, and signature are committed before submission.
  • Restart retries only the exact stored quote and signature.
  • Durable events are stored before event.ack; local handler completion is persisted independently.
  • quote.selected and exit_quote.selected are not fills. Only finalized trade.filled and exit.filled are canonical execution signals.
  • Signatures and private signer data are never included in SDK status events.

The low-level MakerWsClient remains available for makers requiring custom orchestration. Releases must pass the shared fixture/digest suite and all fail-closed maker conformance scenarios.

Development

python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/ruff check .
.venv/bin/mypy src
.venv/bin/pytest
.venv/bin/python -m build

Release

PyPI releases use trusted publishing from .github/workflows/publish-python-sdk.yml; no long-lived API token is stored in GitHub. Configure the PyPI publisher for repository macols77/olive, workflow publish-python-sdk.yml, and environment pypi, and protect the pypi environment with required reviewers.

Pushing a python-sdk-v<pyproject version> tag only builds and verifies; it never uploads. The build job:

  • requires the tag's commit to be on origin/main (merge first, then tag the merged commit);
  • when a coordinated_tag (solana-sdk-v*) is given, requires it to point at the same commit, and otherwise warns with the TypeScript tags found on that commit;
  • requires the SDK's program id to equal the program's declare_id! and to be live (executable) on devnet;
  • requires the tag to equal python-sdk-v<pyproject version>;
  • runs ruff, mypy and pytest, builds and twine checks the wheel and sdist, and reruns the tests against the built wheel in a clean environment.

To publish, run the workflow manually (Run workflow) with release_tag set to the existing tag, publish typed as PUBLISH, and coordinated_tag set to the sibling TypeScript tag for a coordinated release. The publish job then waits for the pypi environment's reviewers and uploads both distributions. The same dispatch retries a failed release.

Upgrading from 0.x

  • The program is V12. Entry quotes sign under OLIVE_ENTRY_QUOTE_V12 (0.4.x had separate ..._CREDIT_ENTRY_QUOTE_V11 and ..._JIT_ENTRY_QUOTE_V11 domains); exit quotes stay OLIVE_EXIT_QUOTE_V6.
  • The WebSocket is /maker/v3/ws with protocolVersion 3.0 (was /maker/v1/ws, 1.0). The server refuses 0.x clients.
  • maker.capacity rows are topic, product, marketConfig, available, unavailableReasons and projectionSlot: collateralMode, facility, fundingMandate, collateralSource, sourceSlot, availableForNewQuotes and the JIT limits are gone, and there is no unavailableRoutes. With scope all the result adds facility, margin, markets and buckets; size with capacity_entry_route or capacity_max_size instead of availableForNewQuotes.
  • Bucket objects and bucket events carry index (0 to 7), and bucket_address takes it as a required argument. Do not assume one bucket per market and maturity.
  • Bucket slots report addon (the slot's time-value add-on), not a per-slot requirement; the bucket's required is the netted total.
  • Entry strikes are on the strike grid; see "Strike grid".
  • Remove entry_collateral_modes and the collateral_mode= argument of rfq.quote(...); the jit_funding module and its mandate helpers are gone.
  • Entry RFQs carry strikeNotionalUsdc instead of expectedMaxPayout and no underlyingMint; exit RFQs and positions carry strikeNotional instead of maxPayout, and exit RFQs name their bucket. Positions report marginStatus and a bucket with phase, required, locked, prefunded, unfunded and shortfallSince.
  • trade.filled, exit.filled, position.redeemed and position.expired report the V12 program events (bucket requirement and facility exposure, released notional, gross payout and haircut phase).
  • Implement on_incident (or on_event): bucket.incident is a money-at-risk event, and an unhandled one is never acknowledged and blocks new entries. The five informational events (bucket.default_finalized, facility.changed, maker.status_changed, market.risk_changed, market.controls_changed) have optional handlers.
  • PostgreSQL stores keep schema version 2. Quotes signed before the V12 program do not verify: start a fresh store for the V12 deployment.

Metadata

Release files for olive-solana-sdk 1.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for olive-solana-sdk 1.3.2
File Size Uploaded
olive_solana_sdk-1.3.2.tar.gz 325.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for olive-solana-sdk 1.3.2
File Interpreter ABI Platform
olive_solana_sdk-1.3.2-py3-none-any.whl Python 3 none any Details

Total release size: 610.3 kB

Release files / olive_solana_sdk-1.3.2.tar.gz

Download URL olive_solana_sdk-1.3.2.tar.gz
Size 325.0 kB
Tags Source
SHA-256 checksum
How to use checksums
001acceec013be58dfdcb8ffade571b60e06e9f3a9ff6dcf71376e411584c277
BLAKE2b-256 checksum
How to use checksums
bd463a986fbf6b380066fcbca58ff769b4a24b9e42057533380bca8edff5770f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / olive_solana_sdk-1.3.2-py3-none-any.whl

Download URL olive_solana_sdk-1.3.2-py3-none-any.whl
Size 285.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b8448d40ea17c736782d125b35d36304d488085c0a9d95c602a9b4da7ba56435
BLAKE2b-256 checksum
How to use checksums
5f9798be7f39311dbac59ab03aff0cfccd2c4a9f57777da327aa3ea8f4713c8f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

3.1.0

2 release files

3.0.0

2 release files

2.0.0

2 release files

This release

1.3.2 This release

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page