Dune入门指南——以Pooly为例,做一个NFT看板

本文翻译自@0xPhillan,原文链接:

Dune是一款非常强大的、面向大众的、完全免费的区块链链上数据分析工具,你可以通过SQL查询Dune公开的数据库,获得链上数据,并根据你的奇思妙想定制一个分析仪表板。Dune帮我们收集归类好了链上数据,我们只要学习一些简单的SQL,就可以成长为链上数据分析师啦!

本教程将手把手带你从头开始,以Pooly NFT为例,做一个NFT分析板!内容包括:项目募集资金(ETH本位和U本位),支持者数量(去重复的唯一地址),消费排行榜,剩余供应量百分比,总募集资金随时间的变化等,适用于调研和分析新开放mint的NFT。

Pooly NFT的mint即将截止,抓紧时间mint一个吧!

在本指南中,你将学到:

  • Dune的基本介绍和交互界面
  • 如何使用SQL建立你自己的查询并做成可视化图表
  • 如何构建一个汇集各个查询的仪表板

Pooly NFT系列构建查询和仪表盘:

https://dune.com/phillan/pooly-nft-by-0xphillan
https://dune.com/phillan/pooly-nft-by-0xphillan

让我们开始吧~!

目录:

  • 第 1 部分:Dune功能概述
    • 仪表板
    • 查询
    • 分叉
    • 查询编辑器
    • 数据集浏览器和数据类别
    • 保存分叉查询
  • 第 2 部分:构建查询
    • 确定要构建的查询
    • 寻找正确的信息
    • 在 Dune 中构建你的第一个查询
      • 查询 1:ETH 本位的募集资金
      • 查询 2:美元本位的募集资金
      • 查询 2a:以当前 ETH 价值筹集的资金
      • 查询 2b:以购买时 ETH 价值筹集的资金
      • 查询 3:支持者总数
      • 查询 4a:用 erc721抽象做的排行榜
      • 查询 4b:用 poolysupporter解码表做的排行榜。
      • 查询 5:每种 NFT 的最大供应量和剩余供应量
      • 查询 6:随时间筹集的 ETH 时间序列图
  • 第 3 部分:整理仪表板
  • 结束语

第1部分:Dune功能概览

打开Dune的网站时,会看到以下窗口。窗口顶部可以在仪表板、查询和分析师(Wizard)中切换浏览,你可以看看最新最火的仪表板,看看大家都在关心、查询什么数据,也可以慕名来看某个大神的分析板。也可以在右边按关键字搜索,或者按分类、热度查询。

Dune.com 页面
Dune.com 页面

仪表板(Dashborad)

仪表板是一系列查询的组合。查询是一个个具体的信息检索,比如查询某个人的年龄、身高、体重、血压等,把这些集合到一起变成一个体检报告,就是对一个人身体情况的基本描述,而仪表板就是这个体检报告。下面一个示例是大神@hildobby的以太坊仪表板。这里我们可以看到从 Dune 数据库中提取的各种数据,以总和、时间序列图的形式呈现。

 https://dune.com/hildobby/Ethereum-Overview
 https://dune.com/hildobby/Ethereum-Overview

在 Dune 中,每个仪表板的发布都是公开的,可以查看和复制其他人构建的查询或者仪表板,方便我们学习其他大神的分析,站在巨人的肩膀上看得更远。

查询(Query)

前面提到过,仪表盘是查询的集合,如果你点击仪表盘中的任意部分,就会进入SQL查询:

来自 Ethereum 仪表板的查询编辑器的两个示例
来自 Ethereum 仪表板的查询编辑器的两个示例

我们可以看到查询界面主要由两部分组成:上方黑色区域是查询编辑器,作为输入部分,下方是结果输出区域。这里就是我们的主战场了,输入SQL代码,从Dune的数据库中摘取想要的数据。

分叉(Fork)

可以简单理解为全套复制。可以将整个仪表板或仅图表的查询全套复制到自己的帐户,这跟GitHub一样。如果你只复制SQL代码,可能会忽略到数据集的选择,运行就会出错,但是通过单击右上角的“分叉”(Fork),把所有内容都复制到一个新窗口就不会出岔,你可以再次基础上继续编辑。

下图是一个以太坊价格表的查询,对这个查询点击“分叉”按钮,界面会来到一个新的查询编辑器,之前的查询代码已经全都复制进去了。

以太坊价格, https://dune.com/queries/663019/1231425
以太坊价格, https://dune.com/queries/663019/1231425

查询编辑器(Query Editor)

