Skip to main content
Diese Seite wurde mit KI automatisch übersetzt. Maßgeblich ist stets die englische Version.Englische Version ansehen →

Die Invariante

CPMM erhält die klassische Constant-Product-Invariante auf seinen beiden Vaults: x⋅y=kx \cdot y = k wobei x der Vault0-Saldo nach allen Token-2022-Transfergebühren beim Empfang ist, und entsprechend für y. Jeder Swap muss k' ≥ k hinterlassen, nachdem Handelsgebühren berücksichtigt wurden, die den LPs gutgeschrieben werden (die Protokoll-, Fonds- und Creator-Buckets werden nicht zu k gezählt — sie befinden sich im Vault, sind aber von der Kurvenansicht ausgeschlossen, siehe Gebühren auf der Kurve unten). k wächst daher monoton über die Zeit, wenn LPs Gebühren akkumulieren. LP-Anteile werden nach den Pool-Reserven bewertet, nicht nach k: LP-Preis in Token0=xlpSupply,LP-Preis in Token1=ylpSupply\text{LP-Preis in Token0} = \frac{x}{\text{lpSupply}}, \qquad \text{LP-Preis in Token1} = \frac{y}{\text{lpSupply}} Das Verbrennen von ΔLP LP-Token gibt genau ΔLP × x / lpSupply von Token0 und ΔLP × y / lpSupply von Token1 zurück. Weder die Kurve noch k bewegen sich bei Einzahlungen oder Auszahlungen — nur Swaps ändern den Preis.

Gebührenmodell auf dem Swap-Pfad

CPMM wendet zwei unabhängig bewertete Gebühren auf jeden Swap an:
  • Die Handelsgebühr wird auf der Eingabenseite erhoben und mit AmmConfig.trade_fee_rate berechnet. Sie wird dann in LP-, Protokoll- und Fonds-Anteile aufgeteilt (der LP-Anteil bleibt im Vault und vergrößert k; die Protokoll- und Fonds-Anteile werden aus der Vault-Buchhaltung extrahiert).
  • Die Creator-Gebühr (aktiv nur wenn enable_creator_fee == true) wird mit AmmConfig.creator_fee_rate berechnet. Sie wird auf der Eingabe- oder Ausgabenseite erhoben, abhängig von PoolState.creator_fee_on und der Swap-Richtung (siehe products/cpmm/fees). Sie ist ein eigener Bucket — niemals ein Teil der Handelsgebühr.
Der Protokoll-Anteil der Creator-Gebühr erscheint nirgendwo auf dieser Seite, und das ist beabsichtigt. Er wird angewendet, wenn CollectCreatorFee akkumulierte Gebühren zwischen zwei Zählern verschiebt, die die Kurve bereits ausschließt — nicht während eines Swaps. Swap-Mathematik, Quotes und k sind mit und ohne ihn identisch. Siehe products/cpmm/fees.
Sei:
  • FEE_RATE_DENOMINATOR = 1_000_000
  • trade_fee_rate — aus AmmConfig, z.B. 2500 = 0,25% der relevanten Volumenenseite
  • creator_fee_rate — aus AmmConfig, z.B. 1000 = 0,10% der relevanten Volumenenseite
  • protocol_fee_rate, fund_fee_rate — in Einheiten von 1/FEE_RATE_DENOMINATOR der Handelsgebühr, nicht des Volumens
Wenn die Creator-Gebühr auf der Eingabenseite ist:
Wenn die Creator-Gebühr auf der Ausgabenseite ist:
In beiden Fällen wird die Handelsgebühr auf die gleiche Weise aufgeteilt:
Der Betrag protocol_fee + fund_fee + creator_fee wird in den Vaults gehalten, aber separat im Pool-Status verfolgt (protocol_fees_token*, fund_fees_token*, creator_fees_token*). Wenn die Constant-Product-Invariante k' ≥ k prüft, verwendet sie Vault-Salden minus alle drei akkumulierten, aber noch nicht eingezogenen Gebühren — sodass LPs nur lp_fee erfassen. Siehe products/cpmm/fees für die Einzugsinstruktionen und durchgerechnete numerische Beispiele.

SwapBaseInput (Input-exakt)

„Der Benutzer gibt uns genau amount_in des Input-Mint und erhält mindestens minimum_amount_out des Output-Mint.” Token-2022 ignorierend:
Nach Algebra: amount_out=y⋅Δxnetx+Δxnet\text{amount\_out} = \frac{y \cdot \Delta x_{\text{net}}}{x + \Delta x_{\text{net}}} wobei Δx_net = amount_in_after_trade_fee. Das Programm aktualisiert dann die Vault-Buchhaltung so, dass der Anteil von trade_fee, der Protokoll/Fonds/Creator geschuldet wird, in „akkumulierten” Buckets sitzt (nicht in der nächsten x der Kurve enthalten), während der LP-Anteil x für den nächsten Swap beitritt.

Token-2022 auf der Eingabenseite

Wenn der Input-Mint eine Transfer-Fee-Erweiterung hat, zieht der Mint seine Gebühr beim Transfer von Benutzer → Vault ab. Der Vault erhält also tatsächlich amount_in − transfer_fee_in(amount_in). Das CPMM-Programm berechnet daher:
und führt die Kurve gegen amount_in_after_trade_fee aus. Das ist wichtig, weil der Kurvenprice vom Nettobetrag berechnet wird, der im Vault gelandet ist, nicht vom Headline-Betrag des Benutzers.

Token-2022 auf der Ausgabenseite

