原标题:《解码以太坊智能合约数据》
正如我们在之前的文章中所讨论的,智能合约交易类似于智能合约驱动的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))
Meta正测试如何在Facebook和Instagram之间进行切换:9月27日消息,Meta Platform正测试如何轻松地在旗下Facebook和Instagram两款软件之间进行切换。(财联社)[2022/9/27 22:31:29]
在示例代码中有几点需要注意:
此代码设计用于批量处理大量交易。它假设数据已经存在于本地存储中(而不是从区块链实时获取),并且非常适合像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
同样,相关详细信息在topics和data字段中编码为十六进制字符串。与transaction的情况一样,input浏览这些数据字段的结构是有益的。topics是一个数组,其中第一个元素表示事件接口定义的哈希签名。topics数组中的任何其他元素通常是事件中涉及的区块链地址,根据具体上下文可能存在,也可能不存在。data表示事件参数值,其长度根据事件定义而不同。与交易的情况一样,我们需要引用合约ABI,以便将其转换为人类可读的形式。
美国货币监理署新署长:期望进一步了解银行与加密货币机构如何相互作用:美国货币监理署(OCC)新署长Brian Brooks表示,OCC正寻求与银行和加密货币机构的行业领袖进行更多的对话,期望了解如何进一步促进双方相互作用。他表示加密货币机构需要银行服务,他们需要跨银行通道进行交易的。他期望进一步了解有关加密货币对银行的需求以及银行对加密货币的需求,因为他们确实想在这方面有所作为。OCC是美国财政部的主要银行监管机构,Brooks于3月份离开Coinbase,加入OCC并担任首席法律官。(Cointelegraph)[2020/6/5]
敏锐的读者会注意到上面日志中的合约地址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))
声音 | 虫哥:不管市场如何 两个原因让我对比特币的信仰不会变:今天江西世星科技在江西抚州才都电子科技产业园举行厂区开业典礼。原壹比特创始人、亿算科技创始人虫哥分享称,半导体芯片在人才集中的大城市完成研发,然后在内地城市落地更划算。而其目前关注两块业务。第一是从近阈值技术研发高算力低功耗制定芯片。第二,研发 POC容量证明这类新型的绿色环保节能 POW挖矿共识机制。2018年数字货币进入寒冬,但他依然拥有坚定信念,理由有两个。其一,比特币第一次用密码学确保了个人数字资产不可侵犯。第二,比特币基于去中心化、数量有限、不可伪造等特点,是极具流动性的、可抵御通货膨胀的收藏品。[2019/1/11]
与交易解码的代码类似,示例代码针对批量解码用例进行了优化,并与类似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
欧链老狼:全球出块节点大致分为三个组,每个组都在预演如何启动EOS网络:EOS超级节点竞选团队欧链的老狼在《欧链·宁话区块链》第二季的节目中称 “全球出块节点大致分为三个组,每个组都在预演如何从无到有启动EOS网络。具体什么时候主网上线,需要大家一起协同来做。或许在某一个预定的时间点,大家觉得有些准备工作没有做好,希望把这个时间点再往后延一点,这种情况是有可能发生的。”[2018/6/2]
韩国将于7日在国会召开‘虚拟货币制度化,该如何接近’研讨会:最近对虚拟货币的担忧和关注,虚拟货币相关学界及业界专家和政府核心相关人员将于韩国时间7日早上9点30分在韩国国会第二会议室中召开‘虚拟货币制度化,该如何接近’的研讨会。[2018/2/6]
作者:MarioGabriele文章翻译:Blockunicorn原标题:《思考NFT的未来》 可操作的见解 如果您只有几分钟的空闲时间.
10月27日,由万向区块链实验室主办的“2021上海区块链国际周·第七届区块链全球峰会”在万向区块链董事长兼总经理肖风博士的闭幕演讲中圆满结束.
MicroStrategy在第三季度增持了近9000个比特币,使其持有的BTC总量的估值达到70亿美元左右.
巴比特讯,10月26日,NFT平台SuperRare发推宣布与电影制片人及奥斯卡金像奖终身成就奖大卫·林奇(DavidLynch)及美国后朋克国际刑警乐队Interpol合作.
独立智库观察家研究基金会在最新的一篇文章中表示,G20国家在协调有关Crypto和非公开投资政策上既有“机会”也有责任。它有利于建立一个“可持续、平衡和包容的全球经济架构”.
要数今年互联网热词有哪些?相信“元宇宙”一定能排上号。尤其是前不久Facebook公司更名为“Meta”一事,更是让这个概念彻底出圈,进一步走进公众视野.