feat(amm): bootstrap pool TWAP current-tick account at pool creation#149
feat(amm): bootstrap pool TWAP current-tick account at pool creation#1490x-r4bbit wants to merge 2 commits into
Conversation
Add a `CreatePriceObservations` instruction that registers a TWAP price-observations account for a pool over a time window, via a chained call to the configured TWAP oracle program. The pool acts as the price source: the AMM authorizes it with its pool PDA seed so the oracle ties the feed to that pool. The feed's initial tick is read from the pool's authoritative `CurrentTickAccount` (validated against its pool-derived PDA) rather than being supplied by the caller, so the feed cannot be seeded at a forged price — mirroring what `RecordTick` does. The clock is verified to be the canonical 1-block LEZ clock, and creation is rejected if the observations account already exists. To support the chained call, `AmmConfig` and the `Initialize` instruction are extended with a `twap_oracle_program_id` that the instruction reads.
5ac79c9 to
4c9ef12
Compare
Extend new_definition to also create the pool's TWAP current-tick account via a chained CreateCurrentTickAccount, so a pool and its price feed are born together. The opening tick is derived on-chain from the pool's own reserves (reserve_b / reserve_a as Q64.64), not caller-supplied, so it cannot be forged. The pool is passed in its post-claim state and authorized as the price source via its pool PDA seed. Add spot_price_q64_64 to amm_core (not the oracle): the reserves -> price mapping is the price source's concern; the oracle only converts price to a tick.
fa05bae to
ca59f7d
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates AMM pool creation (new_definition) to also bootstrap the TWAP oracle’s per-pool CurrentTickAccount in the same transaction, ensuring the pool and its initial price feed state are created together. It introduces a shared, deterministic reserve-ratio → Q64.64 spot-price helper in amm_core, which is then passed to the oracle’s CreateCurrentTickAccount.
Changes:
- Extend
new_definitionto include a chained call to the TWAP oracle to create the pool’sCurrentTickAccount, passing the pool as an authorized price source and using the canonical clock. - Add
amm_core::spot_price_q64_64(reserve_base, reserve_quote)with saturation behavior and unit tests. - Update AMM unit/integration tests, guest method interface, and generated IDL to include the new accounts (
current_tick_account,clock) and validate seeded tick behavior.
Reviewed changes
Copilot reviewed 7 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| programs/integration_tests/tests/amm.rs | Updates integration tests to create pools via new_definition and assert the seeded oracle tick derived from opening reserves. |
| programs/amm/src/tests.rs | Updates AMM unit tests to expect the additional chained oracle call and extra echoed post-states (current-tick + clock). |
| programs/amm/src/new_definition.rs | Adds current_tick_account + clock inputs, validates their PDAs/IDs, and chains oracle CreateCurrentTickAccount using spot_price_q64_64. |
| programs/amm/methods/guest/src/bin/amm.rs | Extends the guest-exposed new_definition method signature to pass the new accounts through. |
| programs/amm/methods/guest/Cargo.lock | Locks guest dependency graph changes for amm_core (now includes alloy/ruint). |
| programs/amm/core/src/lib.rs | Adds spot_price_q64_64 helper and tests for correctness/overflow behavior. |
| programs/amm/core/Cargo.toml | Adds alloy-primitives and pins ruint to a guest-compatible version. |
| Cargo.lock | Updates workspace lockfile to include the new direct dependencies. |
| artifacts/amm-idl.json | Updates the AMM IDL to include current_tick_account and clock in new_definition accounts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
4c9ef12 to
b245910
Compare
| pool_price_source, | ||
| clock.clone(), | ||
| ], | ||
| &twap_oracle_core::Instruction::CreateCurrentTickAccount { initial_price }, |
There was a problem hiding this comment.
This creates the pool CurrentTickAccount with the opening price, but there is nowhere a UpdateCurrentTick call.
I assume this is due the scope of PR is to only bootstrap pool.
Extend new_definition to also create the pool's TWAP current-tick account via a chained CreateCurrentTickAccount, so a pool and its price feed are born together. The opening tick is derived on-chain from the pool's own reserves (reserve_b / reserve_a as Q64.64), not caller-supplied, so it cannot be forged. The pool is passed in its post-claim state and authorized as the price source via its pool PDA seed.
Add spot_price_q64_64 to amm_core (not the oracle): the reserves -> price mapping is the price source's concern; the oracle only converts price to a tick.