# Orb Trading Sprint

> Current status reviewed September 29, 2026. See [the release index](README.md) for shipped versus planned features, network, wallet signing and deployment boundaries. Older dated experiments below are retained as history.

Trading Sprint is a three-minute multiplayer **market game**, available in Arena and Markets. Up to 24 wallets start with 10,000 nontransferable game credits. Players buy and sell SPARK against a shared constant-product pool; transactions change the price for everyone. Credits and SPARK are internal contract balances, not ERC-20 tokens, deposits, or redeemable assets. Only testnet gas is paid. Public lobbies use one entry per wallet; this is not Sybil resistance or verified community membership.

## Rules and execution

- Monad testnet 10143 only, enforced in the contract constructor, reader and transaction path.
- A host creates a round. At least two players must join before the host starts it. Joining closes at the start; the round lasts 180 seconds.
- Market orders cap input at 2,500 game units and charge a 0.3% in-game pool fee. The UI uses 0.5% output tolerance and a 20-second deadline. No margin, leverage, deposits, token allowances, withdrawals or cash prizes.
- One conditional order per player. It has direction, trigger, input, minimum output and expiry. While active it blocks that player's manual trades. Cancelling releases the balance; a replacement order undergoes fresh balance checks.
- Anyone can submit a batch of up to 24 conditional orders. The contract rechecks the price after every fill; expired, untriggered, duplicate, underfunded or slippage-blocked orders skip. An unmet order is never a guaranteed fill.
- The score is cash plus SPARK valued at a common hypothetical aggregate liquidation price: `cash + tokens * poolCash / initialPoolTokens`. Pool and player token supply is conserved. All scores freeze when the round ends. This avoids marking all positions at the marginal spot price; it is a game scoring convention, not a redeemable claim or real investment return. No onchain NFT prize is minted in this mode.
- The last 32 fills and all standings are returned in one contract snapshot. Orb shares concurrent snapshot reads between viewers with a one-second cache. The UI pauses hidden-tab polling and disables trades after read errors or stale blocks. Quotes are exact integer arithmetic. Display refresh is not proof of network TPS, finality or guaranteed execution latency.

## Wallet UX

The selected wallet is the separate Privy embedded Orb Wallet; external login wallets are not fallback signers. Normal actions open the wallet review. Users may explicitly enable quick clicks for a round. Only `trade` and `executeBatch` suppress the extra modal; each still requires a click. The UI caps quick-mode test gas to 0.03 MON per transaction and 0.3 per browser session, reset on round/wallet change or reload. This is a frontend convenience budget, **not an onchain session policy**. Contract entrypoints never transfer funds or call another contract.

The measured UI duration starts after transaction submission and ends when a receipt is observed. It does not measure the full click-to-confirmation path or demonstrate Monad's maximum throughput.

## Operator

Build and test:

```sh
npm run sprint:compile
npm run sprint:test
node scripts/test-sprint-api.mjs
node scripts/test-sprint-ui.mjs
```

UI tests require Playwright (`ORBITA_PLAYWRIGHT_PATH` may point to the module) and Microsoft Edge. They replace only wallet authentication/signing hooks and the RPC URL in a disposable harness; transactions execute on an actual local EVM. They do not validate a real Privy login.

Deploy with the existing private test operator configuration:

```sh
node --env-file=.env.arena.local scripts/deploy-trading-sprint.mjs
node --env-file=.env.arena.local scripts/deploy-trading-sprint.mjs --deploy
```

The deployer refuses wrong networks, duplicate configured contracts, and costs above 0.35 test MON. It persists a signed pending deployment before broadcast. If interrupted, inspect that transaction before retrying. It verifies runtime bytecode and saves the address as `ORB_SPRINT_CONTRACT` in the ignored local configuration. Set the same public address in `/etc/orb/orb.env` and restart the Orb service after deploying the application. No new database migration is required.

A conditional-order keeper is included. Configure a **dedicated** `ORB_SPRINT_KEEPER_KEY` and `ORB_SPRINT_ROUND`, then run `node scripts/sprint-keeper.mjs` for dry-run observations or append `--execute`. It performs one shared snapshot per second, processes eligible orders in a single batch, waits for the receipt, and stops at the end of the round. Gas limits are 0.03 test MON per batch and 0.3 per process run. Do not run multiple executors with the same wallet or blindly restart after an unknown receipt. Without a running keeper, participants use **Process ready orders**. A global managed keeper, community admission checks, NFT prizes and real-asset strategy execution are separate work.

## Deployment record

Monad testnet contract: `0x18C05a2889A7A51D21E474a88D0AF45a8CfD12aE`.

Deployment transaction: `0xa6053a59bf9d929b29524acf35d29c2eb46f637a0f4e20a0aa3f4272cc50b519`.

The sprint game runs on its own testnet contract and is independent of the perpetual desk: it neither enables nor automates real orders on Perpl.
