1

I am trying to make a swap directly via the pair address without a router.

I'm trying to get token0 by sending token1.

The amount of token0 I will receive does not matter, but when I run the node.js code below, I constantly get the error "Fail with error 'Pancake: INSUFFICIENT_INPUT_AMOUNT'". What do you think could be the reason?

const { ethers } = require('ethers');

const provider = new ethers.providers.JsonRpcProvider('https://data-seed-prebsc-1-s1.binance.org:8545/'); 
const privateKey = 'xxx'; 
const wallet = new ethers.Wallet(privateKey, provider);

const token1Address = '0xae13d989dac2f0debff460ac112a837c89baa7cd'; 
const pairContractAddress = '0xd08759b57bbd0158feac17457ce5871b45e85bd9'; 
const tokenAbi = [
  "function approve(address spender, uint256 amount) external returns (bool)"
];
const pairAbi = [
  "function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external"
];

const tokenContract = new ethers.Contract(token1Address, tokenAbi, wallet);
const pairContract = new ethers.Contract(pairContractAddress, pairAbi, wallet);

async function approveAndSwapToken() {
  const amountToApprove = ethers.utils.parseUnits("0.1", "ether"); 
  console.log(`Approving ${amountToApprove.toString()} tokens for swap...`);
  const approveTx = await tokenContract.approve(pairContractAddress, amountToApprove);
  await approveTx.wait();
  console.log(`Approved ${amountToApprove.toString()} tokens for swap.`);


  const amount0Out = ethers.utils.parseUnits("0", "ether"); 
  const amount1Out = ethers.utils.parseUnits("0.1", "ether"); 
  const toAddress = wallet.address;
  const data = ethers.utils.randomBytes(0); 

  console.log("Performing swap...");
  const swapTx = await pairContract.swap(amount0Out, amount1Out, toAddress, data, {
    gasLimit: ethers.utils.hexlify(250000), 
    gasPrice: ethers.utils.parseUnits('5', 'gwei'), 
  });
  console.log('Transaction hash:', swapTx.hash);
  const receipt = await swapTx.wait(); 
  console.log('Transaction confirmed in block', receipt.blockNumber);
}

approveAndSwapToken().catch(console.error);

1 Answer 1

0

It's more challenging to swap tokens without a PancakeRouter and direct calls to the PancakePair only, because you have to first transfer the input (aka "from") tokens to the pair, and only then the call will succeed. That's why the PancakeRouter is supposed to do all that lower-level logic (and complete appropriate checks) for you.

The PancakeRouter first does a transfer of the input token to the pair contract (to meet the condition of balances > the recorded reserves), and only then calls pair.swap(amount0Out, amount1Out, to, new bytes(0));:

TransferHelper.safeTransferFrom(
     path[0], msg.sender, PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]
);

(https://github.com/pancakeswap/pancake-smart-contracts/blob/d8f55093a43a7e8913f7730cfff3589a46f5c014/projects/exchange-protocol/contracts/PancakeRouter.sol#L271)


You granting token transfer approval to the PancakePair contract does not make any sense here, because there's no function in the PancakePair that would do a transferFrom(...) on your assets.

This logic is only valid for the PancakeRouter, not the PancakePair:

  const approveTx = await tokenContract.approve(pairContractAddress, amountToApprove);
  await approveTx.wait();

So you have to do transfer your input tokens to the PancakePair yourself first.


The problem with that direct is that you are in risk of being front-run, and someone can use the tokens you transferred to the PancakePair contract to get profit from that. Impersonating you as the original sender, and instead calling the mint(...) or swap(...) functions himself first (using front-running bots).


That's why in order to protect the users from front-running, the PancakeSwap protocol utilizes a Router, which completes all these steps (i.e. transfer input tokens to the pair, call swap/mint, check the return values and compare them with tokensOut [expected tokens out]) in ONE ATOMIC TRANSACTION, and will revert at any moment if something goes wrong (because the block is not mined during a transaction yet).


To summarize:

You are getting the INSUFFICIENT_INPUT_AMOUNT error because you have not transferred your input tokens to the PancakePair contract prior to calling the swap(...) method. (https://github.com/pancakeswap/pancake-swap-core/blob/3b214306770e86bc3a64e67c2b5bdb566b4e94a7/contracts/PancakePair.sol#L178)

The function compares the recorded reserves of the pair and perceives that you have not made a token A deposit, so it won't give you any token B out.

13
  • 1
    Thank u, I will try this I will first transfer the tokens to the pair and then perform the swap. Thank you Feb 20 at 10:27
  • Let me know how it turns out! ;) Glad to help
    – Mila A
    Feb 20 at 10:29
  • 1
    I'm trying to do this on the tesnet network. I have sufficient balance in the Testnet network. Wallet: testnet.bscscan.com/address/… Tx: testnet.bscscan.com/tx/… Feb 20 at 12:03
  • 1
    I completed the transfer, but still no swap :( testnet.bscscan.com/tx/… I did it with another account. Feb 20 at 12:31
  • 1
    I understand, thank you very much for your help. If I can achieve this, I will let you know. Feb 20 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.