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.
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;0accepts anything) ormax_slippage_bpsbelow a fresh quote. Neither, or both, is aKashConfigError(INVALID_SLIPPAGE). - Signers.
keypair_signer(keypair)for bots and scripts. Anything with apubkeyand an asyncsign_message(message) -> SignaturesatisfiesSolanaSigner(a KMS, an HSM, a remote signer). Passfee_payer=tosendto sponsor fees from a second signer. - Amounts. USDC is an atomic
int(6 decimals). Outcome balances are a WADint(18 decimals) — the program stores each position as au128, so 18 decimals is the native scale on Solana too. - Sell fee. Each market charges its own
sell_fee_bps(onSolanaMarket), and quotes and slippage floors use it. - First buy. The program requires a position account before
buy;build_buyopens it in the same transaction when the receiver has none. - Refused before signing.
build_buy/build_sellraiseKashValidationError(with the program's error name onprogram_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 withBlockhashNotFound) — neither landed. A preflight reportingAlreadyProcessedmeans 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.
- a preflight revert (
- Other deployments.
create_solana_client(cluster="devnet", rpc_url=...), orcluster=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_groupsis 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→SolanaClientwithmarkets,account,protocolandtrades - 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 viakash_market_pdas - Transactions:
SolanaComputeBudget,SolanaSendResult,SolanaSimulationResult,decode_program_error - Errors:
ErrorCodeand 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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| kashdao_protocol_sdk-0.3.0b2.tar.gz | 146.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.