开源分享:PancakeSwap 自动市场制造商(AMM)模型的核心代码

Technical Blog1years go (2023)更新 Dexnav
0

开源分享:PancakeSwap 自动市场制造商(AMM)模型的核心代码

PancakeSwap是一个去中心化交易所(DEX),基于Binance Smart Chain(BSC)运行。它允许用户在BSC上交易代币,并提供了一种简单易用的交易方式。以下是PancakeSwap的开发逻辑:

  1. Provide liquidity 交流分享tg: t.me/dexdao123

PancakeSwap是基于自动市场制造商(AMM)模型的,因此需要提供足够的流动性。为此,用户可以通过提供代币对的流动性来获得奖励,并获得交易费用的一部分。

以下是基于PancakeSwap AMM的源码片段:

// 1. 用户提供代币对的流动性
function addLiquidity(uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);

// 2. 用户移除代币对的流动性
function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) external returns (uint256 amountA, uint256 amountB);

// 3. 交易
function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);

// 4. 获取代币对当前价格和交易费用
function getReserves() public view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) internal pure returns (uint256 amountB);
function getAmountsOut(uint256 amountIn, address[] memory path) public view returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] memory path) public view returns (uint256[] memory amounts);
  1. Trading    交流分享tg: t.me/dexdao123

用户可以在PancakeSwap上交易代币。在交易时,用户选择要交换的代币,并输入要交换的数量。PancakeSwap将自动计算汇率,并显示最终的交易金额。交易完成后,代币会转移到用户的钱包中。

以下是基于PancakeSwapSWAP模型的源码片段:

import Web3 from 'web3';
import BigNumber from 'bignumber.js';

const web3 = new Web3('https://bsc-dataseed1.binance.org:443');

// Token addresses
const fromTokenAddress = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'; // WBNB
const toTokenAddress = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'; // BUSD

// Token contracts
const fromToken = new web3.eth.Contract(abi, fromTokenAddress);
const toToken = new web3.eth.Contract(abi, toTokenAddress);

// User inputs
const fromAmount = new BigNumber(1); // Amount to swap from
const slippage = new BigNumber(5); // Maximum slippage percentage
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from now

// Get token prices
const fromPrice = await fromToken.methods.getReserves().call();
const toPrice = await toToken.methods.getReserves().call();

// Calculate exchange rate
const exchangeRate = new BigNumber(toPrice.reserve0).div(fromPrice.reserve1);

// Calculate minimum amount to receive
const minToAmount = exchangeRate.times(fromAmount).times(1 - slippage.div(100));

// Approve token transfer
await fromToken.methods.approve(pancakeSwapAddress, fromAmount).send({from: userAddress});

// Swap tokens
await pancakeSwap.methods.swapExactTokensForTokens(
  fromAmount.toFixed(),
  minToAmount.toFixed(),
  [fromTokenAddress, toTokenAddress],
  userAddress,
  deadline
).send({from: userAddress});
注:上述代码仅作为示例,实际使用时需要根据具体情况进行修改。
  1. 奖励  交流分享tg: t.me/dexdao123

PancakeSwap采用的是类似挖矿的奖励机制。当用户提供流动性时,系统会向其提供奖励。这些奖励是由交易费用和PancakeSwap代币的供应量决定的。

以下是一个简单的PancakeSwap奖励机制示例代码:

const pancakeSwapToken = 'PANCAKE_TOKEN_ADDRESS';
const liquidityProviderReward = 0.003; // 0.3%
const tradingFee = 0.0025; // 0.25%

function calculateRewards(liquidityPoolSize, tradeAmount) {
  const liquidityProviderShare = liquidityPoolSize / totalLiquidity;
  const tradingFeeShare = tradeAmount * tradingFee / liquidityPoolSize;
  const pancakeSwapReward = liquidityProviderShare * tradingFeeShare * liquidityProviderReward;
  const userReward = (1 - liquidityProviderReward) * tradingFeeShare;
  
  // Return the PancakeSwap token reward and the user's reward
  return {
    pancakeSwapReward: pancakeSwapReward,
    userReward: userReward
  };
}


    // 以下是一个代码示例,展示了PancakeSwap智能合约的基本结构和功能:

pragma solidity ^0.8.0;

