关于 feeds
Goldsky Feeds 是通过 HTTP 查询钱包余额和转账记录的服务,面向需要跨支持链读取标准化钱包数据的调用方。它由 Goldsky 负责索引、归一化和定价,无需用户运行数据管道。
主要功能
- 01查询钱包代币余额及美元总值
- 02获取按时间倒序排列的转账
- 03按链、代币和方向筛选
- 04支持分页读取结果
- 05通过 API 密钥进行 HTTP 请求
适用场景
- 01查看钱包当前持有的资产
- 02查询钱包的转入与转出记录
- 03按链或代币合约筛选钱包数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ goldsky-io/ goldsky-agent --skill feeds安装后在 Claude Code 中输入/feeds确认已加载。
详细介绍
Goldsky Feeds
Feeds 通过 HTTP 回答有关单个钱包的一个问题:它持有什么,或它在受支持的链上发送和接收了什么;一次请求即可获取。Goldsky 会为这些记录建立索引、进行规范化并定价。调用方无需运行管道。
同一主机和同一个密钥也提供 Polymarket 和区块头 feeds。这些列在“此密钥上的其他 feeds”下,且不遵循以下约定。
CLI 获取密钥(goldsky feeds key reveal);feeds 本身使用纯 HTTP。没有 goldsky feeds 读取命令。不要使用 goldsky edge create 创建密钥。端点名称 feeds 在 Edge 创建流程中为保留名称,因此该命令会被拒绝。CLI 登录令牌是另一种凭据,无法用于验证这些请求。不要打印 Feeds 密钥。
何时不该使用此工具
- 需要将记录写入用户自己的数据库或 webhook。这属于 Turbo 管道(
/turbo-builder、/datasets)。Feeds 不会将数据流式传输到接收端;目前尚未提供流式传输(https://docs.goldsky.com/feeds/streaming)。 - 问题涉及 Turbo 数据集名称或链前缀。这属于
/datasets。这些前缀有所不同:Feeds 使用polygon和arbitrum_one,Turbo 使用matic和arbitrum。 - 问题涉及 JSON-RPC。这属于
/edge;如果用户想继续使用当前的服务提供商,则属于/boost。
密钥
一个项目只有一个 Feeds 密钥,所有 feed 都使用该密钥进行响应。通过 CLI 获取。不要让用户前往控制面板,也不要运行 goldsky edge create。
goldsky feeds key reveal
export GOLDSKY_FEEDS_API_KEY="$(cat "$HOME/.goldsky/feeds-api-key")"
reveal 会在项目没有密钥时创建密钥,否则获取现有密钥,并将其写入 ~/.goldsky/feeds-api-key(权限模式为 600)。它绝不会打印或轮换密钥,因此可以安全地重复运行。不要将该文件的内容 cat 到聊天中,也不要将密钥写入其他任何位置。
成功时会打印 Created Feeds API key and saved it to ~/.goldsky/feeds-api-key 或 Saved existing Feeds API key to ~/.goldsky/feeds-api-key。如果它打印的是通用帮助信息,则说明 CLI 版本低于 13.17.0(旧版 CLI 在这种情况下仍会以 0 退出,因此应查看输出,而不是退出代码);运行 /auth-setup 安装指定版本。不要传入 --token。401 表示用户未登录:先使用 /auth-setup。403 表示用户不是该项目的 Editor。409 表示存在名为 feeds 的 Edge 端点,且它并非 Feeds 密钥;必须先删除该端点。
除非用户提出要求,否则不要轮换密钥:轮换会立即撤销当前密钥。
在 x-api-key 标头中发送密钥。也接受 ?key= 和 Authorization: Bearer,但应优先使用标头,以免密钥出现在 URL 日志中。缺少密钥时会返回带有 x402 付款要求正文的 402,而非 401,因为这些 feeds 也支持按请求付费。密钥已提供但不正确时会返回 401。因此,收到 402 时,表示标头未送达;在认定密钥无效之前,请检查是否已设置 GOLDSKY_FEEDS_API_KEY。
调用
curl -sS -H "x-api-key: $GOLDSKY_FEEDS_API_KEY" \
"https://edge.goldsky.com/data/feeds/wallets/balances?address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
curl -sS -H "x-api-key: $GOLDSKY_FEEDS_API_KEY" \
"https://edge.goldsky.com/data/feeds/wallets/transfers?address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
Balances 会返回该钱包所持每种代币的最新余额,包括原生资产,并附带 total_value_usd。Transfers 会按时间从新到旧返回该钱包的资金变动。direction 相对于 address,取值为 in 或 out。
在使用快速入门未展示的参数或响应字段之前,请先阅读 https://edge.goldsky.com/data/openapi.json。该文档是接口规范。指南为 https://docs.goldsky.com/feeds/quickstart,概览为 https://docs.goldsky.com/feeds。
当 ClickHouse 上游服务失败时,两个 feed 都可能返回 502;当某些链上的原生余额不可用时,balances 可能返回 503。503 响应会在 error.chains 中列出这些链,并设置 Retry-After;这是部分服务中断,应重试,而不是报告该钱包为空。
address 为必填项,且只能是一个钱包。EVM 地址的格式为 0x 加 40 位十六进制数字。Base58 Solana 地址可以通过验证,但目前尚无对应的链,因此会返回 200 和空的 data。非 200 响应正文表示错误,而非空钱包。
参数
请求被拒绝时,请重新读取 OpenAPI 规范。这些是 URL 上的查询参数。链集合由 chains 参数指定。
- 省略
chains可查询所有受支持的链。传入以逗号分隔的规范 slug。matic、arbitrum和mainnet分别是polygon、arbitrum_one和ethereum的别名。匹配不区分大小写,-会按_读取。其他拼写都会返回 400。 token_symbol按符号匹配,因此两个合约都可能匹配——usdc一次会返回多个链上的原生合约和桥接合约。若要指定某个合约的代币,请使用token_address;最多可传入 100 个,以逗号分隔。在余额查询中,零地址会选择范围内每条链的原生资产。include_unknown_price默认为 false,这会排除 Goldsky 没有价格来源的代币。这并不保证每一行都有价格:默认情况下,即使代币可定价,返回行中的price_usd和value_usd仍可能为 null。请对每一行的 null 价格进行处理。include_historical默认为 false。在余额查询中将其设为 true,还会返回余额为零的行:已全部卖出的代币,以及钱包未持有的原生资产。一个钱包的返回行数因此从 373 增至 517。要回答“这个钱包是否曾持有 X”,需要启用此项;若要了解“它现在值多少”,则不需要。min_value_usd会删除低于该美元价值的行,也会删除未定价的行。它也适用于total_value_usd。- 在转账查询中,
from和to是block_timestamp的 RFC 3339 起止边界,且包含边界值。from_block和to_block必须恰好指定一条链,因为不同链的区块编号无法比较;若未指定单条链,则返回 422CONFLICTING_FILTERS,而非 400。transfer_type可设为native、erc20或两者,以逗号分隔。NFT 类型(erc721、erc1155)会返回 400。spl可接受,并会返回 200,且data为空,因为目前尚未提供 Solana 链:这个空页面表示该筛选条件未匹配到 EVM 链上的记录,并不表示钱包为空。direction可设为in或out。 page_size默认为 100,最大值为 1000。超出时会截断为 1000,而不是拒绝请求,因此请读取pagination.page_size,不要假定请求的数量已获接受。下一页需将page_token设为上一响应中的pagination.next_page_token。令牌仅对生成它的筛选条件有效。每一页都是单独计费的请求(https://docs.goldsky.com/pricing/summary#feeds)。除非用户要求查询相应范围,否则不要遍历完整历史记录。
此密钥可访问的其他数据流
/polymarket/activity、/polymarket/positions、/polymarket/balances、/blocks/{chain} 和 /blocks/{chain}/head 由同一主机和同一密钥提供服务。查询 Polymarket 问题不一定要构建成管道:只有当数据行必须写入用户自己的数据库时,才使用 /turbo-builder。调用方式相同,都需要使用 x-api-key 标头。调用前请先阅读 OpenAPI 规范,因为以上三种约定都有所不同:
- 分页参数是
limit和cursor,而不是page_size和page_token;下一页游标位于顶层的next_cursor,而不是pagination.next_page_token。传入page_size会被接受但静默忽略,因此,本想请求 2 行数据的请求会返回默认的 100 行——且每一行都会计费。请检查返回的数据。 - 链名称与钱包数据流使用的名称不同。
/blocks提供 21 条链,并将 Polygon 写作matic;polygon、mainnet以及任何arbitrum拼法在这里都会返回 400。钱包数据流提供 7 条链,并将其写作polygon,matic仅是别名。在一个接口中可用的标识符,不代表在另一个接口中也可用。 - 错误响应不总是
{"error":{"code","message"}}这种格式。 这些路径上的错误查询字符串会以纯字符串形式返回(Failed to deserialize query string: ...),因此读取.error.message会得到 null。请根据状态码分支处理,而不要根据响应体的结构处理。 - 不同路径的数值缩放方式不同。
/polymarket/activity返回的 JSON 数值已经是十进制形式(price: 0.65、amount_shares: 84.615385、amount_usdc: 55.0,且amount_usdc / amount_shares == price)。/polymarket/positions和/polymarket/balances返回的是原始 1e6 整数单位的字符串,因此avg_price: "100000"表示 $0.10,amount: "12120000000"表示 12120 股。向用户显示这两项之前,都要除以 1e6。positions.amount和balances.balance使用相同的缩放比例,但并非相同数量;在此抽样的行中,有一半两者数值不一致:amount是根据交易计算得出的净持仓,balance是实际持有的条件代币余额,而拆分、合并、赎回和普通转账都会在没有成交的情况下转移代币。请选择能回答问题的字段,不要用一个替代另一个。 /polymarket/activity不允许进行无筛选的宽泛查询。 必须提供以下条件之一:address、token_id、不超过 300000 个区块的闭合区块范围、不超过 604800 秒的闭合时间范围,或者在无筛选条件时将limit设为 100 或更小。其他情况都会返回 400MISSING_SELECTIVE_FILTER。- 规范中有三个值附带警告。 源数据中,某些 maker/taker 配对的
activity.fee基准不一致。positions.last_updated_at是管道的 upsert 时间,而非区块时间,因此不同block_number的行可能具有相同的时间;请使用block_number排序。balances.as_of_block是按插入顺序确定的不晚于该区块的最新余额,并非对该区块状态的重建。
针对响应编写代码
- 余额是每种代币的最新数量,而非历史记录。同一区块内的多笔转账会合并为一条余额行。请从转账数据流重建代币变动。
- 转账对象没有 ID。不要将
block_number或block_timestamp纳入主键:经过重组后仍保留的交易会带有不同的区块字段。也不要假设一笔交易只会产生一条转账记录。 price_usd和amount_usd是在处理请求时计算的。之后再次读取同一笔转账时,显示的美元数值可能不同。