# Solve the BEX riddle: a prompt for your coding agent

You are helping a human play the BEX riddle on their own machine: write a solver, simulate its claim on the Eureka builder, and send it when they say so. Follow these steps in order. Stop and ask the human when a step says so.

The tool is the `bex` CLI from the npm package `@eurekabuilder/bex`. Its commands are `init`, `doctor`, `simulate`, `send`, `status` and `withdraw`. `bex --help` is the source of truth for every command and flag: do not use a flag it does not list.

## Safety rules

- The signer key is the one on the human's handout. It is the key registered for the round, and the key the riddle pays the reward to. Do not make a new key: an unregistered key cannot claim.
- Never print the key, never ask the human to paste it into this chat, never commit it, and never write it to a file inside the project. Never read the key file aloud or `cat` it.
- The human saves the key themselves, in a file outside the project, readable only by them (`chmod 600`), and you pass it with `--key-file <path>`. The other way the kit reads the key is the `BEX_SIGNER_KEY` environment variable, set by the human in their own shell. There is no third way.
- Never run `bex send` without the human's go-ahead (step 6).
- The kit sends only to Eureka's endpoint, `https://rpc.eurekabuilder.xyz`: `bex.toml`'s `[hosts] network = "mainnet"` maps to it. (`hosts.json` is only a reference copy; the kit does not read it.) Do not add `--hosts.urls`, and do not send the request anywhere else.
- `bex simulate --verbose` prints the round's `compute.to` and the request. Do not paste them anywhere public: anyone who funds `compute.to` with 1 wei makes the builder drop the request.

## Steps

1. **Check the environment.**
   - `node --version`: Node.js 22 or later. If it is older, ask the human to upgrade.
   - `npm ls -g @eurekabuilder/bex`: the kit, version 0.1.0 or later. If it is missing, run `npm install -g @eurekabuilder/bex`. Then run `bex --help` and check that it lists `init`, `doctor`, `simulate`, `send`, `status` and `withdraw`. (`bex` has no `--version` flag.)
   - `forge --version`: Foundry, which builds and tests the solver. If it is missing, ask the human to install it from https://getfoundry.sh, then continue.
   - If a general BEX setup prompt ran before this one, its setup (Node.js, the kit, Foundry, `bex doctor`) is expected to be done: check it quickly with the commands above, and run `bex doctor` again in step 5. The riddle uses the handout key, not a new one.

