events.Swap is not triggered in web3 for a Uniswap Pool - javascript

Visual Studio Code 1.66.2
ganache v7.1.0 (#ganache/cli: 0.2.0, #ganache
I am new to Solidity and this is my first example I am trying out.
I am trying to get noticed when there is a swap event in the Uniswap Pool "ETH-APE" using:
uPair.events.Swap
The code seems to start where: Waiting for swaps...
I can see on Uniswap itself that there is regular swaps but the swap event seems to not trigger where the console.log should show: someone swapped now!
I have started this blockchain successfully with the command like this:
Notice: I have a real apikey from alchemy and a real mnemonic from ganache-cli
ganache-cli -f wss://eth-mainnet.alchemyapi.io/v2/myAPIkey --mnemonic "word1 word2 word3 etc" -p 7545
I have just followed some examples and are not sure exactly what I am doing:
As I am a beginner I must also ask about ganache. As I have understand this is a "Fake and local Sandboxed" blockchain just existing on my computer?
I think I understand that I start ganache-cli on my computer but are not sure if the uPair.events.Swap listen to my local blockchain which is not the REAL blockchain and this is because the swap event is not triggered. If that is the case then that is what I wonder what I am missing?
(I am not even sure I need ganache to listen to this swap event?)
I am not sure what the alchemyapi.io with myAPIkey is doing in the command to start the local ganache-cli where in the same command I use the mnemonic which has been generated from ganache?
// -- HANDLE INITIAL SETUP -- //
require("dotenv").config();
const Web3 = require('web3')
const IERC20 = require('#openzeppelin/contracts/build/contracts/ERC20.json')
const IUniswapV2Pair = require("#uniswap/v2-core/build/IUniswapV2Pair.json")
const IUniswapV2Factory = require("#uniswap/v2-core/build/IUniswapV2Factory.json")
const { ChainId, Token } = require("#uniswap/sdk")
let web3 = new Web3('ws://127.0.0.1:7545')
const main = async () => {
const _eth_address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const _apecoin_address = "0x4d224452801aced8b2f0aebe155379bb5d594381";
const _uniswap_factory_address = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f";
const uFactory = new web3.eth.Contract(IUniswapV2Factory.abi, _uniswap_factory_address) // UNISWAP FACTORY CONTRACT
const { token0Contract, token1Contract, token0, token1 } = await getTokenAndContract(_eth_address, _apecoin_address)
let uPair = await getPairContract(uFactory, token0.address, token1.address)
console.log("Waiting for swaps...");
uPair.events.Swap({}, async () => {
console.log("someone swapped now!");
})
}
async function getPairAddress(_V2Factory, _token0, _token1) {
const pairAddress = await _V2Factory.methods.getPair(_token0, _token1).call()
return pairAddress
}
async function getPairContract(_V2Factory, _token0, _token1) {
const pairAddress = await getPairAddress(_V2Factory, _token0, _token1)
const pairContract = new web3.eth.Contract(IUniswapV2Pair.abi, pairAddress)
return pairContract
}
async function getTokenAndContract(_token0Address, _token1Address) {
const token0Contract = new web3.eth.Contract(IERC20.abi, _token0Address)
const token1Contract = new web3.eth.Contract(IERC20.abi, _token1Address)
const token0 = new Token(
ChainId.MAINNET,
_token0Address,
18,
await token0Contract.methods.symbol().call(),
await token0Contract.methods.name().call()
)
const token1 = new Token(
ChainId.MAINNET,
_token1Address,
18,
await token1Contract.methods.symbol().call(),
await token1Contract.methods.name().call()
)
return { token0Contract, token1Contract, token0, token1 }
}
main()

Related

I'm trying to listen to addliquidity event from uniswap router02

I'm trying to listen to addliquidity events to scrape newly added pairs data
const Web3 = require('web3');
const NODE_URL = "https://mainnet.infura.io/v3/d3c5832256754c85be86b4c97de2d3d3"
const web3 = new Web3(NODE_URL);
const CONTRACT_ADDRESS = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D";
const CONTRACT_ABI = require('./abi.json');
const contract = new web3.eth.Contract(CONTRACT_ABI, CONTRACT_ADDRESS);
async function getEvents() {
let latest_block = await web3.eth.getBlockNumber();
let historical_block = latest_block - 10000; //change the value to 'latest' if you have a upgraded rpc
console.log("latest: ", latest_block, "historical block: ", historical_block);
const events = await contract.events.addLiquidity(
{ fromBlock: historical_block, toBlock: 'latest' }
);
await addLiquidity(events);
};
async function getaddLiquidityDetails(data_events) {
for (i = 0; i < data_events.length; i++) {
let address_tokenA = data_events[i]['returnValues']['address tokenA'];
let address_tokenB = data_events[i]['returnValues']['address tokenB'];
console.log("address tokenA:",address_tokenA,"address tokenB:",address_tokenB);
}
};
getEvents(CONTRACT_ABI, CONTRACT_ADDRESS);
i got this error: contract.events.addLiquidity is not a function
I copied this code and havent fully edit it yet but i didnt expect this error event at this level
source:https://ferhatkochan.medium.com/how-to-listen-to-smart-contract-events-with-web3js-345608f916c4
I double checked the abi and I found that the event addLiquidity exists, and i doubled check that the address is the right one using etherscan and indeed it is. and I checked the documentation of web3.js and it seems that there's nothing wrong with the syntax.

.sendSignedTransaction() Not sending Tx

Bit of context; this was working fine on Goerli just a few days a go but the script now works intermittently. At the moment im thinking its down to one of the following:
Node issue - currently using infura and have tried changing it across other public RPCS but didn't work any better
Web3 issue - not sure if something is now outdated
Nonce issue with wallets, not sure if there is something obvious in the code here that is causing my Txs to get stuck and as such never return a receipt
For some reason this was all working fine last night after having not worked all day. Bit stuck as to what i could be doing wrong tbh. The logic is that based on a mempool tx, the sendTx function is invoked with the 'targetAddress' param which contains all the necessary objects to replicate the tx which i am tracking.
Tx.js:
const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
process.removeAllListeners('warning');
require('dotenv').config();
const INFURA_URL_TESTNET = process.env.INFURA_URL_TESTNET;
const web3 = new Web3(INFURA_URL_TESTNET);
const BN = web3.utils.BN;
// Tx details:
const sendTx = async (targetAddress) => {
const address = targetAddress.address;
const ethAmmount = targetAddress.value;
const data = targetAddress.input;
const gasLimit = targetAddress.gas;
//const gasPrice = targetAddress.gasPrice - web3.utils.toWei('1', 'gwei');
const maxFeePerGas = targetAddress.maxFeePerGas //- 1000000;
const maxPriorityFeePerGas = targetAddress.maxPriorityFeePerGas //- 1000000;
const privKey = targetAddress.privKey;
const from = targetAddress.from;
const _txCount = await web3.eth.getTransactionCount(from);
const createTransaction = await web3.eth.accounts.signTransaction(
{ to: address,
from: from,
data: data,
gas: gasLimit,
value: ethAmmount,
nonce: _txCount,
maxFeePerGas: maxFeePerGas,
maxPriorityFeePerGas: maxPriorityFeePerGas,
},
privKey,
);
// Send Tx and Wait for Receipt
const createReceipt = await web3.eth.sendSignedTransaction(createTransaction.rawTransaction);
//const transaction = await web3.eth.getTransaction(createReceipt.transactionHash);
console.log(`Tx successful with hash: ${createReceipt.transactionHash}`);
};
module.exports = {sendTx};
The code stops at the await .sendSignedTx and doesn't return a receipt. As i said, this does work exactly as expected sometimes and i can figure out why sometimes it works and sometimes it doesn't?
Thanks everyone!
Since you are using web3js, you have to handle the event promise chain when calling sendSignedTransaction and log all the payloads. That will tell you the reason for it not being broadcast. Could be a network error, gas issue, maybe nonce .e.t.c.
See https://web3js.readthedocs.io/en/v1.2.11/callbacks-promises-events.html#callbacks-promises-events

.balanceOf is not a function - Interact with existing Contract on Blockchain

I want to automate my staking on The Sandbox. For that I need in the first step to interact with the mSand-Matic Pool Contract. It is this one: https://polygonscan.com/address/0x4ab071c42c28c4858c4bac171f06b13586b20f30#code
I have written a little program in a GitHub repository to show what I have done: https://github.com/ChristianErdtmann/mSandMaticStakingAutomation
Or here is the code example from the contract-interact.js
Web3 = require('web3')
const fs = require('fs');
const web3 = new Web3("https://polygon-rpc.com")
const contractAddress = "0x4AB071C42C28c4858C4BAc171F06b13586b20F30"
const contractJson = fs.readFileSync('./abi.json')
const abi = JSON.parse(contractJson)
const mSandMaticContract = new web3.eth.Contract(abi, contractAddress)
mSandMaticContract.balanceOf('0x7e5475290Df8E66234A541483453B5503551C780')
The ABI I have taken from the contract link on the top. But it seems there is a problem.
I tried for testing to read something from the contract. For that I used the function balanceOf(address), how you can see in the code.
But I always get this error:
TypeError: mSandMaticContract.balanceOf is not a function
I found the solution
web3 needs .methots to get acces to the balanceOf() function
if we want only to read so we need to add .call()
we need to add await before the function is called this needs to be in a asynchonus function
So the final working code is:
Web3 = require('web3')
const fs = require('fs');
const web3 = new Web3("https://polygon-rpc.com")
const contractAddress = "0x4AB071C42C28c4858C4BAc171F06b13586b20F30"
const contractJson = fs.readFileSync('./abi.json')
const abi = JSON.parse(contractJson)
const mSandMaticContract = new web3.eth.Contract(abi, contractAddress)
asyncCall()
async function asyncCall() {
console.log(await mSandMaticContract.methods.balanceOf('0x7e5475290Df8E66234A541483453B5503551C780').call())
}
If you dont want only to read you need addtional to sign the transaction with:
The solution is, to sign the transaction before sending we can doing this with any method by this code:
encoded = mSandMaticContract.methods.getReward().encodeABI()
var block = await web3.eth.getBlock("latest");
var gasLimit = Math.round(block.gasLimit / block.transactions.length);
var tx = {
gas: gasLimit,
to: publicKey,
data: encoded
}
web3.eth.accounts.signTransaction(tx, privateKey).then(signed => {
web3.eth.sendSignedTransaction(signed.rawTransaction).on('receipt', console.log)
})

I am trying to execute a swap on Pancakeswap using web3, but I get an error when calculating transaction cost

I am new at ethereum development and I am working on a simple script to execute swaps using Pancakeswap. Everything seems to be working well up to the point where I am building my transaction and calculate the tx-cost. I am using the UniswapRouterV02 abi create my Pancakeswap contract. The code:
const init = async () => {
const [WBNB, BUSD] = await Promise.all(
[addresses.WBNB, addresses.BUSD].map(tokenAddress => (
new Token(
ChainId.MAINNET,
tokenAddress,
18
)
)));
const pair = await Fetcher.fetchPairData(WBNB, BUSD, provider)
const route = await new Route([pair], WBNB)
const trade = await new Trade(route, new TokenAmount(WBNB, tradeAmount), TradeType.EXACT_INPUT)
const executionPrice = trade.executionPrice.toSignificant(12)
// Correct prices; everything seems correct up until here
const slippageTolerance = new Percent('50', '10000')
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw
const path = [WBNB.address, BUSD.address]
const to = MY_ADDRESS
const deadline = Math.floor(Date.now() / 1000) + 60 * 20
const value = trade.inputAmount.raw
// Correct prices everything seems correct up until here
const pancakeSwap = new web3.eth.Contract(
abis.uniswapRouter.abi,
addresses.PANCAKE_ROUTER //'0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F'
);
let tx = pancakeSwap.methods.swapExactTokensForTokens(
tradeAmount,
web3.utils.toBN(amountOutMin.toString()),
path,
to,
deadline
)
const [gasPrice, gasCost] = await Promise.all([
web3.eth.getGasPrice(),
tx.estimateGas({from: admin}),
]);
console.log(`gasPrice: ${gasPrice}`)
console.log(`gasCost: ${gasCost}`)
}
init()
The price calculation for the swap returns correct prices. However when I try to calculate the transaction costs the following error is thrown:
Error: Returned error: gas required exceeds allowance (44038122) or always failing transaction
Any help would be greatly appreciated, please let me know if more of my code should be clarified!
In turns out that with web3 it is not possible to interact with the Pancakeswap contract. I found a solution using ethers.js. Following code worked for me to execute a swap on Pancake on mainnet.
Before executing the first transaction Pancakeswap needs to be allowed, this code is commented out.
I had to play around with the gasprice and gasLimit a bit to make it work.
require("dotenv").config()
const ethers = require('ethers')
const {ChainId, Token, TokenAmount, Fetcher, Pair, Route, Trade, TradeType, Percent} =
require('#pancakeswap-libs/sdk');
const Web3 = require('web3');
const web3 = new Web3('wss://apis.ankr.com/wss/c40792ffe3514537be9fb4109b32d257/946dd909d324e5a6caa2b72ba75c5799/binance/full/main');
const {JsonRpcProvider} = require("#ethersproject/providers");
const provider = new JsonRpcProvider('https://bsc-dataseed1.binance.org/');
const { address: admin } = web3.eth.accounts.wallet.add(process.env.PRIVATE_KEY)
const addresses = {
WBNB: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c',
BUSD: '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56',
PANCAKE_ROUTER: '0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F'
}
const ONE_ETH_IN_WEI = web3.utils.toBN(web3.utils.toWei('1'))
const tradeAmount = ONE_ETH_IN_WEI.div(web3.utils.toBN('1000'))
const init = async () => {
const [WBNB, BUSD] = await Promise.all(
[addresses.WBNB, addresses.BUSD].map(tokenAddress => (
new Token(
ChainId.MAINNET,
tokenAddress,
18
)
)));
const pair = await Fetcher.fetchPairData(WBNB, BUSD, provider)
const route = await new Route([pair], WBNB)
const trade = await new Trade(route, new TokenAmount(WBNB, tradeAmount), TradeType.EXACT_INPUT)
const slippageTolerance = new Percent('50', '10000')
// create transaction parameters
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw
const path = [WBNB.address, BUSD.address]
const to = admin
const deadline = Math.floor(Date.now() / 1000) + 60 * 20
// Create signer
const wallet = new ethers.Wallet(
Buffer.from(
process.env.PRIVATE_KEY, // paste your private key from metamask here
"hex"
)
)
const signer = wallet.connect(provider)
// Create Pancakeswap ethers Contract
const pancakeswap = new ethers.Contract(
addresses.PANCAKE_ROUTER,
['function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'],
signer
)
// Allow Pancakeswap
// let abi = ["function approve(address _spender, uint256 _value) public returns (bool success)"]
// let contract = new ethers.Contract(WBNB.address, abi, signer)
// await contract.approve(addresses.PANCAKE_ROUTER, ethers.utils.parseUnits('1000.0', 18), {gasLimit: 100000, gasPrice: 5e9})
// Execute transaction
const tx = await pancakeswap.swapExactTokensForTokens(
ethers.utils.parseUnits('0.001', 18),
ethers.utils.parseUnits(web3.utils.fromWei(amountOutMin.toString()), 18),
path,
to,
deadline,
{ gasLimit: ethers.utils.hexlify(200000), gasPrice: ethers.utils.parseUnits("10", "gwei") }
)
console.log(`Tx-hash: ${tx.hash}`)
const receipt = await tx.wait();
console.log(`Tx was mined in block: ${receipt.blockNumber}`)
}
init()
You can check this working example that buys a token from 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 you are interested.
I am a total beginner but have the same goal as you. I'm trying to get your code to work.
I used the following Code to create the signer. I used my 'mnemonic' instead of the private key:
const wallet = ethers.Wallet.fromMnemonic(mnemonic);
I noticed that pancake uses the swapExactETHForTokens() function instead of swapExactTokensForTokens() for the transactions. Does that make any difference?
I am not quite sure whether the Output and Input Amount is calculated correctly... I don't quite understand it yet, but will try to go through it as soon as possible.
jklepatch has written a code which contains trading via pancakeswap V2. However, the trade does not work if i execute the code because the AmountOut generats an error (codeline 78)...
In the meantime, have you been able to modify your code or make it work? If it is helpful I can also post my version of your code here.

How to wait for the promise when using get in Firestore

I am just trying a simple get command with Firestore, using this code from Google it doesn't work because it's not waiting for the promise?
Earlier I had put only a snippet of code, this is the entirety of index.js -- I'm using Firestore with Dialogflow to build a Google Assistant app and trying to call a function from the welcome intent that gets a field from Firestore, then writes that field to a string (named question1), and then this string should be spoken by the assistant as part of the ssml response. I've been on this for at least 30 hours already, can't seem to comprehend promises in regards to intents, firestore, etc. I've tried about 10 different solutions, this one works, only it says "undefined" in other variations I have tried it would say undefined several times but after 2-3 passes the get command would be complete and then the variable would be read out. I'm just trying to figure out how to get the get command and variable set before moving onto the SSML response. Can anyone point me in the right direction?
'use strict';
const functions = require('firebase-functions'); //don't forget this one
// Import Admin SDK
var admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();
const collectionRef = db.collection('text');
const Firestore = require('#google-cloud/firestore');
var doc;
var question1;
const url = require('url');
const {
dialogflow,
Image,
Permission,
NewSurface,
} = require('actions-on-google');
const {ssml} = require('./util');
const config = functions.config();
const WELCOME_INTENT = 'Default Welcome Intent';
const app = dialogflow({debug: true});
async function dbaccess(rando) {
console.log("dbaseaccess started")
var currentquestion2 = 'question-' + rando.toString();
var cityRef
try { return cityRef = db.collection('text').doc(currentquestion2).get();
console.log("get command completed")
//do stuff
question1 = cityRef.data().n111
} catch(e) {
//error!
}
console.log("one line above return something");
return rando;
}
app.fallback((conv) => {
// intent contains the name of the intent
// you defined in the Intents area of Dialogflow
const intent = conv.intent;
switch (intent) {
case WELCOME_INTENT:
var rando = Math.floor(Math.random() * 3) + 1;
dbaccess(rando);
const ssml =
'<speak>' +
question1 +
'</speak>';
conv.ask(ssml);
break;
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
You have 2 options: you can use async/await or you can use Promise.then() depending on how you want the code to execute.
Async/await:
async function databasetest {
var cityRef;
try{
cityRef = await db.collection('cities').doc('SF');
// do stuff
} catch(e) {
// error!
}
Promise.then():
db.collection('cities').doc('SF').then((cityRef) => {
cityRef.get()
.then(doc => { /* do stuff */ })
.catch(err => { /* error! */ });
});
maybe a little of work around could help you, I'm not sure yet how you are trying to implement it.
function databasetest () {
var cityRef = db.collection('cities').doc('SF');
return cityRef.get()
}
// so you can implement it like
databasetest().then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc.data());
}
})
.catch(err => {
console.log('Error getting document', err);
});
More context would help to understand your use case better :)

Categories