Cover photo

Dune基础入门-part2

我认为作为一名想进入web3行业的数据分析师,掌握一些区块链的基础知识很有必要。比如能看懂etherscan上记录的数据的含义、合约的调用等等,对我们理解数据是至关重要的~因此这篇文章打算对part1中一些没有讲的特别清楚的细节问题打一些小补丁~

我们还是以在ethereum链上转移USDT为例,结合etherscan和dune的数据表来理解数据,顺便介绍一些sql的常用函数:

(https://etherscan.io/tx/0x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6)
(https://etherscan.io/tx/0x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6)
  • 第一个小补丁- etherscan数据解析

在上面的交易中,aa40给b632转了400USDT,转账过程调用了USDT的合约1e37。Transaction Hash对每笔交易来说是唯一的,简单理解就是唯一ID。Status记录的是这笔交易的状态。Transaction Fee(0.001314332814012091 Ether)=Gas price(20.797392503 Gwei)*gas used by transaction(63197) (p.s. 1 Ether=10^9 Gwei)。Gas Limit是用户最多愿意为这笔交易支付的gas fee,如果超过的话该笔交易就会失败。Usage by Txn表示的是该笔交易实际使用的gas fee。Gas Fees中Base是由整个eth网络决定而不是人为决定的(具体计算规则:

https://www.blocknative.com/blog/eip-1559-fees#:~:text=The%20New%20Terminology%20of%20EIP%2D1559%20Transactions&text=Instead%20of%20a%20singular%20Gas,is%20paid%20directly%20to%20miners.

),max是用户最多愿意支付的,max priority通常被称为矿工小费,是一种可选择的额外费用,直接支付给矿工,以激励他们将你的交易优先打包在区块中。Base Fee是被燃烧掉了(18.797392503 Gwei*63197/10^9=0.001187938814012091 Ether),矿工拿到的费用就是我们支付的max priority fee。

  • 第二个小补丁- 链上存储数值精度问题

    这张图的数据是存在ethereum."logs"表中~

(https://etherscan.io/tx/0x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6#eventlog)
(https://etherscan.io/tx/0x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6#eventlog)
select data, bytea2numeric("data") from ethereum."logs"  where tx_hash='\x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6'
post image

上面的图可以看出,ethereum."logs"表中存的data是byte数据类型,在转换成numeric数据类型后是400000000。这里为什么是400000000而不是我们实际转移的400USDT呢?是因为链上不支持小数存储,所以每一个与数值有关的存储(比如代币数量,lp数量等等)其实都是有一个最小单位的,比如eth的最小单位是wei,1 eth=10^18wei。其他代币的最小单位可以在它的合约中找到,USDT的精度就是10^6。

post image
select data, bytea2numeric("data")/1e6 as usdt_data from ethereum."logs" where tx_hash='\x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6'
post image

因此我们在转换类型后的data数据上除以它的精度就能得到实际转移的USDT数量。

关于每个代币的decimal精度值,dune已经将数据存在了erc20.tokens表中。

  • 第三个小补丁-Transaction Receipt Event Logs(Dune中ethereum.logs数据表)解析

    我们先使用logs数据查询eth链上USDT代币的ERC20传输记录:

  • select concat('\x',RIGHT(encode("topic2",'hex'),40)) as sender, concat('\x',RIGHT(encode("topic3",'hex'),40)) as reveiver, bytea2numeric(data)/1e6 AS value from ethereum."logs" where contract_address = '\xdac17f958d2ee523a2206206994597c13d831ec7' and topic1='\xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' limit 10

post image

首先我们看一下ERC20合约发出的Transfer事件的结构:

event Transfer(address indexed from, address indexed to, uint value);

在代币进行传输的过程中,logs提供了合约地址,最多四个topic以及一些任意长度的二进制数据(

https://docs.soliditylang.org/en/v0.8.15/abi-spec.html?highlight=events#events

):

contract_address: ERC20代币的合约地址

topic1: keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")") 简单理解就是事件名+参数的keccak256哈希值。对于我们这个事件,topic1就是0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef。(一些常用事件的topic:

https://raw.githubusercontent.com/DAppBoard/dappboard-ethereum-metadata/master/events/events.csv

topic2:event的第一个参数from

topic3:event的第二个参数to

data:event的raw data,转移的代币数量。

其实Dune已经提供了很多解码之后的数据,不需要我们再手动处理了。对于上面的ERC20代币的转移,这张表erc20."ERC20_evt_Transfer”可以直接查询~

select "from","to",value as value from erc20."ERC20_evt_Transfer" where evt_tx_hash = '\x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6'
post image

我们使用第二个小补丁中的ERC20代币精度表erc20.tokens和erc20."ERC20_evt_Transfer"表,就可以得到实际转移的value值了~

select a."from", a."to",a.value/10^(b."decimals") as value
from
(
select "from","to",value,contract_address
from erc20."ERC20_evt_Transfer"
where evt_tx_hash = '\x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6'
) a
left join erc20.tokens b
on a.contract_address = b.contract_address
post image
  • 总结

    作为一名数据分析师,我认为理解数据是第一步,要先知道数据是怎样产生的。因为要做的是链上数据分析,重点还是理解区块链上数据产生的原理,再将其转换成web2大数据的一套完整的知识体系,会让我们的数据分析做的更好~