教學課程:搭配 Embark Subspace 和 Infura 使用的即時前端資料

在前端開發的上一篇貼文中,我們說明了允許使用者透過 MetaMask 連接的網站,並且展示使用者的 Ether 帳戶餘額。但有許多 Ethereum 的使用案例 (例如:DeFi) 都與傳送和接收 ERC20 語彙基元有關,而且追蹤方式都與原生 Ether 不同。在本指南中,我們將說明如何追蹤已部署合約的交易,並且由於這些交易可能會在每個新的已確認區塊中更新,因此我們也將說明如何在前端展示和更新這些數據。以此為例,讓我們在 Uniswap 中追蹤 Dai<>Eth 交易。

Uniswap

為了執行此操作,我們將使用 Embark 團隊在 Status 中稱為 Subspace 的資料庫。我們在追蹤即時資料時偏好使用的方式,是使用 React Hook,所以我們將透過使用此處找到的 Embark 範例程式碼進行處理,藉以逐步說明如何使用 Ethereum 資料串流設定前端。所以總結來說,此前端使用 Infura、React (搭配協助程式資料庫) 和 Subspace。

  • 本教學課程的網站與之前的前端教學課程網站不同。我們將逐步說明重要的程式碼,但不會說明所有程式碼,因此建議您複製範例存放庫,然後在根目錄 (或其他使用 Yarn) 中執行 npm install 和 npm start,這樣您的網站就可以在 localhost:3000 中架設。然後我們將說明使用 Hook 和 useEffect() 新增更多資料追蹤有多麼簡單。

我們只需要查看 3 個重要的檔案。首先是查看 src/index.js 的簡短檔案,其中我們有 <SubspaceProvider> 包裝整個應用程式,這可讓每個元件存取 web3 物件,而這也是我們透過 Infura 做為 web3 提供者與 Ethereum 的連線。我們之後將於 App.js 中進行設定,以於 web3 連線使用 Infura。

const rootElement = document.getElementById('root')
ReactDOM.render(
  <SubspaceProvider web3={web3}>
    <App />
  </SubspaceProvider>,
  rootElement
);

在 contracts/exchange_abi.json 中,我們有 Uniswap 的 ABI,這是我們 Subspace 追蹤中每一個功能的已部署 Uniswap 合約的規格。ABI 會在 JSON 中指定,然後我們針對 web3 的合約物件使用此 ABI 以與 dapp 中的 Uniswap 互動。每個在 Ethereum 中部署的合約都有一個 ABI,因此您可以新增任何現有的合約至此前端,並依照 ABI 及部署合約的位址追蹤其交易。


    {
        "name": "TokenPurchase",
        "inputs": [
            {
                "type": "address",
                "name": "buyer",
                "indexed": true
            },
            {
                "type": "uint256",
                "name": "eth_sold",
                "indexed": true
            },
  ... and a lot more

在 App.js 中,我們首先要使用我們的 Infura 連線初始化 web3 物件。如果您沒有 API 金鑰,您可以註冊以免費取得。接下來,結合 ABI 及該 ABI 的合約位址以建立合約物件。此位址是 Uniswap 在其流動資產集區保留 Dai 的合約。

  • 請注意,現在您可以返回至 index.js,將此相同的 Infura URL 新增為 Web3 提供者。
const web3 = new Web3("wss://mainnet.infura.io/ws/v3/806ce35b64344f04a9a7e47379d9ca41");
const dai = new web3.eth.Contract(exchangeABI, '0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667');

接下來,我們要設定 Subspace 將使用的 React 狀態變數。子空間物件是由 useSubspace() 建立,然後我們傳入我們剛才建立的 Contract 物件。然後是幾個定義,協助處理來自交易、以 wei 為單位的值。

function App(props) {

    const subspace = useSubspace();
    const daiContract = subspace.contract(dai);

    const [txnObserver, setObservable] = useState();
    const [last5Observable, setlast5Observable] = useState();
    const [latestBlock, setBlock] = useState();
    const [last5, setLast5] = useState([]);

    //Trade details object for calculating exchange rate
    function TradeDetails(tokensSold, ethBought) {
        this.tokensSold = web3.utils.fromWei(tokensSold);
        this.ethBought = web3.utils.fromWei(ethBought);
        this.exchangeRate = this.tokensSold / this.ethBought;
    }

接下來的 3 個程式碼區塊是 dapp 神奇的 Hook,而且可為我們提供所需的即時串流。我們將加以設定,這樣我們就可以查看最後 50 個採礦區狀況,然後顯示 5 筆在這些區塊中發生的最新 Eth->Dai 交易,而由於有更多採礦的區塊及更多交易,這些也將持續更新。

useEffect(() => {
        web3.eth.getBlockNumber().then((block) => setBlock(block));
        if (typeof(latestBlock) != "number") 
            return;

        const EthPurchased$ = daiContract.events.EthPurchase.track({
            fromBlock: latestBlock - 50
        });
        const last5$ = EthPurchased$.pipe($latest(5));
        setObservable(EthPurchased$);
        setlast5Observable(last5$)
    },[latestBlock])

以上 useEffect() 會設定從 50 個最新 Ethereum 區塊取得最後 5 個 EthPurchase 事件的 Hook。請注意,setObservable(EthPurchased$) 是我們追蹤的每一個交易事件,而且我們會使用管道運算子 (從 RxJS 匯入) 將其限制在於前端顯示 5 個事件,並建立這 5 個事件的 Observable。

接下來,我們有另一個 useEffect() Hook,可訂閱所有符合我們針對 EthPurchase 所定義規定的交易,而且會將這些儲存在 console.log

   useEffect(() => {
        if ((txnObserver === undefined) || (typeof latestBlock != "number")) {
            return;
        }
        txnObserver.subscribe((trade) => {
            console.log(trade);
        });
    
        return () => { txnObserver.unsubscribe(); }
    }, [txnObserver, latestBlock]);

從我們第一個 Hook 中建立的 last5Observable,我們可在此取得相關的交易詳細資料:

  useEffect(() => {
        if (last5Observable === undefined) {
            return;
        }
        last5Observable.subscribe((fiveTrades) => {
            const prices = fiveTrades.map(trade => {
                const txnDetails = new TradeDetails(trade.tokens_sold, trade.eth_bought);
                return {'block': trade.blockNumber, 'rate': txnDetails.exchangeRate}
            });
            setLast5(prices);
        });
    
        return () => { last5Observable.unsubscribe(); }
    }, [last5Observable]);

最後,我們有一些 React UI 程式碼,然後您就可以查看前端!以下是說明這個部分的 gif。這個部分最近才開始,到目前為止已有 3 筆交易。在開發人員主控台中,我們可以查看每筆交易的額外交易詳細資料。由於我們追蹤的交易會串流,最舊的就會從記錄中剔除。


我們希望這對於 Subspace 資料庫的說明對您有幫助;Subspace 資料庫讓 dapps 的前端開發變得簡單又容易,特別是在 web3 資料部分使用 Infura 時更是如此!所以請在此複製此重複使用存放庫、使用 Subspace,如果您對此有任何疑問,請在此與我們討論。如需更多教學課程,請造訪我們社群中的「教學課程」部分