SunSwap兑换简介

SunSwap兑换协议核心概念: 做市商原理、流动性池及兑换

背景

SunSwap AMM(自动做市商)是目前DeFi领域应用最多的交易模型, 与订单簿的交易方式不 同,AMM采用的是固定乘积的方式换算兑换池内的代币,交易自动成交,并保证交易对的流动性不枯竭。

任何人都可以通过存入某种代币来换取等值的交易池代币,并成为这个交易池的流动性提供者(LP)。 这些代币数量除以交易池中LP总储备量代表流动性提供者的在该交易池中的资产占比,且流动性提供者可以随时赎回相关资产。

原理简介

基于恒定乘积公式来推演兑换的逻辑, 以x和y代表两种代币(假设为X和Y)的数量,则:

xy=kx * y = k

如果我们想用X从流动池中兑换Y,假设输入X的数量为Δx\Delta x,兑换得到的Y的量为Δy\Delta y,在交易池资金足够的前提下,则:

(x+Δx)×(yΔy)=kΔy=ykx+Δx=Δx×yx+Δx(x + \Delta x) \times (y - \Delta y) = k \\\\ \Delta y = y - \frac{k}{x + \Delta x} = \frac{\Delta x \times y}{x + \Delta x}

也就是说交易前后,流动性池中两种代币的乘积是恒定不变的,基于以上,如果交易的量相对于流动性池的量很小,那么交易价格就近似为两种代币的数量比:

pricey=ΔxΔy=x+Δxyxyprice_y = \frac{\Delta x}{\Delta y} = \frac{x + \Delta x}{y} \approx \frac{x}{y}

而兑换前,流动性池中y的单价为xy\frac{x}{y}, 那么y单价的滑点就产生了:

Slippagey=ΔxΔyxy=ΔxySlippage_y = \frac{\Delta x}{\Delta y} - \frac{x}{y} = \frac{\Delta x}{y}

交易量Δx\Delta x越大,产生的滑点就越大,偏离实际价位就越大,而池中的资金储备越多、交易深度越大,则能尽量减少滑点,使用户的交易损失降低。在实际交易过程中,会先扣除0.3%的手续费,再利用乘积公式进行计算。

示例: 原流动性池有100X和1Y。此时通过流动性池交易20X, 则实际交易量(扣除0.3%手续费)为19.94X, 按照xy=kx * y = k公式进行计算:

(100+19.94)×(1Δy)=100Δy=0.1662(100 + 19.94) \times (1 - \Delta y) = 100 \\\\ \Delta y = 0.1662

流动性池

SUN.io的Sunswap合约实现了普通代币兑换和流动性增删的功能, 能支撑多种代币之间的兑换,目前在TRON主网上主要部署了V1/V2两种版本的合约。

V1版本

Factory合约地址: TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF

V2版本

Factory合约地址: TKWJdrQkqHisa1X8HUdHEfREvTzw4pMAaY

Router合约地址: TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax

与合约交互

我们利用TronWeb与合约交互, 初始化TronWeb实例后, 就能很方便的与线上合约交互

初始化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,
      })

获取流动性信息

  • 获取V1版本的流动性池地址

    • 名称:getExchange(address)

    • 参数:代币地址

>>> let contract = await tronWeb.getContract('TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF')
>>> await contract.methods.getExchange('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t').call()
0x4cAD2750821493b093133B7bf10568bAEc000971
  • 获取V2版本的流动性池地址

    • 名称:getPair(address,address)

    • 参数:token0代币地址,token1代币地址

>>> let contract = await tronWeb.getContract('TKWJdrQkqHisa1X8HUdHEfREvTzw4pMAaY')
>>> await contract.methods.getPair('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', 'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR')
0x4cAD2750821493b093133B7bf10568bAEc000971

执行交易

  • V1版本卖出TRX买入Token

    • 名称:trxToTokenTransferInput(uint256, uint256, address)

    • 参数:预期购买金额最小值,时间期限,收款地址