下面介绍查询界面的各个元素,对应下图的数字标记:

1、查询文件位置和名称

2、数据集浏览器 - 搜索特定数据集

3、查询窗口 - 在此处输入您的 SQL 查询

4、可视化选择器 - 选择是否查看查询结果、分叉折线图或创建新的可视化

5、运行 - 运行黑色窗口的SQL代码

6、结果/可视化 - 查看查询结果或使用查询结果创建的可视化

7、保存 - 保存查询

Dune查询编辑器概览
Dune查询编辑器概览

数据集浏览器和数据类别

数据集浏览器中有六个功能区域:

  1. 链的选择(如ETH、Polygon)
  2. 搜索数据集
  3. 原始区块链数据
  4. 解码合约数据
  5. 抽象
  6. 社区提供的数据
Dune数据集浏览器概览
Dune数据集浏览器概览

数据集选择(Dataset Selection)

在数据集选择中选择要解析的链。在以太坊上就选以太坊,在Polygon上就选Polygon,如果选择“Dune Engine V2(Beta)”就能使用 Dune 的最新增强功能,如多链查询,同时性能上有10 倍的提升,让数据查询更高效。

数据集资源管理器中的数据集选择选项
数据集资源管理器中的数据集选择选项

比如选择以太坊,可以看到很多合约调用和事件列表,有的是已经总结好的一些表。

选择“1. Ethereum”时的数据集浏览器
选择“1. Ethereum”时的数据集浏览器

搜索(Search)

在搜索框中输入搜索想要找的能容,比如想搜有关池子的,就搜索“Pool”,Dune 会搜索包含该关键字的所有数据表。用V2搜索的话,会和之前的链搜索结果不同,细微的区别可以自己发掘体验一下。

“1. Ethereum”和“7. Dune Engine V2 (Beta)”搜索结果对比
“1. Ethereum”和“7. Dune Engine V2 (Beta)”搜索结果对比

原始区块链数据(Raw Blockchain Data)

在原始区块链数据这栏里可以轻松找到 Dune 支持的各种区块链的查询,在原始表里选择想要的特定表列,或者过滤筛选特定的搜索结果精确获得链上数据。

Dune Engine V2(测试版)原始区块链数据
Dune Engine V2(测试版)原始区块链数据

解码项目(Decoded Projects)

解码项目是 Dune 团队将项目拆解、标记并分门别类,以便用户使用。对于解码项目,可以过筛选项目中特定的智能合约,从智能合约中又可以获得各种数据表格,就像处理原始区块链数据一样。

Dune Engine V2(测试版)解码项目
Dune Engine V2(测试版)解码项目

抽象(Abstractions)

抽象可以理解为连接、组合各种查询和数据的自定义表。抽象可帮助用户更轻松地查询他们正在寻找的特定数据,而无需手动组合各种数据。

一般来说,抽象可以分为两大类:

  • 类别抽象:特定类别的数据
  • 项目抽象:特定项目的数据

从抽象子菜单中,我们可以看到带有类别抽象或是项目抽象标签的抽象列表。

Dune Engine V2(测试版)抽象
Dune Engine V2(测试版)抽象

社区(Community)

社区部分可以认为是抽象部分的扩展,但数据聚合由 Dune 社区成员提供。目前只有一个条目“flashbots”是因为 Dune Engine V2 刚刚发布!随着时间的推移,我们可以期待看到越来越多靠谱的社区成员构建的社区数据集。

Dune Engine V2(测试版)社区概述
Dune Engine V2(测试版)社区概述

数据集浏览器标签(Dataset Explorer Labels)

下图可以看到 Dune Engine V2 发布时在 Dune 中如何汇总数据。四个主要数据类别是:原始区块链数据、解码项目、抽象和社区;不同链分类;以及保存数据的类型。

Dune Engine V2(测试版)数据浏览器中的标签概述
Dune Engine V2(测试版)数据浏览器中的标签概述

以上就是对Dune各个部分的简单介绍了,相信能给大家留下一个简单的印象了,接下来在教大家自己动手做查询之前,我们先来学一个更重要的,怎么分叉(抄)别人的代码!

如何分叉一个查询

找个你想要的分叉的查询,点击分叉,保存查询时要先为查询命名。

保存查询弹出窗口
保存查询弹出窗口

保存完后就如下图, (1) 处查询文件位置和名称已更新,并且 (2) 输出框显示正在运行,这是 Dune 正在从他们的数据库中获取最新数据,该数据库会定期使用来自各种区块链的最新数据进行更新。

