mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-08-25 06:01:11 +00:00
refactor(amm): rename the create-pool quote surface for symmetry
Two naming cleanups on the create-pool quote, aligning it with the add / remove counterparts (per modules/amm/INTERFACE.md). Pure renames — no behavior change. - `liquidityQuote` → `createPoolQuote` across the stack: the FFI op (`liquidity_quote` → `create_pool_quote`, `LiquidityQuoteRequest` → `CreatePoolQuoteRequest`, `amm_liquidity_quote` → `amm_create_pool_quote`, cbindgen header regenerated), the module method, the AmmUiBackend slot, and the QML call site. It really is the create-pool quote — `addLiquidityQuote` / `removeLiquidityQuote` are the other branches — so the old name misled. - `initialPriceRealRaw` → `priceRaw` (request field `initial_price_real_raw` → `price_raw`): drops the legacy "Real" and unifies the price key with the add / remove quotes, which already return `priceRaw`. Create, add, and remove quotes now all speak `priceRaw`; the create-vs-add routing in NewPositionFlow keys on `request.priceRaw`.
This commit is contained in:
@@ -124,7 +124,7 @@ AmmActionCard {
|
||||
// missing_pool quote can't submit a duplicate NewDefinition.
|
||||
&& !(root.missingPool && root.transactionId.length > 0)
|
||||
// Per-side funding check, decoupled from buildQuoteRequest/the quote: the deposit each side
|
||||
// spends must fit its selected holding's balance (the lean liquidityQuote / addLiquidityQuote
|
||||
// spends must fit its selected holding's balance (the lean createPoolQuote / addLiquidityQuote
|
||||
// ops never compare amount to balance, so a submit would otherwise fail on an
|
||||
// insufficient-balance transfer). amountA / selectedBalanceARaw are both the display token-A
|
||||
// side, so no canonical reorientation is needed.
|
||||
@@ -1022,7 +1022,7 @@ AmmActionCard {
|
||||
root.canonicalDecimalsB,
|
||||
root.displayIsCanonical)
|
||||
if (actualPrice.ok) {
|
||||
request.initialPriceRealRaw = actualPrice.raw
|
||||
request.priceRaw = actualPrice.raw
|
||||
priceFromAmounts = true
|
||||
} else {
|
||||
errors.push(root.localIssue(actualPrice.code, ["initialPrice"]))
|
||||
@@ -1031,7 +1031,7 @@ AmmActionCard {
|
||||
}
|
||||
}
|
||||
if (price.ok && !priceFromAmounts)
|
||||
request.initialPriceRealRaw = price.raw
|
||||
request.priceRaw = price.raw
|
||||
|
||||
if (!root.missingPool) {
|
||||
var probeA = root.probeRaw(root.tokenA, root.decimalsA)
|
||||
@@ -1105,7 +1105,7 @@ AmmActionCard {
|
||||
return root.displayIsCanonical ? "amountA" : "amountB"
|
||||
if (field === "amountBRaw")
|
||||
return root.displayIsCanonical ? "amountB" : "amountA"
|
||||
if (field === "initialPriceRealRaw")
|
||||
if (field === "priceRaw")
|
||||
return "initialPrice"
|
||||
return field
|
||||
}
|
||||
@@ -1397,9 +1397,9 @@ AmmActionCard {
|
||||
}
|
||||
|
||||
function activePriceValue() {
|
||||
var priceRaw = String(root.quotePayload.initialPriceRealRaw || "")
|
||||
var priceRaw = String(root.quotePayload.priceRaw || "")
|
||||
if (priceRaw.length === 0 && root.quoteMatchesSelectedPair(root.activePoolQuote))
|
||||
priceRaw = String(root.activePoolQuote.initialPriceRealRaw || "")
|
||||
priceRaw = String(root.activePoolQuote.priceRaw || "")
|
||||
return AmountMath.priceFromQ64(priceRaw,
|
||||
root.canonicalDecimalsA,
|
||||
root.canonicalDecimalsB,
|
||||
|
||||
@@ -239,12 +239,12 @@ QtObject {
|
||||
})
|
||||
}
|
||||
|
||||
// Create-pool preview via the lean liquidityQuote (dual-mode: price-only returns the
|
||||
// Create-pool preview via the lean createPoolQuote (dual-mode: price-only returns the
|
||||
// minimum opening deposit; supplied amounts return the actual). Assembled into the
|
||||
// missing-pool shape the form consumes. built.request carries the price (+ amounts once
|
||||
// the user edits past the minimum), so it can be forwarded as-is.
|
||||
function requestCreateQuote(serial, built) {
|
||||
root.runtime.watch(root.backend.liquidityQuote(built.request),
|
||||
root.runtime.watch(root.backend.createPoolQuote(built.request),
|
||||
function(quote) {
|
||||
if (serial !== root.quoteSerial)
|
||||
return
|
||||
@@ -265,7 +265,7 @@ QtObject {
|
||||
})
|
||||
}
|
||||
|
||||
// Maps liquidityQuote into the quote shape NewPositionForm reads for a missing pool.
|
||||
// Maps createPoolQuote into the quote shape NewPositionForm reads for a missing pool.
|
||||
// Amounts are in the request's (canonical) order, matching the form's displayIsCanonical
|
||||
// mapping; minimumAmount* is what the form validates the entered deposit against.
|
||||
function assembleCreateQuote(built, quote) {
|
||||
@@ -279,7 +279,7 @@ QtObject {
|
||||
"minimumAmountBRaw": String(quote.minimumAmountBRaw || "0"),
|
||||
"expectedLpRaw": String(quote.expectedLpRaw || "0"),
|
||||
"lockedLpRaw": String(quote.lockedLpRaw || "0"),
|
||||
"initialPriceRealRaw": String(quote.initialPriceRealRaw || "0")
|
||||
"priceRaw": String(quote.priceRaw || "0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ QtObject {
|
||||
"reserveARaw": String(pool.reserveA || "0"),
|
||||
"reserveBRaw": String(pool.reserveB || "0"),
|
||||
"poolFeeBps": pool.feeBps,
|
||||
"initialPriceRealRaw": String(quote.priceRaw || "0")
|
||||
"priceRaw": String(quote.priceRaw || "0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,12 +313,12 @@ QtObject {
|
||||
return
|
||||
}
|
||||
|
||||
// Route by pool state: creation (initialPriceRealRaw is set only on the missing-pool
|
||||
// Route by pool state: creation (priceRaw is set only on the missing-pool
|
||||
// path) goes through createPool; the active-pool branch through addLiquidity. Both
|
||||
// mint a fresh LP holding then submit via the lean module ops (hex ids,
|
||||
// caller-provided accounts). Quoting for both branches is now on the lean ops
|
||||
// (liquidityQuote / addLiquidityQuote), routed by resolvePool in requestQuoteNow.
|
||||
if (snapshot.request.initialPriceRealRaw !== undefined)
|
||||
// (createPoolQuote / addLiquidityQuote), routed by resolvePool in requestQuoteNow.
|
||||
if (snapshot.request.priceRaw !== undefined)
|
||||
root.createPool(snapshot)
|
||||
else
|
||||
root.addLiquidity(snapshot)
|
||||
|
||||
@@ -228,11 +228,11 @@ QVariantList AmmUiBackend::tokenList()
|
||||
return m_logos->amm_module.tokenList();
|
||||
}
|
||||
|
||||
QVariantMap AmmUiBackend::liquidityQuote(QVariantMap request)
|
||||
QVariantMap AmmUiBackend::createPoolQuote(QVariantMap request)
|
||||
{
|
||||
// Read-only create-pool preview — no wallet guard. The module prices the opening
|
||||
// LP and price server-side from the two deposit amounts.
|
||||
return m_logos->amm_module.liquidityQuote(request);
|
||||
return m_logos->amm_module.createPoolQuote(request);
|
||||
}
|
||||
|
||||
QVariantMap AmmUiBackend::addLiquidityQuote(QVariantMap request)
|
||||
|
||||
@@ -69,11 +69,11 @@ public slots:
|
||||
// Reads the token list from TOKENS_CONFIG (via the module) so the Swap UI's
|
||||
// token picker is config-driven instead of hardcoded.
|
||||
QVariantList tokenList() override;
|
||||
// Create-pool preview (liquidityQuote, read-only) and submit (createPool). The caller
|
||||
// Create-pool preview (createPoolQuote, read-only) and submit (createPool). The caller
|
||||
// supplies lpHoldingId in the request — a fresh account it created via
|
||||
// createAccountPublic() — so createPool forwards to the module and creates no wallet
|
||||
// accounts here.
|
||||
QVariantMap liquidityQuote(QVariantMap request) override;
|
||||
QVariantMap createPoolQuote(QVariantMap request) override;
|
||||
// Read-only add-liquidity preview (forwards to the module).
|
||||
QVariantMap addLiquidityQuote(QVariantMap request) override;
|
||||
QVariantMap createPool(QVariantMap request) override;
|
||||
|
||||
@@ -101,7 +101,7 @@ class AmmUiBackend
|
||||
// same_token_pair, amount_too_low, amount_required, bad_amount, backend_error.
|
||||
// Read-only, no submission (the fee is not needed — it isn't part of the pool
|
||||
// PDA nor the pricing).
|
||||
SLOT(QVariantMap liquidityQuote(QVariantMap request))
|
||||
SLOT(QVariantMap createPoolQuote(QVariantMap request))
|
||||
// Server-side add-liquidity preview from the two max deposit amounts. `request`
|
||||
// carries { tokenAId, tokenBId, maxAmountARaw, maxAmountBRaw, slippageBps } (ids hex or
|
||||
// base58). Reads the pool and returns { status:"ok", error:"", amountARaw, amountBRaw
|
||||
|
||||
@@ -197,7 +197,7 @@ TestCase {
|
||||
verify(built.ok)
|
||||
compare(built.request.amountARaw, "100")
|
||||
compare(built.request.amountBRaw, "150")
|
||||
compare(built.request.initialPriceRealRaw, "27670116110564327424")
|
||||
compare(built.request.priceRaw, "27670116110564327424")
|
||||
verify(!built.request.hasOwnProperty("depositScaleBps"))
|
||||
|
||||
form.finishMissingAmount("B", "200")
|
||||
|
||||
@@ -36,7 +36,7 @@ char *amm_swap_exact_in_plan(const char *request_json);
|
||||
|
||||
char *amm_swap_exact_out_plan(const char *request_json);
|
||||
|
||||
char *amm_liquidity_quote(const char *request_json);
|
||||
char *amm_create_pool_quote(const char *request_json);
|
||||
|
||||
char *amm_create_pool_plan(const char *request_json);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! returning JSON `Value`, and the token pair canonicalized server-side so callers
|
||||
//! keep no ordering logic.
|
||||
//!
|
||||
//! `liquidity_quote` is a **pure create-pool preview**: a function of the caller's
|
||||
//! `create_pool_quote` is a **pure create-pool preview**: a function of the caller's
|
||||
//! own inputs (the two deposit amounts) with no chain reads and no commitment
|
||||
//! — it prices the opening LP and price via the same `amm_core` primitives the guest
|
||||
//! runs (`isqrt_product`, `MINIMUM_LIQUIDITY`, `spot_price_q64_64`), so the preview
|
||||
@@ -22,7 +22,7 @@ use super::{
|
||||
pair::{derive_pair, is_canonical_pair},
|
||||
quote::minimum_opening_pair,
|
||||
AddLiquidityPlanRequest, AddLiquidityQuoteRequest, CreatePoolPlanRequest,
|
||||
LiquidityQuoteRequest, RemoveLiquidityPlanRequest, RemoveLiquidityQuoteRequest,
|
||||
CreatePoolQuoteRequest, RemoveLiquidityPlanRequest, RemoveLiquidityQuoteRequest,
|
||||
SyncReservesPlanRequest,
|
||||
};
|
||||
use crate::account::{account_id_from_hex, account_id_hex, parse_program_id};
|
||||
@@ -91,14 +91,14 @@ fn plan_response(
|
||||
///
|
||||
/// The opening price *is* the deposit ratio. With **amounts** supplied, the op uses them and
|
||||
/// derives the price (`spot_price_q64_64`); **price-only** (no amounts), it takes
|
||||
/// `initial_price_real_raw` (Q64.64, canonical) and uses `minimum_opening_pair` — the smallest
|
||||
/// `price_raw` (Q64.64, canonical) and uses `minimum_opening_pair` — the smallest
|
||||
/// deposit at that price that clears the permanently-locked `MINIMUM_LIQUIDITY`. Either way it
|
||||
/// also returns that `minimum*` pair (the form validates entered amounts against it) and
|
||||
/// `expected_lp = floor(sqrt(a·b)) - MINIMUM_LIQUIDITY` (LP is orientation-independent — the
|
||||
/// product is symmetric). Errors: `same_token_pair`, `amount_required` (price-only without a
|
||||
/// price), `invalid_raw_amount`, `amount_must_be_positive`, `amount_too_low` (deposits too
|
||||
/// small to clear the locked minimum).
|
||||
pub(super) fn liquidity_quote(request: LiquidityQuoteRequest) -> Result<Value, String> {
|
||||
pub(super) fn create_pool_quote(request: CreatePoolQuoteRequest) -> Result<Value, String> {
|
||||
let token_a = account_id_from_hex(&request.token_a_id, "token A id")?;
|
||||
let token_b = account_id_from_hex(&request.token_b_id, "token B id")?;
|
||||
if token_a == token_b {
|
||||
@@ -116,7 +116,7 @@ pub(super) fn liquidity_quote(request: LiquidityQuoteRequest) -> Result<Value, S
|
||||
};
|
||||
let price = match amounts {
|
||||
Some((amount_a, amount_b)) => spot_price_q64_64(amount_a, amount_b),
|
||||
None => positive_amount(request.initial_price_real_raw.as_deref())?,
|
||||
None => positive_amount(request.price_raw.as_deref())?,
|
||||
};
|
||||
let (minimum_a, minimum_b) = minimum_opening_pair(price)?;
|
||||
let (actual_a, actual_b) = amounts.unwrap_or((minimum_a, minimum_b));
|
||||
@@ -136,7 +136,7 @@ pub(super) fn liquidity_quote(request: LiquidityQuoteRequest) -> Result<Value, S
|
||||
"minimumAmountBRaw": minimum_b.to_string(),
|
||||
"expectedLpRaw": expected_lp.to_string(),
|
||||
"lockedLpRaw": MINIMUM_LIQUIDITY.to_string(),
|
||||
"initialPriceRealRaw": price.to_string(),
|
||||
"priceRaw": price.to_string(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -635,11 +635,11 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::account::{account_read, AccountRead};
|
||||
|
||||
fn quote_request(token_a: AccountId, token_b: AccountId) -> LiquidityQuoteRequest {
|
||||
LiquidityQuoteRequest {
|
||||
fn quote_request(token_a: AccountId, token_b: AccountId) -> CreatePoolQuoteRequest {
|
||||
CreatePoolQuoteRequest {
|
||||
token_a_id: account_id_hex(token_a),
|
||||
token_b_id: account_id_hex(token_b),
|
||||
initial_price_real_raw: None,
|
||||
price_raw: None,
|
||||
amount_a_raw: Some(String::from("1000000")),
|
||||
amount_b_raw: Some(String::from("4000000")),
|
||||
}
|
||||
@@ -673,7 +673,7 @@ mod tests {
|
||||
fn create_quote_prices_supplied_amounts() {
|
||||
let token_a = AccountId::new([0xAA; 32]);
|
||||
let token_b = AccountId::new([0xBB; 32]);
|
||||
let value = liquidity_quote(quote_request(token_a, token_b)).unwrap();
|
||||
let value = create_pool_quote(quote_request(token_a, token_b)).unwrap();
|
||||
|
||||
// Amounts supplied ⇒ actual == the amounts; the price is derived from them.
|
||||
assert_eq!(value["actualAmountARaw"], "1000000");
|
||||
@@ -686,7 +686,7 @@ mod tests {
|
||||
(initial_lp - MINIMUM_LIQUIDITY).to_string()
|
||||
);
|
||||
let price = spot_price_q64_64(1_000_000, 4_000_000);
|
||||
assert_eq!(value["initialPriceRealRaw"], price.to_string());
|
||||
assert_eq!(value["priceRaw"], price.to_string());
|
||||
// The minimum opening deposit for that price is echoed for the form to validate against.
|
||||
let (min_a, min_b) = minimum_opening_pair(price).unwrap();
|
||||
assert_eq!(value["minimumAmountARaw"], min_a.to_string());
|
||||
@@ -704,10 +704,10 @@ mod tests {
|
||||
let price = spot_price_q64_64(1_000_000, 4_000_000);
|
||||
let (min_a, min_b) = minimum_opening_pair(price).unwrap();
|
||||
|
||||
let value = liquidity_quote(LiquidityQuoteRequest {
|
||||
let value = create_pool_quote(CreatePoolQuoteRequest {
|
||||
token_a_id: account_id_hex(token_a),
|
||||
token_b_id: account_id_hex(token_b),
|
||||
initial_price_real_raw: Some(price.to_string()),
|
||||
price_raw: Some(price.to_string()),
|
||||
amount_a_raw: None,
|
||||
amount_b_raw: None,
|
||||
})
|
||||
@@ -718,19 +718,19 @@ mod tests {
|
||||
assert_eq!(value["actualAmountBRaw"], min_b.to_string());
|
||||
assert_eq!(value["minimumAmountARaw"], min_a.to_string());
|
||||
assert_eq!(value["minimumAmountBRaw"], min_b.to_string());
|
||||
assert_eq!(value["initialPriceRealRaw"], price.to_string());
|
||||
assert_eq!(value["priceRaw"], price.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_quote_lp_is_orientation_independent() {
|
||||
let token_a = AccountId::new([0xAA; 32]);
|
||||
let token_b = AccountId::new([0xBB; 32]);
|
||||
let ab = liquidity_quote(quote_request(token_a, token_b)).unwrap();
|
||||
let ab = create_pool_quote(quote_request(token_a, token_b)).unwrap();
|
||||
// Swap display order and the paired amounts: the LP figure is symmetric.
|
||||
let mut ba = quote_request(token_b, token_a);
|
||||
ba.amount_a_raw = Some(String::from("4000000"));
|
||||
ba.amount_b_raw = Some(String::from("1000000"));
|
||||
let ba = liquidity_quote(ba).unwrap();
|
||||
let ba = create_pool_quote(ba).unwrap();
|
||||
assert_eq!(ab["expectedLpRaw"], ba["expectedLpRaw"]);
|
||||
}
|
||||
|
||||
@@ -738,7 +738,7 @@ mod tests {
|
||||
fn create_quote_rejects_same_token_and_tiny_amounts() {
|
||||
let token = AccountId::new([0xAA; 32]);
|
||||
assert_eq!(
|
||||
liquidity_quote(quote_request(token, token)),
|
||||
create_pool_quote(quote_request(token, token)),
|
||||
Err(String::from("same_token_pair"))
|
||||
);
|
||||
|
||||
@@ -747,7 +747,7 @@ mod tests {
|
||||
let mut tiny = quote_request(token, token_b);
|
||||
tiny.amount_a_raw = Some(String::from("1"));
|
||||
tiny.amount_b_raw = Some(String::from("1"));
|
||||
assert_eq!(liquidity_quote(tiny), Err(String::from("amount_too_low")));
|
||||
assert_eq!(create_pool_quote(tiny), Err(String::from("amount_too_low")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::{error::Error, fmt};
|
||||
|
||||
pub use request::{
|
||||
AddLiquidityPlanRequest, AddLiquidityQuoteRequest, ConfigIdRequest, ContextRequest,
|
||||
CreatePoolPlanRequest, LiquidityQuoteRequest, PairIdsRequest, PoolIdRequest, ProgramIdRequest,
|
||||
CreatePoolPlanRequest, CreatePoolQuoteRequest, PairIdsRequest, PoolIdRequest, ProgramIdRequest,
|
||||
RemoveLiquidityPlanRequest, RemoveLiquidityQuoteRequest, ResolvePoolRequest,
|
||||
SwapExactInPlanRequest, SwapExactInQuoteRequest, SwapExactOutPlanRequest,
|
||||
SwapExactOutQuoteRequest, SwapPairRequest, SyncReservesPlanRequest, TokenHoldingsRequest,
|
||||
@@ -118,8 +118,8 @@ pub fn swap_exact_out_plan(request: SwapExactOutPlanRequest) -> AmmResult {
|
||||
}
|
||||
|
||||
/// Prices a create-pool deposit: the LP the creator receives and the opening price.
|
||||
pub fn liquidity_quote(request: LiquidityQuoteRequest) -> AmmResult {
|
||||
liquidity::liquidity_quote(request).map_err(Into::into)
|
||||
pub fn create_pool_quote(request: CreatePoolQuoteRequest) -> AmmResult {
|
||||
liquidity::create_pool_quote(request).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Builds the `NewDefinition` submission for creating a pool.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Shared opening-deposit math for pool creation.
|
||||
//!
|
||||
//! Reused by `liquidity::liquidity_quote` to size the smallest deposit that clears
|
||||
//! Reused by `liquidity::create_pool_quote` to size the smallest deposit that clears
|
||||
//! `MINIMUM_LIQUIDITY` for a given opening price.
|
||||
|
||||
use alloy_primitives::U256;
|
||||
|
||||
@@ -137,14 +137,14 @@ pub struct SwapExactOutPlanRequest {
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LiquidityQuoteRequest {
|
||||
pub struct CreatePoolQuoteRequest {
|
||||
pub token_a_id: String,
|
||||
pub token_b_id: String,
|
||||
/// The opening price as a `Q64.64` fixed-point value (token B per token A, canonical
|
||||
/// order). Required only in the price-only mode (no `amount_*_raw`), where it drives the
|
||||
/// minimum opening deposit; when amounts are supplied the op derives the price from them.
|
||||
#[serde(default)]
|
||||
pub initial_price_real_raw: Option<String>,
|
||||
pub price_raw: Option<String>,
|
||||
#[serde(default)]
|
||||
pub amount_a_raw: Option<String>,
|
||||
#[serde(default)]
|
||||
@@ -174,7 +174,7 @@ pub struct CreatePoolPlanRequest {
|
||||
}
|
||||
|
||||
/// Prices an `AddLiquidity` into an existing pool — the add counterpart of
|
||||
/// `LiquidityQuoteRequest`. The two max amounts are the caller's caps (display order);
|
||||
/// `CreatePoolQuoteRequest`. The two max amounts are the caller's caps (display order);
|
||||
/// `pool_data` is the hex Borsh `PoolDefinition` (empty ⇒ no pool), same as the swap quotes.
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
||||
@@ -7,7 +7,7 @@ use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
use crate::api::{
|
||||
self, AddLiquidityPlanRequest, AddLiquidityQuoteRequest, AmmApiError, AmmResult,
|
||||
ConfigIdRequest, ContextRequest, CreatePoolPlanRequest, LiquidityQuoteRequest, PairIdsRequest,
|
||||
ConfigIdRequest, ContextRequest, CreatePoolPlanRequest, CreatePoolQuoteRequest, PairIdsRequest,
|
||||
PoolIdRequest, ProgramIdRequest, RemoveLiquidityPlanRequest, RemoveLiquidityQuoteRequest,
|
||||
ResolvePoolRequest, SwapExactInPlanRequest, SwapExactInQuoteRequest, SwapExactOutPlanRequest,
|
||||
SwapExactOutQuoteRequest, SwapPairRequest, SyncReservesPlanRequest, TokenHoldingsRequest,
|
||||
@@ -136,8 +136,8 @@ pub extern "C" fn amm_swap_exact_out_plan(request_json: *const c_char) -> *mut c
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn amm_liquidity_quote(request_json: *const c_char) -> *mut c_char {
|
||||
call::<LiquidityQuoteRequest>(request_json, api::liquidity_quote)
|
||||
pub extern "C" fn amm_create_pool_quote(request_json: *const c_char) -> *mut c_char {
|
||||
call::<CreatePoolQuoteRequest>(request_json, api::create_pool_quote)
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
||||
@@ -6,10 +6,10 @@ mod ffi;
|
||||
pub mod api;
|
||||
|
||||
pub use api::{
|
||||
config_id, context, create_pool_plan, liquidity_quote, pair_ids, pool_id, program_id,
|
||||
config_id, context, create_pool_plan, create_pool_quote, pair_ids, pool_id, program_id,
|
||||
resolve_pool, swap_exact_in_plan, swap_exact_in_quote, swap_exact_out_plan,
|
||||
swap_exact_out_quote, swap_pair, token_ids, AccountRead, AmmApiError, AmmResponse, AmmResult,
|
||||
ConfigIdRequest, ContextRequest, CreatePoolPlanRequest, LiquidityQuoteRequest, PairIdsRequest,
|
||||
ConfigIdRequest, ContextRequest, CreatePoolPlanRequest, CreatePoolQuoteRequest, PairIdsRequest,
|
||||
PoolIdRequest, ProgramIdRequest, ResolvePoolRequest, SwapExactInPlanRequest,
|
||||
SwapExactInQuoteRequest, SwapExactOutPlanRequest, SwapExactOutQuoteRequest, SwapPairRequest,
|
||||
TokenIdsRequest, WalletAccount,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use amm_ffi::{
|
||||
config_id, create_pool_plan, liquidity_quote, AmmResult, ConfigIdRequest,
|
||||
CreatePoolPlanRequest, LiquidityQuoteRequest,
|
||||
config_id, create_pool_plan, create_pool_quote, AmmResult, ConfigIdRequest,
|
||||
CreatePoolPlanRequest, CreatePoolQuoteRequest,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -15,14 +15,14 @@ fn direct_rust_api_does_not_require_ffi() {
|
||||
}
|
||||
|
||||
// The create-pool surface must be reachable from the crate root too — Rust callers import from
|
||||
// `amm_ffi::`, not `amm_ffi::api`. liquidity_quote is a pure preview, so exercise it directly;
|
||||
// `amm_ffi::`, not `amm_ffi::api`. create_pool_quote is a pure preview, so exercise it directly;
|
||||
// create_pool_plan needs chain reads, so a typed reference is enough to pin the re-export.
|
||||
#[test]
|
||||
fn create_pool_surface_is_reexported_from_crate_root() {
|
||||
let quote = liquidity_quote(LiquidityQuoteRequest {
|
||||
let quote = create_pool_quote(CreatePoolQuoteRequest {
|
||||
token_a_id: "11".repeat(32),
|
||||
token_b_id: "22".repeat(32),
|
||||
initial_price_real_raw: None, // amounts supplied ⇒ the op derives the price
|
||||
price_raw: None, // amounts supplied ⇒ the op derives the price
|
||||
amount_a_raw: Some("1000000".into()),
|
||||
amount_b_raw: Some("4000000".into()),
|
||||
})
|
||||
|
||||
@@ -733,7 +733,7 @@ std::string AmmModuleImpl::swapExactOutput(const std::string& def_a_hex,
|
||||
return jStr(obj, "tx_hash");
|
||||
}
|
||||
|
||||
LogosMap AmmModuleImpl::liquidityQuote(const LogosMap& request) {
|
||||
LogosMap AmmModuleImpl::createPoolQuote(const LogosMap& request) {
|
||||
auto error = [](const std::string& err) {
|
||||
return LogosMap{{"status", "error"}, {"error", err}};
|
||||
};
|
||||
@@ -753,11 +753,11 @@ LogosMap AmmModuleImpl::liquidityQuote(const LogosMap& request) {
|
||||
{"tokenAId", token_a},
|
||||
{"tokenBId", token_b},
|
||||
};
|
||||
// initialPriceRealRaw is the Q64.64 opening price; used when no amounts are supplied
|
||||
// priceRaw is the Q64.64 opening price; used when no amounts are supplied
|
||||
// (price-only ⇒ the op returns the minimum opening deposit). Left out if absent.
|
||||
std::string price_decimal;
|
||||
if (jsonAmountToDecimal(request.value("initialPriceRealRaw", json()), price_decimal))
|
||||
quoteRequest["initialPriceRealRaw"] = price_decimal;
|
||||
if (jsonAmountToDecimal(request.value("priceRaw", json()), price_decimal))
|
||||
quoteRequest["priceRaw"] = price_decimal;
|
||||
if (request.contains("amountARaw")) {
|
||||
std::string amount_a_decimal;
|
||||
if (!jsonAmountToDecimal(request.at("amountARaw"), amount_a_decimal))
|
||||
@@ -771,12 +771,12 @@ LogosMap AmmModuleImpl::liquidityQuote(const LogosMap& request) {
|
||||
quoteRequest["amountBRaw"] = amount_b_decimal;
|
||||
}
|
||||
|
||||
const FfiResult quoteResult = call(amm_liquidity_quote, quoteRequest);
|
||||
const FfiResult quoteResult = call(amm_create_pool_quote, quoteRequest);
|
||||
if (!quoteResult.ok)
|
||||
return error(quoteResult.error.empty() ? "backend_error" : quoteResult.error);
|
||||
|
||||
// Success: wrap { actualAmountARaw, actualAmountBRaw, minimumAmountARaw,
|
||||
// minimumAmountBRaw, expectedLpRaw, lockedLpRaw, initialPriceRealRaw } in the envelope.
|
||||
// minimumAmountBRaw, expectedLpRaw, lockedLpRaw, priceRaw } in the envelope.
|
||||
LogosMap out = quoteResult.value;
|
||||
out["status"] = "ok";
|
||||
out["error"] = "";
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
/// `invalid_raw_amount`, `amount_must_be_positive`, `same_token_pair`, and
|
||||
/// `amount_too_low` come from the FFI; the rest from the module. The caller decides
|
||||
/// create-vs-add by pool existence before calling this.
|
||||
LogosMap liquidityQuote(const LogosMap& request);
|
||||
LogosMap createPoolQuote(const LogosMap& request);
|
||||
|
||||
/// Submits a `NewDefinition` transaction creating the pool for the request's pair.
|
||||
/// `request` carries `{ tokenAId, tokenBId, holdingAId, holdingBId, lpHoldingId,
|
||||
@@ -136,7 +136,7 @@ public:
|
||||
|
||||
/// Prices an `AddLiquidity` into the existing pool for (tokenAId, tokenBId) from the
|
||||
/// two max deposit amounts. Reads the pool server-side (like the swap quotes) and runs
|
||||
/// the guest's proportional-deposit math. Returns the same shape as `liquidityQuote`
|
||||
/// the guest's proportional-deposit math. Returns the same shape as `createPoolQuote`
|
||||
/// minus the create-only locked LP: `{ status:"ok", error:"", amountARaw, amountBRaw,
|
||||
/// expectedLpRaw, priceRaw }` — the actual ratio-matched deposits (display order), the
|
||||
/// LP minted, and the pool's spot price. Slippage is applied at submit, not here.
|
||||
|
||||
Reference in New Issue
Block a user