SUN.io 中文文档
SUN.ioSunPump
  • SUN.io 简介
    • 入门指南(TRON)
      • 创建钱包
      • TRON 网络代币标准
      • 连接钱包
    • 风险
    • 白皮书
    • 服务条款
    • 隐私协议
    • 最新公告
  • 开始使用
    • 兑换
      • 代币兑换
        • 如何给token授权?
        • 如何兑换token?
        • 如何查看我最近的交易记录?
        • 如何查看交易对价格走势?
      • 稳定币兑换
        • 稳定币池介绍
        • 如何进行稳定币交易?
        • 如何提供稳定币池的流动性?
        • 如何提取稳定币池流动性?
        • 如何查看自己提供的流动性?
      • 智能路由
      • 交易手续费
        • 收取手续费奖励
      • 流动性资金池
        • 如何创建交易对
        • 如何增加流动性?
        • 如何删除流动性?
        • 增加/删除资金池的token比例是如何计算的?
        • 如何录入一个新的token?
        • 创建资金池初始价格是多少?
      • 代币列表
    • 矿池
      • SUN.io 平台挖矿细则
      • 如何参与LP挖矿?
      • 如何获取LP挖矿收益?
      • 如何退出LP挖矿?
      • 如何计算LP矿池加速倍数?
      • 如何锁定SUN?
      • 如何投票?
      • 如何重置投票?
      • 智能矿池
        • 如何参与 LP 矿池的定期质押?
        • 如何在 LP 矿池中追加定期质押?
        • 如何中途延长 LP 矿池定期质押锁定期?
        • 如何提前解锁 LP 矿池中定期质押的资产?
        • 如何领取 LP 矿池的定期质押奖励?
      • Farm
      • 历史矿池
    • SunPump
      • 🌞 怎么运行的?
      • 🚀 如何启动?
      • 💡代币详情
      • 👤 个人主页
      • 🏦 服务费
      • SunPump DLive Streaming 功能使用教程
    • SunPump Referral
      • 参与方式
      • 活动规则
      • FAQ
    • PSM
      • 如何使用 PSM 在 USDD 和其他稳定币之间进行 1:1 兑换?
    • 代币经济
      • SUN 代币经济模型
        • SUN 回购及销毁
      • veSUN
      • 空投
  • 治理
    • SUN DAO 治理
    • 参与治理
      • 提案
        • SUN DAO 论坛
        • 获得选票
        • 发起提案
        • 进行投票
        • SUN DAO 提案查看
      • DAO 权益
        • 矿池权重
        • veSUN
  • 开发者
    • 兑换
      • 稳定币兑换简介
      • SunSwap兑换简介
      • SunSwap v3兑换简介
      • 智能路由
    • 挖矿
      • 智能挖矿V1
      • 智能挖矿V2
      • 治理挖矿
    • Sunpump
      • Sunpump Contracts
    • Github
    • 相关合约及ABIs
  • FAQ
    • 如何在手机 TronLink APP中使用SUN.io?
    • 价格是由什么决定的?
    • 兑换支持哪些Token?
    • 为什么我的兑换会失败?
    • 关于 SUN.io 平台能量补贴的详细说明
Powered by GitBook
On this page
  • 背景
  • 原理简介
  • 流动性池
  • 与合约交互
  • 获取流动性信息
  • 执行交易
  • 增删流动性
  1. 开发者
  2. 兑换

SunSwap兑换简介

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

Previous稳定币兑换简介NextSunSwap v3兑换简介

Last updated 8 months ago

背景

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

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

原理简介

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

x∗y=kx * y = kx∗y=k

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

(x+Δx)×(y−Δy)=kΔy=y−kx+Δ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}(x+Δx)×(y−Δy)=kΔy=y−x+Δxk​=x+ΔxΔx×y​

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

pricey=ΔxΔy=x+Δxy≈xyprice_y = \frac{\Delta x}{\Delta y} = \frac{x + \Delta x}{y} \approx \frac{x}{y}pricey​=ΔyΔx​=yx+Δx​≈yx​

流动性池

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

V1版本

Factory合约地址: TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF

V2版本

Factory合约地址: TKWJdrQkqHisa1X8HUdHEfREvTzw4pMAaY

Router合约地址: TXF1xDbVGdxFGbovmmmXvBGu8ZiE3Lq4mR

注意:旧 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)

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

Slippagey=ΔxΔy−xy=ΔxySlippage_y = \frac{\Delta x}{\Delta y} - \frac{x}{y} = \frac{\Delta x}{y}Slippagey​=ΔyΔx​−yx​=yΔx​

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

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

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