6

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

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

使用 RPC 或 web3.js 获得此功能的最佳方法是什么?

4

2 回答 2

7

您可以获取过去的日志

  • 合约部署时的区块

  • 直到当前块

  • 由代币合约地址发出

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

    如果发生Transfer(address,address,uint256)事件,keccak256 哈希是0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

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

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

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

于 2021-06-16T07:43:44.630 回答
5

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

详细解答:

(1) 初始化合约实例

有一个 RPC 数据提供程序 GetBlock ,您可能会认为它类似于 支持 RSK的 Infura 。

对于查询大量数据(例如历史数据),Websockets 可以比 HTTP 更快/更高效,因此让我们将其 Websockets RPC 端点用于 RSK 主网:

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 个参数:

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

(我们在这里只关心我们目标的数量)

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

7 * (24 * 60 * 60) / 30 = 20160

请注意,与其他区块链一样,每个块的时间是近似的,因此这为我们提供了大约 1 周内的块数。块的确切数量也可以通过检查块时间戳来计算

// 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) 计算合计

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

请注意,这是作为BN(BigNumber) 返回的,并且有充分的理由 - 它是 a ,对于 Javascript 的内置类型uint256来说太大了。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,并计算聚合值。

下面我使用.iadd()代替,.add()以便可以就地进行添加,以避免重新分配/内存分配开销(但这是可选的)。

  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 总量。

于 2021-06-17T04:26:45.817 回答