查询完成运行后,在 (3)处可以看到查询结果。

分叉一个查询
分叉一个查询

接下来对查询结果进行可视化编辑,在“查询结果”、“折线图”或“新可视化”中选择任何一个, 在(3)的设置里进行设置,命名等,2里面的结果会实时更新。这里还有一个“添加到仪表板”按钮,可以将新的查询结果或可视化结果添加到新的或现有的仪表板。

查询结果和可视化部分
查询结果和可视化部分

分叉完我下次打开Dune要如何查看我的查询呢?只要点击右上角的小圆圈就可以了。

我的查询
我的查询

查询列表包括之前保存在帐户中的所有查询。在下面的顶部屏幕截图中,我们可以看到创建的最新查询:

带有最新查询的查询列表保存在顶部
带有最新查询的查询列表保存在顶部

这就完成一个分叉并保存了一个查询!

分叉是 Dune 很牛逼的一个地方,它可以帮你通过借鉴其他大神构建过的内容,轻松快速地创建新查询,也可以组合多个分叉查询来构建自己的仪表板!

接下来将教你不通过分叉,自己动手从零开始建立一个自己的仪表板!

第 2 部分:构建查询

这节教你:

  1. 如何找到特定项目所需的正确信息
  2. 一些基本的SQL

第二部分的内容以Pool Together DeFi 协议的 Pooly NFT为主题!(快到mint截止时间了,抓紧去mint一个吧!)

Pooly NFT 铸造页面。https://mint.pooltogether.com/
Pooly NFT 铸造页面。https://mint.pooltogether.com/

我们可以在 Dune 上先尝试着搜索一下“Pooly”,ok果然可以找到一些由社区创建的 Pooly NFT 追踪器。但是我们的目标是从头开始构建一个仪表板,学习如何搜索分析链上数据!

在 Dune.com 上搜索 Pooly 的结果
在 Dune.com 上搜索 Pooly 的结果

确定要构建的查询

第一步,要构思一下这个仪表板从哪些角度来对目标项目进行分析,这里我们可以通过浏览Pooly NFT的官网来给一些参考思路。

带有资金跟踪器的 Pooly NFT 登录页面。https://mint.pooltogether.com/
带有资金跟踪器的 Pooly NFT 登录页面。https://mint.pooltogether.com/
Pooly NFT 排行榜
Pooly NFT 排行榜
Pooly NFTmint选项和供应
Pooly NFTmint选项和供应

我们可以在官网看到:

  • 筹集的资金与以 ETH 计价
  • 筹集的资金与以美元计价
  • 支持者总数(购买 Pooly 的唯一地址)
  • 排行榜包括地址、每个地址购买的 NFT 数量以及按降序排列的总 ETH
  • 三种 NFT 类型中的每一种的最大供应量和剩余供应量

我们可以将这些指标作为我们仪表板中的内容!更进一步地,我们还可以添加

  • 随时间上升的 ETH 时间序列图

接下来我们将用Dune实现这些链上信息的检索提取,并做成我们的仪表板!

寻找正确的信息

在使用Dune查找数据前,我们必须先找到正确的信息,比如目标代币或者NFT的合约地址。从PoolTogether上可以看出来,一共有三种NFT在售:

  • 支持者 – 9 个随机NFT中的 1 个,售价 0.1 ETH
  • 律师 –只有一种,售价 1 ETH
  • 评委——只有一种,售价75 ETH

那么Pooly 是通过一份合约出售所有三种 NFT,还是通过三种不同的合约出售?我们要先弄明白这点。由于这是在以太坊主网上发行的NFT,我们到Eherscan上找找Pooly相关的智能合约。打开Etherscan,输入“Pooly”查看智能合约的所有者是否在 Etherscan 注册了它们。

在 Etherscan 上搜索 Pooly
在 Etherscan 上搜索 Pooly

OK,可以发现确实有三个智能合约,可能对应于三个 NFT 集合中的每一个。此外,我们现在知道每个 Pooly 都是一个 ERC721 代币。

打开三个集合中的每一个,并通过单击将鼠标悬停在地址上时出现的复制图标来复制智能合约地址,在页面底部我们还可以看到所有最近的交易。

通过 Etherscan 查找 Pooly 合约地址。https://etherscan.io/token/0x90B3832e2F2aDe2FE382a911805B6933C056D6ed
通过 Etherscan 查找 Pooly 合约地址。https://etherscan.io/token/0x90B3832e2F2aDe2FE382a911805B6933C056D6ed