contract PancakeSwap {
    // 代币池
    mapping(address => mapping(address => uint256)) private _liquidityPools;

    // 代币交换
    function swap(address tokenA, address tokenB, uint256 amountIn) public returns (uint256 amountOut) {
        // 计算交换比率
        uint256 reserveA = _liquidityPools[tokenA][tokenB];
        uint256 reserveB = _liquidityPools[tokenB][tokenA];
        amountOut = (amountIn * reserveB) / reserveA;

        // 更新代币池
        _liquidityPools[tokenA][tokenB] += amountIn;
        _liquidityPools[tokenB][tokenA] -= amountOut;

        // 转移代币
        // ...

        // 分配交易手续费
        // ...
    }

    // 奖励机制
    function provideLiquidity(address tokenA, address tokenB, uint256 amountA, uint256 amountB) public {
        // 存储代币池信息
        _liquidityPools[tokenA][tokenB] += amountA;
        _liquidityPools[tokenB][tokenA] += amountB;

        // 发放奖励
        // ...
    }

    // ...
}





以下是PancakeSwap的核心代码示例:

Solidity合约代码:

pragma solidity ^0.6.12;

import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/IBEP20.sol";
import "@pancakeswap/pancake-swap-lib/contracts/access/Ownable.sol";
import "@pancakeswap/pancake-swap-lib/contracts/math/SafeMath.sol";
import "@pancakeswap/pancake-swap-lib/contracts/utils/ReentrancyGuard.sol";
import "./CakeToken.sol";
import "./SyrupBar.sol";

contract MasterChef is Ownable, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;

    // Info of each user.
    struct UserInfo {
        uint256 amount;     // How many LP tokens the user has provided.
        uint256 rewardDebt; // Reward debt. See explanation below.
        //
        // We do some fancy math here. Basically, any point in time, the amount of CAKEs
        // entitled to a user but is pending to be distributed is:
        //
        //   pending reward = (user.amount * pool.accCakePerShare) - user.rewardDebt
        //
        // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
        //   1. The pool's `accCakePerShare` (and `lastRewardBlock`) gets updated.
        //   2. User receives the pending reward sent to his/her address.
        //   3. User's `amount` gets updated.
        //   4. User's `rewardDebt` gets updated.
    }

    // Info of each pool.
    struct PoolInfo {
        IBEP20 lpToken;           // Address of LP token contract.
        uint256 allocPoint;       // How many allocation points assigned to this pool. CAKEs to distribute per block.
        uint256 lastRewardBlock;  // Last block number that CAKEs distribution occurs.
        uint256 accCakePerShare; // Accumulated CAKEs per share, times 1e12. See below.
    }

    // The CAKE TOKEN!
    CakeToken public cake;
    // The SYRUP TOKEN!
    SyrupBar public syrup;
    // Dev address.
    address public devaddr;
    // CAKE tokens created per block.
    uint256 public cakePerBlock;
    // Bonus muliplier for early cake makers.
    uint256 public BONUS_MULTIPLIER = 1;
    // The block number when CAKE mining starts.
    uint256 public startBlock;
    // Total allocation points. Must be the sum of all allocation points in all pools.
    uint256 public totalAllocPoint = 0;
    // Info of each pool.
    PoolInfo[] public poolInfo;
    // Info of each user that stakes LP tokens.
    mapping (uint256 => mapping (address => UserInfo)) public userInfo;
    // The block number when SYRUP mining starts.
    uint256 public syrupStartBlock;

    event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
    event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);

    constructor(
        CakeToken _cake,
        SyrupBar _syrup,
        address _devaddr,
        uint256 _cakePerBlock,
        uint256 _startBlock,
        uint256 _syrupStartBlock
    ) public {
        cake = _cake;
        syrup = _syrup;
        devaddr = _


// 从智能合约中获取交易信息
const tx = await contract.methods.swapExactTokensForTokens(
  amountIn,
  amountOutMin,
  [tokenIn, tokenOut],
  recipient,
  deadline
).send({ from: account });

console.log(`Transaction hash: ${tx.transactionHash}`);

这段代码通过调用智能合约中的swapExactTokensForTokens方法,将输入的代币数量amountIn交换成目标代币tokenOut,并且要求输出的代币数量不少于amountOutMin。同时还需要指定交易的一些参数,比如输入和输出代币的类型、接收地址和截止时间等。交易成功后,可以通过tx.transactionHash获取交易哈希值,用于查询交易状态。

© 版权声明

Related posts

No comments

No comments...