Rust SDK for MineBTC, the Solana country-warfare game. It
decodes live round and cycle state, derives PDAs, and builds betting, claim,
stake, and marketplace transactions — straight from RPC, with no MineBTC
backend, GraphQL, or socket. The low-level client is generated from the on-chain
IDLs with Codama
(renderRustVisitor); ergonomic wrappers sit on top.
[dependencies]
minebtc-sdk = "0.1"The crate is named minebtc-sdk; the library is imported as minebtc_sdk.
use minebtc_sdk::{BetSelection, MinebtcClient, SendTxOptions};
let client = MinebtcClient::new("https://your-rpc-endpoint");
// Read the current round's pools.
let pools = client.reads().get_country_pools(None)?;
println!("active countries: {:?}", pools.active_faction_ids);
// Build and send a bet (signer is any solana-signer Signers, e.g. a Keypair).
let ixs = client.writes().place_bet(
&[BetSelection { faction_id: 0, direction: 2 }], // USA, Up
100_000, // lamports per position
&signer.pubkey(),
None, None, None,
)?;
let sig = client.send(&signer.pubkey(), &ixs, &[&signer], &SendTxOptions::default())?;// Mainnet config (program ids, mints, collection, fee recipients,
// marketplace PDA) is pinned. Bring your own RPC URL.
let client = MinebtcClient::new("https://your-rpc-endpoint");
// Public Solana Labs endpoint — rate-limited, fine for a smoke test.
let client = MinebtcClient::public_mainnet();
// Devnet (or any non-mainnet): program ids are identical, so supply the
// chain-specific addresses via an explicit NetworkConfig.
let client = MinebtcClient::with_config("https://api.devnet.solana.com", devnet_config);- RPC. Bring your own URL. The public Solana Labs endpoint is available via
public_mainnet()— fine for a smoke test, rate-limited for anything real. - Network. Only mainnet values are pinned. Program ids are identical across
networks; for devnet pass a
NetworkConfigwith the chain-specific addresses. - Keypair. The SDK signs nothing on its own — write builders return unsigned
Vec<Instruction>. You supply the signers (see the examples for loading one from a Solana CLI keypair). - Commitment is
confirmedeverywhere, matching the on-chain cranker. - Features. The
fetchfeature (on by default) pulls insolana-rpc-clientfor the read layer andclient.send. Disable default features for a pure no-RPC build that only derives PDAs and builds instructions.
Each returns a decoded DecodedAccount<T> (or a derived view).
| Method | Returns |
|---|---|
get_global_state() |
GlobalGameSate — round id, duration, jackpot pot |
get_global_config() |
GlobalConfig — fee config, tuning |
get_mining() |
DegenBtcMining — dBTC per round, LP op count, prices |
get_round(round_id) |
GameSession — boards, totals, result; None = current |
get_country_pools(round_id) |
per-country×direction {points, wgtd_points, sol, active} view |
get_faction_state(id) |
one FactionState (name-keyed PDA) |
get_factions() |
all 12 FactionState, indexed by faction id |
get_cycle_config() |
FactionWarConfig — war id, cutoff round, multipliers |
get_cycle_state(war_id) |
FactionWarState — scores, round wins, MVP; None = current |
get_cycle_settlement(war_id) |
FactionWarSettlement — final ranks |
get_rankings(war_id) |
current standings sorted by score (the public leaderboard) |
get_player(wallet) |
PlayerData |
get_pending_claims(wallet) |
pending round + cycle claim counts |
get_user_game_bet(wallet, round_id) |
UserGameBet |
get_user_cycle_bets(wallet, war_id) |
UserFactionWarBets |
get_autominer(wallet) |
AutominerVault |
get_stake_position(w, idx, type) |
StakedPosition (dBTC / LP) |
get_hashbeast(asset) |
HashBeastMetadata |
Each returns an unsigned Vec<Instruction> (compute-budget, ATA/WSOL pre-ix, and
the program ix in order). Sign and send yourself, or pass to client.send.
Vectors let you batch — e.g. several claim_round_rewards in one transaction.
| Method | Instruction |
|---|---|
place_bet(bets, amount_per_bet, …) |
join_bets (+ WSOL unwrap) |
claim_round(round_id, wallet, caller) |
claim_round_rewards |
claim_rounds_batch(round_ids, wallet, caller) |
batched claim_round_rewards (1.4M CU) |
claim_autominer(round_id, owner, caller) |
claim_autominer_rewards |
claim_cycle(war_id, wallet, cranker) |
claim_war_rewards |
stake_dbtc / unstake_dbtc |
stake_degenbtc / unstake_degenbtc (Token-2022) |
stake_lp / unstake_lp |
stake_lp_tokens / unstake_lp_tokens (classic SPL) |
claim_staking_rewards / withdraw_dbtc_rewards |
claim_staking_rewards / withdraw_dbtc_rewards |
lock_for_gameplay / request_unlock / withdraw_gameplay |
HashBeast gameplay lock / unlock |
init_player / claim_referral |
initialize_player / claim_referral_rewards |
market_buy / market_list / market_cancel / market_update_price |
marketplace CPI wrappers |
The builders fold in correctness work the IDL can't express, each verified
against the production frontend: exact IDL account order; the required
UserFactionWarBetCloseState remaining account on claims, with user_bet_rent_payer
read from the on-chain close-state; CU bumps on heavy claims; mpl-core (not SPL)
on HashBeast and marketplace ix; Token-2022 dBTC vs classic-SPL LP ATAs with
idempotent creation; native-SOL bets that unwrap WSOL first; the optional
referrer and gameplay-HashBeast accounts.
Unlike the TypeScript SDK's async builders, the Codama Rust client takes every account explicitly, so the wrappers derive every PDA for you and read the few on-chain values (current ids, home faction, close-state rent payers, listing price) needed to assemble a correct account list.
PDA helpers (derive_global_game_state, derive_faction_state,
derive_game_session, derive_stake_position, …), SPL helpers (derive_ata,
create_dbtc_ata_idempotent, …), and the send path (send_transaction,
build_signed_transaction, clamp_priority_fee) are exported from the crate
root. The raw Codama client lives under minebtc_sdk::generated for anything the
wrappers don't cover.
The generated client is plain Borsh + the split Solana crates, so it works in
both off-chain tooling and on-chain programs. The account names and orders match
the IDL exactly; the per-instruction *Cpi structs (e.g. JoinBetsCpi) are
generated for CPI from another program.
In examples/. RPC and keypair come from env (RPC_URL,
KEYPAIR_PATH); nothing is hardcoded.
read_state— connect and print global state, factions, and the current round's pools.place_bet— build and send one bet from the env keypair.auto_claimer— self-scan a wallet's unclaimed rounds and batchclaim_round_rewards(permissionless cranker).
RPC_URL=https://your-rpc cargo run --example read_stateThe generated client under src/generated/ is committed and reproducible from
the vendored IDLs — never hand-edit it; change the IDL or codegen and regenerate.
When the contract changes, copy the new IDL into idl/, run the codegen, and
update any wrapper whose account list or args changed.
./scripts/codegen.sh && git diff --exit-code src/generated # no codegen drift
cargo build
cargo clippy --all-targets -- -D warnings
cargo testCI runs the same checks.
- Play: minebtc.fun
- Engine and programs:
LifeOrDream/MineBtc-fi—minebtc1eotiTH2UxCpPMmtzUDGqf1b8dwM7AMKb8a2Tio51an,degenbtc_marketBCuofnvb7QUP6xLH83EEbKFNjxz5T5Jp4xLqfEdURYRg - This SDK:
LifeOrDream/minebtc-rust-sdk - TypeScript SDK:
LifeOrDream/minebtc-ts-sdk
MIT — see LICENSE.