如何使用Web3 JS在Uniswap上交换令牌

15

我正在尝试使用Uniswap合约方法,仅仅用来交换来自Metamask钱包的ETH获得代币。Uniswap合约方法如下:

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

我天真地认为它应该像这样,但我确定我错过了几个关键部分(比如签署交易,使用适当的回调方法),并且我找不到一个完整的综合性例子。一个完整的工作示例应该是什么样子的?

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")

Uniswap有一个JavaScript SDK。如果你是新手开发者,我建议使用他们的SDK,而不是自己去尝试弄清楚它。 - Mikko Ohtamaa
3
据我所知,Uniswap SDK 不执行交易。 - User
1
@lxx 你可能是对的。谢谢你纠正我。 - Mikko Ohtamaa
2个回答

9
您可以查看这个可行的例子,用于在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;
}

如果您有兴趣,还可以向该代码库做出贡献。


1
这个变量abiArray的abi代码是什么意思:var abiArray = JSON.parse(JSON.parse(fs.readFileSync('onlyone-abi.json','utf-8')));? - kasper
2
我一直遇到这个错误: 错误:交易已被EVM撤销:这是我使用BSC网络上某些代币进行的交易 https://bscscan.com/tx/0x0e8132f929175eb14f4807d8197f4f64457b7f2243b95838697aa57b4aee1611 - kasper
1
有没有一种自动检索令牌路径的方法? - Mat.C
1
@Mat.C 你可以查看Uniswap的Github上的https://github.com/religion-counter/onlyone/issues/10和https://github.com/Uniswap/v2-sdk/blob/20b63757676074c3d6b8f3a2c854b28c6045e357/src/entities/trade.ts#L214,其中有一个函数可以计算给定输入和输出代币的最佳路径。 - Simple Pools
1
我认为您也可以使用图形API来查看给定代币的所有交易对:https://docs.uniswap.org/protocol/V2/reference/API/queries#token-overview Pancakeswap应该有类似的API。此致敬礼 - Simple Pools
显示剩余3条评论

8
首先,您应该登录您的eth账户,如下所示。
const keystore = fs.readFileSync("your keystore path", "utf8");
var activeAccount = web3.eth.accounts.decrypt(keystore, password);

现在您可以签署和广播交易。您必须对交换消息进行编码并添加tx数据字段。不要忘记指定以太币数量和想要与代币交换的数量。
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)
});

4
你能在哪里找到UniswapV2Router02Contract合约?你能发一个完整的例子吗? - arisalexis
你知道如何找到UniswapV2Router02Contract @arisalexis吗? - Valentin Garreau
在这里:https://etherscan.io/address/0x7a250d5630b4cf539739df2c5dacb4c659f2488d - Savas Adar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接