# Dune基础入门-part2

By [sherry](https://paragraph.com/@sherry-3) · 2022-07-09

---

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

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

![（https://etherscan.io/tx/0x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6）](https://storage.googleapis.com/papyrus_images/13e4ad25fad1054bdc140f98c51cf455d440669ec5d57acaea1867a862d63872.png)

（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.](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://storage.googleapis.com/papyrus_images/73a6d1bd30e7c5eda8821deba3323756e7e625d54ce9da2608232fe20fee0f3d.png)

（https://etherscan.io/tx/0x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6#eventlog）

    select data, bytea2numeric("data") from ethereum."logs"  where tx_hash='\x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6'
    

![](https://storage.googleapis.com/papyrus_images/933b73b2cfd89dee5fa2143b35e297475e08a3329e10a130ccdbfcbddd1776e5.png)

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

![](https://storage.googleapis.com/papyrus_images/271b6d549fbc23f3e798c3f8c13048b8daa65a0fd2540a78c6246e214354b697.png)

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

![](https://storage.googleapis.com/papyrus_images/10a972be4b2f35c9708294cfae6fe6f67de2aac5f1b3332e90d8d97aa2eecfce.png)

因此我们在转换类型后的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`
    

![](https://storage.googleapis.com/papyrus_images/3dac0e30f98ec9257494437ddda240466c4c5e0e1c96c2de58949225678d621e.png)

首先我们看一下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](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](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'
    

![](https://storage.googleapis.com/papyrus_images/b76f7005fda37b68e7ac179aa9725aa530dfccd9ebf8d6be6c0f17a71408d2ac.png)

我们使用第二个小补丁中的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
    

![](https://storage.googleapis.com/papyrus_images/bb3dbd12c42f5565e234555e57d6e60dd8fc33749e171555d640b6c73ae9a807.png)

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

---

*Originally published on [sherry](https://paragraph.com/@sherry-3/dune-part2)*
