在区块链数据分析中,ERC20 代币价格查询是一项常见且关键的技能。无论是追踪特定代币的价格波动,还是分析地址持有的资产价值,掌握高效的价格查询方法都至关重要。本文将系统介绍多种查询策略,帮助你在不同场景下灵活获取准确的价格数据。
为什么需要查询 ERC20 代币价格?
ERC20 是以太坊上最广泛的代币标准,众多 DeFi 项目依赖其实现代币交换、流动性提供和收益 farming 等功能。项目方也常通过发行 ERC20 代币进行募资,或通过空投奖励社区用户。准确获取代币价格不仅有助于投资决策,更是进行数据分析和资产估值的基础。
主流数据平台如 CoinGecko 提供了丰富的代币价格信息,而在链上分析工具 Dune 中,价格数据被结构化地存储在 prices.usd 和 prices.usd_latest 表中,方便分析师直接调用与集成。
基础查询:获取单个代币的最新价格
通过代币符号查询
prices.usd 表按分钟记录代币价格,结合时间筛选可获取最新数据。以下查询以 WETH 为例,从最近 6 小时数据中取最新记录:
SELECT * FROM prices.usd
WHERE symbol = 'WETH'
AND blockchain = 'ethereum'
AND minute >= NOW() - INTERVAL '6 hours'
ORDER BY minute DESC
LIMIT 1通过合约地址查询
若已知代币合约地址,可替代符号进行查询,提高准确性:
SELECT * FROM prices.usd
WHERE contract_address = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
AND minute >= NOW() - INTERVAL '6 hours'
ORDER BY minute DESC
LIMIT 1使用 usd_latest 表简化查询
prices.usd_latest 表视图中每个代币仅保留最新价格记录,使查询更简洁:
SELECT * FROM prices.usd_latest
WHERE symbol = 'WETH'
AND blockchain = 'ethereum'尽管查询简单,但该视图基于 prices.usd 表生成,执行效率略低,在复杂查询中需注意性能影响。
进阶查询:获取多个代币价格与日均数据
批量查询最新价格
同时获取多个代币价格时,prices.usd_latest 的优势明显:
SELECT * FROM prices.usd_latest
WHERE symbol IN ('WETH', 'WBTC', 'USDC')
AND blockchain = 'ethereum'若需从 prices.usd 表实现相同功能,需使用窗口函数按代币分组排序:
SELECT symbol, decimals, price, minute
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY minute DESC) AS row_num,
*
FROM prices.usd
WHERE symbol IN ('WETH', 'WBTC', 'USDC')
AND blockchain = 'ethereum'
AND minute >= NOW() - INTERVAL '6 hours'
) p
WHERE row_num = 1计算每日平均价格
分析历史价格趋势常需计算日均价,此时需使用 prices.usd 表并按天聚合:
SELECT
DATE_TRUNC('day', minute) AS block_date,
AVG(price) AS price
FROM prices.usd
WHERE symbol = 'WETH'
AND blockchain = 'ethereum'
AND minute >= '2022-01-01'
GROUP BY 1
ORDER BY 1添加代币信息字段时,需将这些字段纳入 GROUP BY 子句:
SELECT
DATE_TRUNC('day', minute) AS block_date,
symbol,
decimals,
contract_address,
AVG(price) AS price
FROM prices.usd
WHERE symbol = 'WETH'
AND blockchain = 'ethereum'
AND minute >= '2022-01-01'
GROUP BY 1, 2, 3, 4
ORDER BY 1批量查询多个代币日均价仅需调整 WHERE 条件:
SELECT
DATE_TRUNC('day', minute) AS block_date,
symbol,
decimals,
contract_address,
AVG(price) AS price
FROM prices.usd
WHERE symbol IN ('WETH', 'WBTC', 'USDC')
AND blockchain = 'ethereum'
AND minute >= '2022-10-01'
GROUP BY 1, 2, 3, 4
ORDER BY 2, 1高阶方法:当标准价格表缺失时的应对策略
从 DEX 兑换数据推导价格
新兴代币可能未被收录至标准价格表,此时可从去中心化交易所的兑换记录中推导价格。以 Uniswap V3 中的 XEN 代币为例:
WITH xen_price_in_usdc AS (
SELECT
DATE_TRUNC('hour', evt_block_time) AS block_date,
'XEN' AS symbol,
'0x06450dee7fd2fb8e39061434babcfc05599a6fb8' AS contract_address,
18 AS decimals,
AVG(amount1 / amount0) / POW(10, (6-18)) AS price
FROM (
SELECT
contract_address,
ABS(amount0) AS amount0,
ABS(amount1) AS amount1,
evt_tx_hash,
evt_block_time
FROM uniswap_v3_ethereum.Pair_evt_Swap
WHERE contract_address = '0x353bb62ed786cdf7624bd4049859182f3c1e9e5d'
AND evt_block_time > '2022-10-07'
AND evt_block_time > NOW() - INTERVAL '30 days'
) s
GROUP BY 1, 2, 3, 4
),
usdc_price AS (
SELECT
DATE_TRUNC('hour', minute) AS block_date,
AVG(price) AS price
FROM prices.usd
WHERE contract_address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
AND minute > '2022-10-07'
AND minute > NOW() - INTERVAL '30 days'
GROUP BY 1
)
SELECT
x.block_date,
x.price * u.price AS price_usd
FROM xen_price_in_usdc x
INNER JOIN usdc_price u ON x.block_date = u.block_date
ORDER BY x.block_date使用 dex.trades 魔法表简化计算
若代币交易已集成至 dex.trades 表,可直接利用其中的美元计价数据简化计算:
WITH trade_detail AS (
SELECT
block_time,
tx_hash,
amount_usd,
token_bought_amount,
token_bought_symbol,
token_sold_amount,
token_sold_symbol
FROM dex.trades
WHERE project_contract_address = '0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8'
AND block_date >= NOW() - INTERVAL '3 days'
ORDER BY block_time DESC
LIMIT 1000
)
SELECT
AVG(
CASE
WHEN token_bought_symbol = 'WETH' THEN amount_usd / token_bought_amount
ELSE amount_usd / token_sold_amount
END
) AS price
FROM trade_detail处理原生代币与跨链价格查询
以太坊原生代币 ETH 虽非 ERC20 标准,但可通过等值的 WETH 代币获取其价格。对于其他区块链上的代币,若标准价格表未覆盖,可通过地址映射关联至以太坊主网代币:
WITH token_mapping_to_ethereum(aave_token_address, ethereum_token_address, token_symbol) AS (
VALUES
('0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', '0xdac17f958d2ee523a2206206994597c13d831ec7', 'USDT'),
('0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f', '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', 'WBTC')
-- 更多代币映射条目
),
latest_token_price AS (
SELECT
DATE_TRUNC('hour', minute) AS price_date,
contract_address,
symbol,
decimals,
AVG(price) AS price
FROM prices.usd
WHERE contract_address IN (
SELECT ethereum_token_address FROM token_mapping_to_ethereum
)
AND minute > NOW() - INTERVAL '1 day'
GROUP BY 1, 2, 3, 4
)
-- 更多处理逻辑...从原始事件日志中解析价格
在缺乏结构化数据的极端情况下,可直接解析区块链事件日志计算价格。以下示例通过解析 Optimism 链上 Swap 事件计算 OP 代币价格:
WITH op_price AS (
SELECT
'0x4200000000000000000000000000000000000042' AS token_address,
'OP' AS token_symbol,
18 AS decimals,
AVG(
(CASE WHEN amount0_in > 0 THEN amount1_out ELSE amount1_in END) /
(CASE WHEN amount0_in > 0 THEN amount0_in ELSE amount0_out END)
) AS price
FROM (
SELECT
tx_hash,
bytea2numeric_v2(SUBSTRING(data, 3, 64)) / 1e18 AS amount0_in,
bytea2numeric_v2(SUBSTRING(data, 3 + 64, 64)) / 1e6 AS amount1_in,
bytea2numeric_v2(SUBSTRING(data, 3 + 64 * 2, 64)) / 1e18 AS amount0_out,
bytea2numeric_v2(SUBSTRING(data, 3 + 64 * 3, 64)) / 1e6 AS amount1_out
FROM optimism.logs
WHERE block_time >= NOW() - INTERVAL '2 days'
AND contract_address = '0x47029bc8f5cbe3b464004e87ef9c9419a48018cd'
AND topic1 = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822'
ORDER BY block_time DESC
LIMIT 1000
)
)
SELECT * FROM op_price常见问题
如何选择最适合的查询方法?
根据数据新鲜度、准确性和执行效率综合考量:需最新价格时优先使用 prices.usd_latest;历史分析使用 prices.usd 表聚合;标准表缺失时从 DEX 数据推导。
查询性能优化有哪些技巧?
限制时间范围可显著提升查询效率;对常用代币创建物化视图;在频繁查询的字段上建立索引;避免全表扫描和使用复杂函数。
如何处理稳定币价格波动?
稳定币理论上锚定法币,但市场波动会导致轻微偏差。可查询多个稳定币价格取平均值,或指定特定稳定币作为计价基准减少误差。
新兴代币价格何时会被收录至标准表?
取决于数据提供商更新频率,通常需满足一定交易量和流动性门槛。在此期间需依赖 DEX 数据推导,并交叉验证多个交易所价格。
跨链价格查询有哪些注意事项?
不同链上相同代币可能有不同合约地址,需建立映射关系;注意跨链桥接代币与原生代币的汇率差异;考虑跨链交易延迟对价格的影响。
原始日志解析的主要挑战是什么?
需深入了解事件签名和数据编码规则;处理不同代币的小数位差异;验证解析结果的准确性;处理大数据量时的性能问题。
掌握这些方法后,你将能应对绝大多数 ERC20 代币价格查询场景,为区块链数据分析和投资决策提供坚实支撑。