15

I am trying to use uniswap contract method to simply swap eth for token, using eth from metamask wallet. Uniswap contract method is:

function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
  external
  payable
  returns (uint[] memory amounts);

My naive impression is that it should look something like this, but I am sure I am missing several crucial parts (like signing the transaction, use apropriate callback method) and I cannot find a full comprehensive example. How should a full working example look like?

const ETHaddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
const DAIaddress = "0x6b175474e89094c44da98b954eedeac495271d0f"

const routerContract = new web3.eth.Contract(
                  UniswapRouterABI,
                  "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
                );

routerContract.methods.swapExactETHForTokens(500,[ETHaddress,DAIaddress],myWalletAddress,someDeadline)
.send(from: myWalletAddress, value: "1000000000000")
TylerH
  • 20,799
  • 66
  • 75
  • 101
user3338991
  • 431
  • 2
  • 5
  • 9

2 Answers2

9

You can check this working example for buying on pancakeswap.finance: https://github.com/religion-counter/onlyone/blob/main/helper-scripts/buy-onlyone-pancakeswap.js

// Helper script that buys ONLYONE token from a specified address specified on text file SPECIFY_ACCOUNTS_YOU_WANT_TO_BUY_FOR_HERE.json
// The amount is specified with 'originalAmountToBuyWith' variable in the source
// The JSON file should have an array with objects with 'address' field and 'privateKey' field.
// Buys ONLYONE for ${bnbAmount} BNB from pancakeswap for address ${targetAccounts[targetIndex].address}
// targetIndex is passed as an argument: process.argv.splice(2)[0]

var fs = require('fs')
var Tx = require('ethereumjs-tx').Transaction;
var Web3 = require('web3')
var Common = require('ethereumjs-common').default;

var web3 = new Web3(new Web3.providers.HttpProvider('https://bsc-dataseed.binance.org/'))
var BSC_FORK = Common.forCustomChain(
    'mainnet',
    {
        name: 'Binance Smart Chain Mainnet',
        networkId: 56,
        chainId: 56,
        url: 'https://bsc-dataseed.binance.org/'
    },
    'istanbul',
);

// SPECIFY_THE_AMOUNT_OF_BNB_YOU_WANT_TO_BUY_FOR_HERE
var originalAmountToBuyWith = '0.007' + Math.random().toString().slice(2,7);
var bnbAmount = web3.utils.toWei(originalAmountToBuyWith, 'ether');

var targetAccounts = JSON.parse(fs.readFileSync('SPECIFY_ACCOUNTS_YOU_WANT_TO_BUY_FOR_HERE.json', 'utf-8'));

var targetIndex = Number(process.argv.splice(2)[0]);
var targetAccount = targetAccounts[targetIndex];

console.log(`Buying ONLYONE for ${originalAmountToBuyWith} BNB from pancakeswap for address ${targetAccount.address}`);

var res = buyOnlyone(targetAccounts[targetIndex], bnbAmount);
console.log(res);

async function buyOnlyone(targetAccount, amount) {

    var amountToBuyWith = web3.utils.toHex(amount);
    var privateKey = Buffer.from(targetAccount.privateKey.slice(2), 'hex')  ;
    var abiArray = JSON.parse(JSON.parse(fs.readFileSync('onlyone-abi.json','utf-8')));
    var tokenAddress = '0xb899db682e6d6164d885ff67c1e676141deaaa40'; // ONLYONE contract address
    var WBNBAddress = '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'; // WBNB token address

    // var onlyOneWbnbCakePairAddress = '0xd22fa770dad9520924217b51bf7433c4a26067c2';
    // var pairAbi = JSON.parse(fs.readFileSync('cake-pair-onlyone-bnb-abi.json', 'utf-8'));
    // var pairContract = new web3.eth.Contract(pairAbi, onlyOneWbnbCakePairAddress/*, {from: targetAccount.address}*/);
    var amountOutMin = '100' + Math.random().toString().slice(2,6);
    var pancakeSwapRouterAddress = '0x10ed43c718714eb63d5aa57b78b54704e256024e';

    var routerAbi = JSON.parse(fs.readFileSync('pancake-router-abi.json', 'utf-8'));
    var contract = new web3.eth.Contract(routerAbi, pancakeSwapRouterAddress, {from: targetAccount.address});
    var data = contract.methods.swapExactETHForTokens(
        web3.utils.toHex(amountOutMin),
        [WBNBAddress,
         tokenAddress],
        targetAccount.address,
        web3.utils.toHex(Math.round(Date.now()/1000)+60*20),
    );

    var count = await web3.eth.getTransactionCount(targetAccount.address);
    var rawTransaction = {
        "from":targetAccount.address,
        "gasPrice":web3.utils.toHex(5000000000),
        "gasLimit":web3.utils.toHex(290000),
        "to":pancakeSwapRouterAddress,
        "value":web3.utils.toHex(amountToBuyWith),
        "data":data.encodeABI(),
        "nonce":web3.utils.toHex(count)
    };

    var transaction = new Tx(rawTransaction, { 'common': BSC_FORK });
    transaction.sign(privateKey);

    var result = await web3.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex'));
    console.log(result)
    return result;
}