我们需要这些智能合约地址,以便从Dune中提取正确的数据,把这些准备好:

0.1 ETH Pooly 支持者:

0x90B3832e2F2aDe2FE382a911805B6933C056D6ed

1.0 ETH Pooly 律师:

0x3545192b340F50d77403DC0A64cf2b32F03d00A9

75 ETH Pooly 法官:

0x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523

准备在 Dune 中构建查询

首先,到 dune.com 并单击屏幕右上角的“新建查询”。

创建新查询
创建新查询

打开查询编辑器,开始处理我们的查询!

新建的查询窗口
新建的查询窗口

查询 1:以 ETH计算筹集的资金

首先,左上角从“7. Dune Engine V2 (Beta)”切换到“1. Ethereum”。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'
https://dune.com/queries/882266
https://dune.com/queries/882266

上面的代码是一个 SQL 查询,它解析 Dune 的数据库以获取我们请求的特定数据。可以将 Dune 的数据库想象为各种表的集合,每个表都包含您可能想要提取的特定信息。使用 SQL,你可以

  • 指定想要的数据(表中的哪一列)
  • 转换、操作数据
  • 决定从哪个表中获取数据
  • 决定是否要过滤数据

为了具体说明上述操作,让我们逐段运行上述代码。将以下代码复制到 Dune 的查询编辑器并运行它:

select * from ethereum.transactions
where "to" = '\x3545192b340F50d77403DC0A64cf2b32F03d00A9'

你会得到一个包含很多信息的大表:

使用 * 命令返回表中所有列
使用 * 命令返回表中所有列

让我们看一下 SQL 代码:

SQL代码分解
SQL代码分解

这段代码在说:

“从以太坊类别中的交易表中选择所有列,其中to列中的值为*\x3545192b340F50d77403DC0A64cf2b32F03d00A9* ”

说人话:给我看所有与 Pooly2 有关的智能合约交互记录

数据集浏览器这里已经有很多做好的表,可以直接搜索相关的表:

使用数据浏览器在“ethereum”中搜索相关表
使用数据浏览器在“ethereum”中搜索相关表

上述代码中,第三行起到过滤的作用,如果把它删去,搜索结果会返回以太坊上所有的交易记录,返回结果会非常慢,因为数据太多。显然查询越精准,运行速度越快。

因为我们只关心筹集的资金,不需要所有信息。所以让我们调整我们的代码,只抓取“value”列:

select "value" from ethereum.transactions
where "to" = '\x3545192b340F50d77403DC0A64cf2b32F03d00A9'

这样就只返回了一列值,需要注意的是合约地址这里,开头的0都需要替换成\

返回“value”列中的值
返回“value”列中的值

这些值看起来都非常大,这是因为他的计算单位是Wei而不是ETH,我们对这个值的数据处理一下就行,换算成ETH:

select "value"/1e18 from ethereum.transactions
where "to" = '\x3545192b340F50d77403DC0A64cf2b32F03d00A9'
将“value”单位转换成ETH
将“value”单位转换成ETH

这样我们看到的计价单位就是ETH,而不是Wei了。

而我们想要的是个总值,即求和,所以可以先加再转换单位,将“value”/1e18 包装在 SUM() 语句中:

select SUM("value"/1e18) from ethereum.transactions
where "to" = '\x3545192b340F50d77403DC0A64cf2b32F03d00A9'
使用 SUM() 将“value”列中的所有值合并为一个总和
使用 SUM() 将“value”列中的所有值合并为一个总和

这样我们就可以看到在 Pooly2 上花费的 ETH 总数!我们想要获得所有三个 Pooly NFT的总金额,需要把另外两个NFT的信息也加进来:

select SUM("value"/1e18) from ethereum.transactions
where "to" = '\x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or "to" = '\x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or "to" = '\x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
得到三个NFT的总金额
得到三个NFT的总金额

代码中“where”起筛选作用,“or”表示或集,但凡有一个是就算进来。

现在看到总共有 773.7 ETH 花费于所有三个 Pooly NFT上,与官网数据对比一下:

将我们的输出与 Pooly NFT 页面上的官方数据进行比较。
将我们的输出与 Pooly NFT 页面上的官方数据进行比较。

在 Pooly 网站上,我们看到 776.5 ETH ——恭喜实现目标!和我们计算的有 2.8 ETH 的差异,但是问题不大,Dune 会定期同步区块链数据,而且由于他们同步到数据库的数据集非常庞大,因此需要一些时间,数据将在接下来的一两个小时内刷新。

