Repository navigation
feat(scenarios): add Orca Whirlpool templates - #22
92Infinitus92 wants to merge 8 commits into
Conversation
f707a78 to
7c17d84
Compare
Tests were not run. |
Tests could not run: Rustup attempted to write to a read-only directory. |
Review based on static inspection; live RPC tests were not run. |
fcbf4b2 to
bcfbf46
Compare
|
This PR swaps the six hardcoded Whirlpool templates for two: a pool template that takes an address ( Main concern: the Kamino liquidation-arbitrage example and the Kamino README no longer do what they describe. The old Smaller points:
Now that
The comment says "sell the seized collateral", but this pool is SOL/USDC. The seized collateral is POPCAT, so this pool can't be the exit for it. The recipe needs a POPCAT/SOL pool, or the text needs updating.
Nit: pools only store and read
Nit: |
There was a problem hiding this comment.
Summary
This PR replaces the six hard-coded Whirlpool templates with two: whirlpool-pool-state, which takes a pool address, and whirlpools-config, the mainnet singleton. It moves the IDL to whirlpool/v1/, adds labels, descriptions and llm_context, a README, registry unit tests, and live integration tests (byte-for-byte round-trip, config singleton check, materializer byte-diff). The template design is clean, and the coupling, liquidity and clock caveats are well documented.
Issues
- The Kamino arbitrage example no longer matches its own description.
Czfq3x…used to be labelled POPCAT/SOL; this PR relabels it SOL/USDC (tick spacing 4). The scenario description still says the seized collateral is sold POPCAT → SOL → USDC. IfCzfq3x…really is SOL/USDC, no POPCAT pool is deepened, and both depth overrides now target SOL/USDC pools. - Breaking change: the template IDs
whirlpool-sol-usdc,-sol-usdt,-msol-sol,-orca-usdc,-popcat-soland-customare removed with no alias. Saved scenarios that use them stop resolving. This should at least be called out in the release notes. - Unrelated CI change: the diff adds
.github/workflows/claude-review.yml, from commitseb2619aand7092c18. That is out of scope for a scenarios PR and should go in its own PR. - Minor: the integration tests default to the public
api.mainnet-beta.solana.comendpoint, which is rate-limited and will be flaky in CI. Consider skipping them unlessSURFPOOL_TEST_RPC_URLis set.
| ``` | ||
| whirlpool-popcat-sol liquidity: 5000000000000000 # sell the seized collateral | ||
| whirlpool-sol-usdc liquidity: 50000000000000000 # route back to the debt token | ||
| whirlpool-pool-state on Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE (SOL/USDC, tick spacing 4) |
There was a problem hiding this comment.
Czfq3x… was previously the whirlpool-popcat-sol template, used to "sell the seized collateral" (POPCAT). It is now labelled SOL/USDC tick spacing 4. If that label is right, this recipe and examples/kamino-liquidation-arbitrage.json no longer deepen any POPCAT pool. The example's description still says the route is POPCAT → SOL → USDC. Either point this at an actual POPCAT/SOL Whirlpool, or update the example's description and route.
| together: | ||
| price_raw = (sqrt_price / 2^64)^2 | ||
| price = price_raw * 10^(decimals_a - decimals_b) | ||
| tick_current_index = floor(log(price_raw) / log(1.0001)) |
There was a problem hiding this comment.
Floating-point floor(log(...)/log(1.0001)) can be off by one when the price sits near a tick boundary. A mismatched tick_current_index is exactly the failure described a few lines below. Consider telling the LLM to check that sqrt_price_at(tick) <= sqrt_price < sqrt_price_at(tick+1), or to nudge sqrt_price slightly inside the tick.
|
|
||
| This template's address is the one deployed WhirlpoolsConfig singleton, | ||
| 2LecshUwdy9xi7meFgHtFJQNSKk4KdTrcpvaB56dP2NQ. Every Whirlpool pool was created under it and | ||
| reads/writes it as the field at offset 8 of its own Whirlpool account. |
There was a problem hiding this comment.
Nit: pools only read whirlpools_config, they never write it. "reads/writes" could mislead the model into thinking pool state changes propagate to the config.
SummaryThis PR replaces the six hardcoded Whirlpool templates (
It also moves the IDL to I checked the hardcoded offsets against the Whirlpool layout and they are right: Issues
Both deepened pools are now SOL/USDC (
Same mismatch as the example JSON: this pool is SOL/USDC, so the comment
Nit: the Whirlpool README says u128 values like
Nit: |
Adds Orca Whirlpool state prep.
Templates:
whirlpool-pool-state(sqrt price, tick, liquidity, fee rate, protocol fee)and
whirlpools-config(the mainnet singleton). Templates take a pool address; theREADME explains how to find one.
YAML and IDL only, like Kamino: no protocol Rust and no MCP tool. The price/tick coupling,
the 88-tick array PDA recipe and the "stay inside the current tick array" rule live in the
template's
llm_contextand in the README; the Studio card computes the shock client-side(LimeChain/surfpool-web-ui#20).
One caveat, documented in the README and in the template's llm_context: Whirlpool
rejects swaps with
InvalidTimestampwhile the surfnet clock is behind the pool's lastupdate, which happens after Studio's Play pauses the clock.
surfnet_resumeClockorsurfnet_timeTravelfixes it.Tests: live tests round-trip a real mainnet pool byte for byte, check the config singleton
against a live pool, and apply overrides through the materializer asserting only the
targeted bytes change. Verified on a forked surfnet: a 0.5 shock made a real swap fill at
half the mainnet quote, and a 1% fee override charged exactly 1%.