Developers
Run it locally
Clone, build, test, and point at devnet.
- Install
Node 22 and pnpm 10, then
pnpm install. - Start the app
NEXT_PUBLIC_DEV_WALLET=1 pnpm devon localhost:3000, against devnet. - Build the programs
pnpm build:programs, thencargo test --workspace. - Check
Build the app, run tsc, eslint and the tests; run the keeper once with
--dry-run. - What you will have
The app running locally with a dev wallet, all programs built and tested, and the same devnet deployment to check against.
Requirements
- Node 22 (Next.js 16 needs 20.9 or newer) and pnpm 10.
- For the programs: Rust 1.91.1 (pinned by
rust-toolchain.toml), Anchor 0.31.1, and Solana platform tools v1.54, which the build script requests. - For the contracts: Foundry.
The app
pnpm install
NEXT_PUBLIC_DEV_WALLET=1 pnpm dev # http://localhost:3000, with a dev-only local walletEvery RPC defaults to https://rpc.magicblock.app/devnet, so no configuration is needed. To use your own endpoints, create app/.env.local with only the variables you set (app/.env.example lists them) and leave unset variables out: an empty value overrides the default.
| Variable | Side | Purpose |
|---|---|---|
NEXT_PUBLIC_SOLANA_RPC | browser | Single-account reads, sends and confirmations. Ships to the browser: use a domain-restricted key. |
TESORO_BASE_RPC | server | Reads and sends in API routes. |
TESORO_GPA_RPC | server | getProgramAccounts list queries behind /api/chain/accounts. |
NEXT_PUBLIC_DEV_WALLET=1 | browser | Dev-only local wallet instead of Privy. Compiled out of production builds. |
NEXT_PUBLIC_PRIVY_APP_ID | browser | Privy sign-in. Without it the app runs signed out. |
TESORO_RELAYER_* | server | Low-balance relayer keys for the demo funding routes. Without them those routes answer 503. |
With the dev wallet on, ?dev=<name> (for example /lobby?dev=alice) picks a named wallet, so two browser windows can be two Accounts that play each other. In the Wallet, “Get test simSOL” then “Open a Position”; in the Lobby, pick an entry and Play now.
Checks
pnpm build:app # production build; also generates Next's route types
pnpm --filter @tesoro/app exec tsc --noEmit # run after build:app or `next typegen`
pnpm --filter @tesoro/app exec eslint src
pnpm --filter @tesoro/app test # vitestPrograms
export TMPDIR=$HOME/.cache/tesoro-tmp # /tmp is a small shared tmpfs on some machines
pnpm build:programs # Anchor 0.31.1 with platform tools v1.54 (plain `anchor build` fails)
cargo test --workspace # ledger property tests and LiteSVM integration testsThe bridge is its own Anchor workspace because of its LayerZero git dependency: cd bridge && anchor build --no-idl -- --tools-version v1.54. Program IDs are fixed by declare_id! and deploy keypairs that are not in the repository, so a local build produces the same programs but cannot be deployed over these IDs.
Contracts
pnpm build:contracts # forge build
pnpm test:contracts # forge testDeploy scripts: contracts/script/deploy-oapp.sh <hoodi|hyperevm> <sim|wsteth> and contracts/script/oapp.sh. Bridge wiring: pnpm lz wire … in bridge/.
Keeper
pnpm --filter @tesoro/keeper start --once --dry-run # one pass that prints what it would do, sends nothing
pnpm --filter @tesoro/keeper start # loop every 20 s
pnpm --filter @tesoro/keeper testThe keeper uses a payer at ~/.config/tesoro/keeper.json, created on first run and never funded by itself. At startup it checks the genesis hash of its RPCs and refuses to run unless they are Solana devnet. Some jobs need keys only the team holds: the oracle key signs set_price and the EVM key sends reportYield; without them the other jobs still run. Every job is permissionless on chain, so anyone can send the same transactions. Jobs, flags and limits: keeper/README.md.
Where to start reading
CONTEXT.md: the domain language, used verbatim in code and copy.docs/adr/: the five decisions that bind the build.docs/tesoro-core.md,docs/games/,docs/cross-chain.md,docs/yield-model.md,docs/deployments.md.