现在查询已经完成,设置一个计数器以便稍后在我们的仪表板上显示它。如下图,在查询结果框下方,单击新的可视化,在出现的下拉菜单中单击“计数器”。

在查询中添加一个计数器
在查询中添加一个计数器

最后,点击“添加可视化”:

向查询添加计数器可视化
向查询添加计数器可视化

出现一个计数器,向下滚动会看到各种设置,根据自己的喜好调整设置。

计数器可视化标签和标题设置
计数器可视化标签和标题设置

完成后,点击 (1)“添加到仪表板”并选择 (2)“新仪表板”,然后 (3) 为仪表板命名,点击 (4) “保存仪表板”。新仪表板将出现在您的仪表板列表中。从这里单击 (5),将可视化结果添加到的仪表板上的“添加”。

将可视化结果添加到仪表板
将可视化结果添加到仪表板

打开自己的仪表板,可以看到:

添加了可视化的仪表板
添加了可视化的仪表板

查询 2:筹集的资金以美元作为单位

这个问题分两种情况分析:

  1. 使用用于购买 NFT 的ETH资金的当前价值
  2. 使用购买时NFT时ETH的美元价值

如果我们查看 Etherscan 上的智能合约,可以看到大部分 ETH 已经从智能合约中移出,截至撰写本文时,Poly NFT 智能合约中还剩下 299.2 ETH。

Etherscan.io 上的 Pooly1/2/3 智能合约 ETH 余额
Etherscan.io 上的 Pooly1/2/3 智能合约 ETH 余额

如果我们查看之前的 Pooly 网站截图,776.5 ETH 的价值为 1,411,249 美元(1,817 美元/ETH),这暗示着 Pooly项目方可能将资金保留为 ETH,而不是美元。

很难说 Pooly 采用哪种方法,但两种计算美元价值的方法都很有趣:

  1. 告诉我们资金现在的美元价值
  2. 告诉我们购买时的预期美元价值

那两种都来计算一下吧!

查询 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 数量就是它当前的美元价值。

让我们分解这部分代码:

计算WETH价格的代码
计算WETH价格的代码
  1. 从 price.usd 表中选择“price”列
  2. 过滤筛选出“WETH”
  3. 仅查看过去 1 小时内的价格(这将显着加快查询速度)
  4. 按降序排列(最新的在前)
  5. 将查询限制为一个结果(第一个结果,即最新价格)

为了更好地理解这段代码,(1)用**“*”替换“price”**(返回所有列); (2) 仅选择第 2 到 5 行的代码,(3) 运行:

稍作调整运行
稍作调整运行

在查询结果中看到由五列组成的完整表。首先检查一下 Etherscan.io 中的WETH合约地址:

Etherscan.io 上的 WETH 智能合约
Etherscan.io 上的 WETH 智能合约

这就是Dune中搜索的数据来源,现在回到刚刚搜出来的结果:

查询结果表
查询结果表

这里几列数据,第一列“minute”,指以分钟为单位的时间列,我们设了一小时的时间限制,所以只会返回最近一小时内的数据。查询限制根据需要,可做任意更改。第二列是价格,第三列是精确到多少位小数,第四列是代币合约地址,第五列是代币简称。

好,恢复前面的代码,再次运行查询:

https://dune.com/queries/883725
https://dune.com/queries/883725

运算结果是Pooly NFT总ETH对应的当前美元价值。

类似的,给他加个计数器,向下滚动并(1)单击计数器,(2)调整数据源和(3)更改标签。

调整计数器可视化。 https://dune.com/queries/883725
调整计数器可视化。 https://dune.com/queries/883725

完成后,记得保存并添加到我们的仪表板:

保存查询并将可视化添加到我们之前的仪表板
保存查询并将可视化添加到我们之前的仪表板

添加后,它将如下图所示:

添加了第二个查询的仪表板
添加了第二个查询的仪表板

查询 2b:筹集的资金按购买时的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 汇率查询。https://dune.com/queries/884492
使用购买 NFT 时的 ETH-USD 汇率查询。https://dune.com/queries/884492

运行代码,可以看到价值是140万美元。剖析这段代码,可以分成三个部分:

将查询分为三个部分
将查询分为三个部分

第 1 部分

第一部分构建了我们将引用的第一个表,命名为“poolyTransactions”,保存来自 ethereum.transactions 的 block_time 和 value_eth(以 wei 为单位的值除以 10^18转换为ETH,我们给它一个自定义的名称value_eth)。这个表中我们过滤已知的三个 Pooly NFT地址。

