Skip to content

Sandbox self-test

operator-conformance is a command-line tool that calls your wallet endpoints exactly the way the platform does and checks every rule of the protocol: idempotency, rollbacks and tombstones, staged debits, batch semantics and signature rejection. Passing it is a prerequisite for production review.

The tool is written in Go. Request it from your Star Game contact (contact@sentosatower.com): we send a prebuilt binary for Linux, macOS or Windows, or the Go source. To build from source (Go 1.26 or later):

Terminal window
go build -o operator-conformance ./cmd/operator-conformance
  1. Create a test player in your sandbox wallet with a balance of at least 1000 minor units.

  2. Issue two fresh launch codes for that player.

  3. Run the tool with your sandbox wallet base URL and the sandbox signing secret:

    Terminal window
    OPERATOR_WALLET_URL=https://api.example.com/game-wallet/v1 \
    OPERATOR_WALLET_SECRET=whsec_… \
    GAME_ID=lantern \
    ./operator-conformance <launch_code_1> <launch_code_2>

    GAME_ID is optional (default conformance). The run takes a few seconds and has a 2-minute limit.

When it finishes, the test player’s balance is back where it started: every debit is either rolled back or offset by an equal credit. Transaction ids are prefixed conf-<random>: so you can find them in your logs.

Exit codes: 0 all checks passed (WARN lines are advisory), 1 at least one check failed, 2 the run could not start (bad configuration, authentication failed, balance below 1000).

# Check Rule
1 authenticate Launch code returns player_id, session_id, currency
2 launch code is single-use (SHOULD) Reusing the first code is refused — advisory (WARN, not a failure)
3 balance sufficient for the suite Test player has ≥ 1000
4 debit books and returns balance Debit of 100 → ok, balance reduced
5 replayed debit returns first result without booking again Idempotency
6 same id with different amount is duplicate_mismatch Content mismatch detection
7 debit above balance is insufficient_funds Refusal
8 replayed failed debit returns the first result Failures are idempotent too
9 credit referencing a booked debit books Payout
10 several debits in one round all book; payout references the first Staged debits
11 rollback refunds the debit Rollback
12 second rollback of the same debit does not refund twice Rollback idempotency
13 credit referencing a rolled-back debit is reference_not_found No payout for reversed stakes
14 rollback before its debit is ok, and the late debit is rolled_back and not booked Tombstones
15 batch returns one result per item in order; one failure does not fail the batch Batch semantics (21 items)
16 batch rollback restores the balance Batch of 20 rollbacks
17 second launch code authenticates the same player New session for the same player
18 unsigned, wrong-key, tampered-body and stale requests are rejected with 401 Signature verification
19 net balance unchanged after the suite Nothing leaked

Output from a run against our reference operator:

PASS authenticate (player=p1 session=true currency=GOLD err=<nil>)
PASS launch code is single-use (SHOULD) (second use err=wallet: invalid launch code)
PASS balance sufficient for the suite (balance=100000 need>=1000)
PASS debit books and returns balance (status=ok balance=99900 want=99900)
PASS replayed debit returns first result without booking again (status=ok balance=99900)
PASS same id with different amount is duplicate_mismatch (status=duplicate_mismatch)
PASS debit above balance is insufficient_funds (status=insufficient_funds)
PASS replayed failed debit returns the first result (status=insufficient_funds)
PASS credit referencing a booked debit books (status=ok balance=100000 want=100000)
PASS several debits in one round all book; payout references the first (debits=ok,ok credit=ok balance=100000 want=100000)
PASS rollback refunds the debit (debit=ok rollback=ok balance=100000 want=100000)
PASS second rollback of the same debit does not refund twice (status=ok balance=100000)
PASS credit referencing a rolled-back debit is reference_not_found (status=reference_not_found)
PASS rollback before its debit is ok, and the late debit is rolled_back and not booked (rollback=ok late debit=rolled_back balance=100000 want=100000 err=<nil>)
PASS batch returns one result per item in order; one failure does not fail the batch (ok=20/20 last=insufficient_funds)
PASS batch rollback restores the balance (all ok=true balance=100000 want=100000)
PASS second launch code authenticates the same player (player=p1 err=<nil>)
PASS unsigned, wrong-key, tampered-body and stale requests are rejected with 401 (unsigned=401 wrong key=401 tampered=401 stale=401)
PASS net balance unchanged after the suite (balance=100000 start=100000)
19/19 passed

Open a few games from your App against the sandbox entry URL, play real rounds (stake, win, lose, top up mid-round), and compare your wallet ledger with Console → Data (Sandbox tab). Then click Apply for production on Console → Overview.