在以太坊上检索历史数据可能颇具挑战性,尤其是当你只需要特定子集的数据时。本指南将详细介绍如何利用流技术来回填历史以太坊数据,筛选出 ERC-20 代币转账记录,并将其发送至 Postgres 数据库以供进一步分析。
准备工作
在开始之前,请确保您已准备好以下内容:
- 一个可用的账户(立即注册)
- 对以太坊及 ERC-20 代币的基本了解
- 一个 Postgres 数据库(本指南将使用 Supabase)
核心步骤详解
第一步:创建数据流
从您的控制面板导航至“流”页面,点击“+ 创建流”按钮。
- 网络选择:在设置卡中选择“Ethereum”和“Mainnet”网络,数据集选择“Transactions”。
- 流配置:
- 可为您的流设置一个独特的名称,或使用自动生成的名称。
- 设置批次大小(Batch Size):实时流处理默认值为
1
,但对于历史数据回填,较大的批次大小通常更高效。建议本例设置为10
,您也可根据具体需求调整。 - 流起始点:使用给定时间的最新区块号作为起始区块。若回填历史数据,通常需选择更早的区块号作为起点。
- 流结束点:勾选切换框,将结束区块号设置为起始区块后 100 个区块。这为演示提供了可管理的样本量。您也可选择不结束流,但请注意这将导致持续的数据检索。
- 数据处理:选择“在流式传输前修改有效负载”,此步骤至关重要,可确保仅筛选所需数据,避免清理或为不必要的数据付费。
您将看到一个 JavaScript 代码编辑器,用于您的 main
函数。初始代码通常如下:
function main(stream) {
const data = stream.data;
return data;
}
若不进行数据过滤,您将收到指定区块范围内所有交易数据,这可能非常庞大且成本高昂。返回的交易数据是一个 JSON 对象。
第二步:筛选流数据(仅限 ERC-20 转账)
现在,调整过滤器代码,使其仅跟踪 ERC-20 转账交易。将代码更新为以下内容:
function main(stream) {
try {
const data = stream.data;
const transactions = data[0];
const filteredTransactions = [];
const transferMethodId = '0xa9059cbb';
transactions.forEach((transaction) => {
if (
typeof transaction === 'object' &&
transaction !== null &&
typeof transaction.input === 'string'
) {
if (transaction.input.startsWith(transferMethodId)) {
const toAddress = '0x' + transaction.input.substr(34, 40);
const value = BigInt('0x' + transaction.input.substr(74));
filteredTransactions.push({
txHash: transaction.hash,
fromAddress: transaction.from,
toAddress: toAddress,
amount: value.toString(),
tokenContract: transaction.to,
blockNumber: transaction.blockNumber,
});
}
}
});
return filteredTransactions;
} catch (e) {
return { error: e.message };
}
}
代码功能解析:
main
函数接收一个stream
参数,该参数包含有效负载数据(本例中为交易数组)和流的元数据。- 初始化一个空数组
filteredTransactions
用于存储筛选结果。 transferMethodId
设置为 “0xa9059cbb”,这是 ERC20 代币转账函数的方法 ID。- 函数遍历
stream
数组中的每个交易: a. 检查交易是否为具有input
属性(字符串类型)的有效对象。 b. 如果input
以转账方法 ID 开头,则处理该交易:- 从输入数据中提取
toAddress
(输入的字节 4-23,不包括方法 ID)。 - 从输入数据中提取
value
(转账金额,从字节 24 开始)并将其转换为 BigInt。 c. 然后构建一个包含相关交易详情的新对象,并将其添加到filteredTransactions
数组中。
- 从输入数据中提取
- 最后,返回
filteredTransactions
数组。 - 若在此过程中发生任何错误,则捕获错误并返回包含错误消息的对象。
点击“运行测试”,您应能看到一些类似的转账记录(假设测试的区块号包含代币转账交易)。您可以使用区块 20930625
进行测试以复现相同结果。
第三步:设置您的数据库
在设置流的目标之前,我们需要一个存储数据的地方。本指南使用 Postgres 数据库。如果您没有数据库,可以在 Supabase 上创建一个。请记住您的数据库密码,后续步骤需要用到。
我们的流将自动在您的数据库中创建一张表。我们只需向流提供连接详细信息。
如果您使用 Supabase,请在“项目设置”页面的“数据库”选项卡下找到您的连接信息。请准备好此信息。
第四步:设置流的目标
现在我们将告诉流将数据发送到哪里:
- 转到您的流配置页面。
- 在“目标类型”中,选择“PostgreSQL”。
- 输入您的数据库连接详细信息(来自第三步)并为您的表命名 - 我们将使用
erc20-token-transfers
。
填写详细信息后,点击“测试目标”按钮测试连接。如果成功,您将看到一个绿色的弹出窗口。
然后,点击“创建流”完成设置。
第五步:查看数据库与查询
流创建成功后,您应该在 Supabase 的表查看器中看到以太坊交易数据:
我们可以看到每行包含一个 JSON 对象。由于这些转账涵盖所有类型的地址,您可能需要专注于某个特定的钱包地址。在设置新表之前,我们需要找到一个要查询的地址。
返回您的 “erc20-token-transfers” 表,找到一个您想要调查的地址(即在 data
列中,查找 fromAddress
或 toAddress
字段)。确定地址后,您可以继续为该地址创建单独的代币转账跟踪表。
现在,导航到 Supabase 上的“SQL 编辑器”选项卡。我们将一起输入以下查询(即步骤 1 和步骤 2),然后点击“运行”执行它们。
1. 创建表
CREATE TABLE specific_address_transfers (
block_number BIGINT,
network TEXT,
tx_hash TEXT,
amount NUMERIC,
to_address TEXT,
from_address TEXT,
token_contract TEXT
);
这将创建一个名为 specific_address_transfers
的新表,其中包含转账详细信息的列。
2. 插入数据
INSERT INTO specific_address_transfers (
block_number,
network,
tx_hash,
amount,
to_address,
from_address,
token_contract
)
SELECT
(('x' || LTRIM(transfer->>'blockNumber', '0x'))::bit(64)::bigint),
network,
transfer->>'txHash',
(transfer->>'amount')::NUMERIC,
transfer->>'toAddress',
transfer->>'fromAddress',
transfer->>'tokenContract'
FROM
"erc20-token-transfers",
jsonb_array_elements(data::jsonb) AS transfer
WHERE
transfer->>'fromAddress' = 'ETHEREUM_ADDRESS'
OR transfer->>'toAddress' = 'ETHEREUM_ADDRESS';
SELECT COUNT(*) FROM specific_address_transfers;
这将通过以下方式将数据插入新表:
- 从 “erc20-token-transfers” 表中选择(如果需要请更新此表名)
- 解析 ‘data’ 列中的 JSON 数据
- 将十六进制区块号转换为 bigint
- 筛选指定地址作为发送方或接收方的转账(您需要将
ETHEREUM_ADDRESS
值更新为有效的地址) - 计算给定地址检测到的转账次数
重要提示:如果您使用不同的表名,则需要将表名
erc20-token-transfers
更新为您的表名。此外,将ETHEREUM_ADDRESS
更新为您要创建单独表来跟踪转账的有效以太坊地址。
现在,将两个查询都放入编辑器后,点击“运行”按钮执行查询。您应该看到“成功。未返回任何行”或“计数:{数字}”的结果,并且在导航回“表编辑器”选项卡后会看到一个新表。
至此,您已成功创建了一个用于通过流和 Supabase 跟踪 ERC-20 转账的数据管道。这仅仅是开始,您可以探索流的更多功能并实践自己有趣的想法。
拓展应用与进阶探索
想要在此基础上继续构建吗?请尝试以下操作:
- 扩展过滤器:以包含其他代币标准(例如 ERC-721, ERC-1155 等)。
- 获取额外元数据:例如每个代币合约的小数位数(用于准确表示代币数量)、代币名称和代币符号。
- 创建查询:以分析代币转账模式(例如趋势或巨鲸动向)。
- 构建仪表板:以可视化随时间变化的代币转账活动。
👉 探索更多区块链数据策略 以获取实时工具和进阶方法,助您深入了解链上数据。
常见问题
回填历史数据时,批次大小应如何设置?
对于历史数据回填,建议使用较大的批次大小(例如 10 或更高)以提高效率。实时流处理则通常使用较小的批次大小(如 1)。您应根据数据量、网络状况和处理能力进行调整。
除了 ERC-20,还可以筛选哪些类型的交易?
您可以筛选任何具有特定方法 ID 的交易。常见的包括 ERC-721 的 safeTransferFrom
(0x42842e0e)、ERC-1155 的 safeBatchTransferFrom
(0x2eb2c2d6) 等。只需在过滤代码中替换相应的 transferMethodId
即可。
如果遇到连接数据库失败的问题,该如何排查?
首先检查数据库连接字符串(主机、端口、数据库名、用户名、密码)是否正确无误。确保数据库允许从流服务所在网络的连接(检查防火墙或安全组设置)。此外,验证数据库服务是否正常运行。
如何准确处理代币金额?为什么需要小数位数?
原始链上数据中的代币金额是以最小单位(如 Wei)表示的整数。要获得实际金额,需要除以 10^(代币小数位数)
。因此,获取并存储代币合约的小数位数信息对于准确表示金额至关重要。您可以通过调用代币合约的 decimals()
函数来获取该信息。
此方法是否适用于其他以太坊兼容链?
是的,此方法通常适用于任何与以太坊虚拟机(EVM)兼容的区块链网络(如 BNB Smart Chain, Polygon, Avalanche C-Chain 等)。在创建流时,只需选择相应的网络即可。请注意,不同网络的区块数据范围和历史可用性可能有所不同。
通过本指南,您不仅学会了回填特定 ERC-20 代币转账数据,还掌握了构建自定义区块链数据管道的基本方法。这将为您进行链上数据分析、监控和应用开发奠定坚实的基础。