>>> let contract = await tronWeb.getContract('TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
>>> await contract.methods.trxToTokenTransferInput(100, 1662825600, 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
  • V1版本卖出Token买入TRX

    • 名称:tokenToTrxTransferInput(uint256, uint256, uint256, address)

    • 参数:出售币数量,预期购买TRX的最小额度,时间期限,收款地址

>>> let contract = await tronWeb.getContract('TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
>>> await contract.methods.tokenToTrxTransferInput(100, 1500, 1662825600, 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
  • V1版本卖出Token买入Token

    • 名称:tokenToTokenSwapInput( uint256, uint256, uint256, uint256, address)

    • 参数:出售币数量,预期购买币最小值,预期可购买token最小值,时间期限,收款地址

>>> let contract = await tronWeb.getContract('TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
>>> await contract.methods.tokenToTokenSwapInput(100, 100, 1500,1662825600,'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
  • V2版本卖出Token买入Token

    • 名称:swapExactTokensForTokens( uint, uint, address[], address, uint)

    • 参数:出售币数量,预期购买币最小值,兑换路径,收款地址,时间期限

>>> let contract = await tronWeb.getContract('TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax')
>>> await contract.methods.swapExactTokensForTokens(1000000000000000000,1000000,['TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf','TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3'],'TF5MekHgFz6neU7zTpX4h2tha3mijDUj3z',1662825600) 
  • V2版本卖出TRX买入Token

    • 名称:swapExactETHForTokens(uint, address[], address, uint)

    • 参数:预期购买币最小值,兑换路径,收款地址,时间期限

>>> let contract = await tronWeb.getContract('TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax')
>>> await contract.methods.swapExactETHForTokens(100000000,1,['TYsbWxNnyTgsZaTFaue9hqpxkU3Fkco94a','TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf'],'TF5MekHgFz6neU7zTpX4h2tha5miPDUj3z',1662825600)
  • V2版本卖出Token买入TRX

    • 名称:swapExactTokensForETH(uint, uint, address[] , address, uint)

    • 参数:出售币数量,预期购买TRX最小值,兑换路径,收款地址,时间期限

>>> let contract = await tronWeb.getContract('TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax')
>>> await contract.methods.swapExactTokensForETH(1000000,1000000,['TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf','TYsbWxNnyTgsZaTFaue9hqpxkU3Fkco94a'],'TF5MekHgFz6neU7zTpX4h2tha5miPDUj3z',1662825600)

增删流动性

  • V1版本增加流动性

    • 名称:addLiquidity(uint256, uint256, uint256)

    • 参数:预期获取最小流动性,要添加流动性的最大金额,时间期限

>>> let contract = await tronWeb.getContract('TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
>>> await contract.methods.addLiquidity(100, 100, 1662825600)
  • V1版本删除流动性

    • 名称:removeLiquidity(uint256, uint256,uint256, uint256)

    • 参数:移除流动性的数量,预期获取最小的TRX数量,预期获取最小token数量,时间期限

>>> let contract = await tronWeb.getContract('TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE')
>>> await contract.methods.removeLiquidity(100, 100, 100, 1662825600)
  • V2版本增加流动性

    • 名称:addLiquidity(address,address,uint,uint,uint,uint,address,uint)

    • 参数:tokenA地址,tokenB地址,tokenA预期添加的数量,tokenB预期添加的数量,tokenA添加的数量最小接受额,tokenB添加的数量最小接受额,添加流动性地址,时间期限

>>> let contract = await tronWeb.getContract('TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax')
>>> await contract.methods.addLiquidity('TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf','TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3',100000000,27661108481018349141,5000000,200000000000000000000,TF5MekHgFz6neU7zTpX4h2tha5miPDUj3z,1662825600)
  • V2版本删除流动性

    • 名称:removeLiquidity(address,address,uint,uint,uint,address,uint)

    • 参数:tokenA地址,tokenB地址,移除的流动性,预期获得tokenA数量的最小值,预期获得tokenB数量的最小值,token接收地址,时间期限

>>> let contract = await tronWeb.getContract('TKzxdSv2FZKQrEqkKVgp5DcwEXBEKMg2Ax')
>>> await contract.methods.removeLiquidity('TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf','TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3',100000000,1,1,TF5MekHgFz6neU7zTpX4h2tha5miPDUj3z,1962825600)

Last updated