这里逐行解释:

  • 第 1 行:建立个名为“poolyTransactions”的辅助表,具体包含内容如下:
  • 第 3-11 行:通过之前介绍的过滤筛选方法,选择要包含在 ethereum.transcations 表中的列
  • 第 5 行:*value/1e18 as value_eth——*这里我们将列重命名为“value_eth”,方便后面直接调用

第 2 部分

这部分逻辑还是比较简单的,价格乘以数量,从 poolyTransactions 这个表中选择数据。比较神奇的地方是调用了一个还没定义的“price”,这个price在第3部分会定义。

第 3 部分

这是我们定义两个表连接的地方。“left join”关键字允许我们这样做:

  • 第 18 行:*left join——*关键字用于表示我们想将第一个表(左表)与另一个表(右表)连接起来,左表就是第 1 节中定义的,作为基表。
  • 第 19-20 行:这里我们定义了我们想要从 price.usd中创建的表。在第 20 行中,将时间限制为“2022-05-01”之后,因为 Pooly 智能合约在 5 月份部署,不给它加个限制,价格查询要从ETH创世开始查询。
  • 第 21 行:as prices——将第 19-20 行中的筛选出来的表格命名为“prices”,以便后面调用
  • 第 22 行:on data_trunc('minute', block_time) = minute ——这是将基表(第1部分)与价格表(第 3 部分)结合起来的行。这里所说的是从我们的基表中取出列“block_time”,并将其截断为仅分钟,即删除所有其他不是分钟的数据(例如秒、毫秒等)。price.usd 表已经被截断为分钟,所以这里不需要进一步的转换。然后将prices.usd中的分钟列与我们基表中的分钟列进行匹配,从而将对应的价格从prices.usd分配到poolyTransactions中。
在数据集浏览器中查看 price.usd 表的分钟列
在数据集浏览器中查看 price.usd 表的分钟列

第三部分可能稍复杂些,我将各个部分重新组织如下图,便于理解:

left join每一步分析视图
left join每一步分析视图

(1) 创建 poolyTransactions 表1,然后 (2) 告诉 SQL 将它与另一个表2连接起来,(3) 表2是我们从 prices.usd 表中获得分钟和价格列。(4)把从 price.usd创建的表2连接到表 1poolyTransactions 上,使用以分钟为单位的时间作为映射变量,连接两表,两个表之间必须具有完全相同的一项作为桥梁。这里我们将 block_time 变量截断为分钟,在两个表之间创建匹配的时间项。通过以上操作,(5) poolyTransactions 表更新,将ETH的数量和对应当时的价格联系在了一起。

然后我们只需查询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 支持者查询
去重复的Pooly 支持者查询

COUNT会对括号内变量计数,而 DISTINCT 关键字去掉重复计算,得到的结果是 4660 个支持者。将其与 Pooly 网站上的唯一支持者进行比较,发现结果非常接近:

Pooly 实时支持者数据。https://mint.pooltogether.com/
Pooly 实时支持者数据。https://mint.pooltogether.com/

这表明我们的查询是正确的,因为 Dune 的数据库刷新和最新的区块链状态之间存在一点延迟。

同样的,更改计数器可视化并再次添加到仪表板。

调整计数器可视化设置并添加到仪表板
调整计数器可视化设置并添加到仪表板
计数器添加到仪表板
计数器添加到仪表板

查询 4a:使用 erc721.Abstraction 做个排行榜

接下来我们构建一个排行榜,内容包括地址、每个地址购买的 NFT 数量和总消费的ETH,以消费降序排列。那么我们需要的数据首先是购买者的地址,然后是购买的 NFT 数量,最后是购买所有 NFT 所花费的 ETH 数量。

Pooly 排行榜列。来源:https://mint.pooltogether.com/
Pooly 排行榜列。来源:https://mint.pooltogether.com/

我们这里查询的不是NFT持有情况,而是mint情况,可能有的用户mint完了就转走或者卖掉了,这我们不关心,我们只想知道首次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 排行榜表
Pooly 排行榜表

这个表看起来会和“筹集的资金按购买时的ETH价格来计算”这个表非常相似,我们用了相同的方法:首先在 poolyTransactions 表中收集交易数据,然后留下个共同的映射值,让它和表2连接起来。表2我们使用的是erc721."ERC721_evt_Transfer",这是Dune维护的一个抽象,用于追踪以太坊上NFT的转移。在数据集浏览器中输入“erc721”,找到“ERC721_evt_Transfer”,可以看到该表具体包含什么内容。我们选中这部分代码,选择部分执行,可以看看我们从这个表中究竟要获得什么:

