From clone to first solve
Sarpoy is open source and runs locally. Clone the monorepo, bring up the backend and UI, connect a wallet, and either escrow a puzzle pot as a creator or chase one as a solver.
- 1
Clone the monorepo
git clone https://github.com/cryptuon/sarpoy — the FastAPI backend, Nuxt UI, and Anchor program all live in one tree.
- 2
Run the backend and UI
Start the FastAPI service (SQLite + Aerich migrations in dev) and the Nuxt 3 SPA. Sample bot data ships with the backend, so the UI is clickable without a live cluster.
- 3
Connect a Solana wallet
Open the UI and connect any standard wallet adapter — Phantom, Solflare, or Backpack. Auth is a nonce you sign; no passwords or signups.
- 4
Create a bot or solve one
As a creator, escrow a pot with initialize_bot and set the fee curve. As a solver, buy clues with send_message and win the pot with submit_solution.
Escrow a pot and open the arena
One instruction locks the pot in the treasury PDA and sets the rising fee curve.
from sarpoy_client import SarpoyClient, LAMPORTS_PER_SOL
client = SarpoyClient(rpc_url, creator_keypair)
# 1. Escrow a 5 SOL pot and set the rising fee curve
bot = await client.initialize_bot(
bot_id="riddle-of-the-treasury",
objective_hash=hash_secret("the seed is 'treasury'"),
initial_pot=5 * LAMPORTS_PER_SOL,
base_cost=int(0.01 * LAMPORTS_PER_SOL), # first message
cost_multiplier=int(0.002 * LAMPORTS_PER_SOL), # +per message
)
print("Treasury PDA:", bot.treasury_pda) Buy clues and claim the pot
Authenticate with a signed nonce, probe the bot at the current fee, then submit your answer.
from sarpoy_client import SarpoyClient
client = SarpoyClient(rpc_url, solver_keypair)
# 1. Authenticate: sign the server nonce -> short-lived JWT
nonce = await client.request_nonce()
await client.login(sign(nonce, solver_keypair))
# 2. Buy clues — each call costs more than the last
reply = await client.send_message("riddle-of-the-treasury",
"Is the seed a keyword?")
# 3. Submit the answer — settles the pot on success
sig = await client.submit_solution("riddle-of-the-treasury",
"treasury")
print("Payout tx:", sig)