SunSwap V3 Overview

Keywords of SunSwap V3: market making model, liquidity pool, and swap

Background

While SunSwap V2 achieved remarkable success in decentralized trading, it also has its limitations. One of its key drawbacks is the underutilization of liquidity. To address this issue, SunSwap V3 introduces a concept called concentrated capital efficiency. This mechanism empowers liquidity providers to concentrate their funds within a specific price range, thereby allowing them to provide liquidity more effectively and earn higher rewards within a price range featuring high price volatility.

Developed by the SUN.io team, SunSwap V3 was launched in June 2023. It introduces a new trading model called "concentrated liquidity". With this new model, liquidity providers can allocate their funds to a specific price range rather than a fixed trading pair, which improves the efficiency of liquidity and offers better prices for traders. SunSwap V3 has also introduced flexible fee tiers, allowing liquidity providers to set different fee rates for different price ranges accordingly, which generates higher returns for liquidity providers and incentivizes them to provide more liquidity.

Mechanism

The swap logic can be inferred from the constant product formula. Here, x and y represent the respective reserve balance of the tokens involved (token0 and token1):

xy=L\sqrt{xy} = L
p=y/x\sqrt{p} =\sqrt{y/x}

L stands for liquidity, and the liquidity of a pool can be calculated from the reserve balance of the tokens involved. Based on the formula, the product of x and y (denoted as k) remains constant.

Therefore, we can measure the liquidity of a pool by xy\sqrt{xy} L is actually the geometric mean of x and y.

Dividing y by x, we can get the prices of token0 and token1. Since the prices of the two tokens in the pool are reciprocal to each other, we'll only use one of them when doing the calculation (SunSwap V3 uses y/x).

L also indicates the relation between the change of the output amount and the change of p: p\sqrt{p}

L=ΔyΔPL=\frac{\Delta y}{\Delta \sqrt{P}}

Proof:

L=ΔyΔPL=\frac{\Delta y}{\Delta \sqrt{P}}
L=y1y0P1P0L=\frac{y_1-y_0}{ \sqrt{P_1}-\sqrt{P_0}}
(P1P0)xy=y1y0(\sqrt{P_1}-\sqrt{P_0})\sqrt{xy}= {y_1-y_0}{ }
(y1/x1y0/x0)xy=y1y0(\sqrt{y_1/x_1 }-\sqrt{ y_0/x_0})\sqrt{xy}= {y_1-y_0}{ }

xy=x0y0=x1y1\sqrt{xy} =\sqrt{x_0y_0} =\sqrt{x_1y_1} ,, thus:

(y12y02)=y1y0(\sqrt{y_1^2 }-\sqrt{ y_0^2})= {y_1-y_0}
y1y0=y1y0{y_1-y_0}={y_1-y_0}

Contract Addresses

Factory

Contract address on the Mainnet: TThJt8zaJzJMhCEScH7zWKnp5buVZqys9x

Contract address on Nile Testnet: TUTGcsGDRScK1gsDPMELV2QZxeESWb1Gac

SwapRouter

Contract address on the Mainnet: TQAvWQpT9H916GckwWDJNhYZvQMkuRL7PN

Contract address on Nile Testnet: TFkswj6rUfK3cQtFGzungCkNXxD2UCpEVD NonfungiblePositionManager

Contract address on the Mainnet: TLSWrv7eC1AZCXkRjpqMZUmvgd99cj7pPF

Contract address on Nile Testnet: TPQzqHbCzQfoVdAV6bLwGDos8Lk2UjXz2R

Interact with Contract

We utilize TronWeb to facilitate interaction with on-chain contracts. First, you need to initialize the TronWeb instance.

Initialize the TronWeb
const TronWeb = require('tronweb')
const privateKey = process.env.PRIVATE_KEY
const apiKey = process.env.API_KEY

var tronWeb = new TronWeb({
	fullHost: "https://api.trongrid.io",
	headers: { "TRON-PRO-API-KEY": apiKey },
	privateKey: privateKey,
      })

Make queries

  • Query the address of the liquidity pool

    • Name:getPool(address,address,uint24)

    • Contract called: Factory

    • Parameters: address of token0, address of token1, and fee rate

    • Returned value: address of pool

>>> let contract = await tronWeb.getContract('TThJt8zaJzJMhCEScH7zWKnp5buVZqys9x')
>>> await contract.methods.getPool('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',‘TPYmHEhy5n8TCEfYGqW2rPxsghSfzghPDn’,100).call()
0x839538A1B5E9B57C639035A453E07C9A4309F9D9
  • Query the details of pool

    • Name: slot0()

    • Contract called: the pool contract (accessible via factory)

    • Parameters: N/A

    • Returned values: 1. current price (which equals sqrtPriceX96 squared divided by 2 to the power of 192); 2. current tick; 3. the latest index of the observation array; 4. maximum cardinality of the observations currently stored; 5. maximum cardinality that is triggered in the observation and is to be stored next; 6. percentage of the current protocol fee in the swap fee at the time of withdrawal; 7. whether the pool is locked

