原标题:《解码以太坊智能合约数据》
正如我们在之前的文章中所讨论的,智能合约交易类似于智能合约驱动的web3应用程序中的后端API调用。每个智能合约交易和结果应用程序状态更改的细节都记录在称为交易、调用和日志的数据元素中。交易数据元素表示用户发起的函数调用(更准确地说是EOA),调用数据元素表示智能合约在交易中发起的其他函数调用,而日志数据元素表示交易执行期间发生的事件。
使用这些数据元素,可以非常精细地描述由于交易而在应用程序和区块链上发生的状态更改。当对一个去中心化的web3应用程序的所有交易、跟踪和日志进行汇总分析时,可以提供用户群及其在产品中的活动的整体和深刻的观点。然而,这样做是有挑战性的,因为许多显著的细节都被记录为十六进制编码字符串。例如,在以太坊网络上使用Uniswap交换一对代币的交易(该特定记录可以在Etherscan上查看):
如果在Etherscan上查看交易,就可能已经注意到,它已经解码了这个原始记录,并提供了很好的上下文来帮助我们理解交易细节。虽然这非常有帮助,但它并不是为了回答那些需要转换和汇总数据的问题,例如,所有Uniswap用户的总交易价值是多少,或者Uniswap用户3个月的留存率是多少。为了回答这些问题,我们需要能够收集所有记录,对其进行解码,并批量处理相关细节。我们将在接下来的文章中详细介绍如何做到这一点。
解码交易
如果我们检查原始数据记录,我们可以看到交易是由EOA发起的0x3c02cebb49f6e8f1fc96158099ffa064bbfee38b,发送到与Uniswapv2路由器关联的智能合约地址0x7a250d5630b4cf539739df2c5dacb4c659f2488d。但是,相关请求详细信息在input字段中被编码为一个长十六进制字符串。
在我们讨论如何从input中提取人类可读的数据之前,先谈谈它的结构将会很有指导意义。前导0x表示该字符串是十六进制的,因此它与实际的信息内容无关。之后,每2个十六进制字符代表一个字节。前四个字节,在本例中是38ed1739,是被调用函数的哈希签名。其余字节是传递给函数的参数的哈希值。这意味着输入字符串的长度可以根据所调用的特定函数和所需的参数而变化。
为了解码这个十六进制字符串,我们需要引用应用程序二进制接口或ABI。这是一个json对象,包含给定智能合约的所有函数和事件接口定义(即名称和类型)。ABI的功能是查找将交易数据中的散列签名与人类可读的接口定义进行匹配。ABI示例如下所示:
Uniswapv2路由器ABI的部分视图
ABI通常可以在像Etherscan这样的区块浏览器上找到,以及合约源代码。这是Uniswapv2路由器合约的ABI链接。
一旦我们有了ABI,我们就可以编写来解码交易:
importtracebackimportsysfromfunctoolsimportlru_cachefromweb3importWeb3fromweb3.autoimportw3fromweb3.contractimportContractfromweb3._utils.eventsimportget_event_datafromweb3._utils.abiimportexclude_indexed_event_inputs,get_abi_input_names,get_indexed_event_inputs,normalize_event_input_typesfromweb3.exceptionsimportMismatchedABI,LogTopicErrorfromweb3.typesimportABIEventfrometh_utilsimportevent_abi_to_log_topic,to_hexfromhexbytesimportHexBytesimportjsonimportredefdecode_tuple(t,target_field):output=dict()foriinrange(len(t)):ifisinstance(t,(bytes,bytearray)):output]=to_hex(t)elifisinstance(t,(tuple)):output]=decode_tuple(t,target_field)else:output]=treturnoutputdefdecode_list_tuple(l,target_field):output=lforiinrange(len(l)):output=decode_tuple(l,target_field)returnoutputdefdecode_list(l):output=lforiinrange(len(l)):ifisinstance(l,(bytes,bytearray)):output=to_hex(l)else:output=lreturnoutputdefconvert_to_hex(arg,target_schema):"""utilityfunctiontoconvertbytecodesintohumanreadableandjsonserializabledatastructures"""output=dict()forkinarg:ifisinstance(arg,(bytes,bytearray)):output=to_hex(arg)elifisinstance(arg,(list))andlen(arg)>0:target===k]iftarget=='tuple':target_field=targetoutput=decode_list_tuple(arg,target_field)else:output=decode_list(arg)elifisinstance(arg,(tuple)):target_field=foraintarget_schemaif'name'inaanda==k]output=decode_tuple(arg,target_field)else:output=argreturnoutput,{"inputs":,"name":"WETH","outputs":,"stateMutability":"view","type":"function"},{"inputs":,"name":"addLiquidity","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":,"name":"addLiquidityETH","outputs":,"stateMutability":"payable","type":"function"},{"inputs":,"name":"factory","outputs":,"stateMutability":"view","type":"function"},{"inputs":,"name":"getAmountIn","outputs":,"stateMutability":"pure","type":"function"},{"inputs":,"name":"getAmountOut","outputs":,"stateMutability":"pure","type":"function"},{"inputs":","name":"path","type":"address"}],"name":"getAmountsIn","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":","name":"path","type":"address"}],"name":"getAmountsOut","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":,"name":"quote","outputs":,"stateMutability":"pure","type":"function"},{"inputs":,"name":"removeLiquidity","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":,"name":"removeLiquidityETH","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":,"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":,"name":"removeLiquidityETHWithPermit","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":,"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":,"name":"removeLiquidityWithPermit","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":,"stateMutability":"payable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":,"stateMutability":"nonpayable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":","name":"path","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":","name":"amounts","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]'output=decode_tx('0x7a250d5630b4cf539739df2c5dacb4c659f2488d','0x38ed1739000000000000000000000000000000000000000000000000000000009502f900000000000000000000000000000000000000000000a07e38bf71936cbe39594100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000003c02cebb49f6e8f1fc96158099ffa064bbfee38b00000000000000000000000000000000000000000000000000000000616e11230000000000000000000000000000000000000000000000000000000000000003000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000528b3e98c63ce21c6f680b713918e0f89dfae555',sample_abi)print('functioncalled:',output)print('arguments:',json.dumps(json.loads(output),indent=2))
Stargate DAO成员在社区会议上讨论如何处理即将收到的160万枚ARB:3月30日消息,Stargate DAO成员在周三社区电话会议上讨论如何处理160万枚Arbitrum(ARB)代币的预期分配,这些代币价值不到200万美元。LayerZero Labs的员工MaxPower表示,这些代币尚未收到,但当收到时将必须决定是否持有、出售、部署或委托这些代币。
一些与会者建议,DAO应该将ARB代币分发给用户,或将其部署为流动性激励。与此同时,其他治理代币持有者建议委托ARB代币,以便Stargate DAO可以参与Arbitrum治理。
据DeFiLlama的数据,Stargate的总锁定价值(TVL)为3.64亿美元,其中近22%来自Arbitrum平台。(CoinDesk)[2023/3/30 13:34:35]
在示例代码中有几点需要注意:
此代码设计用于批量处理大量交易。它假设数据已经存在于本地存储中(而不是从区块链实时获取),并且非常适合像PySpark这样的分布式处理框架。
这样我们就更容易理解了。
该调用是对名为swapexacttokensfortokens的方法的调用,用户正在放入25亿单位的起始代币,并期望至少返回194,024,196,127,819,599,854,524,737单位的目标代币。这些数字看起来可能是天文数字,但请记住,代币单位通常用1/10^n表示,其中n大约是18。N有时被称为代币的十进制值。该path数组描述了在此交易中交换的代币。每个数组元素都是代币合约的地址。第一个是USDC(一种与美元挂钩的稳定币),第二个是WrappedEth(带有ERC20接口的以太坊),第三个是DXO(一种深空游戏货币)。将1和2放在一起,我们可以推断用户请求交换2,500USDC(USDC的十进制值为6)和大约1.94亿DXO(DXO的十进制值为18)。由于这种特殊的成对交换不能直接获得,交易将通过WETH的中间代币进行调解。解码日志
该交易在执行过程中还触发了7个事件,可以通过logs在以太坊上查询Google的PublicDataset中的表获得,也可以通过Etherscan查看。与用户所要求的交换相对应的两个最显著的记录是:
log_index:47transaction_hash:0x87a3bc85da972583e22da329aa109ea0db57c54a2eee359b2ed12597f5cb1a64transaction_index:37?address:0xb4e16d0168e52d35cacd2c6185b44281ec28c9dcdata:0x000000000000000000000000000000000000000000000000000000009502f90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093f8f932b016b1ctopics:?block_timestamp:2021-10-1900:00:18block_number:13444845block_hash:0xe9ea4fc0ef9a13b1e403e68e3ff94bc94e472132528fe8f07ade422b84a43afc
还有
log_index:50transaction_hash:0x87a3bc85da972583e22da329aa109ea0db57c54a2eee359b2ed12597f5cb1a64transaction_index:37?address:0x242301fa62f0de9e3842a5fb4c0cdca67e3a2fabdata:0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093f8f932b016b1c000000000000000000000000000000000000000000a137bb41b9113069a51e190000000000000000000000000000000000000000000000000000000000000000topics:?block_timestamp:2021-10-1900:00:18block_number:13444845block_hash:0xe9ea4fc0ef9a13b1e403e68e3ff94bc94e472132528fe8f07ade422b84a43afc
Meta正测试如何在Facebook和Instagram之间进行切换:9月27日消息,Meta Platform正测试如何轻松地在旗下Facebook和Instagram两款软件之间进行切换。(财联社)[2022/9/27 22:31:29]
同样,相关详细信息在topics和data字段中编码为十六进制字符串。与transaction的情况一样,input浏览这些数据字段的结构是有益的。topics是一个数组,其中第一个元素表示事件接口定义的哈希签名。topics数组中的任何其他元素通常是事件中涉及的区块链地址,根据具体上下文可能存在,也可能不存在。data表示事件参数值,其长度根据事件定义而不同。与交易的情况一样,我们需要引用合约ABI,以便将其转换为人类可读的形式。
敏锐的读者会注意到上面日志中的合约地址0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc和0x242301fa62f0de9e3842a5fb4c0cdca67e3a2fab与用户EOA最初调用的Routerv2合约0x7a250d5630b4cf539739df2c5dacb4c659f2488d不同。这两个地址对应USDC-WETH和DXO-WETH代币对的Uniswapv2对合约。这些合约负责持有各自交易对的流动性,并实际进行交换。用户最初与之交互的Router合约作为一个协调器,并向适当的配对合约发起内部交易(跟踪)。因此,为了解码这些事件,我们还需要一对合约ABI。解码日志示例如下:
fromweb3._utils.eventsimportget_event_datareturntopic2abievent_abi=topic2abi]evt_name=event_abidata=get_event_data(w3.codec,event_abi,log)target_schema=event_abidecoded_data=convert_to_hex(data,target_schema)return(evt_name,json.dumps(decoded_data),json.dumps(target_schema))exceptException:return('decodeerror',traceback.format_exc(),None)else:return('nomatchingabi',None,None)pair_abi=',"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":,"name":"Approval","type":"event"},{"anonymous":false,"inputs":,"name":"Burn","type":"event"},{"anonymous":false,"inputs":,"name":"Mint","type":"event"},{"anonymous":false,"inputs":,"name":"Swap","type":"event"},{"anonymous":false,"inputs":,"name":"Sync","type":"event"},{"anonymous":false,"inputs":,"name":"Transfer","type":"event"},{"constant":true,"inputs":,"name":"DOMAIN_SEPARATOR","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"MINIMUM_LIQUIDITY","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"PERMIT_TYPEHASH","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"allowance","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"approve","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":,"name":"balanceOf","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"burn","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":,"name":"decimals","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"factory","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"getReserves","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"initialize","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":,"name":"kLast","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"mint","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":,"name":"name","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"nonces","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"permit","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":,"name":"price0CumulativeLast","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"price1CumulativeLast","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"skim","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":,"name":"swap","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":,"name":"symbol","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"sync","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":,"name":"token0","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"token1","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":,"name":"totalSupply","outputs":,"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":,"name":"transfer","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":,"name":"transferFrom","outputs":,"payable":false,"stateMutability":"nonpayable","type":"function"}]'output=decode_log('0x000000000000000000000000000000000000000000000000000000009502f90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093f8f932b016b1c',,pair_abi)print('eventemitted:',output)print('arguments:',json.dumps(json.loads(output),indent=2))
直播 | 九妹 > 如何促进区块链产业良性发展:金色财经 · 直播主办的《 币圈 “后浪” 仙女直播周》第4期今晚20:00准时开始,本期“后浪”仙女OKEx大客户商户总监将在直播间聊聊 “如何促进区块链产业良性发展”,感兴趣的朋友扫码移步收听![2020/6/12]
与交易解码的代码类似,示例代码针对批量解码用例进行了优化,并与类似PySpark的东西一起使用,以处理大量日志事件。运行以上收益率:
eventemitted:Swaparguments:{"sender":"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D","to":"0x242301FA62f0De9e3842A5Fb4c0CdCa67e3A2Fab","amount0In":2500000000,"amount1In":0,"amount0Out":0,"amount1Out":666409132118600476}
还有
eventemitted:Swaparguments:{"sender":"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D","to":"0x3c02cebB49F6e8f1FC96158099fFA064bBfeE38B","amount0In":0,"amount1In":666409132118600476,"amount0Out":194900241391490294085918233,"amount1Out":0}
我们可以认为这两个确实swap是path在初始请求之后发生的事件——USDC>WETH>DXO。我们可以看到路由器合约(以488D结尾)是两个事件中的发送方,充当协调者。USDC-WETH对合约(以c9dc结尾)将25亿单位USDC换成666,409,132,118,600,476单位WETH,然后将产生的WETH转移到DXO-WETH对合约(结束2Fab)。DXO-WETH合约将666,409,132,118,600,476单位的WETH置换为194,900,241,391,490,294,085,918,233单位的DXO,并按照最初的要求将其发送回用户(EOA结束于E38B)。
结束语
正如本例所示,一旦我们有了工具,解码的过程就相对简单了,但知道要解码什么以及如何解释结果数据就不是那么简单了。根据我们尝试回答的具体问题,某些功能和事件比其他功能和事件更相关。为了分析web3应用程序中的经济活动和用户行为,了解特定智能合约的工作方式并确定感兴趣的指标中涉及的关键功能和事件非常重要。这最好是通过实际使用该产品、在像Etherscan这样的区块浏览器上检查数据消耗以及阅读智能合约源代码的组合来实现。这是制定正确的解码和分析策略的关键条件。
Source:https://towardsdatascience.com/decoding-ethereum-smart-contract-data-eed513a65f76
动态 | 人民网:区块链与实业结合应注意如何界定算法和物理设备权责体系:今日人民网发文表示,区块链与实业的结合与我国“数字化”的趋势一致,这一融合过程需要注意三个问题。一是算法和物理设备权责体系如何界定;二是智能制造标准制定思路是否应该转变;三是5G会给边缘计算、区块链和物联网带来什么冲击。[2018/8/24]
金色财经独家整理 贸易战对比特币走势影响如何?贸易战避险,比特币“效果不错”:
今日凌晨,中美史上最大贸易战打响,全球股市重挫,数字资产比特币走势如何再被讨论。重温早在3月2日Brian Kelly在CNBC的关于贸易战的言论:贸易战将加强美元贬值、物价上涨的预期,由于普遍担忧通胀,人们愿意投资比特币这样的“新黄金”、 “硬资产”(避险),“在贸易战中,比特币效果不错”。
Brian Kelly的观点发表于300亿美元贸易战规模预测下,而今600万“变本加厉”。中国已于今晨展开“反击”,外媒也普遍预测美国为长期输家。股市下跌将支撑黄金,金价在昨日由于加息和贸易战担忧下收于两周最高点,而比特币为何反而下跌?据CNBC称:比特币未守住9000美元关口或因日本对加密数字货币加强监管力度的政策可能。金色财经认为,由于政策目前仍为影响比特币的主要因素,在最晚今年7月份国际监管措施出台、政策逐步趋稳后,数字货币价格将逐渐与黄金涨跌保持相似的变动。[2018/3/23]
郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。