Web3 getPastEvents Returned error: limit exceeded - node.js

I am using web3 function getPastEvents and I am getting error:
Returned error: limit exceeded
I also changed RPC url but same error occured their.
Is there any other way to get event data ?
this is my code:
const http = require("http");
const cron = require('node-cron');
const { randomBytes } = require("crypto");
const web3 = new Web3("https://bsc-dataseed.binance.org/");
//console.log("Hello This",web3);
//console.log("hello");
const dexABI =contractAbi;
const contract_address = "0xd19EA9d72828444BC7bAE231fBa66F8050e72b1b";
const contract = new web3.eth.Contract(dexABI, contract_address);
async function generateEventQuery(result) {
console.log(result);
return ;
}
http
.createServer((req, res) => {
web3.eth
.getBlockNumber()
.then((d) => {
let current_block = d;
console.log(current_block);
contract
.getPastEvents({
fromBlock: Number(23390147),
toBlock: Number(23390147)+100,
})
.then( async(events) => {
let resu = await generateEventQuery(events);
})
.catch((e) => {
console.log("Err",e)
res.write("Err:" + JSON.stringify(e));
res.end();
});
})
.catch((e) => e);
})
.listen(8080);

in the function getPastEvents() you have to take the first parameter as your event name which you want to fetch the data. The name should be as same as in your contract and passed into a string.

Actually, this is an RPC problem. I replaced https://bsc-dataseed.binance.org/ with https://bscrpc.com. Now it works properly.

Public RPC URLs like https://bsc-dataseed.binance.org/ or https://bscrpc.com have rate-limiting to prevent people from over using it.
It's fine for testing but in production you should use your own node or a blockchain API like Infura, Alchemy, QuickNode or any other.

Related

Correctly fetch authentication tokens server-side in a node.js React app hosted on Cloud Run

