原文作者:0xPhillan
原文来源:web3edge
原文翻译:老雅痞
Dune 可能是目前大众可以使用的最强大的区块链数据分析工具,而且最棒的是: 免费! 使用 Dune,通过公共数据库你可以近乎实时地访问区块链数据,可以使用 SQL 进行查询。
这是很强大的能量。
Dune 在将区块链数据添加到数据库之前,会对其进行解码,这意味着你不必自己上手搞明白字节码。相反,你可以使用 Dune 的浏览器来浏览数据集、特定的智能合约、事件或调用!
Dune最近发布了 V2 引擎,将性能提高了 10 倍,现在就是你学习如何使用 Dune 的时候了。
在本指南中,你将学到:
-
第 1 部分:Dune 界面
-
第 2 部分:使用 SQL 构建你自己的查询和图表——从最基础开始
-
第 3 部分:将所有内容组织到仪表板中
在此次的分步指南中,我们将为 Pooly NFT 系列构建包含以下内容的仪表板:
让我们开始吧!
内容
第 1 部分:Dune的概述和功能
-
仪表盘
-
查询
-
分叉
-
查询编辑器
-
数据集浏览器和数据分类
-
保存你的分叉查询
第 2 部分:构建你的第一个查询
-
决定建立哪些查询
-
寻找正确的信息
-
准备在Dune中建立你的第一个查询
查询1:以 ETH 形式筹集的资金
查询2:以美元筹集的资金
查询2a: 以当前ETH价值计算的美元筹款
查询2b: 以购买时的ETH价值计算的美元筹款资金
查询 3: 支持者总人数
查询 4:
查询4a: 使用erc721的排行榜。抽象法
查询4b:使用poolysupporter的排行榜。解码表
查询5:每个NFT集的最大供应量和剩余供应量
查询6: 随着时间的推移,ETH筹集的时间序列图
第 3 部分:清理仪表板
结束
第 1 部分:Dune 和功能概述
当你第一次打开 Dune.com 网站时,你会看到下面的窗口。此窗口顶部有一个视图更改器,可让你循环浏览仪表板、查询和向导,然后是详细视图区域,你可以在其中查看左侧的仪表板、查询和向导(用户)列表以及一些搜索- 右侧的相关设置。
仪表板
仪表盘是一个查询的集合,它被安排成一系列的图表、计数器和其他信息,给用户提供关于特定兴趣领域的背景资料。下面,我打开了传奇人物@hildobby的以太坊仪表盘。在这里,我们可以看到从Dune的数据库中提取的各种数据,以集合或者时间序列图的形式显示。
在 Dune 中,每个仪表板都是公开的。这意味着任何人都可以查看和复制你构建的、或其他人构建的所有内容!这大大减少了仪表板的创建时间,并让你可以从其他用户的查询中学习。
查询
如果你还记得,我提到仪表板是查询的集合。如果你单击任何一个仪表板元素的标题,你将被带到该图表的 SQL 查询:
仪表板查询编辑器屏幕的两个示例
在这里,我们可以看到屏幕上的两个主要元素:查询(顶部;黑框)和输出图表(底部)。这就对了:无论你点击哪个区块或图表,你都可以看到用户是如何创建该图表的。
分叉Fork
如果想将整个仪表板或仅图表的查询保存到自己的帐户,可以点击右上角的“Fork”,分叉屏幕上的所有内容都将复制到一个新窗口,可以在其中进行编辑,将视图保存到你的帐户。
以太坊价格查询
让我们分叉以太坊价格图表!在查询上按“Fork”后,你将被带到查询编辑器,之前的代码已经复制进去!
查询编辑器
让我在这里向你介绍各种屏幕上的元素:
-
查询位置和名称——点击保存后可以更改名称!
-
数据集浏览器 - 搜索特定数据集
-
查询窗口 - 在此处输入你的 SQL 查询
-
可视化选择器 - 选择是否查看查询结果、分叉折线图或创建新的可视化
-
运行 - 运行查询窗口中的查询
-
结果/可视化 - 查看查询结果或使用查询结果创建的可视化
-
保存 - 保存你的(分叉的)查询!
Dune 查询编辑器概述
数据集浏览器和数据类别
让我们仔细看看数据集浏览器。数据集浏览器中有六个功能区域:
-
链式选择
-
数据集搜索
-
浏览原始区块链数据
-
浏览解码合约数据
-
浏览数据的摘要
-
浏览社区提供的数据
Dune 数据集浏览器概述
数据集选择
在数据集选择中,你可以选择想要解析的链。选择“Dune Engine V2 (Beta)”可以让你使用 Dune 的最新增强功能,其中包括多链查询和 10 倍的性能提升。
数据集资源管理器中的数据集选择选 项
如果你选择另一个链,类别选择(上图中的第 3-6 项)将消失,而你将看到可以与之交互的合约调用和事件的列表。
选择“1. 以太坊”
搜索
在搜索字段中,你可以输入搜索参数,Dune 将以你的要求搜索包含该关键字的所有表格。
注意:Dune Engine V2 和旧的搜索功能以不同的方式返回结果。旧的搜索返回所有结果的列表,而 Dune Engine V2 返回一个嵌套的结果列表。我们将使用 V2 引擎!
“1. 以太坊”和“7. Dune Engine V2 (Beta)” 搜索结果
原始区块链数据
如果点击原始区块链数据,你可以在嵌套数据结构中轻松找到 Dune 支持的各种区块链的查询,可以首先选择原始表,然后从那里选择你想要进一步调查的特定表列。在每个嵌套级别中,通过选择,你还可以对正在寻找的特定搜索结果进行过滤。
Dune Engine V2(测试版)原始区块链数据概述
这是获取高级区块链数据的一种非常快捷方便的方法。
解码项目
在这里,你将找到已被 Dune 解码的项目。解码的项目是指 Dune 团队将项目拆开,贴上标签放入表格,以便用户对某些数据有一个简单的标准化的参考。
你会再次注意到,搜索结果是嵌套的。在最高级别,有你可以搜索的项目,在较低级别,你可以过滤该项目中的特定智能合约,最后我们会看到从该智能合约生成的各种表格。如果单击任何表格,你将看到一个列表,就像原始区块链数据一样。
Dune Engine V2 (测试版)解码项目概述
摘要
摘要可以被认为是连接和组合各种查询和数据块的,以形成唯一表格的自定义表。摘要可帮助用户更轻松地查询他们正在寻找的特定数据,而无需手动组合各种数据。
一般来说,摘要可以分为两大类:
-
部门摘要:特定部门的数据
-
项目摘要:项目特定数据
从摘要的子菜单中,可以看到带有标签的摘要列表,这些标签可以指定这个摘要是特定于部门还是特定于项目。
Dune Engine V2(测试 版)摘要概述
社区
社区部分可以被认为是摘要部分的扩展,但由 Dune 社区成员提供。
你可能想知道为什么社区部分只有一个条目(“flashbots”)——那是因为 Dune Engine V2 刚刚发布!随着时间的推移,我们可以期待看到越来越多受信任的社区成员构建的社区数据集。
Dune Engine V2(测试版)社区 概述
数据集浏览器标签
在下图中,你可以看到自 Dune Engine V2 发布以来,Dune 中数据如何汇总的摘要:四个主要数据类别是原始区块链数据、解码项目、摘要和社区,它们以表格的形式保存了各种区块链的数据,可以保存各种数据类型。
Dune Engine V2 (测试版)数据浏览器中的标签概述
保存分叉查询
让我们先保存这个查询。点击保存后,会发生一些事情。首先,要为你的查询命名一个名字。
保存查询弹出窗口
选择名称后,你会注意到:
(1) 查询位置和名称已更新,并且 (2) 你的查询正在运行。这意味着 Dune 正在从他们的数据库中获取最新数据,该数据库会定期使用来自各种区块链的最新数据进行更新。查询完成运行后,你将看到查询结果 (3)。
分叉查询概述
从这里,如果你单击 (1) “查询结果”、“折线图”或“新可视化”中的任何一个,(2) 结果/可视化框将与 (3) 显示在其下方的选择设置一起更新。在这里,还有一个“添加到仪表板”按钮,可以快速将你的查询结果或可视化,添加到新的或现有的仪表板——就像之前 @hildobby 的以太坊仪表板一样!
查询结果和可视化部分
如果你点击 (1) 右上角的圆圈,然后点击 (2) “我的查询”,将打开你帐户的查询列表。
导航到你的查询
查询列表包括你曾经保存在帐户中的所有查询。在下面的顶部屏幕截图中,我们可以看到创建的最新查询:
带有最新查询的查询列表保存在顶部
恭喜,你已经学会使用可视化分叉并保存了你的第一个查询!
分叉Forking 是 Dune 的超级强大的功能之一,它可以帮助你通过建立在其他“巫师”(是的,你现在也是巫师了!)在你之前建立的查询上,轻松而快速地创建新的查询。你可以结合多个分叉的查询来建立你自己的仪表板。
让我们动手并构建一个仪表板——一个查询和可视化的集合——从头开始,不走分叉这条路。这部分将教你在哪里可以找到正确的区块链详细信息以查找你的特定项目,并教你 SQL 的 基础知识 。
第 2 部分:构建你的第一个查询
本节的目的是教你:
-
如何找到特定项目所需的正确信息
-
一些基本的SQL知识
但首先,我们需要决定仪表板的用途。Pool Together DeFi 协议的 Pooly NFT 是第一步。
Pooly NFT 铸 造页面。来源:https://mint.pooltogether.com/
如果我们在 Dune 上搜索“Pooly”,果然可以找到一些由社区创建的 Pooly NFT 追踪器。
在 Dune.com 上搜索 Pooly 的结果
我们可以单击@0xbills创建的Pooly 仪表板之一,然后单击“Fork”开始工作……
@0xbills 通过 https://dune.com/0xbills/Pooly-NFT
但是,如果我们从头开始构建它,我们将学习如何成为区块链侦探的同时,学习一些 SQL!因此,需要从头开始构建我们自己的查询。
确定要构建的查询
首先,让我 们决定想要在仪表板上使用哪些图表。让我们重建 Pooly 在其主页上构建的视图!仔细看下面两张截图,我们可以看到一些基于链上数据的指标。
带有资金跟踪器的 Pooly NFT 登录页面
Pooly NFT 排行榜
Pooly NFT 铸币厂选项和供应
我们可以看到:
-
筹集的资金与以 ETH 计价的资金目标
-
筹集的资金与以美元计价的资金目标
-
支持者总数(购买 Pooly 的唯一地址)
-
排行榜包括地址、每个地址购买的 NFT 数量以及按降序排列的总 ETH
-
三种 NFT 类型中的每一种的最大供应量和剩余供应量
是不是超级棒!但这些只是时间的快照。让我们也给自己另一个挑战:
-
制作随时间上升的 ETH 时间序列图
就目前而言,我们无法以与 Pooly 网站相同的方式构建视图,但我们可以捕获相同数量的数据(甚至更多!)来构建我们的仪表板。
寻找正确的信息
在我们开始使用 Dune 之前,我们需要找到正确的信息。从网站上,我们可以看出 PoolTogether 正在销售三套 NFT:
-
支持者 – 9 个随机收藏品中的 1 个,价值 0.1 ETH
-
律师 – 1 ETH 只有一件艺术品
-
评委——75 ETH 只有一件艺术品
Pooly 是通过一份合约出售所有三种 NFT,还是通过三种不同的合约出售?
让我们前往 Etherscan,看看是否能找到与 Pooly 相关的智能合约。打开Etherscan.io后,键入“Pooly”以查看这些智能合约的所有者是否在 Etherscan 上注册了它们。
在 Etherscan 上搜索 Pooly
找到了!共有三个智能合约,可能对应于三个 NFT 集合中的每一个。此外,我们现在知道每个 Pooly 都是一个 ERC721 代币。
打开三个集合中的每一个,并通过单击鼠标悬停在该地址上时出现的复制图标,来复制智能合约地址。在页面底部我们还可以看到最近的所有交易,这将有助于以后的故障排除。
通过 Etherscan 查找 Pooly 合约地址
我们将需要 这些合约地址从 Dune 中提取正确的数据,它们构成了我们所有查询的基础:
0.1 ETH Pooly 支持者:
0x90B3832e2F2aDe2FE382a911805B6933C056D6ed
1.0 ETH Pooly Lawyer:
0x3545192b340F50d77403DC0A64cf2b32F03d00A9
75 ETH Pooly 法官:
0x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523
准备在 Dune 中构建你的第一个查询
首先,导航到 dune.com,然后单击屏幕右上角的“新查询”。
创建新查询
这将打开查询编辑器,我们就可以开始进行查询工作了!
新的和未触及的新查询窗口
查询 1:以 ETH 筹集的资金
首先,在左上角从“7. Dune引擎 V2(测试版)”改为“1. 以太坊”。Pooly 在以太坊上,因此我们只需要以太坊数据来进行此查询。另外,“1. 以太坊”比刚刚进入测试阶段的 Dune Engine V2 更成熟。
对于我们的第一个查询,我们将构建一个计数器,显示以 ETH 计价的募集资金。为此,请将以下代码复制到 Dune 的查询字段中,然后按“运行”(或 CTRL+Enter):
select SUM ( "value" / 1e18 ) from ethereum.transactions
where "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
上面的代码是一个 SQL 查询,它解析 Dune 的数据库以获取我们请求的特定数据。你可以将 Dune 的数据库想象为各种表的集合,每个表都包含你可能想要提取的特定信息。使用 SQL,你可以实现:
-
指定你想要的数据(表中的哪一列)
-
是否要转换该数据
-
你要从哪个表中获取数据
-
是否要过滤数据
为了说明上述情况,让我们逐段运行上述代码。将以下代码复制到 Dune 的查询编辑器并运行它:
select * from ethereum.transactions
where "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
你会得到一个包含很多信息的大表:
使用 * 命令返回表中所有列的示例
现在让我们看一下 SQL 代码:
SQL代码分解
这段代码的意思是“从以太类别中的事务表中选择所有列,其中 to 列的值为
x3545192b340F50d77403DC0A64cf2b32F03d00A9”,或者使用简单的英语: 给我一个表,其中包含与 Pooly2(1 ETH)智能合约的所有智能合约交互(show me a table with all smart contract interactions with the Pooly2 (1 ETH) smart contract.)。
你无需运行查询即可查看表中的列。数据浏览器让你通过其漂亮的搜索功能探索各种表头:
使用数据浏览器在“以太坊”中搜索表
我们可以完全删除第3行,以去除过滤器,然而,这将返回一个巨大的表,查询将需要很长的时间来完成。你的查询越精确,它们就会运行得越快!
因为我们只想查询归还筹集的资金,所以不需要所有列。所以让我们调整我们的代码,只抓取“value”列:
select "value" from ethereum.transactions
where "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
现在我们只有一个“值”列,而不是我们之前看到的很多:
返回“值”列中的所有条目
但是,你可能会注意到,这些值似乎非常大。那是因为它们是以 Wei 而非 ETH 计价的!为了解决这个问题,我们可以简单地将算术运算符应用于“值”列:
select "value" / 1e18 from ethereum.transactions
where "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
这样看起来是不是好多了!SQL 中的 1e18 与 10^18 相同,我们只是告诉 Dune 将这个数字除以 1,000,000,000,000,000,000,以便我们看到以 ETH 计价的值而不是 Wei。
由于我们只想要总值而不是值列表,我们可以将“value”/1e18 包装在 SUM() 语句中:
select SUM ( "value" / 1e18 ) from ethereum.transactions
where "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
太棒了,我们现在可以看到在 Pooly2 上花费的 ETH 总数!由于我们想要获得所有三个 Pooly NFT 智能合约的总花费,我们需要再添加两行以包含有关其他智能合约的详细信息:
select SUM ( "value" / 1e18 ) from ethereum.transactions
where "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
最终输出
“ or ”命令与“ where ”命令协同工作,并指定在过滤“to”列中的值时,如果找到第一个值或第二个值或第三个值,则应考虑该行。
我们现在看到,总共花费了 773.7 ETH 用于所有三个 Pooly 合约。惊人的!让我们去 Pooly 网站看看是否正确:
将我们的输出与 Pooly NFT 页面上的官方数据进行比较。资金目标达到 - 恭喜!
在 Pooly 网站上,我们看到 776.5 ETH - 恭喜实现目标!但是,哦不,有 2.8 ETH 的差异!好吧——这没什么好担心的。Dune 定期同步区块链数据。而且由于他们同步到数据库的数据集非常庞大,因此需要一些时间。我们可以预期数据将在接下来的一两个小时内刷新。
现在我们的查询已经完成,我们需要设置一个计数器以便稍后在我们的仪表板上显示它。在查询结果框下方,单击新的可视化,然后在出现的下拉菜单中单击“计数器”。
在我们的查询中添加一个计数器
最后,单击“添加可视化”:
向查询添加计数器可视化
将出现一个计数器,如果向下滚动,你会看到各种设置。只需根据自己的喜好调整设置。
计数器可视化标签和标题设置
完成后,单击 (1) “添加到仪表板”并选择 (2) “新仪表板”。然后 (3) 为你的仪表板命名并 (4) 单击“保存仪表板”。新仪表板将出现在你的仪表板列表中。从这里单击 (5) 你希望将可视化添加到的仪表板上的“添加”。添加后,标签将从“添加add”变为“已添加added”。
将可视化添加到仪表板
如果你在此子菜单中单击仪表板的名称(“Pooly NFT by 0xPhillan”),你将被带到显示我们跟踪器的仪表板。
添加了可视化的仪表板
干得漂亮!
一旦我们完成了所有查询的设置,我们将回到编辑我们的仪表板。
查询 2:以美元筹集的资金
我们有两种方法可以解决这个问题:
-
使用用于购买NFTs的美元资金的当前价值
-
使用购买时资金的美元价值
如果我们查看 Etherscan 上的智能合约,我们可以看到大部分 776.5 ETH 已经从智能合约中移出,截至撰写本文时,Poly NFT 智能合约中还剩下 299.2 ETH。
Etherscan.io 上的 Pooly1/2/3 智能合约 ETH 余额
如果我们查看之前的 Pooly 网站截图,776.5 ETH 的价值为 1,411,249 美元(1,817 美元/ETH),这暗示着 Pooly 智能合约所有者可能将资金保留为 ETH,而不是美元。
最终,很难说 Pooly 采用哪种方法,但两种计算美元价值的方法都很有趣:
-
当前值告诉我们资金现在的价值
-
购买时的价值告诉我们购买者的预期美元金额
所以……让我们一起创造吧!
查询 2a:以当前 ETH 价值以美元筹集的资金
对于这个,我们将使用我们之前的代码作为基础,并在一些额外的行中插入新代码以获得当前的美元价值。
首先,fork 我们刚刚创建的查询:
分叉上一个查询
然后调整你的代码如下所示:
select SUM ( "value" / 1e18 ) * (
SELECT "price" FROM prices.usd
WHERE "symbol" = 'WETH'
AND "minute" < now () - interval '1 hours'
ORDER BY "minute" DESC
LIMIT 1
)
from ethereum.transactions
where "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
你会注意到我们在SUM(“value”/1e18)命令之后添加了一个乘法运算符*和一个大代码块。
在 Dune 中,你可以突出显示查询的特定部分,并通过单击“运行选择”仅运行该部分。让我们 (1) 仅突出显示括号内的行并 (2) 运行该选择:
通过选择查询的一部分,你可以只运行选定的部分。
在查询结果中你将看到 WETH 的最新美元价格!我们在这里的添加将 WETH 的最新价格乘以筹集的 ETH 数量,从而为我们提供美元价值。
让我们分解这个代码块:
先前代码的细分
-
从 price.usd 表中选择“价格”列
-
过滤“WETH”的符号列
-
仅查看过去 1 小时的时间条目(这将显着加快查询速度)
-
按降序排列(最新的在前)
-
将查询限制为一个结果(第一个结果,即最新价格)
为了更好地理解这段代码,让我们对查询进行一些小的调整。(1) 将“price”替换为*(返回所有列)和 (2) 仅选择第 2 到 5 行的代码,然后 (3) 运行选择:
稍作调整运行上一个查询
在查询结果中,你将看到由五列组成的完整表。首先,让我们检查一下 Etherscan.io 中的合约地址:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Etherscan.io 上的 WETH 智能合约
该智能合约控制以太坊区块链上的 WETH 资产。距离我们的目标更进一步了!现在我们从之前的屏幕截图中知道了表格的来源,该屏幕截图显示了 WETH 的美元价格。
让我们将注意力转移回上一张表:
查询结果表我们之前的查询
在这里,我们有一个名为“分钟 minute ”的列,它每分钟跟踪 ETH 到美元的价值。由于我们将查询限制为“间隔 1 小时”,因此我们只能获得最新一小时的可用数据。出于我们的目的,我们实际上只需要最新的数据输入,因此将此查询限制在最后一小时会显着加快查询速度。例如,也可以将其更改为“1 天”、“3 天”或“1 周”,以获取更多历史数据。
这里重要的是列名是“分钟”,因此我们的查询引用“分钟”列,不要将其误认为与时间相关的命令。
让我们将我们的代码恢复到我们在本节开头更改的内容并运行查询:
保存查询
结果是已经转移到 Pooly1、Poly2 和 Pooly3 智能合约以换取 Pooly NFT 的 ETH 的当前美元价值。
为此,我们将再次使用计数器,因此向下滚动并(1)单击从我们之前的查询分叉的计数器,(2)调整数据源和(3)更改标签。
调整计数器可视化
完成后,记得保存并添加到我们的仪表板:
保存查询并将可视化添加到我们之前的仪表板
添加后,它将如下图所示。别担心,在本指南的最后,我们会清理它。现在,不要担心外观!
添加了第二个查询的仪表板
查询 2b:筹集的资金以美元计算,购买时为ETH价值
这个查询会稍微复杂一些,因为我们必须查询两个表并组合结果。具体来说,我们将必须获取单个交易并使用交易时的 ETH 价格转换为每笔交易的 ETH 价值。
同样,让我们先 fork 之前的查询,为我们的下一个查询做准备:
分叉上一个查询。
从分叉的代码中,我们要进行以下操作:
with poolyTransactions as
(
select
block_time,
value / 1e18 as value_eth
from ethereum.transactions
where "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
)
select
sum (value_eth * price)
from poolyTransactions tx
left join
( select minute , price from prices.usd
where symbol = 'WETH' and minute > '2022-05-01' )
as prices on date_trunc( 'minute' , block_time) = minute
使用购买 NFT 时的 ETH-USD 汇率查询。
如果我们在此处运行此代码,我们会看到我们收到了 140 万美元的美元价值。
让我们把这段代码分成三个部 分:
将查询分为三个部分
第 1 节
在这里,我们构建了我们将引用的第一个表。我们在这里所做的是创建一个我们称之为“poolyTransactions”的辅助表,它将保存来自 ethereum.transactions 表的 block_time 和 value_eth(以 wei 为单位的值除以 10^18 以转换为 ETH,我们给它一个自定义名称)。对于这个表,我们过滤了我们知道的三个 Pooly 地址。
这里逐行解释:
-
第 1 行:使用 poolyTransaction 作为- 定义名为“poolyTransaction”的辅助表具有以下属性
-
第 3-11 行:选择要包含在 ethereum.transcations 表中的列和过滤器
-
第 5 行:value/1e18 as value_eth——这里我们将列重命名为“value_eth”,以便我们可以在第 2 节中直接引用它,而不是进行其他计算
第 2 节
这是我们创建输出表的地方。你会注意到我们正在从 poolyTransactions 构建一个表,这是我们在第 1 节中创建的辅助表,但我们还引用了一个我们尚未定义的名为“price”的列。价格实际上只在第 19 行后面定义!这是可能的,因为我们在第 3 节中将 poolyTransactions 与 price.usd 表中的某些输出连接起来。所以本质上,我们正在使用我们的辅助表 poolyTransactions 以及我们从 price.usd 中构建的表,创建一个表的下一节。
第 3 节
这是我们定义一个要与另一个表连接的表的地方。“left join”关键字允许我们这样做:
-
第 18 行:left join——关键字用于表示我们想将我们的第一个表(左表)与另一个表(右表)连接起来。这意味着,我们在第 1 节中定义的第一个表作为基表。
-
第 19-20 行:这里我们定义了我们想要从 price.usd 创建的表。在第 20 行中,我们将持续时间限制为“2022-05-01”,因为 Pooly 智能合约仅在 5 月份部署,因此如果我们将其限制在更小的时间范围内,可以显着加快查询数据的过程。
-
第 21 行:作为价格——这将第 19-20 行中的表格命名为“价格”,以便于将来参考
-
第 22 行:on data_trunc('minute', block_time) = minute – 这是将我们的辅助表(第 1 节)与价格表(第 3 节第 19-20 行)结合起来的行。这里所说的是从我们的辅助表中取出列“block_time”,并将其截断为仅按照分钟,即删除所有其他不是分钟的数据(例如秒、毫秒等)。price.usd 表已经被截断为分钟,所以这里不需要进一步的转换。然后将prices.usd中的分钟列与我们辅助表中的分钟列进行匹配,从而将正确的价格从prices.usd分配到poolyTransactions中对应的分钟时间戳。
在数据集浏览器中查看 price.usd 表的分钟列
为了更好地可视化第三部分,我重新组织了各个部分以使其更易于理解:
连接命令每一步的可视化
(1) 我们创建 poolyTransactions 表,然后 (2) 我们告诉 SQL 将它与另一个表连接起来,(3) 我们将它定义为来自 prices.usd 表的分钟和价格列。然后(4)将我们创建的这个 price.usd 表连接到左表 poolyTransactions 上,使用以分钟为单位的时间作为映射变量。要连接表,两个表必须具有完全相同的条目,如果我们将 block_time 变量截断为分钟,我们会在两个表之间创建匹配的分钟。通过这样做,(5) poolyTransactions 表被更新以包括价格列,价格值与相应的日期相匹配。
从这里,我们只需查询连接的 poolyTransactions 表,并将每一行的 value_eth 和 ETH 价格相乘的结果相加。
现在添加一个计数器,保存并添加到仪表板!
向查询添加计数器可视化
计数器可视化设置并添加到仪表板
计数器可视化添加到仪表板
查询 3:支持者总数
对于我们的下一个查询,我们想要计算购买 Pooly NFT 的唯一地址(即支持总数)。这意味着即使一个地址购买了所有三种 Pooly 类型的多个 Pooly,它们也应该只计算一次。
为此,让我们首先打开我们的第一个查询,将其分叉,记住,这一步也要保存。
分叉第一个查询
这里我们简单地改变第一行:
select COUNT ( DISTINCT "from" ) from ethereum.transactions
where "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
独特的 Pooly 支持者查询
COUNT 变量计算所有事务,而 DISTINCT 关键字确保每个唯一条目只计算一次。我们得到的结果是 4660 个独特的支持者。如果我们将其与 Pooly 网站上的独特支持者进行比较,我们会发现他们非常接近:
Pooly 实时支持者数据
这表明我们的查询是正确的,因为 Dune 的数据库刷新和最新的区块链状态之间存在一点延迟。
最后,更改可视化计数器并再次添加到仪表板。
调整计数器的可视化设置并添加到仪表板
计数器添加到仪表板
查询 4a:使用 erc721 的排行榜,摘要
接下来,让我们构建排行榜,包括地址、每个地址购买的 NFT 数量和总 ETH 以降序排列。
同样,让我们分叉之前的查询,这样我们就不必重新输入过滤后的地址。请记住在继续之前保存此新查询。
查看排行榜,我们需要三个信息。首先是购买者的地址,然后是购买的 NFT 数量,最后是购买所有 NFT 所花费的 ETH 数量。
Pooly 排行榜列
在这里,我们正在查看不是购买了但没有持有的情况 。完全有可能有人购买(铸造)了 NFT,然后将其移至 安全 钱包 或稍后转售。我们只对首次购买(mint)感兴趣。
我们使用以下查询来实现这一点:
with poolyTransactions as
(
select
"from" ,
hash ,
value / 1e18 as value_eth
from ethereum.transactions
where "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
)
select
"from" , nfts_purchased, value_eth
from poolyTransactions
left join
( Select evt_tx_hash, COUNT ( "tokenId" ) as nfts_purchased
From erc721. "ERC721_evt_Transfer"
Where (contract_address = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or contract_address = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or contract_address = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523' )
and "from" = 'x0000000000000000000000000000000000000000'
group by 1 )
as nfts
on evt_tx_hash = hash
ORDER BY 3 desc
Pooly 排行榜表
你会注意到这与“购买时以 ETH 价值以美元筹集的资金”中的查询非常相似,这是因为我们使用了相同的方法:我们首先在 poolyTransactions 表中收集交易数据,然后我们留下了第二个表——它上面有一个共同的映射值。
在这里,对于第二个表,我们使用 erc721.“ERC721_evt_Transfer”表,这是 Dune 维护的一个摘要,用于跟踪以太坊上的所有 NFT 传输。如果我们使用数据集浏览器,请输入“erc721”。并滚动到“ERC721_evt_Transfer”,我们可以看到该特定表中包含的所有内容。我们还可以只突出显示第二个表的命令,看看输出是什么:
由于我们只想要智能合约新铸造的 NFT,因此我们必须将“发件人”地址指定为空地址。在以太坊上,所有 NFT 都是从空地址铸造的。通过计算每笔交易的“tokenId”数量,我们可以统计每笔交易铸造的 NFT 总数。
你还会注意到过滤器的定义方式有些特殊。前三个过滤器现在包含在括号中,而最后一个过滤器位于括号之外。
评估前三个过滤器语句是否用括号括起来
括号决定了计算和/或过滤器命令的顺序,就像在 SQL 中执行算术命令时一样。如果我们没有将前三个语句括起来,则and条件将仅适用于最后一个过滤器设置。
不使用括号时的评估
由于我们希望将from null 地址过滤器应用于先前过滤器的所有结果,因此我们需要添加括号。
最后,由于我们使用“COUNT”命令,我们需要指定在哪一列进行计数(即,将计数汇总到哪个变量)。为此,我们使用“group by”命令表示我们要将“tokenId”的计数分组到表中的第一列,即“evt_tx_hash”。
之前提到,我们需要一个通用映射值来将第二个表映射到表。在这里,我们使用交易哈希将每笔交易购买的 NFT 数量映射到我们的 poolyTransactions 表,这次我们也要求了交易哈希值。因此,最终,我们将erc721. "ERC721_evt_Transfer "表(我们命名为 "nfts")的交易哈希值映射到我们的poolyTransactions表中,其中只包括用于购买poolys的交易。
输出是一个表格,其中包括购买者地址、总共购买的 NFT 数量以及花费的 ETH 总价值。
最后,我们告诉 Dune 为“ORDER BY 3 desc”,这意味着我们输出表的第三列应该按降序排列:
“ORDER BY 3 desc”命令。
超棒!我们的排行榜已经完成。让我们将其与 Pooly NFT 网站上的排行榜进行比较:
将 Dune 查询排行榜与 Pooly 网站排行榜进行比较。
并非所有数字都相同,但从这个列表中我们可以看到,一些地址、购买的 NFT 和总 ETH 花费的数字确实相同。这又是Dune和实时区块链数据之间的同步时间问题,无需担心。
请记住保存你的查询并将其添加到仪表板。
查询 4b:使用 poolysupporter 的排行榜 解码表
除了使用 erc721.“ERC721_evt_Transfer”表,我们还可以使用 Dune 团队整理的 poolysupporter.“PoolyNFT_call_mintNFT”解码表。
with poolyTransactions as
(
select
"from" ,
hash ,
value / 1e18 as value_eth
from ethereum.transactions
where "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
)
select
"from" , nfts_purchased, value_eth
from poolyTransactions
left join
( Select call_tx_hash, "_numberOfTokens" as nfts_purchased
From poolysupporters. "PoolyNFT_call_mintNFT"
where contract_address = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or contract_address = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or contract_address = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
)
as nfts
on call_tx_hash = hash
ORDER BY 3 desc
方法与上面相同,只是使用此表我们可以直接返回所有调用 mintNFT 函数的交易哈希,而不是使用空地址来确定来自 erc721 的交易。“ERC721_evt_Transfer”表是mint交易。
使用poolysupporters。而不是erc721。
poolysupporter 数据集允许我们进行更具体和详细的查询,因为我们可以参考特定的合约调用。
让我们比较两个表的结果以确保没有任何问题:
你看,输出是相同的。
请记住保存你的查询并将其添加到仪表板。
查询 5:每个 NFT 集合的最大供应量和剩余供应量
在查询 4 的替代版本中,我们使用了 poolysupporter 函数。你可能已经看到,当你在数据集资源管理器中搜索 pooly 时,你还会看到一个名为“PoolyNFT_call_maxNFT”的函数。
poolysupporters.PoolyNFT_call_maxNFT 函数
你可以得出结论,你可以使用这个函数调用来直接检索最大铸币量的NFT。
使用 poolysupporters.PoolyNFT_call_maxNFT 没有查询结果
不幸的是,这是不可能的:这个函数是一个“读取”函数,因此在调用这个函数时没有链上记录。请参阅下面的 Etherscan:
maxNFT 是一个读取函数,它不会在区块链上留下任何记录
maxNFT 变量是在部署者合约部署 Pooly Supporter 智能合约时设置的,但不幸的是,在撰写本文时,部署者智能合约尚未解码,因此我们无法从链上数据中获得最大铸币厂数量。
相反,我们必须手动输入每个智能合约的 maxNFT 数据:
with poolyContracts as
(
Select contract_address,
COUNT ( "tokenId" ) as nfts_purchased
From erc721. "ERC721_evt_Transfer"
Where (contract_address = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or contract_address = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or contract_address = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523' )
and "from" = 'x0000000000000000000000000000000000000000'
group by 1
)
select
CASE contract_address
WHEN 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed' then 'Pooly_Supporter'
WHEN 'x3545192b340F50d77403DC0A64cf2b32F03d00A9' then 'Pooly_Lawyer'
WHEN 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523' then 'Pooly_Judge'
END as NFT_name,
nfts_purchased,
CASE maxNFT_Supply
WHEN 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed' then 10000
WHEN 'x3545192b340F50d77403DC0A64cf2b32F03d00A9' then 100
WHEN 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523' then 10
END as NFT_Supply,
CASE maxNFT_Supply
WHEN 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed' then 100 -(nfts_purchased/ 10000.0 * 100 )
WHEN 'x3545192b340F50d77403DC0A64cf2b32F03d00A9' then 100 -(nfts_purchased/ 1000.0 * 100 )
WHEN 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523' then 100 -(nfts_purchased/ 10.0 * 100 )
END as percent_supply_remaining
from poolyContracts
left join
(
Select contract_address as maxNFT_Supply
From erc721. "ERC721_evt_Transfer"
Where (contract_address = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or contract_address = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or contract_address = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523' )
and "from" = 'x0000000000000000000000000000000000000000'
group by 1
)
as maxNFT
on maxNFT_Supply = contract_address
ORDER BY 3 desc
Pooly NFT 供应查询
这是必须有点创意的地方。手动将数字添加到 SQL 中的特定表条目是一项艰巨的任务,我不得不应用一些技巧来得到这个,以便留下一个易于阅读的表。
在这里,我们将再次使用左连接来组合两个表,但我们还将在四列中的三列上使用 CASE WHEN 语句来输出我们想要显示的特定信息。我们要做的是首先创建我们的基表,然后创建第二个表,然后将第二个表与第一个表左连接并转换表输入以使其易于阅读,并为我们做一些简单的算术运算。
第二个表的原因是在单个查询中 SQL 不允许你两次调用列。实际上,我们需要多次调用一列,并分别转换每一列调用。然而,连接表允许我们多次调用第二个表中的列,从而使我们能够为我们需要的列中的特定行创建所需的输出。
上述查询的细分
让我们将这个查询分成四个部分以便于消化。
注意顺序!1、3、2、4!
第 1 节
在本节中,我们定义了一个名为“poolyContracts”的表,其中我们计算了来自三个 Pooly 合约地址的空地址的所有单个 tokenId,因此仅包括使用 erc721.“ERC721_evt_Transfer”表铸造的 NFT。然后,我们将它们按第一列分组,从而返回每个池智能合约的铸造 NFT。
poolyContracts 表
第 2 节
在这个代码块中,我们强制查询只显示三个合约地址中的每一个。我们通过使用“按 1 分组”命令来做到这一点,即按第一列的唯一条目对结果进行分组。
第二个表使用“group by 1”命令返回每个合约地址的 1 个
如果没有 group by 命令,查询将返回与这些合约地址相关的所有传输事件,但我们只需要每个出现一次。你将在下一节中看到原因。
第二个表返回一长串没有“group by 1”命令的合约地址
此外,我们将contract_address列重命名为maxNFT_Supply,以便我们可以定义将该表与哪个列连接到 poolyContracts 表中。
第 3 节
这就是魔法发生的地方。
在本节中,我们现在可以从连接表中调用列。我们称之为:
-
合约地址
-
nfts_purchased
-
maxNFT_Supply
-
maxNFT_Supply
你会注意到,我们基本上使用第 1、3 和 4 列检索相同的数据 3 次,而且第 3 和 4 列甚至是相同的列!这是可能的,因为我们连接了两个表。如果在连接表之前调用 contract_address 两次,查询编辑器将返回错误消息。
接下来,你还会注意到第 1、3 和 4 列都嵌入了CASE WHEN子句。因为我们创建的前两个表中的每一个只有一个用于每个智能合约的唯一行,所以我们不能使用CASE WHEN语句来指定是否出现特定的智能合约地址(三个选项之一),在其位置返回其他内容。
未按 nft_supply 排序结果的完整表
你将在此处看到第一列,我们告诉查询编辑器将每个智能合约地址替换为相应 NFT 的名称!
在第三列中,我们将其替换为 Pooly 网站上列出的已知最大 NFT 数量。
在第四列中,我们使用一个公式来计算剩余 NFT 供应的百分比。在这些语句中,至少有一个用于算术运算的数字需要包含一位小数。如果这不包括在内,SQL 查询将被解释为想要返回整数,这意味着我们不会为这些计算获得任何小数。通过包含“ .0”,我们向服务器表明我们希望此计算返回一个十进制数。
第 4 节
最后,我们指出我们希望输出按第三列的降序(从大到小)排序。
按 nft_supply 降序排序后的全表
这张表也做好了。保存你的查询,对表格进行所需的任何更改并将其添加到仪表板。
将表添加到仪表板
查询 6:随时间筹集的 ETH 时间序列图
在我们的最终查询中,我们将创建一个时间序列图表,显示随着时间的推移通过 NFT 销售筹集的 ETH 数量。
select
block_time as time ,
sum ( value / 1e18 ) over ( order by date_trunc( 'minute' , block_time) asc ) as cumu_value_eth
from ethereum.transactions
where ( "to" = 'x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = 'x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = 'x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523' )
and date_trunc( 'day' , block_time) < '2022-06-25’
随着时间的推移,ETH 的累计 NFT 销售额。
这是一段较短的代码,但它包含over命令,这是聚合累积值的重要命令。
在这个查询中,我们首先选择 block_time,然后我们以分钟为间隔将 ETH 值(即value/ 1e18 )与 block_time 相加,我们直接按升序排序,并将列命名为cumu_value_eth。
sum(value/1e18) over (order by date_trunc('minute', block_time) asc) as cumu_value_eth
此外,我们还在结尾处添加了另一个过滤器,其中规定对于这个查询,封锁时间不应超过2022-06-25,根据Pooly网站,这大概是募捐活动结束的时间。这样,我们的区域图将只显示活动的数据,而不是添加一条平线,随着时间的推移,平线将拖入永恒。
要创建区域图,(1)点击 "新可视化",然后在(2)下拉菜单中选择 "区域图",最后(3)点击 "添加可视化"。
创建面积图可视化
你的面积图应该会自动出现,并带有 Dune 预先选择的相关设置。
面积图可视化设置并添加到仪表板
如果未预先选择它们,你可以使用图表下方的设置,直到看起来正确为止。
最后,保存你的查询并再次按“添加到仪表板”。
第 3 部分:清理仪表板
我们构建了很多查询,并直接将它们添加到我们的仪表板中。好吧,让我们来看看它的样子。将最后一个图表添加到仪表板后,只需单击仪表板名称即可。
添加可视化后,单击仪表板的名称将其打开
而且,让我们看看……
清理前的仪表板
这肯定需要在它呈现之前进行清理。
在仪表板屏幕的右上角,单击“编辑”开始编辑。
单击右上角的编辑按钮以编辑仪表板格式
从这里,你可以在移动元素时将单个元素拖放到背景中由红色框显示的网格上,并且可以通过拖动左下角的图标来调整每个元素的大小。简单的!
可视化和其他元素支持拖放和调整大小
要将文本和图像添加到仪表板,请按仪表板编辑屏幕右上角的“添加文本小部件”。
单击“添加文本小部件”以添加文本小部件
在整理时,你可能会注意到这两个查询看起来相同,并且两者都没有真正提供任何有价值的信息......:
两个计数器显示了计算 ETH 美元价值的不同方法
因为我们不知道 PoolTogether 何时或如何提取智能合约中的 ETH,所以我们可以坚持 Pooly 网站是如何做的。我们将删除正确的查询并将其替换为另一个查询。
我们开始吧,最后的仪表板:
最后的仪表板
这看起来比以前好多了,而且它也遵循了与 Pooly 网站相同的格式!
结束
Dune Analytics 是一个强大的平台,可以在合适的人手中提供深度区块链数据能力。我希望通过这篇文章,我能够教你基础知识。从这里开始,你可以接受更大的挑战并制作更好的仪表板。