Frontend development

In order to search logs, for every wallet connection in the Dapp, two Web3 instances must be created, one specific for logs and the other one for Blockchain interaction. This will help a lot specific customizations for fast development, prototyping and testing.

window.web3 = await window.createWeb3(window.context.blockchainConnectionString || window.ethereum);
window.networkId = await window.web3.eth.net.getId();
window.web3ForLogs = await window.createWeb3(window.getNetworkElement("blockchainConnectionForLogString") || window.web3.currentProvider);
window.createWeb3 = async function createWeb3(connectionProvider) {
var web3 = new window.Web3Browser(connectionProvider);
web3.currentProvider.setMaxListeners && window.web3.currentProvider.setMaxListeners(0);
web3.eth.transactionBlockTimeout = 999999999;
web3.eth.transactionPollingTimeout = new Date().getTime();
web3.startBlock = parseInt((typeof connectionProvider).toLowerCase() !== 'string' && window.ethereum && window.ethereum.isMetaMask ? await window.timeoutCall(async call => call(await web3.eth.getBlockNumber())) : await web3.eth.getBlockNumber()) - 100;
return web3;
};
In this specific case, if the blockchainConnectionForLogString configuration parameter is set, the two Web3 instances will have different connection providers:
E.g. the normal web3 instance can be linked to Ganache or local node, while the web3ForLogs one will be linked to a Infura node for fast log searches.
In any case, the log search must be done by specific method:
window.getLogs = async function(a, endOnFirstResult) {
var args = JSON.parse(JSON.stringify(a));
var logs = [];
args.fromBlock = args.fromBlock || (window.getNetworkElement('deploySearchStart') + '');
args.toBlock = args.toBlock || (await window.web3.eth.getBlockNumber() + '');
var to = parseInt(args.toBlock);
var fillWithWeb3Logs = async function(logs, args) {
if (window.web3.currentProvider === window.web3ForLogs.currentProvider) {
return logs;
}
var newArgs = {};
Object.entries(args).forEach(entry => newArgs[entry[0]] = entry[1]);
newArgs.fromBlock = window.web3.startBlock;
newArgs.toBlock = 'latest';
logs.push(...(await window.web3.eth.getPastLogs(newArgs)));
return logs;
};
while (isNaN(to) || parseInt(args.fromBlock) <= to) {
var newTo = parseInt(args.fromBlock) + window.context.blockSearchSection;
newTo = newTo <= to ? newTo : to;
args.toBlock = isNaN(newTo) ? args.toBlock : (newTo + '');
logs.push(...(await window.web3ForLogs.eth.getPastLogs(args)));
if (isNaN(to) || logs.length > 0 && endOnFirstResult === true) {
return await fillWithWeb3Logs(logs, args);
}
args.fromBlock = (parseInt(args.toBlock) + 1) + '';
}
return await fillWithWeb3Logs(logs, args);
};

The window.getLogs method is a simple wrapper of the method web3.eth.getPastLogs, but it does two important things:

  1. Makes searches using block tranches for performances reasons (e.g. Infura can give back only a pre-defined amount of results);

  2. Uses the web3ForLogs instance and then, if necessary (e.g. different Provider), uses the normal one to completely fill the search results.