Commit Graph
3 Commits
Author SHA1 Message Date
r4bbit e302ba557a feat(modules/amm): add swap_exact_in_quote op and module swapExactInQuote
Server-side SwapExactInput preview. The swap_exact_in_quote FFI op orients the pool reserves to the requested in/out direction, prices via the shared amm_core::swap_exact_in_amounts (so expectedOut matches the chain), and derives the slippage floor: { expectedOutRaw, minReceivedRaw, priceImpactBps }. no_pool is returned as an error; pool metadata (reserves/fee) comes from resolve_pool, so it isn't echoed. Read-only — no quoteHash; the on-chain min_amount_out is the real guard.

The module swapExactInQuote(tokenIn, tokenOut, amountIn, slippageBps) method derives the pool via the config-free pool_id op, reads it, and wraps the op in the { status, error, ... } envelope; call() now surfaces the op error code so no_pool propagates.

The QML swap view still uses the old path, so nothing breaks. Will make the QML consume it in a follow-up.
2026-08-06 10:40:52 +02:00
r4bbit 6a951f3cad feat(modules/amm): add pool_id operation
Derives a pool's PDA from the AMM program id and the two token ids —
compute_pool_pda(amm_program, canonical(token_in, token_out)) — returning
{ poolId }. Tokens may be given in either order; the op canonicalizes.

Unlike swap_pair, which derives the whole pair account-set (including the
current-tick PDA, which depends on config.twap_oracle_program_id and so
requires reading the config account), the pool address depends only on the
program id and the token pair. So a caller that just needs to locate and
read the pool can skip the config read entirely.

Exposed as the amm_pool_id C ABI export. Additive — no existing op changes.
It backs the config-free pool lookup the upcoming swap-quote path needs (and,
later, resolvePoolAccount).
2026-08-05 20:24:24 +02:00
r4bbit f5ff9b829f refactor(apps/amm): move the amm_client crate into modules/amm/ffi as amm_ffi
After the amm_module refactor, this crate is linked only by the module (the
UI delegates to modules().amm_module and links nothing), so its home under
apps/amm/ and the name "client" were both misnomers: it's the AMM business
logic the module wraps, reached across an FFI boundary — the same relationship
logos_execution_zone has with wallet_ffi. Co-locate it with the module that
owns it and name it for that role.

The FFI surface is unchanged — the exported functions are already amm_* (not
amm_client_*) — so only the crate, directory, generated header, dylib, and
package names move. The module's call sites are untouched; it just includes the
renamed header.

- apps/amm/client → modules/amm/ffi (git-tracked rename; history preserved)
- crate amm_client → amm_ffi: package name, include/amm_ffi.h, libamm_ffi.dylib,
  AMM_FFI_H guard, build.rs output path, tests/public_api.rs import
- workspace member path + Cargo.lock
- flake.nix: pname, -p, header-copy path, dylib install_name, packages.amm_ffi,
  ammModuleOutputs externalLibInputs, DYLD wrapper
- modules/amm: metadata external_libraries, CMakeLists EXTERNAL_LIBS, impl
  #include + comments, README, flake note
- apps/amm/flake.nix: drop the now-dead amm_client external-lib input (the UI
  links no external lib of its own)

Resulting layout:
  modules/amm/
    src/   # C++ module  (amm_module_impl.{h,cpp})
    ffi/   # Rust crate  amm_ffi  (Cargo.toml, src/, include/amm_ffi.h)
2026-08-03 23:11:06 +02:00