>>> let contract = await tronWeb.getContract('TSUUVjysXV8YqHytSNjfkNXnnB49QDvZpx')
>>> await contract.methods.slot0().call()
[
  sqrtPriceX96: BigNumber { _hex: '0x4714a6b4d8e3d1ab6bcfbe0c', _isBigNumber: true },
  tick: -25629,
  observationIndex: 0,
  observationCardinality: 1,
  observationCardinalityNext: 1,
  feeProtocol: 0,
  unlocked: true
]
  • Query a user’s tokenId

    • Name: tokenOfOwnerByIndex(address,uint256)

    • Contract called: NonfungiblePositionManager

    • Parameters: user's address, user's nth proof of liquidity

    • Returned value: tokenId

>>> let contract = await tronWeb.getContract('TLSWrv7eC1AZCXkRjpqMZUmvgd99cj7pPF')
>>> await contract.methods.tokenOfOwnerByIndex('TF5MekHgFz6neU7zTpX4h2tha5miPDUj3z',0).call()
1
  • Query the details of a user’s liquidity

    • Name: positions(uint256)

    • Contract called: NonfungiblePositionManager

    • Parameter: tokenId

    • Returned values: 1. nonce; 2. address authorized by the tokenId; 3. address of token0 in the pool; 4. address of token1 in the pool; 5. fee rate in the pool; 6. lowest price for the position selected; 7. highest price for the position selected; 8. liquidity; 9. 10. fee growth in all positions at the time the latest change was made to a single position; 11. 12. amount of uncollected tokens owed by this position as of the previous calculation

>>> let contract = await tronWeb.getContract('TLSWrv7eC1AZCXkRjpqMZUmvgd99cj7pPF')
>>> await contract.methods.positions (1).call()
[
  nonce: 0
  operator: T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb
  token0: TF9io9LGyjuK3uTpr73pAaQ5m9scxd9xvr
  token1: TK8E3sFhBt3EB6gTT6d6co8RMB6DFUnNwE
  fee: 3000
  tickLower: -283380
  tickUpper: -269520
  liquidity: 1390641886550414128
  feeGrowthInside0LastX128: 0
  feeGrowthInside1LastX128: 540564213145032425660083902
  tokensOwed0: 0
  tokensOwed1: 0
]

Execute transactions

  • Make a transaction

    • Name: exactInput(ExactInputParams)

    • Contract called: SwapRouter

    • Parameters: [encode of the path, user's address, deadline]

>>> let contract = await tronWeb.getContract('TQAvWQpT9H916GckwWDJNhYZvQMkuRL7PN')
>>> await contract.methods.exactInput(['0xe518c608a37e2a262050e10be0c9d03c7a0877f3000bb843c42f702b0a11565c46e34022aab677d7bd8ae3','TF5MekHgFz6neU7zTpX4h2tha5miPDUj3z',1662825600])
  • Add liquidity

    • Name: increaseLiquidity(IncreaseLiquidityParams)

    • Contract called: NonfungiblePositionManager

    • Parameters: [tokenId, amount of token0 to be added, amount of token1 to be added, minimum amount of token0 to be added, minimum amount of token1 to be added, deadline]

>>> let contract = await tronWeb.getContract('TLSWrv7eC1AZCXkRjpqMZUmvgd99cj7pPF')
>>> await contract.methods.increaseLiquidity(1,'1000000000000000000','1000000000000000000',1,1,1662825600)
  • Reduce liquidity

    • Name: decreaseLiquidity(DecreaseLiquidityParams)

    • Contract called: NonfungiblePositionManager

    • Parameters: [tokenId, liquidity to be removed, minimum amount of token0 to be obtained, minimum amount of token1 to be obtained, deadline]

>>> let contract = await tronWeb.getContract('TLSWrv7eC1AZCXkRjpqMZUmvgd99cj7pPF')
>>> await contract.methods.decreaseLiquidity(1,'1390641886550414128',1,1,1662825600)
  • Collect rewards

    • Name: collect(CollectParams)

    • Contract called: NonfungiblePositionManager

    • Parameters: [tokenId, address to receive rewards, maximum amount of token0 reward, maximum amount of token1 reward]

>>> let contract = await tronWeb.getContract('TLSWrv7eC1AZCXkRjpqMZUmvgd99cj7pPF')
>>> await contract.methods.collect(1,'TF5MekHgFz6neU7zTpX4h2tha5miPDUj3z',‘100000000000000000000000000’,‘100000000000000000000000000’)

Last updated