部分排行榜代码运行结果
部分排行榜代码运行结果

由于我们只关心新mint的NFT,所以限制“from”为空地址。以太坊上所有NFT都是从空地址发起铸造的。通过计算每笔交易的“tokenId”数量,就可以统计出一共有多少个NFT被mint了。

细心的话你会发现or的三个限制条件是在圆括号内的,而and这个限制条件是在圆括号外的。

前三个筛选条件用圆括号括起来
前三个筛选条件用圆括号括起来

括号决定了计算和/或过滤器命令的顺序,就像在 SQL 中执行算术命令时一样。如果我们没有将前三个语句括起来,则“and”条件将仅适用于最后一个过滤器设置。这里圆括号把前三个地址限制绑在一起,和后面“from”条件限制做一个交集。如果不加括号,如下图,那么“and”这个限制条件就会和最后一行“or”绑在一起,和前两个“or”无关。

不使用括号
不使用括号

我们使用“COUNT”命令计算了NFT数量,怎么将它和对应的被统计的地址联系在一起呢?这里使用了“group by”命令,表示我们要把count结果汇总到哪一列上。这里我们汇总到第一列,即“evt_tx_hash”。

之前说过,两个表要连接在一起,必须要有一个共同的映射,也就是要有重叠部分。这里两个表的重叠部分就是交易哈希值。最终,我们把erc721."ERC721_evt_Transfer"这个表(命名为nfts)和poolyTransactions表连接在了一起,输出的是一个表格,包括购买者地址,总购买NFT数量以及总消费ETH的金额。

排行榜部分代码运行
排行榜部分代码运行

最后我们还给了个命令“ORDER BY 3 desc”,意思是按第三列排序,也就是按消费ETH排序,可以一眼看到谁开销最多。

“ORDER BY 3 desc”命令
“ORDER BY 3 desc”命令

OK!排行榜做完了,和Pooly NFT网站上比一比:

将 Dune 查询排行榜与 Pooly 网站排行榜进行比较
将 Dune 查询排行榜与 Pooly 网站排行榜进行比较

老样子,还是由于同步时间问题有些许区别,但从这个列表中我们可以看到,一些地址、购买的 NFT 和总 ETH 花费的数字确实相同。成功!同样不要忘记把结果添加到仪表板!

查询 4b:使用 poolysupporter. Decoded表做排行榜

除了使用 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

方法与上面相同。小区别是不用通过空地址来判断mint的情况,在解码表里直接看谁调用了mint函数就可以。

使用poolysupporters,而不是erc721
使用poolysupporters,而不是erc721

poolysupporter 数据集允许我们进行更具体和详细的​​查询,因为我们可以参考特定的合约调用。将两个结果对比一下:

使用erc721和poolysupporter查询结果比较
使用erc721和poolysupporter查询结果比较

果然一样!

查询 5:每个 NFT的最大供应量和剩余供应量

在查询 4 ​​中,我们使用了 poolysupporter 函数,在数据集资源管理器中搜索 pooly 时,你可能注意到了一个名为“PoolyNFT_call_maxNFT”的函数。

poolysupporters.PoolyNFT_call_maxNFT 函数
poolysupporters.PoolyNFT_call_maxNFT 函数

望文生义,你会觉得这个函数能直接检索NFT的最大可mint量。

使用 poolysupporters.PoolyNFT_call_maxNFT 没有查询结果
使用 poolysupporters.PoolyNFT_call_maxNFT 没有查询结果

很可惜,没有查询结果,从Etherscan上来看,这个函数是一个可读函数,调用的时候是没有链上记录的:

maxNFT 是一个可读函数,不会在区块链上留下任何记录
maxNFT 是一个可读函数,不会在区块链上留下任何记录

maxNFT 变量是在合约部署者部署 Pooly Supporter 智能合约时设置的,但这个智能合约尚未解码,无法直接从链上数据读取出最大供应量,这里我们只能从官方获取消息,手动填入最大供应量:

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 供应查询。https://dune.com/queries/887355
Pooly NFT 供应查询。https://dune.com/queries/887355

手动将数字添加到 SQL 中的特定表条目并不简单,这里用了一些小技巧。

首先再次将两个表连接起来,然后用一些case when的语句来输出特定信息。具体分析,我们把代码拆解为4个部分:

查询的分解
查询的分解

第 1 部分

