PUT:如何解码以太坊智能合约数据,并批量处理相关细节?_TYP币

原标题:《解码以太坊智能合约数据》

正如我们在之前的文章中所讨论的,智能合约交易类似于智能合约驱动的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))

Aave社区正对“如何分配Aave Grants DAO收到的30万枚OP”提案进行投票:5月4日消息,Aave社区正对“如何分配Aave Grants DAO(AGD)收到的30万枚OP”提案进行温度检查投票,该提案目前支持率为99.97%,并将于5月8日结束。根据该提案,Aave社区去年创建了一个提案并成功收到了30万枚OP代币,作为激励基金OP Stimpack阶段0的一部分。这些代币将用于资助项目,以帮助Aave在Optimism上的发展。该提案旨在澄清收到的OP应如何分配并获得社区支持。

该提案建议分配最多10万枚OP用于当前AGD季度的赠款以及以Optimism为中心的事件和赏金,并将剩余的20万枚OP保留在AGD多签钱包中以用于AGD的未来季度赠款或分配。如果该提案获得此次投票通过,AGD将按照上述方式进行资金分配。不需要AIP或进一步的治理行动。[2023/5/4 14:42:34]

在示例代码中有几点需要注意:

此代码设计用于批量处理大量交易。它假设数据已经存在于本地存储中(而不是从区块链实时获取),并且非常适合像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

Euler Finance社区就如何将追回的被盗资金分配给用户进行投票:Euler Finance社区就如何将追回的被盗资金分配给用户进行投票

金色财经报道,DeFi借贷协议Euler Finance背后社区正在就如何将追回的被盗资金分配给用户进行投票,如果该计划获得批准,Euler将使用协议因黑客攻击而被禁用时的价格来计算用户资产和负债的价值。

此前报道,Euler Finance在3月份遭受了2亿美元的黑客攻击,该团队上周表示,它已经收回了在黑客攻击中被盗的所有“可追回资金”。根据Euler治理论坛的提议,收回的资金总额超过95,556个ETH和4300万个DAI稳定币。未追回的资金包括发送到Tornado Cash的1,100ETH和发送到与Lazarus Group相关地址的100ETH,Lazarus Group是一个据称与朝鲜有关的黑客组织。[2023/4/11 13:55:39]

同样,相关详细信息在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))

观点:无论与SEC的诉讼结果如何 对Ripple而言都不是致命打击:1月27日消息,针对美国SEC对Ripple发起的诉讼,律师Jeremy Hogan表示,如果诉讼最终对Ripple有利,在诉讼结束时,XRP价格将上涨2至3倍将只是一个“保守估计”。无论诉讼得出什么结论,对Ripple来说都不是致命的打击。如果诉讼结果不佳,导致Ripple关闭,XRP可能会归零,但这种情况不太可能发生。因为Ripple是一个技术公司,不太依赖实物资产运营。最糟糕的情况可能是其商业模式遭破坏,最终可能退出美国市场。Jeremy Hogan称,SEC诉讼最可能的结果将是双方达成和解。SEC可能会对Ripple包括其2013-2014年度(甚至2015年)的业务处以巨额罚款,以及对托管XRP销售业务进行某种控制或限制。(AMBCrypto)[2021/1/27 21:48:59]

与交易解码的代码类似,示例代码针对批量解码用例进行了优化,并与类似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

动态 | 火币中国CEO与马来西亚总理讨论区块链将如何在马来西亚落地:据雅虎财经消息,近日,火币中国CEO袁煜明与马来西亚总理马哈蒂尔(Mahathir Mohamad)就“如何在制造业和能源行业中应用区块链”以及“区块链将如何在马来西亚落地”进行了讨论。[2019/5/29]

传真格基金创始人徐小平呼吁各CEO了解区块链 学习如何拥抱这场革命:据某互联网知名博主爆料,真格基金创始人徐小平在真格基金投资组合微信群呼吁各CEO积极了解区块链,并立即动员全体高管和员工,学习如何拥抱这场革命。[2018/1/9]

郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。

大币网

[0:0ms0-6:896ms