介绍如何跟踪已部署合约的交易,以及当它们在每个新确认的区块中进行更新时,如何在前端显示和更新这些数据。
在关于前端开发的上一篇文章中,我们最后提供了一个网站。用户可通过 MetaMask 连接该网站,它将显示用户的以太币账户余额。但是,有许多以太坊用例(例如 DeFi)涉及到 ERC20 令牌的发送和接收,其跟踪方式与原生以太币不同。在本指南中,我们将介绍如何跟踪已部署合约的交易,以及当它们在每个新确认的区块中进行更新时,如何在前端显示和更新这些数字。我们以跟踪 Uniswap 上的 Dai<>Eth 交易为例来进行说明。
<center>Uniswap</center>
为此,我们将使用来自 Status Embark 团队的一个库,名为 Subspace。我们首选使用 React Hooks 跟踪实时数据。因此,我们将通过在这里找到的 Embark 示例代码,使用以太坊数据流设置前端。总的来说,该前端使用了 Infura、React(含助手库)和 Subspace。
我们只需要检查 3 个重要文件。首先检查 src/index.js 的短文件,其中的 <SubspaceProvider> 包装整个 App,从而为每个组件提供对 web3 对象的访问权限,该对象即我们通过 web3 提供商 Infura 与以太坊建立的连接。我们将稍后在 App.js 中设置为使用 Infura 进行 web3 连接。
const rootElement = document.getElementById('root')
ReactDOM.render(
<SubspaceProvider web3={web3}>
<App />
</SubspaceProvider>,
rootElement
);
在 contracts/exchange_abi.json 中有 Uniswap 的 ABI,它是我们要求 Subspace 跟踪的每个函数的已部署 Uniswap 合约的规范。ABI 在 JSON 中指定,我们将对 web3 的合约对象使用它来在去中心化应用中与 Uniswap 进行交互。每个在以太坊上部署的合约都有 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 保存在流动性池所使用的合约。
const web3 = new Web3("wss://mainnet.infura.io/ws/v3/806ce35b64344f04a9a7e47379d9ca41");
const dai = new web3.eth.Contract(exchangeABI, '0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667');
在下一部分,我们将设置 Subspace 将会使用的 React 状态变量。Subspace 对象从 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 个代码区块是去中心化应用中非常重要的 Hooks,为我们提供我们需要的实时流。我们将对它进行设置,使我们能够查看最新挖出的 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() 会将 Hook 设置为从最新的 50 个以太坊区块获取最近的 5 个 EthPurchase 事件。重要的是,setObservable(EthPurchased$) 是我们跟踪的每个交易事件,我们通过使用管道操作符(从 RxJS 导入)并创建 5 个事件的 Observable 来限制前端仅显示 5 个事件。
接下来,我们还有一个 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 库。它让去中心化应用前端开发变得非常简单轻松,尤其是使用 Infura 处理 web3 数据非常实用!复制这里的样板库并使用 Subspace。如果您对此有任何问题,请在这里与我们讨论。有关更多教程,请访问我们的社区中的教程部分。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!