You can also contribute to the repository if interested.

Simple Pools
  • 141
  • 1
  • 3
  • 1
    What is this abi code for var abiArray = JSON.parse(JSON.parse(fs.readFileSync('onlyone-abi.json','utf-8')));? – kasper Aug 11 '21 at 22:08
  • The ONLYONE token contract ABI is there: https://github.com/religion-counter/onlyone/blob/main/helper-scripts/onlyone-abi.json You can also check the token contract ABIs in the bscscan in Contract ABI section: https://bscscan.com/address/0xb899dB682e6D6164D885ff67C1e676141deaaA40#code You can export it from there. – Simple Pools Aug 13 '21 at 06:31
  • 2
    i have all the time this error: Error: Transaction has been reverted by the EVM: this is transaction i made with some token available in bscnan https://bscscan.com/tx/0x0e8132f929175eb14f4807d8197f4f64457b7f2243b95838697aa57b4aee1611 – kasper Aug 13 '21 at 14:06
  • 1
    Hi @kasper, I see in your transaction: Gas Used by Transaction: 294,919 (98.31%) Try increasing the gas limit to 460000 or something above and see if you will get the same error. – Simple Pools Aug 15 '21 at 19:34
  • 1
    There is a way to retrive automatically the path of the token? – Mat.C Sep 19 '21 at 21:31
  • 1
    @Mat.C You can check https://github.com/religion-counter/onlyone/issues/10 and https://github.com/Uniswap/v2-sdk/blob/20b63757676074c3d6b8f3a2c854b28c6045e357/src/entities/trade.ts#L214 in the Uniswap github there is a function that calculates the best path given input and output token. – Simple Pools Sep 21 '21 at 07:13
  • 1
    I think you can also use the graph API to see all pairs for a given token: https://docs.uniswap.org/protocol/V2/reference/API/queries#token-overview Pancakeswap should have similar API. Regards – Simple Pools Sep 21 '21 at 07:20
  • @kasper I [see](https://bscscan.com/tx/0x6e46220f660c2764a024c1cb7578a1487c97f607932a53b65bdeddc5039cb2d0) you got this working. Can you share what you did to get it to work? I am getting the same error: "Transaction has been reverted by the EVM" – Naruto Sempai Sep 07 '22 at 14:21
8

First of all you should login your eth account like below

const keystore = fs.readFileSync("your keystore path", "utf8");
var activeAccount = web3.eth.accounts.decrypt(keystore, password);

Now you can sign and broadcast your transaction. You must encode your swap message and add your tx's data field. Don't miss eth amount how many want to swap with token.

var swap = UniswapV2Router02Contract.methods.swapExactETHForTokens(amountOutMin, [WETH[activeChain].address, token.address], activeAccount.address, timeStamp)
var encodedABI = swap.encodeABI()

var tx = {
    from: activeAccount.address,
    to: UniswapV2RouterAddress,
    gas: 200000,
    data: encodedABI,
    value: ethAmount
  };

var signedTx = await activeAccount.signTransaction(tx)

web3.eth.sendSignedTransaction(signedTx.rawTransaction)
.on('transactionHash', function(hash){

})
.on('confirmation', function(confirmationNumber, receipt){

})
.on('receipt', function(receipt){

})
.on('error', function(error, receipt) { // If the transaction was rejected by the network with a receipt, the second parameter will be the receipt.
    console.error("Error:", error, "Receipt:", receipt)
});
Savas Adar
  • 4,083
  • 3
  • 46
  • 54