Wenn der Output-Mint eine Transfergebühr hat, sendet der Pool amount_out aus seinem Vault an den Benutzer. Der Mint wird dann seine Gebühr auf dem Weg heraus abziehen, sodass der Benutzer amount_out − transfer_fee_out(amount_out) erhält. Das Programm berechnet amount_out wie üblich aus der Kurve, aber es ist die Verantwortung des Integrators, die „Vault-Sendung”-Nummer des Pools in eine „Benutzer-Empfang”-Nummer umzuwandeln, wenn Quotes angezeigt werden.

Slippage-Prüfung

Nach Berechnung von amount_out:
Wenn der Output-Mint eine Transfergebühr erhebt, wendet das SDK die Transfergebühr vor dem Setzen von minimum_amount_out an, sodass die Slippage-Konstante in dem denominiert ist, was der Benutzer tatsächlich erhält, nicht in dem, was der Vault sendet.

SwapBaseOutput (Output-exakt)

„Der Benutzer erhält genau amount_out des Output-Mint und ist bereit, bis zu maximum_amount_in des Input-Mint zu zahlen.” Invertieren der Kurve für Δx_net: Δxnet=⌈x⋅amount_outy−amount_out⌉\Delta x_{\text{net}} = \left\lceil \frac{x \cdot \text{amount\_out}}{y - \text{amount\_out}} \right\rceil Die Aufrundung ist wichtig — sie garantiert k' ≥ k nach ganzzahliger Kürzung. Dann:
Bei Token-2022-Input umhüllen mit:
sodass der Benutzer genug zahlt, dass der Pool nach Abzug der Mint-Transfergebühr immer noch gross_needed erhält.

Slippage-Prüfung

Durchgerechnetes Beispiel

Pool-Status, Token-2022 ignorierend:
  • x = 1_000_000_000_000 (1.000.000,000000 von Token0, 6 Dezimalstellen)
  • y = 2_000_000_000_000 (2.000.000,000000 von Token1, 6 Dezimalstellen)
  • AmmConfig: trade_fee_rate = 2500, protocol_fee_rate = 120_000, fund_fee_rate = 40_000, creator_fee_rate = 0
Benutzer: SwapBaseInput mit amount_in = 1_000_000_000 (1.000,000000 von Token0). Creator-Gebühr ist deaktiviert (enable_creator_fee = false).
Wenn derselbe Pool enable_creator_fee = true mit creator_fee_rate = 1000 (0,10%) auf der Eingabenseite hätte, würde das Programm total_input_fee = ceil(1_000_000_000 * 3500 / 1_000_000) = 3_500_000 berechnen, dann als creator_fee = 1_000_000 und trade_fee = 2_500_000 aufteilen. Die Protokoll-/Fonds-/LP-Arithmetik auf trade_fee ist unverändert vom obigen Beispiel — die Creator-Gebühr ist ihr eigener Bucket, akkumuliert zu creator_fees_token0 und ausgeschlossen von curve_x zusammen mit den Protokoll- und Fonds-Buckets. Wenn der Input-Mint eine 1%-Token-2022-Transfergebühr hat, erhält der Vault statt 1_000_000_000 990_000_000 Token, und jede nachfolgende Berechnung verwendet diesen Nettobetrag.

Observation-Aktualisierungsregel

Bei jedem Swap prüft das Programm, ob eine neue Observation in den Ring-Buffer eingefügt werden soll:
Zwei Eigenschaften:
  • Kumulativer Preis, nicht Spot-Preis. Eine einzelne Observation ist kein Preis. Um einen TWAP von Zeit t0 zu t1 zu erhalten, lesen Sie die Observations, die den beiden Enden am nächsten sind, und berechnen Sie (cumulative(t1) − cumulative(t0)) / (t1 − t0).
  • Samples sind ratenbegrenzt. Aufeinanderfolgende Swaps im gleichen Slot können eine Observation teilen. Das Lesen einer Observation unmittelbar nach einem Swap kann daher um einen Slot veraltet aussehen — das ist normal.
Mehr in products/clmm/accounts.

Gebühren auf der Kurve

Das ist der subtile Teil und wert, hervorgehoben zu werden. Die Kurven-Arithmetik arbeitet gegen die Netto-Vault-Salden — d.h. SPL-Rohsaldo minus akkumulierte Protokoll-, Fonds- und Creator-Gebühren (alle drei sind unabhängige Buckets — siehe products/cpmm/fees). Ein konkretes Bild:
Konsequenzen für Integratoren:
  • Zitieren Sie nicht aus Rohsalden. Subtrahieren Sie zuerst die akkumulierten Gebührenfelder, oder rufen Sie SwapBaseInput als Simulation auf und nehmen Sie sein Ergebnis.
  • CollectProtocolFee verschiebt Token aus dem Vault. Nach der Einziehung sinkt raw_vault_balance, aber curve_balance bleibt unverändert; der Pool-Preis bewegt sich nicht. Das ist beabsichtigt.

Präzision und Overflow

  • Alle Kurven-Arithmetik verwendet u128-Zwischenergebnisse, um Overflow bei x * y zu verhindern.
  • Division rundet gegen Null, außer für SwapBaseOutput’s Δx_net, das aufrundet, und Gebührenberechnung, die auf trade_fee aufrundet und auf die Unter-Splits abrundet. Diese Rundungsrichtungen werden gewählt, sodass die Invariante aufgrund ganzzahliger Kürzung niemals abnimmt.
  • Pools mit extremen Vault-Verhältnissen (Milliarden : 1) können bei kleinen Trades auf Präzisionsgrenzen treffen; das Programm gibt in diesem Fall ZeroTradingTokens zurück. Siehe reference/error-codes.

Nächste Schritte

Quellen: