使用代碼實現uniswap和pancakeswap自動化交易

本文章主要分析經過代碼調用 uniswap/pancakeswap 的接口實現自動化交易的流程

本文主要基於 pancakeswap 實現,其餘的交易所 uniswap/mdex 等都基本相似javascript

本文主要實現了 3 個功能java

  • 用 BNB 換其餘 TOKEN
  • 將其餘 TOKEN 換成 BNB
  • 將某一種 TOKEN 換成另一種 TOKEN

一、開發環境

  • 開發語言爲 Javascript/Typescript
  • 經過 ethers.js 和鏈交互

二、構建 provider 和錢包對象

const provider = ethers.getDefaultProvider(
  "https://bsc-dataseed1.binance.org:443"
);
const wallet = new ethers.Wallet(config.privateKey, provider);
複製代碼

這裏首先基於 bsc 的官方節點構建了一個 provider 對象,而後使用私鑰構建了一個錢包對象微信

三、構建 pancakeswap 的 Router 合約對象

const router = new ethers.Contract(
  "0x10ED43C718714eb63d5aA57B78B54704E256024E",
  [
    "function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)",
    "function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)",
    "function swapExactTokensForETHSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)",
    "function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) external returns (uint[] memory amounts)",
    "function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) external returns (uint[] memory amounts)",
  ],
  wallet
);
複製代碼

首先上面這個地址是 pancakeswap 的 Router2 地址,全部的交易都是經過這個合約執行。markdown

下面定義了 4 個函數,做用分別以下app

  • getAmountsOut 估算代幣轉換的時候 基於 AmountIn 估算 AmountOut
  • swapExactETHForTokens 將 BNB 換成指定代幣,注意這裏有一個 payable 修飾符,表示這個接口須要支付 BNB
  • swapExactTokensForETHSupportingFeeOnTransferTokens 將指定代幣換成 BNB
  • swapExactTokensForTokens/swapExactTokensForTokensSupportingFeeOnTransferTokens 這兩個方法都是將某種 ERC20 協議 token 換成另一種 ERC20 協議 token

四、將 BNB 換成其餘 TOKEN

async function bnb2Token(bnbValue, tokenAddress) {
  const amountIn = bnbValue;
  // 估算能得到多少個token
  const amounts = await router.getAmountsOut(amountIn, [
    pancakeAddress.WBNB,
    tokenAddress,
  ]);
  // 滑點
  const amountOutMin = amounts[1].sub(amounts[1].div(config.slide));
  // 發起交易
  const path = [pancakeAddress.WBNB, tokenAddress];
  const gasPrice = await provider.getGasPrice();
  const tx = await router.swapExactETHForTokens(
    amountOutMin,
    path,
    wallet.address,
    Date.now() + 10 * 60_000,
    {
      gasPrice,
      gasLimit: config.gasLimit,
      value: amountIn,
    }
  );
  console.log(`交易已發起, https://bscscan.com/tx/${tx.hash}`);
  try {
    await tx.wait();
    console.log("交易成功");
  } catch (err) {
    console.log("交易失敗");
    throw err;
  }
}
複製代碼

注意這裏有一個 path 變量,表示咱們指定的交易路徑,爲了方便合約處理,Swap 構造了一個叫 WrappedBNB 的 ERC20 代幣,也就是代碼中的 WBNB,合約的處理流程是經過 payable 接收到咱們的 BNB 以後,轉換成 WBNB,而後使用 WBNB -> TOKEN 的交易路徑來完成交易async

五、將其餘 TOKEN 換成 BNB

// 首先咱們須要有一個構建 erc20 合約的構造器
function erc20Contract(tokenAddress) {
  return new ethers.Contract(
    tokenAddress,
    [
      "function symbol() public view returns (string)",
      "function decimals() public view returns (uint)",
      "function balanceOf(address user) public view returns (uint)",
      "function allowance(address a, address b) public view returns (uint)",
      "function approve(address a, uint amount) public",
    ],
    wallet
  );
}

