🌞Moon Will Know
🥞

Pancake Swap 交易流程

Liquidity Pools 流动性资金池


用户向流动性资金池中注入流动性时(例:同时注入 $CAKE$BNB ),会同时获得对应的 $LP (例:$CAKE-BNB-LP)。
用户的 $LP 将用于确认在对应流动池中的份额,可随时通过移除流动性来赎回质押的两种代币。

创建流动性资金池

初始注入的流动性资金池将决定该交易对当前的最低价格。

注入流动性

后续注入的流动性,将受到当时的最低价格影响,若其中一种币的数量不足,将无法注入流动性。

获利方式

用户通过流动性资金池进行交易时,会产生 0.25% 的交易手续费,其中 0.17% 会流入流动性资金池。

不稳定性

质押资金池受交易对双币种影响,有可能面临币价影响而遭受损失。

Exchange 交易


pancakeSwap 中的流动性注入、以及交易都是通过 智能合约 实现的。
最主要的交易合约包括:

PanckaeFactory 工厂

合约地址: 0xca143ce32fe78f1f7019d7d551a6402fc5350c73 Bsc scan: https://bscscan.com/address/0x73feaa1ee314f8c655e354234017be2193c9e24e
getPair 获取交易对
根据 tokenA 和 tokenB 的地址 匹配对应交易对,如果不存在则返回 0x0000000000000000000000000000000000
function getPair(address tokenA, address tokenB) external view returns (address pair);

PanckaeRouter 路由

合约地址: 0x10ed43c718714eb63d5aa57b78b54704e256024e Bscscan: https://bscscan.com/address/0x10ed43c718714eb63d5aa57b78b54704e256024e
getAmountsOut 获取输出金额
通过输入金额,预估输出金额
function getAmountsOut(uint amountIn, address[] memory path) internal view returns (uint[] memory amounts);
swapExactTokensForTokensSupportingFeeOnTransferTokens:
通过输入金额,输出不确定金额
function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline )
swapTokensForExactTokens:
需要获取精确的输出,输入不确定金额(也可以理解买,如购买100个UNI TOKEN,需要未知weth)
function swapTokensForExactTokens( uint amountOut,//期望输出金额 uint amountInMax,//最大输入 (如果到你打包的交易时,如果实际需要输入的金额大于该金额,交易失败!) address[] calldata path, address to, uint deadline )
swapExactTokensForTokens:
通过输入金额,输出不确定金额 (也可以理解为卖, 如卖掉100个UNI TOKEN,可以获得未知WETH)
function swapExactTokensForTokens( uint amountIn,//实际输入金额 uint amountOutMin,//最小输出 (如果到打包你的交易时,实际输出小于该金额,交易失败!) address[] calldata path, address to, uint deadline )
 

交易步骤


1.确定交易合约

用户选择需要交易的 tokenA → tokenB,以及其中一个确定的数额 amountIn

2. 获取交易对

连接 pancakeFactory 合约,调用合约的 getPair 方法,获取对应 pair 合约。
// 连接合约 const factory = new ethers.Contract( '0xca143ce32fe78f1f7019d7d551a6402fc5350c73', ["function getPair(address tokenA, address tokenB) external view returns (address pair)"], account ) // 获取交易对 const pairAddress = await factory.getPair('tokenA address','tokenB address'); // 可能会存在交易对不存在的情况 这里要做出处理 // 或者使用中间币交易

3. 预估交易结果

并通过实时币价计算预估交易结果,通过用户滑点设置计算 amountOutMin
const router = new ethers.Contract( data.router, [ 'function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)', 'function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)', 'function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)' ], account ); const amounts = await router.getAmountsOut(amountIn, [tokenIn, tokenOut]); const amountOutMin = amounts * ( 1 - slippage);

4. 获取流动性

如果存在交易对,需要通过返回的addres查询交易对下的 tokenB 的数量是否满足用户需要兑换的数量
// 连接 tokenB 合约 const tokenBContract = new ethers.Contract( 'tokenB address', 'tokenB ABI', account ); // 获取 tokenB 在交易对中的数额 const balance = tokenBContract.balanceOf(pairAddress); // 判断 balance 是否大于 amountOutMin // 否则提示 流动性不足

5. approve 授权

调用 tokenA 合约的approve方法,授权router合约花费数额。
function approve( address spender, uint value // 数额 ) external returns (bool);

6. 兑换

当流动性充足时,根据具体的交易情况调用 router 合约的交易方法。
当不存在流动性时,可以通过 $BNB 作为中间币种,进行多路径交易。
注意: 这些数字的单位均为 wei
// 发起兑换 const tx = await router.swapExactTokensForTokens( amountIn, amountOutMin, [tokenIn, tokenOut], // 或者中间增加一个token toAddress, // 接受tokenB的账户地址 Date.now() + 1000 * 60 * 5, // 交易超时失败事件 { 'gasLimit': data.gasLimit, 'gasPrice': data.gasPrice, 'nonce ' : null // 设定购买区块位置 }); // 等待兑换结果 const receipt = await tx.wait(); console.log(`Transaction receipt : https://www.bscscan.com/tx/${receipt.logs[1].transactionHash}`);