本文翻译自 0xPhillan;
Dune是一款非常强大的、面向大众的、完全免费的区块链链上数据分析工具,你可以通过SQL查询Dune公开的数据库,获得链上数据,并根据你的奇思妙想定制一个分析仪表板。Dune帮我们收集归类好了链上数据,我们只要学习一些简单的SQL,就可以成长为链上数据分析师啦!
本教程将手把手带你从头开始,以Pooly NFT为例,做一个NFT分析板!内容包括:项目募集资金(ETH本位和U本位),支持者数量(去重复的唯一地址),消费排行榜,剩余供应量百分比,总募集资金随时间的变化等,适用于调研和分析新开放mint的NFT。
在本指南中,你将学到:
Dune的基本介绍和交互界面
如何使用SQL建立你自己的查询并做成可视化图表
如何构建一个汇集各个查询的仪表板
Pooly NFT系列构建查询和仪表盘:
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页面
仪表板(Dashborad)
仪表板是一系列查询的组合。查询是一个个具体的信息检索,比如查询某个人的年龄、身高、体重、血压等,把这些集合到一起变成一个体检报告,就是对一个人身体情况的基本描述,而仪表板就是这个体检报告。下面一个示例是大神 hildobby的以太坊仪表板。这里我们可以看到从Dune数据库中提取的各种数据,以总和、时间序列图的形式呈现。
https://dune.com/hildobby/Ethereum-Overview
在Dune中,每个仪表板的发布都是公开的,可以查看和复制其他人构建的查询或者仪表板,方便我们学习其他大神的分析,站在巨人的肩膀上看得更远。
查询(Query)
前面提到过,仪表盘是查询的集合,如果你点击仪表盘中的任意部分,就会进入SQL查询:
来自Ethereum仪表板的查询编辑器的两个示例
我们可以看到查询界面主要由两部分组成:上方黑色区域是查询编辑器,作为输入部分,下方是结果输出区域。这里就是我们的主战场了,输入SQL代码,从Dune的数据库中摘取想要的数据。
分叉(Fork)
可以简单理解为全套复制。可以将整个仪表板或仅图表的查询全套复制到自己的帐户,这跟GitHub一样。如果你只复制SQL代码,可能会忽略到数据集的选择,运行就会出错,但是通过单击右上角的“分叉”(Fork),把所有内容都复制到一个新窗口就不会出岔,你可以再次基础上继续编辑。
下图是一个以太坊价格表的查询,对这个查询点击“分叉”按钮,界面会来到一个新的查询编辑器,之前的查询代码已经全都复制进去了。
以太坊价格,
https://dune.com/queries/663019/1231425
查询编辑器(Query Editor)
下面介绍查询界面的各个元素,对应下图的数字标记:
1、查询文件位置和名称
2、数据集浏览器-搜索特定数据集
3、查询窗口-在此处输入您的SQL查询
4、可视化选择器-选择是否查看查询结果、分叉折线图或创建新的可视化
5、运行-运行黑色窗口的SQL代码
6、结果/可视化-查看查询结果或使用查询结果创建的可视化
7、保存-保存查询
Dune查询编辑器概览
数据集浏览器和数据类别
数据集浏览器中有六个功能区域:
1、链的选择(如ETH、Polygon)
2、搜索数据集
3、原始区块链数据
4、解码合约数据
5、抽象
6、社区提供的数据
Dune数据集浏览器概览
数据集选择(Dataset Selection)
在数据集选择中选择要解析的链。在以太坊上就选以太坊,在Polygon上就选Polygon,如果选择“Dune Engine V2(Beta)”就能使用Dune的最新增强功能,如多链查询,同时性能上有10倍的提升,让数据查询更高效。
数据集资源管理器中的数据集选择选项
比如选择以太坊,可以看到很多合约调用和事件列表,有的是已经总结好的一些表。
选择“1.Ethereum”时的数据集浏览器
搜索(Search)
在搜索框中输入搜索想要找的能容,比如想搜有关池子的,就搜索“Pool”,Dune会搜索包含该关键字的所有数据表。用V2搜索的话,会和之前的链搜索结果不同,细微的区别可以自己发掘体验一下。
“1.Ethereum”和“7.Dune Engine V2(Beta)”搜索结果对比
原始区块链数据(Raw Blockchain Data)
在原始区块链数据这栏里可以轻松找到Dune支持的各种区块链的查询,在原始表里选择想要的特定表列,或者过滤筛选特定的搜索结果精确获得链上数据。
Dune Engine V2(测试版)原始区块链数据
解码项目(Decoded Projects)
解码项目是Dune团队将项目拆解、标记并分门别类,以便用户使用。对于解码项目,可以过筛选项目中特定的智能合约,从智能合约中又可以获得各种数据表格,就像处理原始区块链数据一样。
Dune Engine V2(测试版)解码项目
抽象(Abstractions)
抽象可以理解为连接、组合各种查询和数据的自定义表。抽象可帮助用户更轻松地查询他们正在寻找的特定数据,而无需手动组合各种数据。
一般来说,抽象可以分为两大类:
类别抽象:特定类别的数据
项目抽象:特定项目的数据
从抽象子菜单中,我们可以看到带有类别抽象或是项目抽象标签的抽象列表。
Dune Engine V2(测试版)抽象
社区(Community)
社区部分可以认为是抽象部分的扩展,但数据聚合由Dune社区成员提供。目前只有一个条目“flashbots”是因为Dune Engine V2刚刚发布!随着时间的推移,我们可以期待看到越来越多靠谱的社区成员构建的社区数据集。
Dune Engine V2(测试版)社区概述
数据集浏览器标签(Dataset Explorer Labels)
下图可以看到Dune Engine V2发布时在Dune中如何汇总数据。四个主要数据类别是:原始区块链数据、解码项目、抽象和社区;不同链分类;以及保存数据的类型。
Dune Engine V2(测试版)数据浏览器中的标签概述
以上就是对Dune各个部分的简单介绍了,相信能给大家留下一个简单的印象了,接下来在教大家自己动手做查询之前,我们先来学一个更重要的,怎么分叉(抄)别人的代码!
如何分叉一个查询
找个你想要的分叉的查询,点击分叉,保存查询时要先为查询命名。
保存查询弹出窗口
保存完后就如下图,(1)处查询文件位置和名称已更新,并且(2)输出框显示正在运行,这是Dune正在从他们的数据库中获取最新数据,该数据库会定期使用来自各种区块链的最新数据进行更新。
查询完成运行后,在(3)处可以看到查询结果。
分叉一个查询
接下来对查询结果进行可视化编辑,在“查询结果”、“折线图”或“新可视化”中选择任何一个,在(3)的设置里进行设置,命名等,2里面的结果会实时更新。这里还有一个“添加到仪表板”按钮,可以将新的查询结果或可视化结果添加到新的或现有的仪表板。
查询结果和可视化部分
分叉完我下次打开Dune要如何查看我的查询呢?只要点击右上角的小圆圈就可以了。
我的查询
查询列表包括之前保存在帐户中的所有查询。在下面的顶部屏幕截图中,我们可以看到创建的最新查询:
带有最新查询的查询列表保存在顶部
这就完成一个分叉并保存了一个查询!
分叉是Dune很牛逼的一个地方,它可以帮你通过借鉴其他大神构建过的内容,轻松快速地创建新查询,也可以组合多个分叉查询来构建自己的仪表板!
接下来将教你不通过分叉,自己动手从零开始建立一个自己的仪表板!
第2部分:构建查询
这节教你:
如何找到特定项目所需的正确信息
一些基本的SQL
第二部分的内容以Pool Together DeFi协议的Pooly NFT为主题!(快到mint截止时间了,抓紧去mint一个吧!)
Pooly NFT铸造页面。https://mint.pooltogether.com/
我们可以在Dune上先尝试着搜索一下“Pooly”,ok果然可以找到一些由社区创建的Pooly NFT追踪器。但是我们的目标是从头开始构建一个仪表板,学习如何搜索分析链上数据!
在Dune.com上搜索Pooly的结果
确定要构建的查询
第一步,要构思一下这个仪表板从哪些角度来对目标项目进行分析,这里我们可以通过浏览Pooly NFT的官网来给一些参考思路。
带有资金跟踪器的Pooly NFT登录页面。https://mint.pooltogether.com/
Pooly NFT排行榜
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
OK,可以发现确实有三个智能合约,可能对应于三个NFT集合中的每一个。此外,我们现在知道每个Pooly都是一个ERC721代币。
打开三个集合中的每一个,并通过单击将鼠标悬停在地址上时出现的复制图标来复制智能合约地址,在页面底部我们还可以看到所有最近的交易。
通过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
上面的代码是一个SQL查询,它解析Dune的数据库以获取我们请求的特定数据。可以将Dune的数据库想象为各种表的集合,每个表都包含您可能想要提取的特定信息。使用SQL,你可以
指定想要的数据(表中的哪一列)
转换、操作数据
决定从哪个表中获取数据
决定是否要过滤数据
为了具体说明上述操作,让我们逐段运行上述代码。将以下代码复制到Dune的查询编辑器并运行它:
select * from ethereum.transactions
where "to" = '\x3545192b340F50d77403DC0A64cf2b32F03d00A9'你会得到一个包含很多信息的大表:
使用*命令返回表中所有列
让我们看一下SQL代码:
SQL代码分解
这段代码在说:
“从以太坊类别中的交易表中选择所有列,其中to列中的值为*x3545192b340F50d77403DC0A64cf2b32F03d00A9*”
说人话:给我看所有与Pooly2有关的智能合约交互记录
数据集浏览器这里已经有很多做好的表,可以直接搜索相关的表:
使用数据浏览器在“ethereum”中搜索相关表
上述代码中,第三行起到过滤的作用,如果把它删去,搜索结果会返回以太坊上所有的交易记录,返回结果会非常慢,因为数据太多。显然查询越精准,运行速度越快。
因为我们只关心筹集的资金,不需要所有信息。所以让我们调整我们的代码,只抓取“value”列:
select "value" from ethereum.transactions
where "to" = '\x3545192b340F50d77403DC0A64cf2b32F03d00A9'这样就只返回了一列值,需要注意的是合约地址这里,开头的0都需要替换成\
返回“value”列中的值
这些值看起来都非常大,这是因为他的计算单位是Wei而不是ETH,我们对这个值的数据处理一下就行,换算成ETH:
select"value"/1e18 from ethereum.transactions
where"to"='x3545192b340F50d77403DC0A64cf2b32F03d00A9'
将“value”单位转换成ETH
这样我们看到的计价单位就是ETH,而不是Wei了。
而我们想要的是个总值,即求和,所以可以先加再转换单位,将“value”/1e18包装在SUM()语句中:
select SUM("value"/1e18)from ethereum.transactions
where"to"='x3545192b340F50d77403DC0A64cf2b32F03d00A9'
使用SUM()将“value”列中的所有值合并为一个总和
这样我们就可以看到在Pooly2上花费的ETH总数!我们想要获得所有三个Pooly NFT的总金额,需要把另外两个NFT的信息也加进来:
select SUM("value"/1e18)from ethereum.transactions
where"to"='x90B3832e2F2aDe2FE382a911805B6933C056D6ed'
or"to"='x3545192b340F50d77403DC0A64cf2b32F03d00A9'
or"to"='x5663e3E096f1743e77B8F71b5DE0CF9Dfd058523'
得到三个NFT的总金额
代码中“where”起筛选作用,“or”表示或集,但凡有一个是就算进来。
现在看到总共有773.7 ETH花费于所有三个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余额
如果我们查看之前的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价格的代码
1、从price.usd表中选择“price”列
2、过滤筛选出“WETH”
3、仅查看过去1小时内的价格(这将显着加快查询速度)
4、按降序排列(最新的在前)
5、将查询限制为一个结果(第一个结果,即最新价格)
为了更好地理解这段代码,(1)用**“*”替换“price”**(返回所有列);(2)仅选择第2到5行的代码,(3)运行:
稍作调整运行
在查询结果中看到由五列组成的完整表。首先检查一下Etherscan.io中的WETH合约地址:
Etherscan.io上的WETH智能合约
这就是Dune中搜索的数据来源,现在回到刚刚搜出来的结果:
查询结果表
这里几列数据,第一列“minute”,指以分钟为单位的时间列,我们设了一小时的时间限制,所以只会返回最近一小时内的数据。查询限制根据需要,可做任意更改。第二列是价格,第三列是精确到多少位小数,第四列是代币合约地址,第五列是代币简称。
好,恢复前面的代码,再次运行查询:
https://dune.com/queries/883725
运算结果是Pooly NFT总ETH对应的当前美元价值。
类似的,给他加个计数器,向下滚动并(1)单击计数器,(2)调整数据源和(3)更改标签。
调整计数器可视化。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
运行代码,可以看到价值是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表的分钟列
第三部分可能稍复杂些,我将各个部分重新组织如下图,便于理解:
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支持者查询
COUNT会对括号内变量计数,而DISTINCT关键字去掉重复计算,得到的结果是4660个支持者。将其与Pooly网站上的唯一支持者进行比较,发现结果非常接近:
Pooly实时支持者数据。https://mint.pooltogether.com/
这表明我们的查询是正确的,因为Dune的数据库刷新和最新的区块链状态之间存在一点延迟。
同样的,更改计数器可视化并再次添加到仪表板。
调整计数器可视化设置并添加到仪表板
计数器添加到仪表板
查询4a:使用erc721.Abstraction做个排行榜
接下来我们构建一个排行榜,内容包括地址、每个地址购买的NFT数量和总消费的ETH,以消费降序排列。那么我们需要的数据首先是购买者的地址,然后是购买的NFT数量,最后是购买所有NFT所花费的ETH数量。
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 descPooly排行榜表
这个表看起来会和“筹集的资金按购买时的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”命令
OK!排行榜做完了,和Pooly NFT网站上比一比:
将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
poolysupporter数据集允许我们进行更具体和详细的查询,因为我们可以参考特定的合约调用。将两个结果对比一下:
使用erc721和poolysupporter查询结果比较
果然一样!
查询5:每个NFT的最大供应量和剩余供应量
在查询4中,我们使用了poolysupporter函数,在数据集资源管理器中搜索pooly时,你可能注意到了一个名为“PoolyNFT_call_maxNFT”的函数。
poolysupporters.PoolyNFT_call_maxNFT函数
望文生义,你会觉得这个函数能直接检索NFT的最大可mint量。
使用 poolysupporters.PoolyNFT_call_maxNFT 没有查询结果
很可惜,没有查询结果,从Etherscan上来看,这个函数是一个可读函数,调用的时候是没有链上记录的:
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
手动将数字添加到SQL中的特定表条目并不简单,这里用了一些小技巧。
首先再次将两个表连接起来,然后用一些case when的语句来输出特定信息。具体分析,我们把代码拆解为4个部分:
查询的分解
第1部分
先定义了一个名为poolyContracts”的表,按三个NFT的每个合约地址,计算了tokenId个数,也就是每种NFTmint了多少个,通过group by 1把他们对应起来了。
poolyContracts表
第2部分
把erc721这个表中,三个NFT mint的事件摘出来。不使用group by 1的话就会每mint一个NFT,就报一遍这个NFT的名字(合约地址),使用group by 1,就只会显示一次,重复不显示。
不使用“group by 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结果
第一个CASE,把三个NFT地址替换成对应的NFT名称;第二个CASE,手动标上每个NFT的最大供应量;第三个CASE,计算了三个NFT的剩余量百分比。
需要注意的是,在进行运算时运算的数字要包含一位小数,否则SQL会以为我们想要返回整数,我们可以添加个“.0”,告诉SQL我们要返回一个精确到一位小数的结果。
第4部分
最后给他按供应排个序,也就是按第三列数据降序排列。
按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的累计
这段代码不长,用了一个“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,每个人都可以成为链上数据分析师,这对每个人来说都不遥远,完全可以做到!
往·期·回·顾
三箭资本(3AC)流动性枯竭背后,清算指标对机构意味着什么?
百亿加密借贷平台Celsius深陷危机,CEL游戏结束了吗?
telegram漏洞致百万KOL内幕曝光?真实性如何?
必查客导航
必查客官网
https://www.bitchecker.com/
客户端下载
https://www.bitchecker.com/downloads/index.html
电报
https://t.me/+s02avqXG2Hw0MTU1
推特
https://twitter.com/BitCheckerLTD
Medium
https://medium.com/@BitChecker
https://www.facebook.com/BCGlobal.CN
点个在看你最好看