如何计算 RSK 上代币的总交易量?

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

我希望能够找出 RDOC 的总交易量, 从部署到现在。

无法从区块浏览器中获取此信息: 0x2d919f19d4892381d58edebeca66d5642cef1a1f

使用 RPC 或 web3.js 获取此信息的最佳方法是什么?

你可以获得past logs

  • 来自部署合约时的区块

  • 直到当前区块

  • 由代币合约地址发出

  • 其中topics[0]是事件签名的keccak256

    Transfer(address,address,uint256) 事件的情况下,keccak256 哈希为 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

由于事件的前两个参数被索引,它们出现在每个事件日志的 topics[1](发送者)和 topics[2](接收者)字段中。第三个参数(金额)没有索引,所以它的值在每个事件日志的 data 字段(作为十六进制数)中。

总交易量只是所有转账金额的总和(来自 data 字段)。

请注意,大多数 RPC 提供程序只允许访问有限数量的历史区块(例如最多 100 个区块)。因此,您可能必须使用不同的提供商或您自己的完整节点才能访问更深层次的历史记录(例如 200 个区块)。

tl;dr= (1) 为 RDOC 部署地址初始化一个 web3.eth.Contract 实例; 然后 (2) 调用 .getPastEvents('Transfer'), 然后 (3) 汇总 Transfer.value 个值的总和。

详细答案:

(1) 初始化合约实例

有一个 RPC 数据提供程序, GetBlock 你可能会认为它类似于 Infura supports RSK.

对于查询大量的数据,比如历史数据, Websockets 可以比 HTTP 更快/更有效, 所以让我们为 RSK 主网使用他们的 Websockets RPC 端点:

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);

一旦我们准备好 web3 实例, 我们需要一个 ABI 和代币智能合约的部署地址:

// 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) 过去 Transfer 个事件

根据ERC20规范, 每次在一个账户之间转移一定数量的代币 另一个账户,ERC20 智能合约应该发出一个 Transfer 事件。 此事件包含 3 个参数:

  • 发件人地址,
  • 收件人地址,
  • 和金额。

(这里只关心我们objective的金额)

在web3.js中,要获取过去的事件,您应该指定区块编号的范围, 然后使用 .getPastEvents() 查询过去的事件。 假设我们要计算总交易量 过去一周的RDOC,我们可以用一周的总秒数 除以每个块的秒数。

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,
};

现在我们可以查询过去的事件:

// get past `Transfer` events
const events = await token.getPastEvents(
  'Transfer',
  blockRange,
);

(3) 计算总和

events数组中的每个事件都包含三个事件参数, 然而,根据 ERC20 规范,我们只对 event.returnValues.value.

感兴趣

请注意,这是作为 BN (BigNumber) 返回的, 并且有充分的理由 - 它是 uint256,对于 Javascript 内置的 Number 类型来说太大了。 另请注意,此数字应除以一定的小数位数,这也在 ERC20 规范中指定。

// 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));

对于包括 RDOC 在内的大多数代币,我们预计 decimalsExp 为 1e18 (1000000000000000000)。

最后,我们可以遍历events,计算合计值。

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 应为所选时间段内已交易 RDOC 的总量。