// 須要有一個受權函數,將 TOKEN 受權給 pancakeswap 處理
async function approve(tokenContract) {
  const amount = await tokenContract.allowance(
    wallet.address,
    pancakeAddress.router
  );
  // 已經受權過
  if (amount.gt(0)) {
    return;
  }
  const gasPrice = await provider.getGasPrice();
  // 從新調用受權
  const tx = await tokenContract.approve(
    pancakeAddress.router,
    ethers.constants.MaxUint256,
    {
      gasPrice,
      gasLimit: config.gasLimit,
    }
  );
  console.log("代幣受權已發起", tx.hash);
  await tx.wait();
  console.log("受權成功");
}

// 將 TOKEN 換成 BNB 的主函數
// amount 若是不指定就賣出所有
async function token2Bnb(tokenAddress, amount) {
  // 拿到token的erc20合約
  const tokenContract = erc20Contract(tokenAddress);

  // 先受權給pancakeswap
  await approve(tokenContract);

  // 檢查剩餘數量
  let amountIn = await tokenContract.balanceOf(wallet.address);
  if (Number(amountIn) === 0) {
    console.log("數量爲0,沒法賣出");
    return;
  }
  // 指定數量
  if (amount) {
    amount = ethers.BigNumber.from(amount);
    // 指定了賣出數量
    if (amountIn.lt(amount)) {
      console.log("餘額不足");
      return;
    }
    amountIn = amount;
  }
  // 賣出
  const gasPrice = await provider.getGasPrice();
  const tx = await router.swapExactTokensForETHSupportingFeeOnTransferTokens(
    amountIn,
    0,
    [tokenAddress, pancakeAddress.WBNB],
    wallet.address,
    Date.now() + 10 * 60_000,
    {
      gasPrice,
      gasLimit: config.gasLimit,
    }
  );
  console.log(`交易已發起, https://bscscan.com/tx/${tx.hash}`);
  try {
    await tx.wait();
    console.log("交易成功");
  } catch (err) {
    console.log("交易失敗");
    throw err;
  }
}
複製代碼

六、將某種 TOKEN 換成另一種 TOKEN

// token換token,第三個參數表示數量,若是all表示全部
async function token2Token(token1, token2, amount) {
  // 拿到token的erc20合約
  const token1Contract = erc20Contract(token1);

  // 先受權給pancakeswap
  await approve(token1Contract);

  // 計算銷售數量
  let amountIn;
  if (amount === "all") {
    amountIn = await token1Contract.balanceOf(wallet.address);
  } else {
    amountIn = amount;
  }

  // 交易路徑,用bnb中轉
  const path = [token1, pancakeAddress.WBNB, token2];
  // 發起交易
  const args = [amountIn, 0, path, wallet.address, Date.now() + 10 * 60_000];
  // 檢查交易是否能成功
  try {
    await router.callStatic.swapExactTokensForTokensSupportingFeeOnTransferTokens(
      ...args
    );
  } catch (e) {
    console.log("測試發起交易出現錯誤");
    throw e;
  }

  const gasPrice = await provider.getGasPrice();
  const tx = await router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
    ...args,
    {
      gasPrice,
      gasLimit: config.gasLimit,
    }
  );
  console.log(`交易已發起, https://bscscan.com/tx/${tx.hash}`);
  try {
    await tx.wait();
    console.log("交易成功");
  } catch (err) {
    console.log("交易失敗");
    throw err;
  }
}
複製代碼

七、實現效果

咱們使用一個簡單的命令行來將上面的程序包裹起來ide

下一篇文章咱們會結合 telegram 機器人實現一個交互式命令交易機器人函數

之前的文章oop

經過程序監控 pancakeswap 中 babydoge 的交易數據測試

聯繫做者

微信:czz5242199

telegram: @zhuozhongcao

相關文章
相關標籤/搜索