原文地址:https://ath.mirror.xyz/mbR1n_CvflL1KIKCTG42bnM4HpfGBqDPNndH8mu2eJw
原文作者:Andrew Hong
如果你曾经在以太坊(或任何启用智能合约的区块链)上进行过交易,那么你可能已经在区块浏览器上查找过,并看到了这堆信息。
学习阅读交易的细节将是所有以太坊数据分析和知识的基础,所以让我们来介绍所有的部分以及如何在SQL中使用它们。我将使用Dune Analytics来运行我的查询,但还有许多其他工具,你可以用来查询链,如Big Query和Flipside Crypto。
如果你对SQL和以太坊完全陌生,我建议先阅读:初学者概述。
我们将分四个层次介绍交易:
事务的基础知识
函数调用和状态
内部交易 (Traces)
日志 (Events Emitted)
作为我们交易实例的基础,我们将使用Mirror Crowdfund合约。简单地说,这是一个智能合约,允许你向该合约捐赠ETH,以获得ERC20(可替换)或ERC721(NFTs)代币。合约的创建者可以通过关闭众筹基金来提取这些资金。这绝不是一个简单的合约,但我想在这里说的是,你不需要了解所有的solidity代码来开始分析--你只需要知道如何浏览上面的四个层次。
我们要研究的三个交易是:
创建/部署众筹合约
向合约缴纳的ETH
关闭和提取合约中的资金
题外话,我们也刚刚开放了众筹给任何人使用,所以如果你好奇或想创建一个众筹,请到mirror.xyz/dashboard开始。
第一个交易: 0x5e5ef5dd9d147028f9bc21127e3de774a80c56a2e510d95f41984e6b7af1b8db
让我们从交易的基本情况开始。
每笔交易都有一个独特的keccak256交易哈希值(transaction hash),包括几个不同的变量
有一个基于交易开采时间的相关区块号码(blocknumber),通常每15秒就有一个新的区块被创建。
From是签署交易的人,To是被交互的合约地址
Value是指从签名者的钱包中转移的ETH价值。即使该值为0,也不意味着交易中没有转移ETH。
Gas有点复杂(尤其是EIP-1559),但只要记住这个公式:Gas Price * Gas Used by Transaction = Transaction Fee
这是函数调用和传入的参数的字节码。前8个字符(4个字节)是函数签名0x849a3aa3,是函数名称和参数类型的哈希值。然而,这个哈希并不一定是唯一的,这有可能导致被黑等安全问题。在这个案例中,这个函数调用合约功能来创建众筹合约(它是一个代理,但我们不会去讨论这个问题)。
Function:createCrowdfund((uint256,uint256,bytes32)[], (address,uint256), string, string, address, address, uint256, uint256, uint256)
如果你点击 "decode input data"(解码输入数据),这就会显示出来,你也可以看到各种变量值的设置。随后的每64个字符(32字节)都是不同的输入变量。众筹有三个层次的版本。在BLVKHVND的这次众筹中,他们使用的数量为1000、250和50,价格分别为0.1、0.3和1ETH。
注意,价格实际上显示为100000000000000000 ,这是因为前18个零代表小数。我们必须在数据中通过除以10^18来进行转换。
这是一个很大的问题,让我们开始查询吧。Dune有一个名为ethereum.transactions的表,其中有我们上面谈到的自第一个区块以来每笔交易的所有变量。我们可以查询这个表,看看在过去几个月里0x849a3aa3的出现。
SELECT * FROM ethereum.transactions
WHERE "block_time" > now() - interval '3 months'
AND "data" is not null
AND SUBSTRING ( encode("data", 'hex'), 1, 8 ) = '849a3aa3'
ethereum.transactions是一个非常大的表,所以如果你在没有过滤器的情况下查询,查询会超时(需要30分钟以上)。按区块时间过滤通常是最有用的,在这种情况下,我们要取3个月内发生的所有行。另外,许多交易只是ETH转账,没有附加任何数据,所以我们将通过只保留数据不为空来过滤掉。现在为了检查函数签名,我们需要将数据从十六进制编码成一个字符串,然后使用SUBSTRING只取位置1到位置8的字符。
现在是复杂的部分,内部事务和事件的排列。对于这一点,看一下代码会更容易。如果你进入etherscan的合约标签,在文件1 of 10上做ctrl+f,你会发现以下代码(我编辑了一些片段,使其更易读)。
function createCrowdfund(
...variables...
) external returns (address crowdfundProxy) {
...some variable prep code...
crowdfundProxy = address(
new CrowdfundWithPodiumEditionsProxy{
salt: keccak256(abi.encode(symbol_, operator_))
}(treasuryConfig, operator_)
);
emit CrowdfundDeployed(crowdfundProxy, name_, symbol_, operator_);
...register to treasury code...
}
这里的第一个关键行是crowdfundProxy = address(contract_to_be_created),这就是部署新的合约并创建一个CREATE 0类型的内部交易。
转移ETH也会创建一个CALL类型的内部交易,我们将在下一个交易中看到它。
我们可以通过如下sql查询所有被创建的众筹合约:
SELECT tx."block_time", tx."from", tr."type", tr."code"
FROM ethereum.transactions tx
LEFT JOIN ethereum.traces tr ON tx."hash"=tr."tx_hash" --tracks internal transactions
WHERE tx."to" = '\x15312b97389a1dc3bcaba7ae58ebbd552e606ed2' -- crowdfund podiums edition
AND tr."type" = 'create'
我们需要ethereum.transactions,因为我们想过滤只与工厂合约相关联的交易内部交易)。这样做的主要原因是内部交易并不总是与整体交易有相同的目的合约地址(To)。我们可以在事务哈希上连接这些表,然后只过滤create类型的内部事务。
这里的第二个关键行是emit CrowdfundDeployed,它创建了一个存储在节点中的日志,但不在块中。如果你看下日志,会发现EditionCreated事件也被排了出来,但这是来自另一个实际创建ERC721代币的合约(因此是不同的合约地址)。
与函数签名类似,事件也有一个唯一的哈希值,位于Topic 0中。对应上面的事件:0x5133bb164b64ffa4461bc0c782a5c0e71cdc9d6c6ef5aa9af84f7fd2cd966d8e是CrowdfundDeployed的哈希值,0xbaf1f6ab5aa5406df2735e70c52585e630f9744f4ecdedd8b619e983e927f0b6是EditionCreated的哈希值。
我们可以通过查询dune中的ethereum.logs表,可以看到所有被创建的众筹:
SELECT * FROM ethereum.logs
WHERE "topic1"='\x5133bb164b64ffa4461bc0c782a5c0e71cdc9d6c6ef5aa9af84f7fd2cd966d8e'::bytea
topic2和topic3通常保存ETH转账的数据,不然事件数据将显示在数据栏中。我们将在后面详细介绍如何处理这个问题。
日志是非常有用的,因为它们可以用来排列状态变量,而不仅仅是函数调用值(TheGraph使用日志来为GraphQL查询建立子图模型)。接下来,我们将动用我们所涉及的一切来研究ETH对我们新创建的众筹合约的贡献(地址:0x320d83769eb64096ea74b686eb586e197997f930 )。
如果你能走到这一步,那么你已经通过了所有艰难的概念。给自己拍拍胸脯吧! 在接下来的两节中,我们将真正进入细节,所以如果你需要的话,可以休息一下。
第二个交易: 0xd4ce80a5ee62190c5f5d5a5a7e95ba7751c8f3ef63ea0e4b65a1abfdbbb9d1ef
这个交易比较容易理解。Jesse支付了1个ETH,从BLVKHVND众筹中铸造了一个tokenId 167的NFT。他还得到了1000个HVND,这是众筹基金根据捐款规模发放的ERC20代币。
但是,如果我们想看看在一段时间内筹集了多少ETH,或者卖出了多少个NFT呢?有时合约会在etherscan上的Read Contract里有一个查看功能,你可以看到总余额。但目前这个案例中,合约并没有这个功能。
记住,函数调用会改变状态数据,我们需要通过对交易历史的汇总来拼凑整体状态数据。有时,合约的整体状态可以在事件中发出,比如Compound V2的AccrueInterest事件。
在我们的例子中,需要在一个查询中做两件事来获得贡献的ETH总量:
获取调用了"contribute"方法的交易
通过过滤具有CALL类型的内部交易,求出转移的ETH总量
记住,可以通过对etherscan上的输入数据(input data)进行解码来获得方法的函数签名(function signature)。
SELECT SUM(tr."value"/1e18) as contribution FROM ethereum.transactions tx
LEFT JOIN ethereum.traces tr ON tx."hash" = tr."tx_hash"
--transactions filtering
WHERE tx."to" = '\x320d83769eb64096ea74b686eb586e197997f930'::bytea
AND tx."data" is not null
AND SUBSTRING ( encode(tx."data", 'hex'), 1, 8 ) IN ('a08f793c', 'ce4661bb')
--traces filtering
AND tr."success"
AND tr."value" > 0
AND tr."call_type" = 'call'
严格来说,还有一个叫做contributionForPodium的方法,这就是我们在上面检查两个函数签名的原因。CALL类型实际上在操作码层面也有子类型,所以我们需要指定具体的基础调用类型的调用(如果你熟悉delegatecall,那么你会知道这将给我们一个双数)。我们加上交易哈希,然后除以10^18,得到正确的ETH的值。
让我们来看看最后一笔交易,在这里,数据开始变得非常棘手。
第三个交易: 0xe9d5fefde77d4086d0f64dd1403f9b6e8e12aac74db238ebf11252740c3f65a8
在这个交易中,我们可以看到转移了337个ETH和1,012,965个HVND代币(后者在第一次交易中由operatorPercent方法处理)。在这个函数被调用后,合约会正常的ERC20的方式执行。
在一个众筹已经结束的情况下,我们可以从这个交易的数据中得到筹集的总额--比如在CALL类型的内部交易中转移的价值。不过,最好是把它和一个事件联系起来,以防有一些我们不知道的转账行为。但是,等等,为什么日志是不可读的?
好吧,这就是我们开始进入一些相当混乱的模式的地方了。早些时候我提到,这个众筹基金是作为代理部署的--这意味着它就像一个空的USB,插在实际持有逻辑规则的电脑上。创建USB要比电脑便宜得多--这种逻辑规则对链上也适用(除了gas花费的成本)。如果你想更详细的了解代理模式,可以看看OpenZeppelin团队的这篇好文章。
在这种情况下,计算机被称为逻辑规则,只部署一次。代理被多次部署,它没有合约代码中的逻辑功能或事件。因此,etherscan并不具备在日志中显示解码数据的能力。那么,我们如何把这些拼凑起来呢?我们可以采取事件的keccak256哈希值,就像我们对函数签名所做的那样。但在这里,阅读代码将帮助你节省一些时间。如果你去查看工厂合约上的Read Contract,你会看到逻辑合约的地址。
在那里,我们可以找到代码中的closeFunding()函数:
function closeFunding() external onlyOperator nonReentrant {
...code...
_mint(operator, operatorTokens);
// Announce that funding has been closed.
emit FundingClosed(address(this).balance, operatorTokens);
...ETH value transfers...
}
ETH价值转移不会发出事件,因为它们只是内部交易。而如果你熟悉ERC20标准的运作方式,你就会知道mint实际上创建了一个转移事件(意味着已经涵盖了我们的第一个事件)。这意味着FundingClosed必须是第二个日志,主题为0x352ce94da8e3109dc06c05ed84e8a0aaf9ce2c4329dfd10ad1190cf620048972。你能想出为什么不可能是第三条日志吗(提示:前两条日志和第三条日志之间有什么关键区别)?
有了这些知识,我们就可以像其他事件一样,通过一些花哨的数据解码来查询这个事件(记住参数是每64个字符(32字节)。我们必须把它变成一个字符串来切分,然后我们把它改成一个数字,再除以10^18来去掉小数。
SELECT "contract_address",
bytea2numeric( decode ( SUBSTRING ( encode("data", 'hex') , 1, 64 ), 'hex'))/1e18 as eth_raised,
bytea2numeric ( decode ( SUBSTRING ( encode("data", 'hex') , 65 , 64 ), 'hex'))/1e18 as tokens_allocated_owned
FROM ethereum.logs
WHERE "topic1"='\x352ce94da8e3109dc06c05ed84e8a0aaf9ce2c4329dfd10ad1190cf620048972'::bytea
AND "contract_address"='\x320d83769eb64096ea74b686eb586e197997f930'::bytea
恭喜你,你现在知道如何处理ethereum.transactions、ethereum.traces和ethereum.logs。它们总是可以通过交易哈希来连接,然后剩下的就是知道如何用encode/decode、substring和一些bytea操作符来处理数据。Woohoo!
我们也可以对上一个事务中的contribute方法做这个练习。因为这一切都发生在代理合同上。
现在,如果我们不得不去跟踪函数签名和事件主题--以及对每个查询中的所有变量进行解码--我想我们现在都会放弃数据分析。幸运的是,大多数数据服务都有一些合约解码的变化,这意味着我可以给一个合约地址,ABI和Dune将为我解决解码的问题。这样一来,事件/功能就变成了它们自己的表,我就可以很容易地用这个来做之前的"total contributions"查询。
WITH
union_sum as (
SELECT SUM("amount")/1e18 as raised FROM mirror."CrowdfundWithPodiumEditionsLogic_evt_Contribution"
WHERE "contract_address"='\x320d83769eb64096ea74b686eb586e197997f930'
UNION ALL
SELECT SUM("amount")/1e18 as raised FROM mirror."CrowdfundWithPodiumEditionsLogic_evt_ContributionForEdition"
WHERE "contract_address"='\x320d83769eb64096ea74b686eb586e197997f930'
)
SELECT SUM("raised") FROM union_sum
https://dune.xyz/queries/192571
值得庆幸的是,这种查询的可读性更强,更容易编写。他们甚至还照顾到了代理/工厂的逻辑模式--感谢团队! 如果没有这个抽象,我保证数据分析的编写会混乱十倍,调试会糟糕一百倍。Dune还有很多其他有用的表格,比如Prices.usd用于每日代币价格,dex.trades用于所有主要交易所的所有代币交易(以及事件nft.trades用于OpenSea NFT交易)。
虽然大部分时间你都在玩解码数据,但了解这些数据下面的真正内容将帮助你在Web3中更快地提高水平!此外,你现在是以太坊的使用者。另外,你现在可以流利地使用etherscan了--我保证这将是未来每个密码工作中重要的一部分。我希望这对你有帮助,如果你需要一些帮助,请随时联系我。
数据里藏着黄金屋,学会分析链上数据是一把掘金铲,虽然有些难,但还是应该花时间去做。
我试着用上面学到的内容,对我发起的一个众筹做了个简单的数据分析:
select count(tx.*) as Backers , SUM(tx."value"/1e18) as Raised, sum((tx.gas_price/1e18)*tx.gas_used) as GasFee from ethereum.transactions tx
where tx."to" = '\x2B3b54932db9a8edd31DCd03aC34B45E98f3FC34'::bytea
《DeFi入门手册》 ,目前支持次数205,筹集到7.6ETH,总花费交易手续费1.21ETH,可以看出在主网做资金筹集成本还是有些高,大概占到项目资金的15%。
crowdfund://0x2B3b54932db9a8edd31DCd03aC34B45E98f3FC34?features=overview,backers
近期文章: Mirror.xyz 通向web3.0的一道窄门 使用Mirror发起一个知识付费项目,做一次WEB3.0的探索
原文地址:https://ath.mirror.xyz/mbR1n_CvflL1KIKCTG42bnM4HpfGBqDPNndH8mu2eJw
原文作者:Andrew Hong
如果你曾经在以太坊(或任何启用智能合约的区块链)上进行过交易,那么你可能已经在区块浏览器上查找过,并看到了这堆信息。
学习阅读交易的细节将是所有以太坊数据分析和知识的基础,所以让我们来介绍所有的部分以及如何在SQL中使用它们。我将使用Dune Analytics来运行我的查询,但还有许多其他工具,你可以用来查询链,如Big Query和Flipside Crypto。
如果你对SQL和以太坊完全陌生,我建议先阅读:初学者概述。
我们将分四个层次介绍交易:
事务的基础知识
函数调用和状态
内部交易 (Traces)
日志 (Events Emitted)
作为我们交易实例的基础,我们将使用Mirror Crowdfund合约。简单地说,这是一个智能合约,允许你向该合约捐赠ETH,以获得ERC20(可替换)或ERC721(NFTs)代币。合约的创建者可以通过关闭众筹基金来提取这些资金。这绝不是一个简单的合约,但我想在这里说的是,你不需要了解所有的solidity代码来开始分析--你只需要知道如何浏览上面的四个层次。
我们要研究的三个交易是:
创建/部署众筹合约
向合约缴纳的ETH
关闭和提取合约中的资金
题外话,我们也刚刚开放了众筹给任何人使用,所以如果你好奇或想创建一个众筹,请到mirror.xyz/dashboard开始。
第一个交易: 0x5e5ef5dd9d147028f9bc21127e3de774a80c56a2e510d95f41984e6b7af1b8db
让我们从交易的基本情况开始。
每笔交易都有一个独特的keccak256交易哈希值(transaction hash),包括几个不同的变量
有一个基于交易开采时间的相关区块号码(blocknumber),通常每15秒就有一个新的区块被创建。
From是签署交易的人,To是被交互的合约地址
Value是指从签名者的钱包中转移的ETH价值。即使该值为0,也不意味着交易中没有转移ETH。
Gas有点复杂(尤其是EIP-1559),但只要记住这个公式:Gas Price * Gas Used by Transaction = Transaction Fee
这是函数调用和传入的参数的字节码。前8个字符(4个字节)是函数签名0x849a3aa3,是函数名称和参数类型的哈希值。然而,这个哈希并不一定是唯一的,这有可能导致被黑等安全问题。在这个案例中,这个函数调用合约功能来创建众筹合约(它是一个代理,但我们不会去讨论这个问题)。
Function:createCrowdfund((uint256,uint256,bytes32)[], (address,uint256), string, string, address, address, uint256, uint256, uint256)
如果你点击 "decode input data"(解码输入数据),这就会显示出来,你也可以看到各种变量值的设置。随后的每64个字符(32字节)都是不同的输入变量。众筹有三个层次的版本。在BLVKHVND的这次众筹中,他们使用的数量为1000、250和50,价格分别为0.1、0.3和1ETH。
注意,价格实际上显示为100000000000000000 ,这是因为前18个零代表小数。我们必须在数据中通过除以10^18来进行转换。
这是一个很大的问题,让我们开始查询吧。Dune有一个名为ethereum.transactions的表,其中有我们上面谈到的自第一个区块以来每笔交易的所有变量。我们可以查询这个表,看看在过去几个月里0x849a3aa3的出现。
SELECT * FROM ethereum.transactions
WHERE "block_time" > now() - interval '3 months'
AND "data" is not null
AND SUBSTRING ( encode("data", 'hex'), 1, 8 ) = '849a3aa3'
ethereum.transactions是一个非常大的表,所以如果你在没有过滤器的情况下查询,查询会超时(需要30分钟以上)。按区块时间过滤通常是最有用的,在这种情况下,我们要取3个月内发生的所有行。另外,许多交易只是ETH转账,没有附加任何数据,所以我们将通过只保留数据不为空来过滤掉。现在为了检查函数签名,我们需要将数据从十六进制编码成一个字符串,然后使用SUBSTRING只取位置1到位置8的字符。
现在是复杂的部分,内部事务和事件的排列。对于这一点,看一下代码会更容易。如果你进入etherscan的合约标签,在文件1 of 10上做ctrl+f,你会发现以下代码(我编辑了一些片段,使其更易读)。
function createCrowdfund(
...variables...
) external returns (address crowdfundProxy) {
...some variable prep code...
crowdfundProxy = address(
new CrowdfundWithPodiumEditionsProxy{
salt: keccak256(abi.encode(symbol_, operator_))
}(treasuryConfig, operator_)
);
emit CrowdfundDeployed(crowdfundProxy, name_, symbol_, operator_);
...register to treasury code...
}
这里的第一个关键行是crowdfundProxy = address(contract_to_be_created),这就是部署新的合约并创建一个CREATE 0类型的内部交易。
转移ETH也会创建一个CALL类型的内部交易,我们将在下一个交易中看到它。
我们可以通过如下sql查询所有被创建的众筹合约:
SELECT tx."block_time", tx."from", tr."type", tr."code"
FROM ethereum.transactions tx
LEFT JOIN ethereum.traces tr ON tx."hash"=tr."tx_hash" --tracks internal transactions
WHERE tx."to" = '\x15312b97389a1dc3bcaba7ae58ebbd552e606ed2' -- crowdfund podiums edition
AND tr."type" = 'create'
我们需要ethereum.transactions,因为我们想过滤只与工厂合约相关联的交易内部交易)。这样做的主要原因是内部交易并不总是与整体交易有相同的目的合约地址(To)。我们可以在事务哈希上连接这些表,然后只过滤create类型的内部事务。
这里的第二个关键行是emit CrowdfundDeployed,它创建了一个存储在节点中的日志,但不在块中。如果你看下日志,会发现EditionCreated事件也被排了出来,但这是来自另一个实际创建ERC721代币的合约(因此是不同的合约地址)。
与函数签名类似,事件也有一个唯一的哈希值,位于Topic 0中。对应上面的事件:0x5133bb164b64ffa4461bc0c782a5c0e71cdc9d6c6ef5aa9af84f7fd2cd966d8e是CrowdfundDeployed的哈希值,0xbaf1f6ab5aa5406df2735e70c52585e630f9744f4ecdedd8b619e983e927f0b6是EditionCreated的哈希值。
我们可以通过查询dune中的ethereum.logs表,可以看到所有被创建的众筹:
SELECT * FROM ethereum.logs
WHERE "topic1"='\x5133bb164b64ffa4461bc0c782a5c0e71cdc9d6c6ef5aa9af84f7fd2cd966d8e'::bytea
topic2和topic3通常保存ETH转账的数据,不然事件数据将显示在数据栏中。我们将在后面详细介绍如何处理这个问题。
日志是非常有用的,因为它们可以用来排列状态变量,而不仅仅是函数调用值(TheGraph使用日志来为GraphQL查询建立子图模型)。接下来,我们将动用我们所涉及的一切来研究ETH对我们新创建的众筹合约的贡献(地址:0x320d83769eb64096ea74b686eb586e197997f930 )。
如果你能走到这一步,那么你已经通过了所有艰难的概念。给自己拍拍胸脯吧! 在接下来的两节中,我们将真正进入细节,所以如果你需要的话,可以休息一下。
第二个交易: 0xd4ce80a5ee62190c5f5d5a5a7e95ba7751c8f3ef63ea0e4b65a1abfdbbb9d1ef
这个交易比较容易理解。Jesse支付了1个ETH,从BLVKHVND众筹中铸造了一个tokenId 167的NFT。他还得到了1000个HVND,这是众筹基金根据捐款规模发放的ERC20代币。
但是,如果我们想看看在一段时间内筹集了多少ETH,或者卖出了多少个NFT呢?有时合约会在etherscan上的Read Contract里有一个查看功能,你可以看到总余额。但目前这个案例中,合约并没有这个功能。
记住,函数调用会改变状态数据,我们需要通过对交易历史的汇总来拼凑整体状态数据。有时,合约的整体状态可以在事件中发出,比如Compound V2的AccrueInterest事件。
在我们的例子中,需要在一个查询中做两件事来获得贡献的ETH总量:
获取调用了"contribute"方法的交易
通过过滤具有CALL类型的内部交易,求出转移的ETH总量
记住,可以通过对etherscan上的输入数据(input data)进行解码来获得方法的函数签名(function signature)。
SELECT SUM(tr."value"/1e18) as contribution FROM ethereum.transactions tx
LEFT JOIN ethereum.traces tr ON tx."hash" = tr."tx_hash"
--transactions filtering
WHERE tx."to" = '\x320d83769eb64096ea74b686eb586e197997f930'::bytea
AND tx."data" is not null
AND SUBSTRING ( encode(tx."data", 'hex'), 1, 8 ) IN ('a08f793c', 'ce4661bb')
--traces filtering
AND tr."success"
AND tr."value" > 0
AND tr."call_type" = 'call'
严格来说,还有一个叫做contributionForPodium的方法,这就是我们在上面检查两个函数签名的原因。CALL类型实际上在操作码层面也有子类型,所以我们需要指定具体的基础调用类型的调用(如果你熟悉delegatecall,那么你会知道这将给我们一个双数)。我们加上交易哈希,然后除以10^18,得到正确的ETH的值。
让我们来看看最后一笔交易,在这里,数据开始变得非常棘手。
第三个交易: 0xe9d5fefde77d4086d0f64dd1403f9b6e8e12aac74db238ebf11252740c3f65a8
在这个交易中,我们可以看到转移了337个ETH和1,012,965个HVND代币(后者在第一次交易中由operatorPercent方法处理)。在这个函数被调用后,合约会正常的ERC20的方式执行。
在一个众筹已经结束的情况下,我们可以从这个交易的数据中得到筹集的总额--比如在CALL类型的内部交易中转移的价值。不过,最好是把它和一个事件联系起来,以防有一些我们不知道的转账行为。但是,等等,为什么日志是不可读的?
好吧,这就是我们开始进入一些相当混乱的模式的地方了。早些时候我提到,这个众筹基金是作为代理部署的--这意味着它就像一个空的USB,插在实际持有逻辑规则的电脑上。创建USB要比电脑便宜得多--这种逻辑规则对链上也适用(除了gas花费的成本)。如果你想更详细的了解代理模式,可以看看OpenZeppelin团队的这篇好文章。
在这种情况下,计算机被称为逻辑规则,只部署一次。代理被多次部署,它没有合约代码中的逻辑功能或事件。因此,etherscan并不具备在日志中显示解码数据的能力。那么,我们如何把这些拼凑起来呢?我们可以采取事件的keccak256哈希值,就像我们对函数签名所做的那样。但在这里,阅读代码将帮助你节省一些时间。如果你去查看工厂合约上的Read Contract,你会看到逻辑合约的地址。
在那里,我们可以找到代码中的closeFunding()函数:
function closeFunding() external onlyOperator nonReentrant {
...code...
_mint(operator, operatorTokens);
// Announce that funding has been closed.
emit FundingClosed(address(this).balance, operatorTokens);
...ETH value transfers...
}
ETH价值转移不会发出事件,因为它们只是内部交易。而如果你熟悉ERC20标准的运作方式,你就会知道mint实际上创建了一个转移事件(意味着已经涵盖了我们的第一个事件)。这意味着FundingClosed必须是第二个日志,主题为0x352ce94da8e3109dc06c05ed84e8a0aaf9ce2c4329dfd10ad1190cf620048972。你能想出为什么不可能是第三条日志吗(提示:前两条日志和第三条日志之间有什么关键区别)?
有了这些知识,我们就可以像其他事件一样,通过一些花哨的数据解码来查询这个事件(记住参数是每64个字符(32字节)。我们必须把它变成一个字符串来切分,然后我们把它改成一个数字,再除以10^18来去掉小数。
SELECT "contract_address",
bytea2numeric( decode ( SUBSTRING ( encode("data", 'hex') , 1, 64 ), 'hex'))/1e18 as eth_raised,
bytea2numeric ( decode ( SUBSTRING ( encode("data", 'hex') , 65 , 64 ), 'hex'))/1e18 as tokens_allocated_owned
FROM ethereum.logs
WHERE "topic1"='\x352ce94da8e3109dc06c05ed84e8a0aaf9ce2c4329dfd10ad1190cf620048972'::bytea
AND "contract_address"='\x320d83769eb64096ea74b686eb586e197997f930'::bytea
恭喜你,你现在知道如何处理ethereum.transactions、ethereum.traces和ethereum.logs。它们总是可以通过交易哈希来连接,然后剩下的就是知道如何用encode/decode、substring和一些bytea操作符来处理数据。Woohoo!
我们也可以对上一个事务中的contribute方法做这个练习。因为这一切都发生在代理合同上。
现在,如果我们不得不去跟踪函数签名和事件主题--以及对每个查询中的所有变量进行解码--我想我们现在都会放弃数据分析。幸运的是,大多数数据服务都有一些合约解码的变化,这意味着我可以给一个合约地址,ABI和Dune将为我解决解码的问题。这样一来,事件/功能就变成了它们自己的表,我就可以很容易地用这个来做之前的"total contributions"查询。
WITH
union_sum as (
SELECT SUM("amount")/1e18 as raised FROM mirror."CrowdfundWithPodiumEditionsLogic_evt_Contribution"
WHERE "contract_address"='\x320d83769eb64096ea74b686eb586e197997f930'
UNION ALL
SELECT SUM("amount")/1e18 as raised FROM mirror."CrowdfundWithPodiumEditionsLogic_evt_ContributionForEdition"
WHERE "contract_address"='\x320d83769eb64096ea74b686eb586e197997f930'
)
SELECT SUM("raised") FROM union_sum
https://dune.xyz/queries/192571
值得庆幸的是,这种查询的可读性更强,更容易编写。他们甚至还照顾到了代理/工厂的逻辑模式--感谢团队! 如果没有这个抽象,我保证数据分析的编写会混乱十倍,调试会糟糕一百倍。Dune还有很多其他有用的表格,比如Prices.usd用于每日代币价格,dex.trades用于所有主要交易所的所有代币交易(以及事件nft.trades用于OpenSea NFT交易)。
虽然大部分时间你都在玩解码数据,但了解这些数据下面的真正内容将帮助你在Web3中更快地提高水平!此外,你现在是以太坊的使用者。另外,你现在可以流利地使用etherscan了--我保证这将是未来每个密码工作中重要的一部分。我希望这对你有帮助,如果你需要一些帮助,请随时联系我。
数据里藏着黄金屋,学会分析链上数据是一把掘金铲,虽然有些难,但还是应该花时间去做。
我试着用上面学到的内容,对我发起的一个众筹做了个简单的数据分析:
select count(tx.*) as Backers , SUM(tx."value"/1e18) as Raised, sum((tx.gas_price/1e18)*tx.gas_used) as GasFee from ethereum.transactions tx
where tx."to" = '\x2B3b54932db9a8edd31DCd03aC34B45E98f3FC34'::bytea
《DeFi入门手册》 ,目前支持次数205,筹集到7.6ETH,总花费交易手续费1.21ETH,可以看出在主网做资金筹集成本还是有些高,大概占到项目资金的15%。
crowdfund://0x2B3b54932db9a8edd31DCd03aC34B45E98f3FC34?features=overview,backers
近期文章: Mirror.xyz 通向web3.0的一道窄门 使用Mirror发起一个知识付费项目,做一次WEB3.0的探索
梯子搭建教程 - iGG
igg是一个chrome浏览器插件,安装后有免费使用的梯子(翻墙软件),也可付费升级更好用的通道。下面介绍安装使用方法: 1、下载igg谷歌助手安装文件:https://www.jianguoyun.com/p/DdaKJMMQruH_CRjSqJoE ,解压到本地,文件名为:igg2.0.5.0.crx 也可至官方下载:https://iguge.xyz/ 2、打开chrome浏览器,在浏览器右上角点击三个竖点,选择“更多工具”->“扩展程序”3、在打开的页面中,将右上角“开发者模式”打开,如下图:4、将下载的igg扩展程序文件(igg2.0.5.0.crx)拖至chrome扩展程序窗口,选择“添加扩展程序”5、在扩展程序页面,找到igg谷歌访问助手,将右下角按钮点至右侧打开状态,如下图:6、打开扩展程序后,默认会弹出注册页面,使用个人邮箱注册,如下图:7、登录后,在chrome浏览器右上角可以看到igg图标为“on”状态,如果看不到,可以点击拼图图标,在下拉页面中查看,如图:8、点击igg图标,可以看到当前链接状态为“免费智能专线”9、点击igg右上角vip红色图标,可以充值...
LUNA 套利者的饕餮盛宴
UST脱锚的前情就不多说了,这个目前已有很多分析文章,本质问题都分析的很透彻。 我也是第一次见第一天跌了95%+的代币,第二天还能继续跌99%,而此种情况下,交易所还暂没下架,借贷协议也没暂停借贷。 从这里可以分析出很多,争取通过这个事件,让自己能学习到更多的风险管理知识、套利策略和风险规避动作。 整个事件的分水岭,应该是DK的发言。在这之前,大家主要关注有什么措施能让UST重新锚定。 而DK的发言, 清晰的表明他们没有任何外部解决方法。从推文可以看出,他先是说了UST稳定的原理,引用了一个DEPEG的详细说明:之后这两条是重点,他明确只能依靠DEPEG机制,不断的燃烧UST,增发LUNA,通过套利的形式让UST回到1。为了增加这一进程,社区还在投票一个增加了燃烧效率的提案,以便加快UST套利速度。看到这两条消息,我的第一反应是项目完蛋了,如果这么燃烧,按照LUNA当时的市值基本很快就会归零。 第一个机会点是消息面做空。风险是交易所关闭充提,杀空头。 DK下午发言后,LUNA在交易所价格也很快到了0.7附近。但这时交易所关闭了充提,LUNA价格被拉到7。 此后大概进入了美区交易时...
遨游元宇宙的必备工具(1)
李老师前几天发文说了他对元宇宙的看法,简单说元宇宙就是网络平行空间,我们每个人都身在其中。 楚门每天过着一样的生活,如果不是他死去的父亲重新出现,可能他也不会对周围的一切产生怀疑。 黑客帝国中,matrix营造了一个非常真实的平行空间,每个人身在其中乐此不疲而不自知。 多年前的某一天,我浑身一个激灵,发现自己也在这个空间里。 发现更大的世界,首先需要的是自我意识的苏醒,另外就是需要得心应手的工具和得当的方法。 前几天介绍过igg的用法,梯子是精神逃离matrix的第一条通道。同时也介绍了加密钱包metamask的用法,加密钱包是生存在元宇宙的最基础工具,衣食住行全靠它。 本文将对其他自认为重要的元宇宙生存必备工具进行介绍:1、chrome浏览器igg梯子和Metamask加密钱包两篇教程,都使用到了chrome作为基础平台。chrome是一个非常好用且必要的浏览器,拥有大量的好用插件,比如梯子、自动翻译、加密钱包、自动格式转换、安全工具等等。 chrome安装资源:windows系统建议直接使用360软件助手安装mac intel安装包:https://www.jianguoyu...
梯子搭建教程 - iGG
igg是一个chrome浏览器插件,安装后有免费使用的梯子(翻墙软件),也可付费升级更好用的通道。下面介绍安装使用方法: 1、下载igg谷歌助手安装文件:https://www.jianguoyun.com/p/DdaKJMMQruH_CRjSqJoE ,解压到本地,文件名为:igg2.0.5.0.crx 也可至官方下载:https://iguge.xyz/ 2、打开chrome浏览器,在浏览器右上角点击三个竖点,选择“更多工具”->“扩展程序”3、在打开的页面中,将右上角“开发者模式”打开,如下图:4、将下载的igg扩展程序文件(igg2.0.5.0.crx)拖至chrome扩展程序窗口,选择“添加扩展程序”5、在扩展程序页面,找到igg谷歌访问助手,将右下角按钮点至右侧打开状态,如下图:6、打开扩展程序后,默认会弹出注册页面,使用个人邮箱注册,如下图:7、登录后,在chrome浏览器右上角可以看到igg图标为“on”状态,如果看不到,可以点击拼图图标,在下拉页面中查看,如图:8、点击igg图标,可以看到当前链接状态为“免费智能专线”9、点击igg右上角vip红色图标,可以充值...
LUNA 套利者的饕餮盛宴
UST脱锚的前情就不多说了,这个目前已有很多分析文章,本质问题都分析的很透彻。 我也是第一次见第一天跌了95%+的代币,第二天还能继续跌99%,而此种情况下,交易所还暂没下架,借贷协议也没暂停借贷。 从这里可以分析出很多,争取通过这个事件,让自己能学习到更多的风险管理知识、套利策略和风险规避动作。 整个事件的分水岭,应该是DK的发言。在这之前,大家主要关注有什么措施能让UST重新锚定。 而DK的发言, 清晰的表明他们没有任何外部解决方法。从推文可以看出,他先是说了UST稳定的原理,引用了一个DEPEG的详细说明:之后这两条是重点,他明确只能依靠DEPEG机制,不断的燃烧UST,增发LUNA,通过套利的形式让UST回到1。为了增加这一进程,社区还在投票一个增加了燃烧效率的提案,以便加快UST套利速度。看到这两条消息,我的第一反应是项目完蛋了,如果这么燃烧,按照LUNA当时的市值基本很快就会归零。 第一个机会点是消息面做空。风险是交易所关闭充提,杀空头。 DK下午发言后,LUNA在交易所价格也很快到了0.7附近。但这时交易所关闭了充提,LUNA价格被拉到7。 此后大概进入了美区交易时...
遨游元宇宙的必备工具(1)
李老师前几天发文说了他对元宇宙的看法,简单说元宇宙就是网络平行空间,我们每个人都身在其中。 楚门每天过着一样的生活,如果不是他死去的父亲重新出现,可能他也不会对周围的一切产生怀疑。 黑客帝国中,matrix营造了一个非常真实的平行空间,每个人身在其中乐此不疲而不自知。 多年前的某一天,我浑身一个激灵,发现自己也在这个空间里。 发现更大的世界,首先需要的是自我意识的苏醒,另外就是需要得心应手的工具和得当的方法。 前几天介绍过igg的用法,梯子是精神逃离matrix的第一条通道。同时也介绍了加密钱包metamask的用法,加密钱包是生存在元宇宙的最基础工具,衣食住行全靠它。 本文将对其他自认为重要的元宇宙生存必备工具进行介绍:1、chrome浏览器igg梯子和Metamask加密钱包两篇教程,都使用到了chrome作为基础平台。chrome是一个非常好用且必要的浏览器,拥有大量的好用插件,比如梯子、自动翻译、加密钱包、自动格式转换、安全工具等等。 chrome安装资源:windows系统建议直接使用360软件助手安装mac intel安装包:https://www.jianguoyu...
Share Dialog
Share Dialog

Subscribe to 不确定思维

Subscribe to 不确定思维
<100 subscribers
<100 subscribers
No activity yet