Skip to content

Resolve DecimalFloat for robinhood-mainnet - #2867

Open
hardyjosh wants to merge 1 commit into
2026-09-11-subgraph-robinhoodfrom
2026-09-11-subgraph-robinhood-float-address
Open

hardyjosh wants to merge 1 commit into
2026-09-11-subgraph-robinhoodfrom
2026-09-11-subgraph-robinhood-float-address

Conversation

@hardyjosh

Copy link
Copy Markdown
Contributor

Stacked on #2866.

What was broken

The Robinhood Chain (4663) deployment from #2866 indexed nothing. _meta reported hasIndexingErrors: true, pinned at block 60339226, with zero entities.

Block 60339226 holds the first orderbook event ever emitted on 4663: a DepositV2 from the smoke-test deposit 0xd71a0df0b1b5de638103ad69123f99cf3ea9937e10d2f48b71901e67d1dffb00 (20 USDG). The event topic matches the committed ABI, so the handler ran - and threw.

Root cause

subgraph/src/float.ts:32 (before this change)

return FALLBACK_DECIMAL_FLOAT_ADDRESS; // 0x0000...0001

Every Float the subgraph stores is produced by an eth_call against the DecimalFloat contract on the indexed chain, and getDecimalFloatAddress() selects that contract from a dataSource.network() name list. robinhood-mainnet was not in the list, so it fell through to the placeholder 0x0000000000000000000000000000000000000001, which has no code on any chain.

handleDeposit (subgraph/src/deposit.ts:26) calls calculator.fromFixedDecimalLossless(...) - a generated non-try_ binding. The call to a codeless address is reported as reverted, the binding traps, the mapping aborts, and the subgraph stops. Nothing before it in the handler survives either, which is why the store was empty rather than partially written: createTransactionEntity / createRaindexEntity were rolled back with the rest of the block.

Verified against the Tenderly archive RPC at the failing block:

$ cast call 0x0000000000000000000000000000000000000001 \
    "fromFixedDecimalLossless(uint256,uint8)(bytes32)" 20000000 6 \
    --rpc-url https://robinhood-chain.gateway.tenderly.co
Error: contract 0x0000000000000000000000000000000000000001 does not have any code

This is not Goldsky-side and not network-feature related. It is a missing config entry, and it would have hit any new chain added without one.

The fix

Point robinhood-mainnet at 0x799632d282178e770C7465cad54aDA1021A913D6, the deterministic DecimalFloat address from rainlanguage/rain.math.float.deploy (src/generated/0_1_2/DecimalFloat.sol DEPLOYED_ADDRESS). On 4663 it first has code at block 59501383 (2026-09-10 15:13 UTC), earlier than the 59557818 start block in networks.json, so no start block change is needed - graph-node makes contract calls against the state of the block being processed, and the calculator is already there for every block this subgraph will touch.

All 39 functions in subgraph/abis/DecimalFloat.json are present in the deployed runtime, and the five the mappings actually call return correct results when called at the failing block 60339226:

add    0x00..00, 0xfffffffa..01312d00 -> 0xfffffffa00000000000000000000000000000000000000000000000001312d00
minus  0xfffffffa..01312d00           -> 0xfffffffafffffffffffffffffffffffffffffffffffffffffffffffffeced300
sub    a, a                           -> 0x00..00
gt     0xfffffffa..01312d00, 0x00..00 -> true
fromFixedDecimalLossless(20000000, 6) -> 0xfffffffa00000000000000000000000000000000000000000000000001312d00

The placeholder fallback is replaced with log.critical, which names the offending network. A chain with no DecimalFloat entry cannot index a single Float-bearing event, so there is no degraded mode to preserve - the only choice is whether the failure says what is wrong. It now does:

🆘 No DecimalFloat deployment known for network: not-a-network

Tests

subgraph/tests/decimal-float-address.test.ts pins every network in networks.json to its expected DecimalFloat address, so adding a network without a calculator entry now fails the suite rather than the deployment.

nix develop github:rainlanguage/rainix#subgraph-shell -c subgraph-test - all 46 tests pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HiqQdxokJ4edjAFyAkN9G3

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 3b5218b2-a204-4333-9b3f-0a1d3549ad67

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

