Building on FXSwap
Protocols can compose FXSwap swaps and LP positions into vaults, strategies, collateral systems, and other financial applications. Safe composition requires separating user-owned LP supply from refuel accounting, valuing positions against executable withdrawals, and treating pool price getters as AMM state rather than automatically safe lending oracles.
Start with the swap integration guide if the protocol only executes trades. This page is for applications that hold LP tokens, consume pool state, or build accounting around FXSwap.
Identify the deployment first
Before accepting an LP token or reading pool state:
- Confirm the pool is registered and is on the protocol's versioned allowlist.
- Read
version(),coins(0),coins(1), and both coin decimals. - Record the pool, factory,
VIEW(), andMATH()addresses. - Verify that the integration supports that exact deployed interface.
The reviewed Ethereum pools report v2.1.0d. Do not assume another pool is compatible because it shares the Twocrypto factory or exposes a similar ABI.
LP-token and supply accounting
The pool contract is also its own ERC-20 LP token:
decimals()returns18;balanceOf(account)is the account's withdrawable LP balance;totalSupply()includes user LP tokens and outstanding refuel shares;donation_shares()is the outstanding refuel-share supply;user_supply()returnstotalSupply() - donation_shares().
Refuel shares have no owner account and cannot be transferred or withdrawn. They can be burned when the pool recenters. A protocol must not treat totalSupply() as entirely user-owned supply when calculating ownership percentages, rewards, or market capitalization.
Use user_supply() when a denominator specifically means the LP tokens held by user accounts, such as distributing a user-only incentive. It is not an unconditional claim on a fixed fraction of each raw pool balance. Pool withdrawals use the deployed pool's accounting and can be affected by fees, imbalance, state changes, refuel shares, and the selected withdrawal method.
Deposits and withdrawals
Use the pool's quote methods before building transaction bounds:
| Task | Quote method | Execution method |
|---|---|---|
| Add two-sided or one-sided liquidity | calc_token_amount(amounts, true) | add_liquidity |
| Proportional withdrawal | Compute the pro-rata starting point and simulate | remove_liquidity |
| Single-coin withdrawal | calc_withdraw_one_coin(lpAmount, i) | remove_liquidity_one_coin |
| Fixed-out withdrawal | calc_withdraw_fixed_out(lpAmount, i, amountI) | remove_liquidity_fixed_out |
Quotes are state-sensitive. Simulate the exact receiver and calldata, set non-zero minimum amounts, and apply a deadline in the calling contract. Test fee-on-transfer, rebasing, callback-capable, or otherwise unusual tokens explicitly before supporting them.
Value LP positions by realizable outcomes
lp_price() and get_virtual_price() are useful pool accounting signals, but neither is a universal mark-to-market price for every integration:
lp_price()is a 1e18 LP-price estimate using pool state;get_virtual_price()calculates the current 1e18 virtual price;virtual_price()exposes the cached internal value;- withdrawal quotes incorporate the selected exit path and current imbalance.
For user-facing valuations, state the block number, external coin prices, token decimals, and valuation method. For solvency or risk decisions, stress executable withdrawal values across imbalance, price movement, fee changes, and refuel depletion instead of multiplying LP balance by a single getter.
Pool balances are accounted balances
balances(i) returns the pool's internally accounted raw balance for coin i. It is not interchangeable with IERC20(coins(i)).balanceOf(pool).
Direct token transfers, pending pre-transfer flows, and other accounting paths can make the ERC-20 balance differ from the pool's stored balance. Use balances(i) for invariant and pool-state interpretation. Use the ERC-20 balance only when the integration specifically needs custody reconciliation, and explain any difference rather than silently treating it as available liquidity.
Fees, imbalance, and refuel depletion
FXSwap charges a dynamic fee between mid_fee() and out_fee(), both at 1e10 precision. The realized fee depends on normalized balances and fee_gamma(). Deposits and withdrawals have their own fee paths, so a balanced-looking notional position does not imply a fee-free exit.
Refuel shares increase totalSupply() but are not user positions. When available refuel shares burn during recentering, both donation_shares() and totalSupply() decrease while account balanceOf values remain unchanged. Applications that snapshot supply, calculate rewards, or reconcile share price must handle this state transition.
Oracle getters are AMM state
| Getter | Meaning | Safe-use boundary |
|---|---|---|
last_prices() | Latest normalized observed pool price | The deployed source explicitly describes it as unsafe and manipulable |
price_oracle() | Exponential moving average of prior observed prices | Useful for understanding pool recentering; not automatically a manipulation-resistant lending price |
price_scale() | Center of concentrated liquidity | A pool parameter/state value, not an external market oracle |
An application may use these values to monitor the pool or reproduce its logic. A lending, liquidation, minting, or solvency system should not adopt them without an independent oracle-security analysis covering manipulation cost, update timing, liquidity, stale states, external reference markets, and failure behavior.
What to monitor
Protocols holding or wrapping FXSwap LP tokens should monitor:
- supported
version(), pool code, factory,VIEW(), andMATH(); - coin addresses, decimals, redemption behavior, and token incidents;
- account LP balance,
user_supply(),totalSupply(), anddonation_shares(); balances, withdrawal quotes, virtual-price signals, and external coin values;last_prices,price_oracle, andprice_scale;- dynamic-fee and recentering parameters;
- refuel unlock, protection, and depletion state;
- admin parameter and periphery events.
Re-evaluate risk assumptions after a parameter change, prolonged imbalance, depleted refuel budget, external-market disruption, or token-behavior change.
Safe composition checklist
- Allowlist exact pool implementations and reject unknown versions.
- Use
user_supply()where the calculation means user-owned LP supply. - Never assign ownership or withdrawal rights to refuel shares.
- Quote and simulate deposits, swaps, and each supported withdrawal path.
- Value positions with explicit external prices and executable exit assumptions.
- Use stored pool balances for pool accounting; reconcile ERC-20 balances separately.
- Treat pool oracle getters as AMM state unless a separate oracle review proves suitability.
- Test every deployment's tokens, parameters, liquidity, and monitoring thresholds independently.
See Mechanism & Parameters for recentering behavior, Oracles for price-state boundaries, and the FXSwap Pool for exact signatures, units, and events.