rename canocial amount to price
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
**Goal:** Build the `solisting` Anchor program — a coordination and discovery layer for product listings and bilateral order consent, orchestrating the full flow from buyer intent → bilateral consent → active `descro` escrow without ever touching the descro vault directly.
|
||||
|
||||
**Architecture:**
|
||||
- `ListingAccount` holds a single canonical price (`canonical_currency` + `canonical_amount`) as the sole source of truth. Alternative currencies (`alt_currencies: Vec<AltCurrencyConfig>`) are always converted from canonical at `create_order` time via on-chain Pyth oracles — no independent price per currency, no arbitrage possible.
|
||||
- `ListingAccount` holds a single canonical price (`canonical_currency` + `price`) as the sole source of truth. Alternative currencies (`alt_currencies: Vec<AltCurrencyConfig>`) are always converted from canonical at `create_order` time via on-chain Pyth oracles — no independent price per currency, no arbitrage possible.
|
||||
- Each `AltCurrencyConfig` carries its own `usd_oracle: Option<Pubkey>` (the Pyth TOKEN/USD feed for that token; `None` = treat as a $1 USD stablecoin). The canonical currency has a parallel `canonical_oracle: Option<Pubkey>`. `Currency::Spl` stores `decimals: u8` so the program never needs to look up the mint.
|
||||
- `OrderAccount` records the bilateral consent: which currency the buyer chose, the oracle-computed amount, and a pointer to the descro escrow.
|
||||
- The oracle module converts between any two currencies through USD as an intermediate (using up to two Pyth feeds): `canonical_usd = amount × canonical_price`, `target_amount = canonical_usd ÷ target_price`. Both sides can independently be a stablecoin (`None` oracle = $1 peg, no account needed).
|
||||
@@ -176,7 +176,7 @@ pub struct ListingAccount {
|
||||
/// Sole source of truth for price. All alt_currencies are derived from this via oracle.
|
||||
pub canonical_currency: Currency,
|
||||
/// Price in canonical_currency's smallest unit.
|
||||
pub canonical_amount: u64,
|
||||
pub price: u64,
|
||||
/// Pyth V2 PriceFeedAccount for the canonical currency priced in USD.
|
||||
/// `None` = canonical is a $1.00 USD stablecoin.
|
||||
/// For Sol canonical: set to the SOL/USD Pyth feed.
|
||||
@@ -208,7 +208,7 @@ pub struct OrderAccount {
|
||||
pub resolver: Pubkey,
|
||||
/// The currency the buyer chose to pay in.
|
||||
pub payment_currency: Currency,
|
||||
/// Actual amount paid (may differ from canonical_amount when oracle-converted).
|
||||
/// Actual amount paid (may differ from price when oracle-converted).
|
||||
pub amount: u64,
|
||||
/// The descro EscrowAccount PDA for this order.
|
||||
pub escrow_account: Pubkey,
|
||||
@@ -264,9 +264,9 @@ verifies that the passed account key matches the stored key (done in `create_ord
|
||||
Math (using USD as pivot):
|
||||
|
||||
```
|
||||
canonical_usd = canonical_amount × (cp_raw × 10^cp_expo) / 10^cd
|
||||
canonical_usd = price × (cp_raw × 10^cp_expo) / 10^cd
|
||||
target_amount = canonical_usd × 10^td / (tp_raw × 10^tp_expo)
|
||||
= canonical_amount × cp_raw / tp_raw × 10^(cp_expo − tp_expo + td − cd)
|
||||
= price × cp_raw / tp_raw × 10^(cp_expo − tp_expo + td − cd)
|
||||
let shift = cp_expo − tp_expo + td − cd (can be positive or negative)
|
||||
```
|
||||
|
||||
@@ -313,7 +313,7 @@ fn usd_price(oracle: Option<&AccountInfo>) -> Result<(i64, i32)> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `canonical_amount` (smallest units of `canonical_currency`) to the equivalent
|
||||
/// Converts `price` (smallest units of `canonical_currency`) to the equivalent
|
||||
/// amount in `target_currency` smallest units, using USD as an intermediate.
|
||||
///
|
||||
/// `canonical_oracle` / `target_oracle`: pass `None` when the currency is a USD stablecoin.
|
||||
@@ -324,7 +324,7 @@ fn usd_price(oracle: Option<&AccountInfo>) -> Result<(i64, i32)> {
|
||||
pub fn convert_with_slippage(
|
||||
canonical_oracle: Option<&AccountInfo>,
|
||||
canonical_currency: &Currency,
|
||||
canonical_amount: u64,
|
||||
price: u64,
|
||||
target_oracle: Option<&AccountInfo>,
|
||||
target_currency: &Currency,
|
||||
expected_amount: u64,
|
||||
@@ -339,9 +339,9 @@ pub fn convert_with_slippage(
|
||||
// shift = cp_expo − tp_expo + td − cd
|
||||
let shift: i32 = cp_expo - tp_expo + td - cd;
|
||||
|
||||
// target = canonical_amount × cp_raw / tp_raw × 10^shift
|
||||
// target = price × cp_raw / tp_raw × 10^shift
|
||||
// Use u128 to avoid overflow. tp_raw and cp_raw are always positive (checked above).
|
||||
let numerator = (canonical_amount as u128)
|
||||
let numerator = (price as u128)
|
||||
.checked_mul(cp_raw as u128)
|
||||
.ok_or(error!(SolistingError::OraclePriceUnavailable))?;
|
||||
|
||||
@@ -418,7 +418,7 @@ fn seller_can_create_sol_only_listing() {
|
||||
|
||||
let listing = read_listing(&svm, &seller.pubkey(), listing_id);
|
||||
assert_eq!(listing.canonical_currency, Currency::Sol);
|
||||
assert_eq!(listing.canonical_amount, price);
|
||||
assert_eq!(listing.price, price);
|
||||
assert_eq!(listing.alt_currencies.len(), 0);
|
||||
assert_eq!(listing.canonical_oracle, None);
|
||||
assert_eq!(listing.quantity, 10);
|
||||
@@ -502,7 +502,7 @@ fn seller_can_update_listing() {
|
||||
send(&mut svm, &[ix_update], &[&seller]);
|
||||
|
||||
let listing = read_listing(&svm, &seller.pubkey(), listing_id);
|
||||
assert_eq!(listing.canonical_amount, 2_000_000_000);
|
||||
assert_eq!(listing.price, 2_000_000_000);
|
||||
assert_eq!(listing.quantity, 20);
|
||||
}
|
||||
|
||||
@@ -558,7 +558,7 @@ pub fn handler(
|
||||
ctx: Context<CreateListing>,
|
||||
listing_id: u64,
|
||||
canonical_currency: Currency,
|
||||
canonical_amount: u64,
|
||||
price: u64,
|
||||
canonical_oracle: Option<Pubkey>,
|
||||
alt_currencies: Vec<AltCurrencyConfig>,
|
||||
accepted_resolvers: Vec<Pubkey>,
|
||||
@@ -568,7 +568,7 @@ pub fn handler(
|
||||
let listing = &mut ctx.accounts.listing_account;
|
||||
listing.seller = ctx.accounts.seller.key();
|
||||
listing.canonical_currency = canonical_currency;
|
||||
listing.canonical_amount = canonical_amount;
|
||||
listing.price = price;
|
||||
listing.canonical_oracle = canonical_oracle;
|
||||
listing.alt_currencies = alt_currencies;
|
||||
listing.accepted_resolvers = accepted_resolvers;
|
||||
@@ -606,7 +606,7 @@ pub struct UpdateListing<'info> {
|
||||
pub fn handler(
|
||||
ctx: Context<UpdateListing>,
|
||||
canonical_currency: Currency,
|
||||
canonical_amount: u64,
|
||||
price: u64,
|
||||
canonical_oracle: Option<Pubkey>,
|
||||
alt_currencies: Vec<AltCurrencyConfig>,
|
||||
accepted_resolvers: Vec<Pubkey>,
|
||||
@@ -615,7 +615,7 @@ pub fn handler(
|
||||
) -> Result<()> {
|
||||
let listing = &mut ctx.accounts.listing_account;
|
||||
listing.canonical_currency = canonical_currency;
|
||||
listing.canonical_amount = canonical_amount;
|
||||
listing.price = price;
|
||||
listing.canonical_oracle = canonical_oracle;
|
||||
listing.alt_currencies = alt_currencies;
|
||||
listing.accepted_resolvers = accepted_resolvers;
|
||||
@@ -702,7 +702,7 @@ pub fn ix_create_listing(
|
||||
seller: &Pubkey,
|
||||
listing_id: u64,
|
||||
canonical_currency: Currency,
|
||||
canonical_amount: u64,
|
||||
price: u64,
|
||||
canonical_oracle: Option<Pubkey>,
|
||||
alt_currencies: Vec<AltCurrencyConfig>,
|
||||
accepted_resolvers: Vec<Pubkey>,
|
||||
@@ -716,7 +716,7 @@ pub fn ix_update_listing(
|
||||
seller: &Pubkey,
|
||||
listing_id: u64,
|
||||
canonical_currency: Currency,
|
||||
canonical_amount: u64,
|
||||
price: u64,
|
||||
canonical_oracle: Option<Pubkey>,
|
||||
alt_currencies: Vec<AltCurrencyConfig>,
|
||||
accepted_resolvers: Vec<Pubkey>,
|
||||
@@ -771,7 +771,7 @@ pub mod solisting {
|
||||
ctx: Context<CreateListing>,
|
||||
listing_id: u64,
|
||||
canonical_currency: state::Currency,
|
||||
canonical_amount: u64,
|
||||
price: u64,
|
||||
canonical_oracle: Option<Pubkey>,
|
||||
alt_currencies: Vec<state::AltCurrencyConfig>,
|
||||
accepted_resolvers: Vec<Pubkey>,
|
||||
@@ -779,7 +779,7 @@ pub mod solisting {
|
||||
metadata_uri: String,
|
||||
) -> Result<()> {
|
||||
create_listing::handler(
|
||||
ctx, listing_id, canonical_currency, canonical_amount,
|
||||
ctx, listing_id, canonical_currency, price,
|
||||
canonical_oracle, alt_currencies, accepted_resolvers, quantity, metadata_uri,
|
||||
)
|
||||
}
|
||||
@@ -787,7 +787,7 @@ pub mod solisting {
|
||||
pub fn update_listing(
|
||||
ctx: Context<UpdateListing>,
|
||||
canonical_currency: state::Currency,
|
||||
canonical_amount: u64,
|
||||
price: u64,
|
||||
canonical_oracle: Option<Pubkey>,
|
||||
alt_currencies: Vec<state::AltCurrencyConfig>,
|
||||
accepted_resolvers: Vec<Pubkey>,
|
||||
@@ -795,7 +795,7 @@ pub mod solisting {
|
||||
metadata_uri: String,
|
||||
) -> Result<()> {
|
||||
update_listing::handler(
|
||||
ctx, canonical_currency, canonical_amount,
|
||||
ctx, canonical_currency, price,
|
||||
canonical_oracle, alt_currencies, accepted_resolvers, quantity, metadata_uri,
|
||||
)
|
||||
}
|
||||
@@ -844,7 +844,7 @@ fn buyer_can_create_order_canonical_sol() {
|
||||
// Buyer creates order paying in Sol
|
||||
// Assert: OrderAccount exists with payment_currency=Sol, amount=0.1 SOL in lamports
|
||||
// Assert: descro EscrowAccount exists, state == AwaitingSellerConfirm
|
||||
// Assert: descro vault has listing.canonical_amount lamports
|
||||
// Assert: descro vault has listing.price lamports
|
||||
// Assert: listing.quantity_reserved == 1
|
||||
let (mut svm, seller, buyer) = setup();
|
||||
let listing_id = 1u64;
|
||||
@@ -1037,7 +1037,7 @@ pub fn handler(
|
||||
// Determine amount in payment_currency
|
||||
let amount = if payment_currency == listing.canonical_currency {
|
||||
// Paying in canonical currency — no oracle needed
|
||||
listing.canonical_amount
|
||||
listing.price
|
||||
} else {
|
||||
// Must be a configured alt_currency
|
||||
let alt_cfg = listing.alt_currencies
|
||||
@@ -1065,7 +1065,7 @@ pub fn handler(
|
||||
oracle::convert_with_slippage(
|
||||
c_oracle,
|
||||
&listing.canonical_currency,
|
||||
listing.canonical_amount,
|
||||
listing.price,
|
||||
t_oracle,
|
||||
&payment_currency,
|
||||
expected_amount,
|
||||
@@ -1745,12 +1745,12 @@ declare_id!("So1istingProgramID11111111111111111111111111"); // replace with: so
|
||||
pub mod solisting {
|
||||
use super::*;
|
||||
|
||||
pub fn create_listing(ctx: Context<CreateListing>, listing_id: u64, canonical_currency: state::Currency, canonical_amount: u64, canonical_oracle: Option<Pubkey>, alt_currencies: Vec<state::AltCurrencyConfig>, accepted_resolvers: Vec<Pubkey>, quantity: u32, metadata_uri: String) -> Result<()> {
|
||||
create_listing::handler(ctx, listing_id, canonical_currency, canonical_amount, canonical_oracle, alt_currencies, accepted_resolvers, quantity, metadata_uri)
|
||||
pub fn create_listing(ctx: Context<CreateListing>, listing_id: u64, canonical_currency: state::Currency, price: u64, canonical_oracle: Option<Pubkey>, alt_currencies: Vec<state::AltCurrencyConfig>, accepted_resolvers: Vec<Pubkey>, quantity: u32, metadata_uri: String) -> Result<()> {
|
||||
create_listing::handler(ctx, listing_id, canonical_currency, price, canonical_oracle, alt_currencies, accepted_resolvers, quantity, metadata_uri)
|
||||
}
|
||||
|
||||
pub fn update_listing(ctx: Context<UpdateListing>, canonical_currency: state::Currency, canonical_amount: u64, canonical_oracle: Option<Pubkey>, alt_currencies: Vec<state::AltCurrencyConfig>, accepted_resolvers: Vec<Pubkey>, quantity: u32, metadata_uri: String) -> Result<()> {
|
||||
update_listing::handler(ctx, canonical_currency, canonical_amount, canonical_oracle, alt_currencies, accepted_resolvers, quantity, metadata_uri)
|
||||
pub fn update_listing(ctx: Context<UpdateListing>, canonical_currency: state::Currency, price: u64, canonical_oracle: Option<Pubkey>, alt_currencies: Vec<state::AltCurrencyConfig>, accepted_resolvers: Vec<Pubkey>, quantity: u32, metadata_uri: String) -> Result<()> {
|
||||
update_listing::handler(ctx, canonical_currency, price, canonical_oracle, alt_currencies, accepted_resolvers, quantity, metadata_uri)
|
||||
}
|
||||
|
||||
pub fn close_listing(ctx: Context<CloseListing>) -> Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user