Skip to content

Deepstate integration on Robinhood Chain - #642

Open
e1Ru1o wants to merge 8 commits into
masterfrom
e1Ru1o/deepstate
Open

e1Ru1o wants to merge 8 commits into
masterfrom
e1Ru1o/deepstate

Conversation

@e1Ru1o

@e1Ru1o e1Ru1o commented Sep 2, 2026

Copy link
Copy Markdown
Member

Summary

Integrates the Deepstate on-chain limit-order engine on Robinhood Chain as the DEEPSTATE action.

  • One book fill per action, funded by the Settler's current sellToken balance via ppm. Multi-hop routes are chained actions, each sized from what actually arrived.
  • token0/token1 ordering and the bid/ask side are derived on-chain from the two tokens, with the ETH sentinel mapped to Deepstate's address(0).
  • Asks are sized directly by the sell amount. Bids are sized through a caller-supplied inversePriceX128 (Q128 token0 per token1), since the engine only accepts token0 quantities. An adverse price move reverts on the engine's transferFrom.
  • noRest is always forced on so unmatched quantity stays in the Settler for later actions instead of resting as an order the Settler could never cancel. fillOrKill is off; the final AllowedSlippage check protects the taker.
  • The call is hand-encoded to fill. No refund logic, no balance reconciliation, no restricted-target override, no custom errors.

Gas Optimization

  • Replaces the previous fillRoute path (route array allocation, three balance reads, temporary approve/reset, refund transfer) with a single hand-encoded fill call, one balance read, and a standing max approval via safeApproveIfBelow.
  • RobinHoodSettler runtime size drops from 22,928 to 20,427 bytes versus the previous Deepstate commit on this branch.
  • No gas snapshot for the action yet. The fork test writes settler_deepstate_robinhood when run in CI; the stale snapshot from the previous implementation was removed.

Testing

  • test/integration/RobinHood.t.sol runs the production RobinHoodSettler against the live engine on a Robinhood Chain fork. Not run locally (no ROBINHOOD_MAINNET_RPC_URL), so CI is the first execution. It currently uses tick 0 and should gain a negative-tick and a bid case before merge.
  • The rest of the unit suite passes locally.

Open items

  • The live engine at 0x6cf19308C22FC82ea620Fa0B3E94948d20f27B96 has not been bytecode-compared against the upstream repository.
  • A quantity at or above 2^160 would overflow into the tick field of the packed order. Left as GIGO, matching Hanji's truncating cast; say if a revert is preferred.

🤖 Generated with Claude Code

dangerousfood and others added 2 commits August 28, 2026 01:05
Add a chain-scoped Settler action for the canonical Deepstate engine with direct-route validation, exact bounded input accounting, unmatched-input refunds, no-rest enforcement, generic-call isolation, and live-fork coverage.

Co-Authored-By: OpenAI Codex <codex@openai.com>
`DEEPSTATE` now fills one Deepstate book from the Settler's current
`sellToken` balance, selecting `token0`/`token1` and the bid/ask side
on-chain from the two tokens. Asks are sized directly by the sell
amount; bids are sized through a caller-supplied `inversePriceX128`
because the engine only accepts `token0` quantities. Unmatched quantity
is discarded via `noRest` so it remains in the Settler for later
actions, and multi-hop routes are expressed as chained actions.

The call is hand-encoded to `fill` rather than passing a `FillParams[]`
to `fillRoute`. Refund handling, balance reconciliation, input
validation, the restricted-target override, and the two custom errors
are removed; none are needed because the engine debits only matched
quantity from `msg.sender` and pays `msg.sender` directly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment thread src/ISettlerActions.sol
Comment thread src/ISettlerActions.sol Outdated
Comment thread src/ISettlerActions.sol
Comment thread src/ISettlerActions.sol Outdated
Comment thread src/core/Deepstate.sol Outdated
Comment thread src/core/Deepstate.sol Outdated
// per-order rounding is absorbed by the caller's choice of `tick`.
uint256 quantity = sellAmount;
if (isBid) {
(uint256 hi, uint256 lo) = tmp().omul(sellAmount, inversePriceX128).into();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait.... is inversePriceX128 the off-chain computed realized price? That's not a good design because then the filling amount depends on slippage.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value, is directly related to the tick, I don't see a way to go around it. It is provided to avoid doing the tick match in the contract

Comment thread src/core/Deepstate.sol Outdated
Comment thread src/core/Deepstate.sol Outdated
e1Ru1o and others added 3 commits September 3, 2026 19:41
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Describe native ETH via ERC-7528, define `inversePriceX128` as the
reciprocal of the limit price one tick past `tick`, and state that the
limit sizing bounds the engine's debit by the sell amount. The mixin
comment names the one-wei partial-fill rounding the extra tick absorbs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@e1Ru1o e1Ru1o self-assigned this Sep 3, 2026
@e1Ru1o
e1Ru1o marked this pull request as ready for review September 3, 2026 18:55
@immunefi-magnus

Copy link
Copy Markdown

🛡️ Immunefi PR Reviews

We noticed that your project isn't set up for automatic code reviews. If you'd like this PR reviewed by the Immunefi team, you can request it manually using the link below:

🔗 Send this PR in for review

Once submitted, we'll take care of assigning a reviewer and follow up here.

Comment thread src/ISettlerActions.sol Outdated
Comment thread src/ISettlerActions.sol Outdated
Comment thread src/core/Deepstate.sol
Comment on lines +115 to +121
// Orders are sized in `token0`. A bid spends `token1`, so the sell amount is converted through the
// reciprocal of the limit price, which bounds the engine's debit by the sell amount. The one wei the
// engine can add when it partially consumes an ask is absorbed by the caller taking `inversePriceX128`
// one tick past the limit.
if (isBid) {
(, sellAmount) = tmp().omul(sellAmount, inversePriceX128).ishr(128).into();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In contrast, #640 does:

sellToken.safeApprove(address(ROBINHOOD_DEEPSTATE), 0);
sellToken.safeApprove(address(ROBINHOOD_DEEPSTATE), maxSellAmount);
ROBINHOOD_DEEPSTATE.fastFill(0, token0, token1, epoch, tick, quantity, isBid);
sellToken.safeApprove(address(ROBINHOOD_DEEPSTATE), 0);

I haven't actually read the Deepstate code. Does Deepstate introspect the allowance amount and only pull up to the limit?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it doesn't introspect, it pull anything needed to pay the debt but, 640 was setting the maxSellAmount as a guard to make sure not more than that is pulled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is gonna be a pain for the liquidity integrations guys, but OK

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you document this thoroughly in the changelog?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get it, that it is going to be pain, but, either they put a price there or we walk the tree. Confirming with Deepstate that there is no other way to go about this

@e1Ru1o
e1Ru1o requested a review from duncancmt September 14, 2026 13:00
Comment thread src/core/Deepstate.sol Outdated
Comment thread src/core/Deepstate.sol Outdated
Comment thread src/core/Deepstate.sol
Comment on lines +115 to +121
// Orders are sized in `token0`. A bid spends `token1`, so the sell amount is converted through the
// reciprocal of the limit price, which bounds the engine's debit by the sell amount. The one wei the
// engine can add when it partially consumes an ask is absorbed by the caller taking `inversePriceX128`
// one tick past the limit.
if (isBid) {
(, sellAmount) = tmp().omul(sellAmount, inversePriceX128).ishr(128).into();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is gonna be a pain for the liquidity integrations guys, but OK

Co-authored-by: duncancmt <1207590+duncancmt@users.noreply.github.com>
@jparklev
jparklev self-requested a review September 15, 2026 04:12
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.

3 participants