2. **Create the riddle project.** Read the session's settings from the live screen's config:

   ```sh
   curl -s https://bex.eurekabuilder.xyz/devcon06/config.json
   ```

   Show the human the three fields you use: `riddle` (the riddle contract's address), `round` (the round of the session) and `chainId`.
   - If `riddle` is `null`, stop: the session's riddle is not deployed yet. Tell the human, and ask them to say when to try again.
   - If `chainId` is not `1`, stop and ask the human: the kit plays on mainnet.

   Then, in a new directory (`bex init` refuses a directory that is not empty):

   ```sh
   bex init riddle-solver --riddle <riddle from config.json>
   cd riddle-solver
   ```

   It writes `.gitignore`, `README.md`, `SNIPPETS.md`, `abi/Riddle.json`, `bex.toml` (the riddle's address, the chain RPC, the solver artifact, the network, and the round settings `bex simulate` fakes while no round is open), `foundry.toml`, `hosts.json`, `prebuilt/PrebuiltSolver.json`, `src/Solver.sol`, `src/riddle/IRiddle.sol`, `src/riddle/Riddle.sol`, `test/Base.sol` and `test/Template.t.sol`.

3. **Read the project.** Read `src/Solver.sol` (the template: the human's code goes in `findNonce`), `SNIPPETS.md` (an optional, faster Yul `findNonce`), `src/riddle/IRiddle.sol` (the riddle's interface) and `README.md`. Then explain the riddle to the human in a few lines:
   - **The puzzle.** A claim carries 64 nonces, and the round checks the first `k` of them (k = 64 by default). For each index `i` from 0 to k − 1, the nonce must make `keccak256(challenge ‖ round ‖ solver ‖ uint32 i ‖ uint32 nonce ‖ 1732 zero bytes)` start with `d` zero bits (d = 10 by default). The preimage is 1,824 bytes: 92 bytes of fields, then the zeros. That is about 65,000 hashes per claim.
   - **The challenge.** While a round is open, the riddle's setter writes a fresh, secret challenge into every Eureka block, in a private transaction. `claim` accepts only a challenge set in the same block (`challengeBlock == block.number`), so only a BEX compute that runs inside Eureka's block, after the setter's write, can solve it in time.
   - **`NotYet()`.** The riddle's `challenge()` does not revert on an old challenge, so the solver must: STEP 2 of the template reverts `NotYet()` when the round is not open or the challenge is not this block's. The builder runs every request on the parent block first, where the challenge is a block old; the cheap revert lets it try again after the setter's write. Keep STEP 2.
   - **The tip and the reward.** The claim signs a tip in basis points (`--tip`), paid to the block's builder at claim, at least the round's floor. After the round closes, the owner settles: rewards go by tier, 5% less per rank, in the order claims landed (earlier block first, then their order in the block), minus the tip each paid.

4. **Write `findNonce`.** Follow the template's rules: no constructor, no immutables, no storage, `solve` stays a view, keep the return tuple, and leave `RIDDLE` at its placeholder (the kit patches the riddle's address into the compiled bytes). In `findNonce`, try nonces from 0 up: per try, call `setNonce(buf, nonce)` and return the first nonce with `uint256(keccak256(buf)) >> shift == 0`. Do nothing else per try: no allocation, no byte-by-byte writes.

   ```sh
   forge build
   forge test -vv
   ```

   `forge test -vv` runs the solver's exact bytes against a local riddle at d = 10 and claims with the answer. It logs "STEP 3 (findNonce) is not written yet" until `findNonce` is written, and the solve's gas once it is. Use `-vv`: without it, `forge test` shows only PASS lines, even before `findNonce` is written.
   - **Gas.** The builder runs the compute with at most 200M gas, and `bex simulate` shows a light: green under 150M, amber under 200M, red at 200M or at the builder's `maxComputeGas`, whichever is lower. A d = 10 solve with the template's loop costs about 31M gas (26M to 40M). The Yul loop in `SNIPPETS.md` is about 7% cheaper: switch to it if the test shows the gas high.
   - **Optional.** An explicit gas amount on each external call, such as `RIDDLE.challenge{gas: 30_000}()`, removes the `GAS` opcode that `bex simulate` warns about.

5. **Check the key, then simulate on the builder.** Ask the human for the path of their key file (the path only, never the key):

   ```sh
   bex doctor --key-file <path>
   bex simulate --key-file <path> --tip <bps>
   ```

   `bex doctor` checks that the key loads, that the builder takes compute code, and that the builder allows the key. It exits 1 when a check fails: show the human which one. `bex simulate` runs one claim on the builder's `bex_simulate`. While a round is open on chain, it uses the real round and fakes only the next block's challenge, the key's registration and the riddle's balance; while none is open, it also fakes the round from `bex.toml`'s `[round]`. `--tip` defaults to the round's floor. Read the report with the human:
   - `verdict.status` is `pass`, or `fail` with `verdict.stage` (`intake`, `compute` or `execute`) and `verdict.reason`, which decodes the riddle's errors, such as `compute reverted: NotYet()` or `execute reverted: BadNonce(3)`.
   - `gas.used` and `gas.light`: the compute's gas against the traffic light above.
   - `staleChallenge`: how the solver behaved on a challenge from an earlier block.
   - `warnings`, also printed as `bex: warning:` lines. A `GAS` opcode warning is fine. A warning that the key is not registered for the open round means a real claim would revert `NotRegistered`: tell the human to check their handout or ask at the door.

   Exit codes: 0 pass. 8: the kit refused the code before sending it: immutables or unlinked libraries in the artifact, empty, too large, starting with `0xEF`, not pushing the riddle's address, or not reverting within 1M gas on a challenge from an earlier block (keep STEP 2). 6: the builder refused the request before simulating it, such as a key it does not allow. 7: the simulate ran and the compute or the execute failed. 9: the builder stayed busy; try again shortly. 4: `compute.to` is not empty. 1: a failure such as a network error, or the builder not reporting compute code enabled; the message says to run `bex doctor`. 2: a bad flag or manifest, or a missing artifact (run `forge build` first). Fix the cause, rebuild, and simulate again until it passes.

6. **Get ready to send, but do not send.** Show the human the exact command:

   ```sh
   bex send --key-file <path> --tip <bps>
   ```

   Explain what it does. It sends the claim to Eureka's endpoint once per slot, as one replacement (the round's fixed replacement uuid, with the target block as the sequence number), and never for a block that starts in under 3 seconds. It prints one JSON line per slot. Once the claim lands, it sends nothing more and prints `landingPending` lines until the landing is final: 2 blocks deep, with its block hash still canonical. Then it stops (exit 0). It also stops when the round closes first (exit 10); when the round is open and the riddle has not registered the key (exit 6); and when the kit refuses the code at a new target block (exit 8). Ctrl-C stops it (exit 130), and a restart resends the same request for a block it already sent for. Then ask the human whether to send. Run it only after they say yes, and only while the round is open.

   After a send:
   - `bex status --key-file <path>` (or `bex status --signer <address>`, without the key) reads the riddle's `Claimed` events. Its report has `landed` (`blockNumber`, `position`, `tip`, `depth`, `final`), waiting until the landing is 2 blocks deep, or `notLanded` with `slotsSinceOpen`.
   - `bex withdraw --key-file <path>` is only for a reward the riddle holds: when the settlement could not push the reward to the key. The key then pays the gas, so it needs a little ETH; `bex withdraw` says how much is missing.

## When you are ready

Tell the human what is done: the kit's version, the riddle address and round you used, the solver's `forge test` gas, and the last `bex simulate` verdict and gas light. Then wait for their go-ahead before any `bex send`.
