This, with the additional problem of requests not being deduplicated for getNodeInfo and getChainInfo, causes a large number of unnecessary requests being made. The initial load of our dapp does 49 requests to the testnet node. We verified that there are not duplicate requests being fired from our own hooks, because of re-renders, etc.
@martines3000 Thanks for adding me to the project! I have a few initial observations:
.get() Method
The .get() method should perform a dryRun. This simulates the contract call, allowing us to retrieve the expected response without incurring the cost of a real transaction.
getNodeInfo and getChainInfo
The getNodeInfo and getChainInfo methods of the Provider class are called each time a new Provider instance is created with await Provider.create(url).
So this means that each await Provider.create(url) will trigger these 2 calls.
However, the results are cached within the instance, so there’s no need to fetch this data again for subsequent calls. You can retrieve the cached data using provider.getChain() and provider.getNode().
@martines3000 After accessing your application, I noticed that, on the main page (Dashboard), GraphQL requests are being triggered repeatedly every few seconds, even without any user interaction or a connected wallet.
Specifically, the dryRun (which also triggers estimateGasPrice as a side effect) and balance queries are being sent continuously.
Is there a particular reason why these requests are being made even when there is no activity on the UI?
We had all queries set to refetch on a 10s interval. I changed this couple of hours ago and optimized it to only do this when refetchOnWindowFocus happens and couple of other scenarios.
Is it expected that the .get() requests execute estimateGasPrice and dryRun ?
Here is a partial example of the network tab when I initially load the dapp and connect the wallet. As you can see, each of these methods is calling a read function, but 2 requests are made for each one (ignore the useTotalCollateral, as we do 3 calls here and will be changed to 1 the next time we redeploy the contract).
Is it expected that the .get() requests execute estimateGasPrice and dryRun ?
Yes, this is expected. The .get() method internally performs a dryRun, which allows us to retrieve the contract call response without executing a real transaction and incurring costs. The estimateGasPrice step is necessary because, even during a dryRun, the gas and fees must be accurately estimated to ensure proper validation of the call.
You can use the multiCall feature to execute multiple contract .get() calls within a single dryRun operation:
// the chain call can be originated for any of the used contracts
const { value: results } = await contract1
.multiCall([
contract1.functions.foo(1336),
contract2.functions.bar(1337),
contract3.functions.baz(1338),
contract1.functions.foo_2(1336),
]).get();
The value property will be an array containing the returned values in the same order as the calls were made.
For example, the result of the first contract function (contract1.functions.foo(1336)) will be at index 0, the second function (contract2.functions.bar(1337)) at index 1, and so on.
We also have these requests:
Are those requests getNodeInfo and getChainInfo? Are they happening for every connector instantiation?
Using multiCall would require a large refactor and it is also very inconvenient, as we currently have 1 hook for 1 contract call. I appreciate the idea .
No, the getNodeInfo and getChainInfo only happen for WalletConnect and Solana connectors. WalletConnect one happens multiple times, as seen in the screenshot.
I will also mark you last answer as the solution as it answers my question