While not a front-end developer, I'm trying to set up a web app to show up a demo for a product. That app is based on the Sigma.js demo app demo repository.
You'll notice that this app relies on a graph which is hosted locally, which is loaded as:
/src/views/Root.tsx :
useEffect(() => {
fetch(`${process.env.PUBLIC_URL}/dataset.json`)
.then((res) => res.json())
.then((dataset: Dataset) => {...
// do things ....
and I wish to replace this by a call to another service which I also host on Cloud Run.
My first guess was to use the gcloud-auth-library, but I could not make it work - especially since it does not seem to support Webpack > 5 (I might be wrong here), the point here this lib introduces many problems in the app, and I thought I'd be better off trying the other way GCP suggests to handle auth tokens: by calling the Metadata server.
So I replaced the code above with:
Root.tsx :
import { getData } from "../getGraphData";
useEffect(() => {
getData()
.then((res) => res.json())
.then((dataset: Dataset) => {
// do even more things!
getGraphData.js :
import { getToken } from "./tokens";
const graphProviderUrl = '<my graph provider service URL>';
export const getData = async () => {
try {
const token = await getToken();
console.log(
"getGraphData.js :: getData : received token",
token
);
const request = await fetch(
`${graphProviderUrl}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const data = await request.json();
console.log("getGraphData.js :: getData : received graph", data);
return data;
} catch (error) {
console.log("getGraphData.js :: getData : error getting graph data", error);
return error.message;
}
};
tokens.js :
const targetAudience = '<my graph provider service base URL>'; // base URL as audience
const metadataServerAddress = "169.254.169.254"; // use this to shortcut DNS call to metadata.google.internal
export const getToken = async () => {
if (tokenExpired()) {
const token = await getValidTokenFromServer();
sessionStorage.setItem("accessToken", token.accessToken);
sessionStorage.setItem("expirationDate", newExpirationDate());
return token.accessToken;
} else {
console.log("tokens.js 11 | token not expired");
return sessionStorage.getItem("accessToken");
}
};
const newExpirationDate = () => {
var expiration = new Date();
expiration.setHours(expiration.getHours() + 1);
return expiration;
};
const tokenExpired = () => {
const now = Date.now();
const expirationDate = sessionStorage.getItem("expirationDate");
const expDate = new Date(expirationDate);
if (now > expDate.getTime()) {
return true; // token expired
}
return false; // valid token
};
const getValidTokenFromServer = async () => {
// get new token from server
try {
const request = await fetch(`http://${metadataServerAddress}/computeMetadata/v1/instance/service-accounts/default/token?audience=${targetAudience}`, {
headers: {
'Metadata-Flavor': 'Google'
}
});
const token = await request.json();
return token;
} catch (error) {
throw new Error("Issue getting new token", error.message);
}
};
I know that this kind of call will need to be done server-side. What I don't know is how to have it happen on a React + Node app. I've tried my best to integrate good practices but most questions related to this topic (request credentials through a HTTP (not HTTPS!) API call) end with answers that just say "you need to do this server-side", without providing more insight into the implementation.
There is a question with similar formulation and setting here but the single answer, no upvote and comments is a bit underwhelming. If the actual answer to the question is "you cannot ever call the metadata server from a react app and need to set up a third-party service to do so (e.g. firebase)", I'd be keen on having it said explicitly!
Please assume I have only a very superficial understanding of node.js and React!

Asynchronous Issue with createCustomerProfile in Sample Node.JS code

Our goal is to integrate Authorize.NET into our application using the Node SDK sample code.
Node SDK: https://github.com/AuthorizeNet/sdk-node
Recommended Sample Code: https://github.com/AuthorizeNet/sample-code-node/tree/ef9e5c2d9e0379b5f47a0ebcb6847e711fe196ef
I am trying to create a customer payment profile and while I am able to create a customer profile successfully and receive a successful response from the API call 
CustomerProfilesModule.createCustomerProfile, the remainder of my auth.controller.js runs before I get the API result. All of the create-customer-profile.js runs up until the ctrl.execute() runs, then the console.log("xxx") in auth.controller.js runs before grabbing the API result. 
I understand this is a synchronous issue with my code, but I don't know how to solve this. I am using the sample code authorize.NET provided, however the code is using the real data from my app rather than the sample data. I am more than happy to provide further information upon request and really appreciate any help! 
// AUTH.CONTROLLER.JS
const httpStatus = require("http-status");
const ApiContracts = require("authorizenet").APIContracts;
const ApiControllers = require("authorizenet").APIControllers;
const SDKConstants = require("authorizenet").Constants;
const User = require("../models/user.model");
const RefreshToken = require("../models/refreshToken.model");
const moment = require("moment-timezone");
const { jwtExpirationInterval } = require("../../config/vars");
const sgMail = require("#sendgrid/mail");
const bcrypt = require("bcryptjs");
const CustomerProfilesModule = require("../utils/authorizeNet/CustomerProfiles");
sgMail.setApiKey(process.env.SENDGRID_API_KEY.replace(/\r?\n|\r/g, ""));
exports.register = async (req, res, next) => {
try {
const userData = req.body;
let customerProfileResult =
await CustomerProfilesModule.createCustomerProfile(userData);
console.log(
"❌ ❌ ❌ ❌ ❌ customerProfile Result ",
customerProfileResult
);
if (!userData || userData.error) {
return next(error);
} else {
const { isTrial } = userData;
const user = await new User(userData).save();
const token = generateTokenResponse(user, user.token());
res.status(httpStatus.CREATED);
return res.json({ token, user });
}
} catch (error) {
console.log(error.message);
return next(User.checkDuplicateEmail(error));
}
};
//////////
// CREATE-CUSTOMER-PROFILE.JS
var ApiContracts = require("authorizenet").APIContracts;
var ApiControllers = require("authorizenet").APIControllers;
var utils = require("../utils.js");
async function createCustomerProfile(user) {
console.log(" user parameter", user);
var merchantAuthenticationType =
new ApiContracts.MerchantAuthenticationType();
merchantAuthenticationType.setName(process.env.AUTHORIZE_NET_API_LOGIN_KEY);
merchantAuthenticationType.setTransactionKey(
process.env.AUTHORIZE_NET_TRANSACTION_KEY
);
var creditCard = new ApiContracts.CreditCardType();
creditCard.setCardNumber(user.cardNumber);
if (user.cardExpiry.length > 4) {
creditCard.setExpirationDate(
`${user.cardExpiry.slice(0, 1)}${user.cardExpiry.slice(3, 4)}`
);
} else {
creditCard.setExpirationDate(user.cardExpiry);
}
console.log("creditCard", creditCard);
var paymentType = new ApiContracts.PaymentType();
paymentType.setCreditCard(creditCard);
var customerAddress = new ApiContracts.CustomerAddressType();
customerAddress.setFirstName(user.firstName);
customerAddress.setLastName(user.lastName);
customerAddress.setAddress(user.mailingAddress);
customerAddress.setCity(user.mailingCity);
customerAddress.setState(user.mailingState);
customerAddress.setZip(user.mailingZip);
customerAddress.setCountry("USA");
customerAddress.setPhoneNumber(user.userPhone);
var customerPaymentProfileType =
new ApiContracts.CustomerPaymentProfileType();
customerPaymentProfileType.setCustomerType(
ApiContracts.CustomerTypeEnum.INDIVIDUAL
);
customerPaymentProfileType.setPayment(paymentType);
customerPaymentProfileType.setBillTo(customerAddress);
var paymentProfilesList = [];
paymentProfilesList.push(customerPaymentProfileType);
console.log(
"paymentProfilesList",
paymentProfilesList
);
var customerProfileType = new ApiContracts.CustomerProfileType();
customerProfileType.setMerchantCustomerId(
"M_" + utils.getRandomString("cust")
);
customerProfileType.setDescription(
`${user.firstName} ${user.lastName}'s Account'`
);
customerProfileType.setEmail(user.userEmail);
customerProfileType.setPaymentProfiles(paymentProfilesList);
var createRequest = new ApiContracts.CreateCustomerProfileRequest();
createRequest.setProfile(customerProfileType);
createRequest.setValidationMode(ApiContracts.ValidationModeEnum.TESTMODE);
createRequest.setMerchantAuthentication(merchantAuthenticationType);
var ctrl = new ApiControllers.CreateCustomerProfileController(
createRequest.getJSON()
);
// All above code is ran when CustomerProfilesModule.createCustomerProfile(userData) is executed in auth.controller.js
// However the following line (line 130 in auth.controller.js) is ran before the below ctrl.execute() code is completed
//
// console.log("❌ ❌ ❌ ❌ ❌ customerProfile Result ", customerProfileResult);
//
// All the above code is executed before that console.log("❌ ❌ ❌") statement above, however the below code doesn't run before that console.log
// I'd like the below code to execute before the remaining register route is finished, but just don't know what is going on!
ctrl.execute(async function () {
var apiResponse = await ctrl.getResponse();
console.log("apiResponse", apiResponse);
var response = new ApiContracts.CreateCustomerProfileResponse(apiResponse);
console.log("response", response);
//pretty print response
//console.log(JSON.stringify(response, null, 2));
if (response != null) {
if (
response.getMessages().getResultCode() ==
ApiContracts.MessageTypeEnum.OK
) {
console.log(
"Successfully created a customer profile with id: " +
response.getCustomerProfileId()
);
} else {
console.log("Result Code: " + response.getMessages().getResultCode());
console.log(
"Error Code: " + response.getMessages().getMessage()[0].getCode()
);
console.log(
"Error message: " + response.getMessages().getMessage()[0].getText()
);
return {
error:
"Error message: " +
response.getMessages().getMessage()[0].getText(),
};
}
} else {
console.log("Null response received");
return { error: "Null response received" };
}
});
}
module.exports.createCustomerProfile = createCustomerProfile;
ctrl.execute is a method handling an IIFE function which is not called.
IIFE functions are invoked as soon as is defined.
You will not be able to run IIFE before declaration.
Possible solution:
Try to create a callback route inside register route and then exclude the IIFE to get the response from the callback inside register before actual route finished.
I don't fully understand your code enough to know how you want it to work. But from my understanding the console.log is running between when you get a call from the api and after you get the api, putting it in an awkward phase.
How asynchronous code works is that JavaScript will let the asynchronous function run, leave, do something else in the meantime, and get back to it when it is done.
The issue I see with your code is that createCustomerProfile doesn't return anything when it's done. You have a function that returns a promise of void. First off, that's a problem because you're using the return value of the function in console.log().
I highly recommend to promisify so that it properly resolves or has an error, which when you're working with API's you're likely to encounter potential errors in which you want to handle that.
You say the console.log() is being called before ctrl.execute() but I don't even see where it is being executed at all because I don't see it in the createCustomerProfile function.

Pass query from Link to server, first time load query value undefined, after reload get correct query

I try to create some API to external adobe stock.
Like in the title, first time i get query from Link router of undefined, but after reload page it work correctly. My
main page
<Link
href={{
pathname: "/kategoria-zdjec",
query: images.zdjecia_kategoria
}}
as={`/kategoria-zdjec?temat=${images.zdjecia_kategoria}`}
className={classes.button}>
</Link>
and my server
app
.prepare()
.then(() => {
server.get("/kategoria-zdjec", async (req, res) => {
const temat = await req.query.temat;
console.log(temat)
const url = `https://stock.adobe.io/Rest/Media/1/Search/Files?locale=pl_PL&search_parameters[words]=${temat}&search_parameters[limit]=24&search_parameters[offset]=1`;
try {
const fetchData = await fetch(url, {
headers: { ... }
});
const objectAdobeStock = await fetchData.json();
res.json(objectAdobeStock);
const totalObj = await objectAdobeStock.nb_results;
const adobeImages = await objectAdobeStock.files;
} catch (error) {
console.log(error);
}
});
and that looks like getInitialProps on page next page
Zdjecia.getInitialProps = async ({req}) => {
const res = await fetch("/kategoria-zdjec");
const json = await res.json();
return { total: json.nb_results, images: json.files };
}
I think it is problem due asynchronous.
I think this might be due to the fact that you are using fetch which is actually part of the Web API and this action fails when executed on server.
You could either use isomorphic-fetch which keeps fetch API consistent between client and server, or use node-fetch when fetch is called on the server:
Zdjecia.getInitialProps = async ({ req, isServer }) => {
const fetch = isServer ? require('node-fetch') : window.fetch;
const res = await fetch("/kategoria-zdjec");
const json = await res.json();
return { total: json.nb_results, images: json.files };
}
This problem is solved, the issue was in another part of my app, directly in state management, just created new variables, and pass to link state value.

nodejs async/await nested API progress

I have an API that searches for the user-provided term, returns an array of results, then fires off async requests for each of the results and gets results for each of these second batch of requests. I'd like the API to report progress as it happens rather than just the final result. So, if I do the following request, I should get updates like so
$ curl 'http://server/?q=foobar'
searching for ${q}…
found 76… now getting images…
found 30 images… done
{
result
}
Most of relevant code is shown below. Fwiw, I am using hapijs for my application.
let imagesOfRecords = {};
const getImages = async function (q) {
console.log(`searching for ${q}…`);
const uri = `http://remoteserver/?q=${q}`;
const {res, payload} = await Wreck.get(uri);
const result = JSON.parse(payload.toString()).hits;
const numOfFoundRecords = result.total;
if (result.total) {
console.log(`found ${result.total}… now getting images…`);
const foundRecords = result.hits.map(getBuckets);
Promise.all(foundRecords).then(function() {
console.log(`found ${Object.keys(imagesOfRecords).length} images… done`);
reply(imagesOfRecords).headers = res.headers;
}).catch(error => {
console.log(error)
});
}
else {
console.log('nothing found');
reply(0).headers = res.headers;
}
};
const getBuckets = async function(record) {
const { res, payload } = await Wreck.get(record.links.self);
const bucket = JSON.parse(payload.toString()).links.bucket;
await getImageFiles(bucket, record.links.self);
};
const getImageFiles = async function(uri, record) {
const { res, payload } = await Wreck.get(uri);
const contents = JSON.parse(payload.toString()).contents;
imagesOfRecords[record] = contents.map(function(el) {
return el.links.self;
});
};
Once I can implement this, my next task would be to implement this progressive update in a web app that uses the above API.
To show result with each step of your requests for backend you can use EventEmitter, which will emit event on each progress step. You can read about events here.
Simple implementation:
const events = require('events');
const eventEmitter = new events.EventEmitter();
//your request code
Promise.all(foundRecords).then(function() {
console.log(`found ${Object.keys(imagesOfRecords).length} images… done`);
eventEmitter.emit('progress');
reply(imagesOfRecords).headers = res.headers;
})
const eventReaction = (e) => {
// do something with event, console log for example.
}
eventEmitter.on('progress', eventReaction);
More examples you can find here and here.
To show events to client you can use library socket.io. I think you can find pretty straightforward explanations how socket.io works in documentation.
If you want to send events between servers or processes and want to go little further, you can read more about 0MQ (zero mq) and it's node implementation

Execute a middleware one-time only at server startup in Koa v2

I created this middleware which executing only once when any route in the website gets the first hit from a visitor:
// pg-promise
const db = require('./db/pgp').db;
const pgp = require('./db/pgp').pgp;
app.use(async (ctx, next) => {
try {
ctx.db = db;
ctx.pgp = pgp;
} catch (err) {
debugErr(`PGP ERROR: ${err.message}` || err);
}
await next();
});
// One-Time middleware
// https://github.com/expressjs/express/issues/2457
const oneTime = (fn) => {
try {
let done = false;
const res = (ctx, next) => {
if (done === false) {
fn(ctx, next);
done = true;
}
next();
};
return res;
} catch (err) {
debugErr(`oneTime ERROR: ${err.message}` || err);
}
};
const oneTimeQuery = async (ctx) => {
const result = await ctx.db.proc('version', [], a => a.version);
debugLog(result);
};
app.use(oneTime(oneTimeQuery));
This code executing on the first-time only when a user visiting the website, resulting:
app:log Listening on port 3000 +13ms
app:req GET / 200 - 24ms +2s
23:07:15 connect(postgres#postgres)
23:07:15 SELECT * FROM version()
23:07:15 disconnect(postgres#postgres)
app:log PostgreSQL 9.6.2, compiled by Visual C++ build 1800, 64-bit +125ms
My problem is that I want to execute it at the server start, when there's no any visit on the site.
The future purpose of this code will be to check the existence of tables in the database.
Solution:
Placing this in ./bin/www before the const server = http.createServer(app.callback()); declaration helped:
const query = async () => {
const db = require('../db/pgp').db;
const pgp = require('../db/pgp').pgp;
const result = await db.proc('version', [], a => a.version);
debugLog(`www: ${result}`);
pgp.end(); // for immediate app exit, closing the connection pool (synchronous)
};
query();
You could start your application using a js script that requires your app and uses node's native http module to fire up the server. Exactly like in koa-generator (click).
This is in your app.js file:
const app = require('koa')();
...
module.exports = app;
And then this is in your script to fire up the server:
const app = require('./app');
const http = require('http');
[this is the place where you should run your code before server starts]
const server = http.createServer(app.callback());
server.listen(port);
Afterwards you start your application with:
node [script_name].js
Of course keep in mind the async nature of node when doing it this way. What I mean by that - run the 'listen' method on 'server' variable in callback/promise.

Resources