hardyjosh pushed a commit to ST0x-Technology/st0x.registry that referenced this pull request Sep 11, 2026
The `-a938b5a` version is wedged: it answers `hasIndexingErrors: true` with an
`indexing_error` and stopped advancing at block 60,339,226. `-b398652` is the
redeploy carrying rainlanguage/raindex#2867 and is clean at 60,357,260.

The trailing hash is a deployment version rather than decoration, so the old
one must not be referenced anywhere - the comment says so at the line.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HiqQdxokJ4edjAFyAkN9G3
hardyjosh added a commit to ST0x-Technology/st0x.registry that referenced this pull request Sep 11, 2026
…#72)

`networks.robinhood` and `rainlangs.robinhood` landed with the token lists in #70. This adds the two pieces an order still needs on chain 4663: the orderbook, and a `robinhood` deployment on **`st0x-fixed-spread-v7`**.

v7, not v5 — Base is migrating to it, so Robinhood launches there directly rather than landing on v5 and being migrated a week later. `st0x-fixed-spread-v5.rain` is untouched and its index pin is back on `f6751291`.

## settings.yaml

`raindexes.robinhood` — the canonical RaindexV6 `0x37FC0EFec37D19f8A221aa4F8F7600C9ba2AcD20`, which every chain except Base runs (Base is still on the older `0xe522cB4a…`). Verified on 4663 with `eth_getCode`; `deployment-block: 59557818` is bisected from the same.

`subgraphs.robinhood` is the **live Goldsky Raindex subgraph** for 4663 at deployment `-b398652`, and `raindexes.robinhood` references it. The trailing hash is a deployment **version**, not decoration: `-a938b5a` is wedged (`hasIndexingErrors: true`, stopped at block 60,339,226) and was redeployed with the DecimalFloat fix, rainlanguage/raindex#2867 — clean at 60,357,260. The old version must not be referenced anywhere. (It started as an RFC 2606 `.invalid` placeholder — omitting `subgraph:` does not parse, which I found by compiling an order rather than by reading the schema: *"Subgraph 'robinhood' not found in orderbook 'robinhood'"*. The real endpoint has since landed.)

`subgraphs.sft-robinhood` is the receipt-vault index for the same chain, 56 vaults, beside `sft-ethereum` / `sft-hyperevm`.

No `local-db-remote:` on `raindexes.robinhood`. Unlike `subgraph:` the schema does not require one, and Base's value names a Base-specific bootstrap snapshot — pointing Robinhood at it would seed a local DB from another chain's orders.

## src/st0x-fixed-spread-v7.rain

New `orders.robinhood`, `scenarios.robinhood-sell` / `robinhood-buy`, matching `deployments.*` and `builder.deployments.*`, mirroring the Base blocks. v7 is two deployments per chain because the strategy must know which side of the pair is the vault: sell binds `wt-vault: ${order.outputs.0.token.address}` with `'derive-sell`, buy binds the input side with `'derive-buy`.

The one value that is **not** a copy of Base's is the subparser: `0x09Bc7AF266012F44fb41D8Bd682da931666605e1`, Robinhood's own, verified on 4663. Base's `0x22839F16…` has no code there.

## The oracle now signs its chain id (slot 9)

Every deployment binds `expected-chain-id` — 8453 on Base, 4663 on Robinhood, declared beside `oracle-signer` — and the strategy asserts it immediately after the schema-version guard:

```
:ensure(equal-to(signed-context<0 9>() expected-chain-id) "Wrong chain"),
```

This closes a real hole rather than tidying one. EIP-191 signing is chain-agnostic and nothing else in the frame names a chain, so before slot 9 a frame signed for one chain verified unchanged inside an order on another wherever the two shared a token address — which ST0x tokens, deployed deterministically, may well do. **A Base v7 frame no longer verifies on Robinhood, or the reverse.**

`st0x-fixed-spread-v7.md` gains the full slot table it never had (0–8 plus 9 = chain id, and there is no slot 10), the cross-chain note, and a line recording that the ERC4626 subparser is Base-only. The stale *"v7 signs no slot 9"* comment in the dotrain is corrected.

**Both deployments still compile** against this branch's pin: `base-sell` and `base-buy` produce `addOrder4` (`0x709fb8a5`) at `0xe522cB4a…`, 18,250 / 17,482 bytes — up from v5's 12,490, consistent with the added assert. `robinhood-sell` gets past the chain bind and everything else and stops only at the missing ERC4626 subparser (below); confirmed by swapping that one binding for an address that does have code on 4663, at which point the error moves on to word resolution.

