Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

kashdao-protocol-sdk (Python)

Official non-custodial Python SDK for the Kash prediction-market protocol on Solana — for trading bots, market makers, AI agents and integrations written in Python.

PyPI version Python versions License: MIT CI mypy: strict Ruff

Status: 0.3.0b2 (beta). Solana-only. Every Kash market is on Solana mainnet-beta, which is the default cluster; devnet is supported. 0.3.0 removed the Base (EVM) clients. If you still hold a position on Base, redeem it with the last EVM-capable release: pip install 'kashdao-protocol-sdk==0.2.0b2'. See the CHANGELOG for the upgrade notes.

Supported clusters

Cluster Identifier Status
Solana mainnet-beta mainnet-beta ✅ Live — the default for create_solana_client
Solana devnet devnet ✅ Live
Custom Solana cluster any ✅ Via cluster=CustomSolanaDeployment(program_id=..., usdc_mint=...) (local validator)

When to use this package

You are… Use
A trader, market maker or agent who signs its own Solana transactions This package — create_solana_client
A research / data-science user reading markets and quotes from a notebook This package — reads and quotes need no signer
A TypeScript / web developer @kashdao/protocol-sdk (TS), same surface in camelCase
Anyone who wants Kash's REST API (no RPC, no transaction building) @kashdao/sdk (REST)

Install

pip install kashdao-protocol-sdk

Requires Python ≥ 3.10. End-user installs touch only the public PyPI registry — no private repos, no auth tokens. Dependencies: solders (keys, instructions, versioned transactions), httpx (the RPC transport is plain JSON-RPC) and pydantic.

pip install 'kashdao-protocol-sdk[solana]' still works: the [solana] extra is kept, empty, so install lines written for 0.2.x resolve without a warning. It adds nothing — Solana is the base install.

Quickstart

The Kash market program on Solana, non-custodially: bring an RPC URL (or any SolanaConnection) and a signer. Mainnet-beta is the default cluster — program Jr8Bd8efPfNYHW65vZrVzeLbYkzy1oo3QB3i8cYdDcy, USDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v — and devnet is supported. Mirrors @kashdao/protocol-sdk (TypeScript) with snake_case names.

import asyncio
import os

from solders.keypair import Keypair

from kashdao_protocol_sdk import (
    KashSimulationRevertedError,
    KashValidationError,
    create_solana_client,
    keypair_signer,
)


async def main() -> None:
    signer = keypair_signer(Keypair.from_base58_string(os.environ["SOLANA_SECRET_KEY"]))
    async with create_solana_client(rpc_url=os.environ["SOLANA_RPC_URL"]) as kash:
        # Read a market (by numeric id or by its account address).
        market = await kash.markets.get(12)
        print(market.status, market.probabilities_wad)

        # Exact quote — the program's own integer curve.
        quote = await kash.markets.quote_buy(market=12, outcome=0, amount_usdc=5_000_000)
        print(quote.tokens_out_wad)

        # Build, sign, send and confirm in one call. A slippage bound is mandatory.
        try:
            result = await kash.trades.buy(
                market=12,
                outcome=0,
                amount_usdc=5_000_000,  # 5 USDC, atomic (6dp)
                max_slippage_bps=100,
                signer=signer,
            )
            print(result.signature, result.plan.min_tokens_out_wad)
        except KashValidationError as e:
            print(f"refused before signing: {e} ({e.program_error})")
        except KashSimulationRevertedError as e:
            print(f"preflight refused: {e.context}")


asyncio.run(main())
Method What it does
markets.get(ref) Decoded market + collateral, status (active/frozen/resolved/cancelled), prices, probabilities
markets.quote_buy / quote_sell / quote_redeem Exact quotes; refusals carry the program's error name on KashValidationError.program_error
account.position / positions / usdc_balance Positions are u128 WAD balances in a program account — not SPL tokens
protocol.config / template / templates Program config (protocol fee, pause) and creation templates
trades.build_buy / build_sell / build_redeem / build_redeem_cancelled / build_open_position / build_close_position A plan: solders Instructions plus the bounds it encodes
trades.simulate(plan, payer=...) / trades.send(plan, signer=...) Simulate unsigned, or sign → send → confirm
trades.buy / sell / redeem / redeem_cancelled / open_position / close_position Build + send in one call, the signer as trader
  • Slippage is mandatory. Every buy, sell and redeem takes exactly one of an explicit floor (min_tokens_out_wad / min_amount_out_usdc; 0 accepts anything) or max_slippage_bps below a fresh quote. Neither, or both, is a KashConfigError (INVALID_SLIPPAGE).
  • Signers. keypair_signer(keypair) for bots and scripts. Anything with a pubkey and an async sign_message(message) -> Signature satisfies SolanaSigner (a KMS, an HSM, a remote signer). Pass fee_payer= to send to sponsor fees from a second signer.
  • Amounts. USDC is an atomic int (6 decimals). Outcome balances are a WAD int (18 decimals) — the program stores each position as a u128, so 18 decimals is the native scale on Solana too.
  • Sell fee. Each market charges its own sell_fee_bps (on SolanaMarket), and quotes and slippage floors use it.
  • First buy. The program requires a position account before buy; build_buy opens it in the same transaction when the receiver has none.
  • Refused before signing. build_buy/build_sell raise KashValidationError (with the program's error name on program_error) when the program is paused (Paused), the market is not active (InvalidState) or frozen, or — for buys only — the market is halted (HaltedEntries; a holder can still sell). A market whose collateral account is missing or not the cluster's USDC is an error, never a zero balance. The instruction builders (buy_instruction, …) apply none of these checks.
  • Closing a position refunds its rent to whoever funded it: plan.rent_recipient, which can differ from the owner who signs.
  • Errors — see Error handling. Every error raised after signing carries context["signature"], computed before the transaction is sent. Sending distinguishes:
    • a preflight revert (KashSimulationRevertedError) and a send the RPC refused BEFORE forwarding it (TX_SEND_FAILED, retryable: JSON-RPC -32003, -32602, or a -32002 preflight with BlockhashNotFound) — neither landed. A preflight reporting AlreadyProcessed means the transaction is already on chain; the SDK goes on to confirm it;
    • KashTransactionExpiredError (TX_EXPIRED, retryable): the blockhash expired and a status read from a node at or after the slot where the expiry was observed found no trace of the signature, so it did not land — rebuild with a fresh quote and resend;
    • TX_REVERTED: it landed and failed on chain;
    • KashTransactionOutcomeUnknownError (WAIT_RECEIPT_FAILED, not retryable, carries .signature): any other outcome — a timeout, a reset, any HTTP error status (429 included), an unreadable body, any other JSON-RPC code (-32603, -32005, vendor codes), or an unreadable confirmation. The transaction may have landed: look the signature up before doing anything else; rebuilding takes a fresh blockhash, which makes a new transaction, and sending both can double the trade.
  • Other deployments. create_solana_client(cluster="devnet", rpc_url=...), or cluster=CustomSolanaDeployment(program_id=..., usdc_mint=...) for a local validator. Instructions always name the cluster's program id, never the IDL's embedded canonical id.
  • kash_groups is not exposed by this SDK.

Runnable examples: examples/solana/.

Error handling

Every error inherits from KashProtocolError and carries a stable code (ErrorCode.*), structured context, plus is_retryable / is_operational flags. Mirrors the TypeScript @kashdao/protocol-sdk hierarchy — same class names, same string-valued codes.

Class Raised when
KashConfigError Bad configuration or arguments (INVALID_CONFIG, UNSUPPORTED_CHAIN, INVALID_SLIPPAGE). Fix code
KashValidationError A value the program would refuse; program_error names the program's own error when it applies
KashChainError An RPC read failed, or the transaction landed and failed (TX_REVERTED). May be retryable
KashTransactionExpiredError TX_EXPIRED: provably did not land — rebuild with a fresh quote and resend (a KashChainError)
KashTransactionOutcomeUnknownError WAIT_RECEIPT_FAILED: may have landed — look up .signature first (a KashChainError)
KashSimulationRevertedError The RPC's preflight refused the transaction; nothing was sent
KashSignerError The signer raised. Never retryable
from kashdao_protocol_sdk import (
    KashChainError,
    KashConfigError,
    KashProtocolError,
    KashSignerError,
    KashSimulationRevertedError,
    KashTransactionExpiredError,
    KashTransactionOutcomeUnknownError,
    KashValidationError,
)

try:
    result = await kash.trades.buy(
        market=12, outcome=0, amount_usdc=5_000_000, max_slippage_bps=100, signer=signer
    )
except KashTransactionOutcomeUnknownError as e:
    # The transaction MAY have landed. Never resend blindly: look it up first.
    print(f"check {e.signature} before doing anything else")
except KashTransactionExpiredError:
    ...  # did not land: rebuild with a fresh quote and resend
except (KashValidationError, KashSimulationRevertedError) as e:
    print(f"refused, nothing sent: {e}")
except KashSignerError:
    raise  # never retry a signer failure
except KashChainError as e:
    if e.is_retryable:
        ...  # back off and retry
except KashConfigError:
    raise  # misconfiguration — fix the code

KashProtocolError.is_(value) is a cross-version identity check (a brand attribute), for errors that crossed a boundary where isinstance cannot be trusted.

What this SDK deliberately does NOT do

  • Kash-orchestrated trade routing. No Kash backend on the trade path. If you want a REST surface that wraps the Kash public API, use @kashdao/sdk.
  • Hold or generate keys. Bring your own signer (a solders Keypair, a KMS, an HSM, a remote signer).
  • Auto-retry a send. A send whose outcome is unknown is never retried: resending can double a trade. Reads raise retryable errors and leave the retry policy to you.
  • Telemetry. Zero phone-home. The SDK never reaches Kash infrastructure; it talks only to the RPC you give it.

Public surface

Everything is importable from kashdao_protocol_sdk. The implementation lives in kashdao_protocol_sdk.solana, which exports the same names (the 0.2.x import path, so from kashdao_protocol_sdk.solana import … keeps working). Groups:

  • Client: create_solana_client → SolanaClient with markets, account, protocol and trades
  • Clusters: SOLANA_CLUSTERS, DEFAULT_SOLANA_CLUSTER, SOLANA_PROGRAM_IDENTITIES, get_solana_deployment, CustomSolanaDeployment
  • Connection: SolanaConnection (Protocol), SolanaRpcConnection (the httpx JSON-RPC implementation)
  • Signers: SolanaSigner (Protocol), keypair_signer / KeypairSigner
  • Instruction builders (no checks applied): buy_instruction, sell_instruction, redeem_instruction, open_position_instruction, close_position_instruction, ensure_usdc_ata_instruction; PDAs via kash_market_pdas
  • Transactions: SolanaComputeBudget, SolanaSendResult, SolanaSimulationResult, decode_program_error
  • Errors: ErrorCode and the classes in Error handling

Architectural boundary

This is a non-custodial library. Consumers bring their own RPC URL and their own signer. Kash never sees a private key, never relays a transaction, never pays fees, and is never on the trade path. The library reads accounts, builds instructions and the unsigned transaction, and forwards the signed transaction to the consumer's RPC.

Source repository

This repository is the canonical public source. PyPI releases are published from tags here via OIDC trusted publishing (.github/workflows/publish-pypi.yml).

The kash_market IDL under kashdao_protocol_sdk/solana/_vendor/ is vendored at release time and shipped in the wheel; runtime loading goes through importlib.resources, so consumers need no post-install fetch step.

See RELEASING.md for the full release runbook, CONTRIBUTING.md for the contributor workflow, and SECURITY.md for the vulnerability-disclosure policy.

License

MIT. The artifact published to PyPI is MIT-licensed; the development repo is private but the published library carries no usage restrictions.

Metadata

Release files for kashdao-protocol-sdk 0.3.0b2

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

Source distribution (sdist)

Source distribution for kashdao-protocol-sdk 0.3.0b2
File Size Uploaded Provenance
kashdao_protocol_sdk-0.3.0b2.tar.gz 146.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for kashdao-protocol-sdk 0.3.0b2
File Interpreter ABI Platform
kashdao_protocol_sdk-0.3.0b2-py3-none-any.whl Python 3 none any Details

Total release size: 214.0 kB

Release files / kashdao_protocol_sdk-0.3.0b2.tar.gz

Download URL kashdao_protocol_sdk-0.3.0b2.tar.gz
Size 146.6 kB
Tags Source
SHA-256 checksum
How to use checksums
1de7ec50cb9d854f3ff7953f0a5479ca3e6d9977ee0827009962a00dc7b56322
BLAKE2b-256 checksum
How to use checksums
edfec93c96ee617f4939c97b1846a351b394e4f093686efcb2a51bb09a8d5fce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / kashdao_protocol_sdk-0.3.0b2-py3-none-any.whl

Download URL kashdao_protocol_sdk-0.3.0b2-py3-none-any.whl
Size 67.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9231e294cbec566a585f3029403183beddba071d676bff76e99fc5e5d762ef9f
BLAKE2b-256 checksum
How to use checksums
7767eed5e97214671079d540c891ac9db5daa9ec163b58851ea36c9c1df85f8d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Security for kashdao-protocol-sdk 0.3.0b2

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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