Web3/nodejs 无法在 Pancakeswapv2 上使用 swapExactTokensForEth
Web3/nodejs not working with swapExactTokensForEth on Pancakeswapv2
我在 BSC 上为 BNB 出售代币 BUNNY 时遇到了实际问题。
这是我所知道的有效方法
- 查看配额显示我已获准在 PCSv2 路由器上交易 BUNNY
- 增加津贴也有效
- 花费 BNB 购买 BUNNY 也有效(swapExactETHforTokens)
- 在 BSC 扫描上手动写入合约也可以
不起作用的是 swapExactTokensForETH - 它会消耗一些 gas 但会抛出:
“传输失败”...原因:'transaction failed',代码:'CALL_EXCEPTION'
这是来自 node.js 脚本的失败交易
https://bscscan.com/tx/0x55d45e5f1e937fcd55294fa3e4d8c4c24d9c578b7ba8361fb12b2a017d7e7a4b
现在我所做的所有研究都表明这是因为我需要批准支出者 - 我已经这样做了...我怎么知道?好吧,我写的函数说它很好,直接查询 BUNNY
另一件奇怪的事情是这完美地工作(没有额外的批准) - 见截图
BSCScan Write Contract that works
这是 BSCscan 写入路由合约部分的成功交易
https://bscscan.com/tx/0xc8d2b999c08cef6ecceecf4bc5d6242bcd43571164016a8372bbf0c02d1a6185
如果有人能弄清楚为什么会抛出这个错误,那将是一个巨大的帮助 tyvm 提前
这是代码:
const ethers = require('ethers');
const Web3 = require('web3');
const abi = require('human-standard-token-abi');
const {ChainId, Token, TokenAmount, Fetcher: v2Fetcher, Pair, Route, Trade, TradeType, Percent} = require('@pancakeswap-libs/sdk-v2');
const {JsonRpcProvider} = require("@ethersproject/providers");
const url = 'https://bsc-dataseed1.binance.org/';
const provider = new JsonRpcProvider('https://bsc-dataseed1.binance.org/');
const web3 = new Web3(url);
const secretKey = process.env.SECRETKEY;
const walletAddress = process.env.WALLETADDRESS;
const wallet = ethers.Wallet.fromMnemonic(secretKey);
const account = wallet.connect(provider);
const pcsRouterV2 = Web3.utils.toChecksumAddress('0x10ED43C718714eb63d5aA57B78B54704E256024E'); //v2 router
const routerV2 = new ethers.Contract (pcsRouterV2, [
'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 swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)',
'function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'
], account );
const bunnyAddress = Web3.utils.toChecksumAddress('0xc9849e6fdb743d08faee3e34dd2d1bc69ea11a51');
const wbnbAddress = Web3.utils.toChecksumAddress('0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'); // WBNB
const gasApprovalLimit = 100000;
const gasTradingLimit = 250000;
const gasPrice = 5;
const getAllowance = async (tickerTokenAddress, thisWalletAddress, liquidtyPoolRouter) => {
var contract = new web3.eth.Contract(abi, tickerTokenAddress);
let approvalLimit = await contract.methods.allowance(thisWalletAddress, liquidtyPoolRouter).call();
let decimals = await contract.methods.decimals().call();
// this comes back with 3 variables, an approval, an approval in token units and the decimals
return [approvalLimit, approvalLimit / (10 ** decimals), decimals];
}
const getApproval = async (thisTokenAddress, approvalAmount, thisDecimals, walletAccount, liquidtyPoolRouter, thisGasPrice = gasPrice, thisGasLimit = gasApprovalLimit) => {
console.log(`getting approval`);
let contract = new ethers.Contract(thisTokenAddress, abi, walletAccount);
let approveResponse = await contract.approve(
liquidtyPoolRouter,
ethers.utils.parseUnits(approvalAmount.toString(), thisDecimals),
{
gasLimit: thisGasLimit,
gasPrice: ethers.utils.parseUnits(thisGasPrice.toString(), 'gwei')
});
console.log(approveResponse);
}
const swapExactBNBForTokens = async (buyAddress, buyDecimals, tokensIn, tradeSlippage, thisGasPrice = gasPrice, thisGasLimit = gasTradingLimit) => {
let amountIn = ethers.utils.parseUnits(tokensIn.toString(), buyDecimals);
let amounts = await routerV2.getAmountsOut(amountIn, [wbnbAddress, buyAddress]);
let amountOutMin = amounts[1].sub(amounts[1].mul(tradeSlippage).div(100));
let tx = await routerV2.swapExactETHForTokens(
amountOutMin,
[wbnbAddress, buyAddress],
walletAddress,
Date.now() + 1000 * 60 * 10,
{
value: amountIn,
gasLimit: thisGasLimit,
gasPrice: ethers.utils.parseUnits(thisGasPrice.toString(), 'gwei')
}
)
console.log(`Transaction Submitted...`);
let receipt = await tx.wait();
console.log(receipt);
}
const swapExactTokensForBNB = async (sellAddress, sellDecimals, tokensIn, tradeSlippage, thisGasPrice = gasPrice, thisGasLimit = gasTradingLimit) => {
let amountIn = ethers.utils.parseUnits(tokensIn.toString(), sellDecimals);
let amounts = await routerV2.getAmountsOut(amountIn, [sellAddress, wbnbAddress]);
let amountOutMin = amounts[1].sub(amounts[1].mul(tradeSlippage).div(100));
let tx = await routerV2.swapExactTokensForETH(
amountIn,
amountOutMin,
[sellAddress, wbnbAddress],
walletAddress,
Date.now() + 1000 * 60 * 10,
{
gasLimit: thisGasLimit,
gasPrice: ethers.utils.parseUnits(thisGasPrice.toString(), 'gwei')
}
)
console.log(`Transaction Submitted...`);
let receipt = await tx.wait();
console.log(receipt);
}
// USAGE
// swapExactBNBForTokens(bunnyAddress, 18, 0.3, 2); // spending 0.3 BNB to buy BUNNY
// swapExactTokensForBNB(bunnyAddress, 18, 3, 2); // spending 3 BUNNY to buy BNB
getAllowance(bunnyAddress, walletAddress, pcsRouterV2).then((value) => {console.log('V2 ' + value);});
这是您在 failed 中提供的 amountIn tx: 3299718614161746000.
这是您在成功 tx: 3299718614161745787中提供的amountIn,它是更少。
所以我假设您提供的 amountIn 不正确,它大于您的余额。
我在 BSC 上为 BNB 出售代币 BUNNY 时遇到了实际问题。 这是我所知道的有效方法
- 查看配额显示我已获准在 PCSv2 路由器上交易 BUNNY
- 增加津贴也有效
- 花费 BNB 购买 BUNNY 也有效(swapExactETHforTokens)
- 在 BSC 扫描上手动写入合约也可以
不起作用的是 swapExactTokensForETH - 它会消耗一些 gas 但会抛出: “传输失败”...原因:'transaction failed',代码:'CALL_EXCEPTION' 这是来自 node.js 脚本的失败交易 https://bscscan.com/tx/0x55d45e5f1e937fcd55294fa3e4d8c4c24d9c578b7ba8361fb12b2a017d7e7a4b
现在我所做的所有研究都表明这是因为我需要批准支出者 - 我已经这样做了...我怎么知道?好吧,我写的函数说它很好,直接查询 BUNNY 另一件奇怪的事情是这完美地工作(没有额外的批准) - 见截图
BSCScan Write Contract that works
这是 BSCscan 写入路由合约部分的成功交易 https://bscscan.com/tx/0xc8d2b999c08cef6ecceecf4bc5d6242bcd43571164016a8372bbf0c02d1a6185
如果有人能弄清楚为什么会抛出这个错误,那将是一个巨大的帮助 tyvm 提前 这是代码:
const ethers = require('ethers');
const Web3 = require('web3');
const abi = require('human-standard-token-abi');
const {ChainId, Token, TokenAmount, Fetcher: v2Fetcher, Pair, Route, Trade, TradeType, Percent} = require('@pancakeswap-libs/sdk-v2');
const {JsonRpcProvider} = require("@ethersproject/providers");
const url = 'https://bsc-dataseed1.binance.org/';
const provider = new JsonRpcProvider('https://bsc-dataseed1.binance.org/');
const web3 = new Web3(url);
const secretKey = process.env.SECRETKEY;
const walletAddress = process.env.WALLETADDRESS;
const wallet = ethers.Wallet.fromMnemonic(secretKey);
const account = wallet.connect(provider);
const pcsRouterV2 = Web3.utils.toChecksumAddress('0x10ED43C718714eb63d5aA57B78B54704E256024E'); //v2 router
const routerV2 = new ethers.Contract (pcsRouterV2, [
'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 swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)',
'function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'
], account );
const bunnyAddress = Web3.utils.toChecksumAddress('0xc9849e6fdb743d08faee3e34dd2d1bc69ea11a51');
const wbnbAddress = Web3.utils.toChecksumAddress('0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'); // WBNB
const gasApprovalLimit = 100000;
const gasTradingLimit = 250000;
const gasPrice = 5;
const getAllowance = async (tickerTokenAddress, thisWalletAddress, liquidtyPoolRouter) => {
var contract = new web3.eth.Contract(abi, tickerTokenAddress);
let approvalLimit = await contract.methods.allowance(thisWalletAddress, liquidtyPoolRouter).call();
let decimals = await contract.methods.decimals().call();
// this comes back with 3 variables, an approval, an approval in token units and the decimals
return [approvalLimit, approvalLimit / (10 ** decimals), decimals];
}
const getApproval = async (thisTokenAddress, approvalAmount, thisDecimals, walletAccount, liquidtyPoolRouter, thisGasPrice = gasPrice, thisGasLimit = gasApprovalLimit) => {
console.log(`getting approval`);
let contract = new ethers.Contract(thisTokenAddress, abi, walletAccount);
let approveResponse = await contract.approve(
liquidtyPoolRouter,
ethers.utils.parseUnits(approvalAmount.toString(), thisDecimals),
{
gasLimit: thisGasLimit,
gasPrice: ethers.utils.parseUnits(thisGasPrice.toString(), 'gwei')
});
console.log(approveResponse);
}
const swapExactBNBForTokens = async (buyAddress, buyDecimals, tokensIn, tradeSlippage, thisGasPrice = gasPrice, thisGasLimit = gasTradingLimit) => {
let amountIn = ethers.utils.parseUnits(tokensIn.toString(), buyDecimals);
let amounts = await routerV2.getAmountsOut(amountIn, [wbnbAddress, buyAddress]);
let amountOutMin = amounts[1].sub(amounts[1].mul(tradeSlippage).div(100));
let tx = await routerV2.swapExactETHForTokens(
amountOutMin,
[wbnbAddress, buyAddress],
walletAddress,
Date.now() + 1000 * 60 * 10,
{
value: amountIn,
gasLimit: thisGasLimit,
gasPrice: ethers.utils.parseUnits(thisGasPrice.toString(), 'gwei')
}
)
console.log(`Transaction Submitted...`);
let receipt = await tx.wait();
console.log(receipt);
}
const swapExactTokensForBNB = async (sellAddress, sellDecimals, tokensIn, tradeSlippage, thisGasPrice = gasPrice, thisGasLimit = gasTradingLimit) => {
let amountIn = ethers.utils.parseUnits(tokensIn.toString(), sellDecimals);
let amounts = await routerV2.getAmountsOut(amountIn, [sellAddress, wbnbAddress]);
let amountOutMin = amounts[1].sub(amounts[1].mul(tradeSlippage).div(100));
let tx = await routerV2.swapExactTokensForETH(
amountIn,
amountOutMin,
[sellAddress, wbnbAddress],
walletAddress,
Date.now() + 1000 * 60 * 10,
{
gasLimit: thisGasLimit,
gasPrice: ethers.utils.parseUnits(thisGasPrice.toString(), 'gwei')
}
)
console.log(`Transaction Submitted...`);
let receipt = await tx.wait();
console.log(receipt);
}
// USAGE
// swapExactBNBForTokens(bunnyAddress, 18, 0.3, 2); // spending 0.3 BNB to buy BUNNY
// swapExactTokensForBNB(bunnyAddress, 18, 3, 2); // spending 3 BUNNY to buy BNB
getAllowance(bunnyAddress, walletAddress, pcsRouterV2).then((value) => {console.log('V2 ' + value);});
这是您在 failed 中提供的 amountIn tx: 3299718614161746000.
这是您在成功 tx: 3299718614161745787中提供的amountIn,它是更少。
所以我假设您提供的 amountIn 不正确,它大于您的余额。