Downstream, `raindex-deploy`'s `plan --chain robinhood` still plans all **96** orders against this commit.

## Two things that do not work yet, both stated at the file

**The ERC4626 subparser has no code on 4663 yet.**

Robinhood binds `0x03e3f0C80332fB1b57EC884E9d481bAa58969883`, **not** Base's `0xd69dC3d58a7C875117f9c7cecF4F1A7f3CA47254`. The Base address can never exist on another chain — it was an EOA `CREATE` at nonce 531, so its address is a function of that deployer's nonce there. `rain.erc4626.words` has been redeployed deterministically through Zoltu (rainlanguage/rain.erc4626.words#268) at the address above, which *is* reproducible: live on Base and Arbitrum with byte-identical runtime, `keccak(code)` = `0x7c48ecdfa342cf99e4f4af1ed7e09c5cb9389561681b21dccce1411f7c61311e`. The 4663 and BSC deploys are waiting on the deployer key being funded.

**Base keeps the legacy address.** It is live and in use; re-pointing it would change every Base order's identity for no gain.

Until 4663 has code at the new address this fails **closed**: the parser `eth_call`s the subparser while compiling, an address with no code answers empty, and the compile dies with `AbiDecodeFailedErrors(NoData)`. So consumers refuse these orders rather than deploying something that could never quote — `validate --chain robinhood` in `raindex-deploy` will compile only once that address has code on 4663. Nothing here changes when it does; the bound address is already the final one.

**`oracle-url` is Base's `/context/v7`, with a TODO.** `st0x-oracle-server` ships `deploy/config/robinhood.toml`, but its README records it as "not yet wired to a service", and that config names two properties the current binary lacks: the signed context carries no chain id, and the pricing quote cache is keyed by symbol alone.

## The index re-pin

Separate commits on purpose. The `registry` index pins each strategy and the shared settings by commit, so content is unreachable through it until the pointer moves; consumers hash that index URL into order identity, so content-then-pointer keeps the two honest. Only the `settings.yaml` and `st0x-fixed-spread-v7.rain` lines move.

One more thing worth knowing: **the Rainlang parser rejects a literal em dash anywhere in the dotrain**, YAML frontmatter comments included (`illegal character` at the byte offset of the one in a comment). Also found by compiling, not by review.

## Consumer

`ST0x-Technology/st0x.raindex-deploy` [#71](https://app.graphite.com/github/pr/ST0x-Technology/st0x.raindex-deploy/71) / [#72](https://app.graphite.com/github/pr/ST0x-Technology/st0x.raindex-deploy/72) need this to plan or apply on 4663. #71's manifest is pinned at `135d2e3e` and must be bumped to this branch's post-merge commit — it is a spec-hash input, so the bump is a deliberate edit there, never a floating ref.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01HiqQdxokJ4edjAFyAkN9G3
Every Float the subgraph stores is produced by an `eth_call` against the
DecimalFloat contract on the indexed chain, and `getDecimalFloatAddress`
picks that contract by network name. `robinhood-mainnet` had no entry, so
it fell through to the placeholder `0x...0001`, which has no code on any
chain. The first Float-bearing event on Robinhood Chain (4663) - the
`DepositV2` in block 60339226, the first orderbook event ever emitted
there - therefore reverted inside `handleDeposit`, trapped the mapping and
stopped the subgraph with zero entities written.

DecimalFloat is deployed on 4663 at the deterministic
0x799632d282178e770C7465cad54aDA1021A913D6 (block 59501383, before the
Raindex start block), so point the network at it.

Replace the silent placeholder fallback with `log.critical`, which names
the missing network instead of leaving an unconfigured chain to present
itself as an opaque "Ethereum call reverted" at its first event.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HiqQdxokJ4edjAFyAkN9G3
@hardyjosh
hardyjosh force-pushed the 2026-09-11-subgraph-robinhood-float-address branch from b398652 to f3b7157 Compare September 13, 2026 11:32
@hardyjosh
hardyjosh force-pushed the 2026-09-11-subgraph-robinhood branch from a938b5a to 6fdf127 Compare September 13, 2026 11:32

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add the label Raindex-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant