本文章主要分析通過代碼呼叫 uniswap/pancakeswap 的介面實作自動化交易的流程
本文主要基于 pancakeswap 實作,其他的交易所 uniswap/mdex 等都基本類似
本文主要實作了 3 個功能
用 BNB 換其他 TOKEN
將其他 TOKEN 換成 BNB
將某一種 TOKEN 換成另外一種 TOKEN
1、開發環境
開發語言為 Javascript/Typescript
通過 ethers.js 和鏈互動
2、構建 provider 和錢包物件
const provider = ethers.getDefaultProvider(
“https://bsc-dataseed1.binance.org:443”
);
const wallet = new ethers.Wallet(config.privateKey, provider);
這里首先基于 bsc 的官方節點構建了一個 provider 物件,然后使用私鑰構建了一個錢包物件
3、構建 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 地址,所有的交易都是通過這個合約執行,
下面定義了 4 個函式,作用分別如下
getAmountsOut 估算代幣轉換的時候 基于 AmountIn 估算 AmountOut
swapExactETHForTokens 將 BNB 換成指定代幣,注意這里有一個 payable 修飾符,表示這個介面需要支付 BNB
swapExactTokensForETHSupportingFeeOnTransferTokens 將指定代幣換成 BNB
swapExactTokensForTokens/swapExactTokensForTokensSupportingFeeOnTransferTokens 這兩個方法都是將某種 ERC20 協議 token 換成另外一種 ERC20 協議 token
4、將 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 的交易路徑來完成交易
5、將其他 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;
}
}
6、將某種 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;
}
}
7、實作效果
我們使用一個簡單的命令列來將上面的程式包裹起來

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/309575.html
標籤:區塊鏈
上一篇:數字資產數字交易
下一篇:Fabric系列 - 錨節點