先定义了一个名为poolyContracts”的表,按三个NFT的每个合约地址,计算了tokenId个数, 也就是每种NFTmint了多少个,通过group by 1 把他们对应起来了。

poolyContracts 表
poolyContracts 表

第 2 部分

把erc721这个表中,三个NFT mint的事件摘出来。不使用group by 1的话就会每mint一个NFT,就报一遍这个NFT的名字(合约地址),使用group by 1,就只会显示一次,重复不显示。

不使用“group by 1”命令调用一次就返回一次
不使用“group by 1”命令调用一次就返回一次
使用“group by 1”命令返回每个合约地址的 1 个
使用“group by 1”命令返回每个合约地址的 1 个

把“contract_address”这一栏命名为maxNFT_Supply,方便后面用于两个表的连接。

第 3 部分

这部分是比较神奇的地方,这个连接起来的表,有四个变量:

  1. contract_address
  2. nfts_purchased
  3. maxNFT_Supply
  4. maxNFT_Supply

我们这里相当于把一份数据拷贝成三份,每份后面都会对应一个操作。实际上1,3,4是一样的数据,3和4甚至名字都一样,但是他们分别来自两个表里,不会冲突。

选择1,3,4,分别嵌入CASE WHEN的语句,我们不能用CASE WHEN对一个数据集做三次申明,所以前面拷贝成了三份。

 nft_supply结果
nft_supply结果

第一个CASE,把三个NFT地址替换成对应的NFT名称;第二个CASE,手动标上每个NFT的最大供应量;第三个CASE,计算了三个NFT的剩余量百分比。

需要注意的是,在进行运算时运算的数字要包含一位小数,否则SQL会以为我们想要返回整数,我们可以添加个“.0”,告诉SQL我们要返回一个精确到一位小数的结果。

第 4 部分

最后给他按供应排个序,也就是按第三列数据降序排列。

按 nft_supply 降序排序后的全表
按 nft_supply 降序排序后的全表

ok,这个查询就做完了,添加到仪表板中。

将表添加到仪表板
将表添加到仪表板

查询 6:时间序列图——募集金额随时间变化情况

最后一个查询,我们来关心一个项目方募集的金额随时间的变化情况。

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 的累计
随着时间的推移,ETH 的累计

这段代码不长,用了一个“over”的手法,这是求累积值的一个重要命令。

在这个查询中我们以分钟为间隔将 ETH 值(即value/ 1e18 )按block_time累加,按时间升序排列,并命名为cumu_value_eth。

sum(value/1e18) over (order by date_trunc('minute', block_time) asc) as cu

另外在末尾添加了个限制,让查询时间不超过2022.6.25,这是Pooly筹款活动结束的时间。我们的这个查询就只会显示活动时间内的金额变化。如何创建一个面积图:(1) 单击“新建可视化”,然后在 (2) 下拉菜单中选择“面积图”,最后 (3) 单击“添加可视化”。

创建面积图可视化
创建面积图可视化

这样面积图就会出现!并带有 Dune 默认的相关设置。

面积图可视化设置并添加到仪表板
面积图可视化设置并添加到仪表板

在下面的设置自由发挥,完成后保存到仪表板中不要忘了!

至此我们就完成了Pooly NFT看板的绝大部分内容了!最后来一点美观的整理!

第 3 部分:清理仪表板

我们构建了很多查询,并直接将它们添加到我们的仪表板中。好吧,让我们来看看它的样子。将最后一个图表添加到仪表板后,只需单击仪表板名称即可。

添加可视化后,单击仪表板的名称将其打开
添加可视化后,单击仪表板的名称将其打开

先来看看现在啥样:

整理前的仪表板
整理前的仪表板

其实我觉得这样已经挺棒了^_^

追求更美观的话点击右上角编辑

单击右上角的编辑按钮以编辑仪表板格式
单击右上角的编辑按钮以编辑仪表板格式

然后就可以随意地拖拉每个元素,任意放大缩小,这都很简单,自由发挥吧!

支持拖放和调整大小
支持拖放和调整大小

再加点小图片,美化一下……

成品!
成品!

感觉又专业又好看!

结束语

Dune Analytics 是一个强大的链上数据分析平台,而且完全免费,在追求数据自由的Web3,每个人都可以成为链上数据分析师,这对每个人来说都不遥远,完全可以做到!

参考链接:

Subscribe to LVIS
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.
Author Address
0xa741296A1E9DDc3…C6225cFb5F6693a
Content Digest
iVzr5bGcGKKCzuv…2qWfqfIHwmCXDI4