How to calculate the total volume transacted for a token on RSK?
Asked Answered
E

2

6

I would like to be able to find out the total volume transacted for RDOC, from deployment until now.

Unable to get this information from the block explorer: 0x2d919f19d4892381d58edebeca66d5642cef1a1f

What's the best way to get this using RPC or web3.js?

Evyn answered 16/6, 2021 at 7:24 Comment(1)
using a web3.eth.Contract instance and calling .getPastEvents('Transfer'), then aggregating them should give you the answerSimmon
S
6

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.

Simmon answered 17/6, 2021 at 4:26 Comment(0)
M
8

You can get past logs

  • from the block when the contract was deployed

  • until the current block

  • emitted by the token contract address

  • where the topics[0] is keccak256 of the event signature

    In case of Transfer(address,address,uint256) event, the keccak256 hash is 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

Since the first two params of the event are indexed, they are present in the topics[1] (sender) and topics[2] (receiver) fields of each event log. The third param (amount) is unindexed, so its value is in the data field (as a hex number) of each event log.

The total transacted volume is simply a sum of all transferred amounts (from the data field).

Mind that most RPC providers allow accessing only limited amount of historic blocks (e.g. max 100 blocks). So you might have to use a different provider or your own full node in order to access a deeper history (e.g. 200 blocks).

Miracle answered 16/6, 2021 at 7:43 Comment(0)
S
6

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.

Simmon answered 17/6, 2021 at 4:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.