Concentrated Liquidity Pool Integration
Purpose
Guide on how to Build Transaction Swap Concentrated Pool Token:
Example transaction on preprod: https://preprod.cardanoscan.io/transaction/77a2a7786629f9280a9e0653e07d8bf153376555307efd3d066fd6ebae881140
Example transaction on mainnet: https://cardanoscan.io/transaction/402a6320fe48781cf103d42951c22fc0aeb782a35c9306db1ba258397b02d65b
Constants
Preprod:
POOL_SCRIPT_HASH="04041c3c6ba87b33f2c9eb7f7dbeae3b26003c3e199d438bb99932a2"
POOL_SCRIPT_OUT_REF="2e19cca74e3badcab26aef7574aa1885ba97228a254ca227ba2f79f2b75fd136#0"
PROTOCOL_SCRIPT_HASH="26ec271e96420bd548932f350e76ea38590da68e12f0f55bd5473f67"
PROTOCOL_CONFIG_OUT_REF="3775af36f485f9c97101ee5b9b360c34f0f8e12186bc9060f358b7fc8ce468a4#0"Mainnet:
POOL_SCRIPT_HASH="d8b69fc53637bcfadbc4469083f706bc293f4d9d2296646c5ca167bb"
POOL_SCRIPT_OUT_REF="64d111b957e7d7848ffdde5149aa77fa4090a7fa1ad0ac108067900614848501#0"
PROTOCOL_SCRIPT_HASH="fa991bc2f9c4206e72d713bc3487a72e7901057cabb8d364bebeef8f"
PROTOCOL_CONFIG_OUT_REF="2cafd7c92f7093e5229af274be83dea660b0590b4174bbed79ba662b44fbd1ee#0"Steps to Build a Transaction Swap Token
Step 1: Retrieve Necessary Parameters
Call the API GetListConcentratedPool to get list pools. For example, to get all pools with given token pair:
Mainnet API:
Use
lpTokenfrom each pool to call the API GetConcentratedPoolParams to retrieve the necessary parameters from a pool:
Mainnet API:
Step 2: Build the Redeemer Structure
Concentrated ExchangeActionRedeemer Structure:
To optimize data size and allow one transaction (txn) to swap across multiple pools simultaneously, the Redeemer is a ByteArray, where each field has a defined index and byte size.
ExchangeActionRedeemer structure for Token Swap:
Diagnostic Notation format:
CBOR format (single pool):
Step 3: Create the Transaction
Use the retrieved parameters to create the token swap transaction.
Note: To minimize DDoS attacks in multi-hop pools, each pool, when swapped, will collect ADA fees according to protocol_config.swap_fee and add them to the Pool Datum:
Amount of
swapFeeto be charged and currenttotalSwapFeein Pool Datum is returned by API.
Input
Note: The
outRef,address,coin, andmultiAssetsinformation is fully returned by API Get Params.PoolInUtxo: The pool you intend to swap tokens with.
Spend Redeemer: Build the redeemer according to the ExchangeActionRedeemer Swap structure for Concentrated Pool, ensuring the specified indices are correct.
The input Pool UTxO must have the valid PoolNFT:
pool_in_asset[PoolNFT] = 1
Output
PoolOutUtxo: The output of the pool after the swap.
delta_amount > 0 -> Trader sells X, Pool receives X and pays Y. Simultaneously increases platform_fee_X accumulation.
poolChangeX = redeemer.delta_amount
delta_amount < 0 -> Trader sells Y, Pool receives Y and pays X. Simultaneously increases platform_fee_Y accumulation.
poolChangeY = -redeemer.delta_amount
The pool datum structure must adhere to the correct order:
Temporary variables:
basis = 10000
pool_utxo_min_ada = 3_000_000 (lovelace)
poolinX:
tokenAReservefrom the APIpoolinY:
tokenBReservefrom the APIpoolinLPX: liquidity of token X before the txn
if token X is ADA: = poolinX - pool_in_datum.platform_fee_x - pool_in_datum.total_swap_fee - pool_utxo_min_ada
else: = poolinX - pool_in_datum.platform_fee_x
poolinLPY: liquidity of token Y before the txn = pool_in_asset[Y] - pool_in_datum.platform_fee_y
Constraints:
|poolChangeX| >= pool_in_datum.min_x_change
|poolChangeY| >= pool_in_datum.min_y_change
IF pool_in_datum.token_x == ""
Required withdrawal of the rewards by the pool's stake credential (before this action)
if poolChangeX > 0:
else:
pool_out_datum.last_withdraw_epoch = curEpoch
pool_out_datum.total_swap_fee = pool_in_datum.total_swap_fee + protocol_config_ref.swap_fee
Other fields in datum are not changed:
pool_out_datum.lp_fee_rate = pool_in_datum.lp_fee_rate
pool_out_datum.token_x = pool_in_datum.token_x
pool_out_datum.token_y = pool_in_datum.token_y
pool_out_datum.sqrt_lower_price = pool_in_datum.sqrt_lower_price
pool_out_datum.sqrt_upper_price = pool_in_datum.sqrt_upper_price
pool_out_datum.circulating_lp_token = pool_in_datum.circulating_lp_token
Pool UTxO's address must not be changed
Diagnostic Notation format:
Reference Input
Add all reference inputs:
pool_script_out_ref: current smart contract's out ref is
64d111b957e7d7848ffdde5149aa77fa4090a7fa1ad0ac108067900614848501#0protocol_config_out_ref: returned by the API, field
pool.protocolConfigOutRefIf withdraw staking, add staking_script_out_ref: returned by the API, field
stakingUtxo.outRef
Withdrawal
Withdraw Pool Script Hash:
Add withdraw-zero: Add withdrawal to reward address of Pool Script Hash with reward amount = 0
Note: Pool Script Hash can be extracted using lpToken's policy ID from the API
Redeemer: Built according to the ExchangeActionRedeemer structure.
Withdraw Staking Reward: Must add staking withdrawal if pool contains ADA and current_epoch > pool_datum.last_withdraw_epoch.
Check reward amount of pool script hash and add withdrawal to its reward account.
Redeemer: Built according to the ExchangeActionRedeemer structure.
Note: After sorting the inputs and reference inputs according to the chain's sort order, ensure the correct indices are used when specifying them in the redeemers.
We've built a typescript SDK for your reference: Here
Last updated