tl;dr= (1) init a web3.eth.Contract
instance for the RDOC deployed address;
then (2) call .getPastEvents('Transfer')
,
then (3) aggregate the sum of Transfer.value
values.
Detailed answer:
(1) Init the contract instance
There is a RPC data provider,
GetBlock
which you may think of as similar to an Infura that
supports RSK.
For querying large amounts of data, such as historical data,
Websockets can be faster/ more efficient than HTTP,
so let's use their Websockets RPC endpoint for RSK Mainnet:
wss://rsk.getblock.io/mainnet/websocket
// init web3 instance
const GETBLOCK_API_KEY = /* copy the API key from GetBlock dashboard */;
const rpcWebsocketsUrl =
`wss://rsk.getblock.io/mainnet/websocket`;
const rpcWebsocketsOptions = {
timeout: 5000, // ms
headers: {
'x-api-key': GETBLOCK_API_KEY,
},
};
const web3Provider = new Web3.providers.WebsocketProvider(
rpcWebsocketsUrl,
rpcWebsocketsOptions,
);
const web3 = new Web3(web3Provider);
Once we have a web3 instance ready,
we need an ABI and the token smart contract's deployed address:
// init token contract instance
const tokenAbi = require('./abi.json'); // any standard ERC20 ABI will suffice for this purpose
const tokenAddress = '0x2d919f19d4892381d58edebeca66d5642cef1a1f'; // RDOC deployed address
const token = new web3.eth.Contract(tokenAbi, tokenAddress);
(2) Get past Transfer
events
According to the ERC20 specification,
each time an amount of the token is transferred between one account
and another account, the ERC20 smart contract should emit a Transfer
event.
This event contains 3 parameters:
- The sender address,
- the receiver address,
- and the amount.
(We only care about the amount for our objective here)
In web3.js, to get past events, you should specify the range of block numbers,
and then query the past events using .getPastEvents()
.
Assuming we want to calculate the total transaction volume
of RDOC in the past week, we can use the total number of seconds in a week
divided by the number of seconds per block.
7 * (24 * 60 * 60) / 30 = 20160
Note that as with other blockchains, the time per block is approximate,
therefore this gives us the number of blocks in approximately 1 week.
The exact number of blocks can also be calculated by inspecting block timestamps
// get the range of blocks to query
const rangeNumberOfBlocks = 20160;
const latestBlockNumber = await web3.eth.getBlockNumber().toNumber();
const blockRange = {
fromBlock: latestBlockNumber - rangeNumberOfBlocks,
toBlock: latestBlockNumber,
};
Now we can query past events:
// get past `Transfer` events
const events = await token.getPastEvents(
'Transfer',
blockRange,
);
(3) calculate the aggregate
Each event in the events
array contains the three event parameters,
as per the ERC20 specification, however, we are only interested in event.returnValues.value
.
Note that this is returned as a BN
(BigNumber),
and for good reason - it is a uint256
, which is too large for Javascript's built in Number
type.
Also note that this number has a certain number of decimal places that it should be divided by, also specified in the ERC20 specification.
// prepare for division for decimal places
const decimals = await token.methods.decimals().call();
const decimalsExp = new web3.utils.BN(10).pow(new web3.utils.BN(decimals));
For most tokens, including RDOC, we expect decimalsExp
to be 1e18 (1000000000000000000).
Finally, we can loop over the events
, and calculate the aggregate value.
Below I'm using .iadd()
instead of .add()
so that the addition can occur in-place,
so as to avoid reassignment/ memory allocation overhead (but this is optional).
const sum = new web3.utils.BN(0);
for (let eventIdx = 0; eventIdx < events.length; eventIdx += 1) {
const event = events[eventIdx];
sum.iadd(
new web3.utils.BN(event.returnValues.value),
);
}
const displaySum = sum.div(decimalsExp).toString();
displaySum
should be the total amount of transacted RDOC for the selected time period.
web3.eth.Contract
instance and calling.getPastEvents('Transfer')
, then aggregating them should give you the answer – Simmon