# Dune基础入门-part2 **Published by:** [sherry](https://paragraph.com/@sherry-3/) **Published on:** 2022-07-09 **URL:** https://paragraph.com/@sherry-3/dune-part2 ## Content 我认为作为一名想进入web3行业的数据分析师,掌握一些区块链的基础知识很有必要。比如能看懂etherscan上记录的数据的含义、合约的调用等等,对我们理解数据是至关重要的~因此这篇文章打算对part1中一些没有讲的特别清楚的细节问题打一些小补丁~ 我们还是以在ethereum链上转移USDT为例,结合etherscan和dune的数据表来理解数据,顺便介绍一些sql的常用函数:(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)select data, bytea2numeric("data") from ethereum."logs" where tx_hash='\x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6' 上面的图可以看出,ethereum."logs"表中存的data是byte数据类型,在转换成numeric数据类型后是400000000。这里为什么是400000000而不是我们实际转移的400USDT呢?是因为链上不支持小数存储,所以每一个与数值有关的存储(比如代币数量,lp数量等等)其实都是有一个最小单位的,比如eth的最小单位是wei,1 eth=10^18wei。其他代币的最小单位可以在它的合约中找到,USDT的精度就是10^6。select data, bytea2numeric("data")/1e6 as usdt_data from ethereum."logs" where tx_hash='\x09ecb3cbf332b30e432307624ed463d3639cf2b8c5b1108099b46a2f585f6ec6' 因此我们在转换类型后的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首先我们看一下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' 我们使用第二个小补丁中的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 总结 作为一名数据分析师,我认为理解数据是第一步,要先知道数据是怎样产生的。因为要做的是链上数据分析,重点还是理解区块链上数据产生的原理,再将其转换成web2大数据的一套完整的知识体系,会让我们的数据分析做的更好~ ## Publication Information - [sherry](https://paragraph.com/@sherry-3/): Publication homepage - [All Posts](https://paragraph.com/@sherry-3/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@sherry-3): Subscribe to updates