天天看點

multicall以太坊批量查詢工具

在DEFI資料分析應用中通常需要擷取大量區塊鍊資料進行顯示或分析,而這往往會多次調用合約,進而導緻總查詢時間過長。并且,如果我們使用的是Infura這樣的第三方提供程式,短時間内的多次請求還有可能觸發服務商的限流管控。MakeDAO的Multicall就是解決這一問題的最佳方案,它包含鍊上合約與鍊下NPM包兩個部分,可以将多個針對以太坊區塊鍊查詢請求合并為一個,進而有效縮短響應時間并降低eth_call調用的消耗。

為了幫助你了解這種機制的工作原理以及其相對于傳統方法是否确實有所改進(每個函數調用n次),我們将舉一個示例,分别在不使用/使用Multicall的情況下進行操作,然後分析結果。為此,我們将通過調用Compound協定的

getAccountLiquidity()

函數來查詢1,000個不同的位址的流動性資料。

用自己熟悉的語言學習 以太坊DApp開發 : Java | Php Python .Net / C# Golang Node.JS Flutter / Dart

1、multicall對比測試:安裝NPM依賴包

為了進行此測試,我們将建立一個Node項目,并将安裝如下依賴:

  • ethers.js:和以太坊區塊鍊進行互動
  • money-legos:以更簡單的方式通路DeFi協定
  • ethers-multicall:multicall調用的封裝包

首先使用以下指令建立項目:

npm init -y           

然後安裝上述依賴包:

npm install -S @studydefi/money-legos ethers ethers-multicall           

2、multicall對比測試:導入NPM依賴包

無論是否使用multicall,我們都要使用一些公共的依賴包并執行個體化提供程式以便連接配接區塊鍊。我們通過以下代碼實作這一點:

const { ethers } = require("ethers");
const { ALCHEMY_URL } = require('./config')
const compound = require("@ studydefi/money-legos/compound");
const { accounts } = require("./accounts");
const { Contract, Provider } = require('ethers-multicall');
const provider = new ethers.providers.JsonRpcProvider(ALCHEMY_URL);           

接下來建立一個函數,以便顯示測試結果和執行時間,如下所示:

const calculateTime = async () => {
  const startDate = new Date();
  const result = await getLiquidity()
  const endDate = new Date();
  const milliseconds = (endDate.getTime() - startDate.getTime());
  console.log(`Time to process in milliseconds: $ {milliseconds}`)
  console.log(`Time to process in seconds: $ {milliseconds / 1000}`)
  const callsCount = Object.keys(result).length;
  console.log(`Number of entries in the result: $ {callsCount}`);
}           

3、multicall對比測試:傳統方式循環調用合約

為了使用傳統方法進行測試,我們将周遊包含1000個位址的數組,然後在一個map循環中,逐個傳回每個位址的查詢結果。為此,可以實作如下函數代碼:

const getLiquidity = () => {
  const compoundContract = new ethers.Contract(
  compound.comptroller.address,
  compound.comptroller.abi,
  provider
  )
  
  return Promise.all(accounts.map(account => {
  let data
  try {
     data = compoundContract.getAccountLiquidity(account.id)
  } catch (error) {
     console.log(`Error getting the data $ {error}`)
  }
     return data
  }))
}           

在上面的代碼中,我們執行個體化compound協定的comptroller合約,然後為每個位址調用帳戶流動性查詢函數。

4、multicall對比測試:使用multicall調用的優化實作

使用Multicall調用時,上述代碼需要稍作更改:

const getLiquidity = async () => {
  const ethcallProvider = new Provider(provider);
  await ethcallProvider.init();
  
  const compoundContract = new Contract(
    compound.comptroller.address,
    compound.comptroller.abi,
  )
  
  const contractCalls = accounts.map(account => compoundContract.getAccountLiquidity(account.id))
  const results = await ethcallProvider.all(contractCalls);
  return results
}           

在上面的代碼中,我們利用了Multicall包中的Provider和Contract類。

首先,利用compound協定的comptroller合約的位址和abi初始化提供程式。然後将位址數組映射為合約調用數組,并在最後将得到的合約調用數組傳入提供器的all函數,這時請求才真正發送到網絡中。

5、結果分析

讓我們看一下執行時間的差異。

普通方法(不使用multicall):

  • 處理時間:124.653 秒
  • 結果條目:1000

改進方法(使用mutlicall):

  • 處理時間:9.591 秒

6、結論

正如我們所看到的,使用multicall時執行時間的減少是相當可觀的,從124秒減少到9.5秒,花費的時間減少到原來的大約十分之一。

此外,如果我們比較eth_call請求數量,也會看到非常明顯的減少,從上千個減少到隻有一個。是以,如果我們依賴以太坊的通路提供商,而在該提供商中對API的調用受到限制,則需要考慮這一點。

原文連結:

用multicall加速DeFi查詢 — 彙智網