BlockVectra

Robinhood Chain 代币化股票(Stock Tokens)数据集

Robinhood Chain 的招牌资产:把美股/ETF 映射成链上 ERC-20 代币(TSLA、AAPL、 NVDA ……)。本文档记录这套代币是怎么部署/管理的(附证据:交易哈希、合约地 址)、识别规则和置信度、由此建出的表,以及几条可以直接抄的查询。

Robinhood Chain 的招牌资产:把美股/ETF 映射成链上 ERC-20 代币(TSLA、AAPL、 NVDA ……)。本文档记录这套代币是怎么部署/管理的(附证据:交易哈希、合约地 址)、识别规则和置信度、由此建出的表,以及几条可以直接抄的查询。

研究方法:生产 ClickHouse 只读轻量查询(max_threads=2, max_execution_time=90)

  • 对候选合约做 eth_call name()/symbol()/decimals()(单次 JSON-RPC batch, 102 个合约 × 3 个方法 = 306 次调用打包成 1 次 HTTP 请求,对节点几乎零负载)。 研究日期:2026-09-25,生产链上高度 72,035,708。

1. 这些代币是怎么发出来的

1.1 单一工厂合约,单一部署者

生产链上现存的 102 个"股票代币"全部由同一个工厂合约创建:

  • 工厂合约:0x4783c67b63de2b358ac5951a7d41f47a38f3c046
  • 调用方(部署者 EOA):0x5516b3451d4d6c9f63353fe7bc9537477ecce000 (102/102 次创建调用都来自这个地址;另有 1 次来自 0x697e774d60c1a3769f2ed0b919aacf17be0ae553,selector 是标准 UUPS upgradeToAndCall(address,bytes)(0x4f1ef286),即工厂本身是可升级代理,这 1 次是对工厂的一次合约升级,不是创建代币)
  • 创建方法 selector:0xb2670cc5(createToken(...),参数签名未逐字节反解, 不影响识别规则)

实锤交易(均可在生产 robinhood.transactions/robinhood.logs 里查到):

代币创建区块创建交易
TSLA (Tesla)34,7670xc4c1c585493272cb137f1039546033e9200c249e82579f77eed26041929e80a8
AAPL (Apple)48,2760x5ddd494c3217a5e3ef5b8f32471669c4d09d544354d790e744cd9c39ded5901b
NVDA (NVIDIA)45,8980xcdb797c54ff55ef4008f254c486cc52d7393a65a6e6fb622c44b0260eecb755f

两笔交易(TSLA、AAPL)的 from/to/selector 完全一致: from = 0x5516b345...ecce000,to = 0x4783c67b...f3c046(工厂), input 前 4 字节 = 0xb2670cc5;transactions.contract_address 为 NULL——代币合约不是这笔交易的顶层创建(to = NULL 的那种),而是工厂内部 CREATE/CREATE2 出来的,所以只能从工厂发出的事件里拿到代币地址。

1.2 工厂发出的 TokenCreated 事件

每次创建都在工厂地址上产生 1 条日志,topic0 = 0xd9b0c6a1c0de228715ad0fa09f3259686ee84f8cc675e03ef7e47a9cdafa76d6,1 个未解 出具体含义的 indexed 参数(topic1,不是地址形状,可能是内部 id 或 symbol 的哈希——没有查证,这里不猜),data 是标准 ABI 编码的 (address token, string name, string symbol):

data (TSLA 创建事件, 十六进制, 已按 32 字节分段):
  000000000000000000000000322f0929c4625ed5bad873c95208d54e1c003b2d   -- token 地址
  0000000000000000000000000000000000000000000000000000000000000060  -- name 的偏移量
  00000000000000000000000000000000000000000000000000000000000000a0  -- symbol 的偏移量
  0000000000000000000000000000000000000000000000000000000000000019  -- name 长度 = 25
  5465736c6120e280a220526f62696e686f6f6420546f6b656e00...             -- "Tesla • Robinhood Token"
  0000000000000000000000000000000000000000000000000000000000000004  -- symbol 长度 = 4
  54534c4100...                                                       -- "TSLA"

代币合约自己在同一笔交易里还会发 2 条日志(topic0 = 0x1cf3b03a... 携带一个地址型参数,topic0 = 0xc7f505b2... 携带值 1 — 后者和 OpenZeppelin Initializable 的 Initialized(uint8) 形状吻合,说明代币 合约本身是可初始化的(代理/克隆)实现,但没有逐字节核对具体是哪个开源库版 本,同样不过度声称)。

1.3 命名规律 + 代币属性

  • 命名:"<公司/资产名> • Robinhood Token"(中间是 U+2022 项目符号), symbol = 真实的美股/ETF ticker(TSLA、AAPL、NVDA、MSFT、AMZN、 GOOGL、META、COIN、ORCL、INTC、AMD、MU、BA、ARM、XOM ……)。

  • 不止"单一股票":102 个里有少数是 ETF,例如 WEEK = "Roundhill Weekly T-Bill ETF",走的是完全相同的工厂/事件/命名路径。本数据 集不把 ETF 排除在外,stock_tokens 表按行如实记录,不做"这个其实不算 股票"的静默改写。

  • decimals() 对全部 102 个代币做了 eth_call,结果全部是 18(不是假 设值——见下方 money-safety 说明)。

  • name() 存在事后改名的情况:102 个里有 4 个的当前 name() 和 创建时 TokenCreated 事件里的 name 不一致(symbol 均未变):

    代币地址创建时 name当前 name
    0xc93a8c...5099fRoundhill Weekly T-Bill ETFRoundhill Weekly T-Bill ETF • Robinhood Token
    0xc583c6...cea1ccD-Wave Quantum • Robinhood TokenD-Wave Quantum Inc. Common Stock • Robinhood Token
    0xf9b46d...f1a2d5Exxon Mobil • Robinhood TokenExxonMobil Holdings Corporation • Robinhood Token
    0x4a0e65...fae35eea (SPCX)SpaceX • Robinhood TokenSpace Exploration Technologies Corp. Class A Common Stock • Robinhood Token

    这是目前唯一观察到的"类企业行动"迹象(更规范的展示名称替换),没有看到 拆股/合股(split)迹象——erc20_transfers 里没有任何脱离正常 mint/transfer/burn 模式的批量再分配。是否存在更早期、本研究窗口之外的拆 股,未验证,不下结论。

1.4 铸造 / 赎回

  • 铸造(from = 零地址):97/102 个代币出现过铸造,共 1,367 笔,其中 1,367 笔里绝大多数的 to 都是同一个地址 0xcfaece2151502da2a21d47234ae1f08618a60a94(这就是发行方/托管方地址)。 示例:TSLA 首次铸造 0x66c9dd9bc1e983dee62b8d61499594b61ccde1f60fc8a7617e7a616fe3a4191e (区块 143,822,铸造 0.1 TSLA 给该地址)。
  • 赎回销毁(to = 零地址):37/102 个代币出现过销毁,共 171 笔,主要 from 是另一个地址 0xa8553db0049fc6843c0d00d0efc08d31848e3c74(和铸造地 址不同——推测是"发行"与"赎回处理"分别由两个角色地址执行,未向 Robinhood 官方核实,仅基于链上行为归纳)。
  • 5/102 个代币截至研究时还没有任何转账(刚创建、尚未启用交易)。
  • 这 97 个有活动的代币累计转账 25,373,473 笔——印证"招牌资产"级别的量。

1.5 未识别的伴生事件(如实标注不确定性)

统计全部 102 个代币合约日志的 topic0 分布:Transfer (0xddf252ad...) 和一个每次 Transfer 都伴生 1 条、次数完全相等 (均为 26,129,631)的未识别事件 0x37e7f0db430edc9dd31bc66f25f8449353aa0818f503b906747dd8f286cd3802 同时出现,含义未解码(推测可能与投票权快照/checkpoint 类的 ERC20 扩展有关, 但没有验证,不作为结论);Approval (0x8c5be1e5...) 342,848 次;另有 6 种 仅出现 1~8 次的稀有事件(0x2205df45...、0xa274116f...、0x0030cda6...、 0xe28b7053...、0xa45f47fd...、0x9e87fac8...),形状上像是权限 (role/ownership)或升级相关的管理事件,同样未逐个解码,不在此确认是否为 "暂停"(pause)——本研究没有找到确凿的 pause 事件证据,也没有证据证明不存 在,如实标注为未知。

2. 识别规则与置信度

规则:{db}.logs 里 address = 0x4783c67b63de2b358ac5951a7d41f47a38f3c046 且 topic0 = 0xd9b0c6a1c0de228715ad0fa09f3259686ee84f8cc675e03ef7e47a9cdafa76d6 的每一条日志,其 ABI 解出的 token 字段地址即为一个股票/ETF 代币。

置信度:HIGH。三条独立线索在生产数据上互相印证、完全收敛到同一批 102 个地址:

  1. 按转账笔数排序的高频 ERC-20 代币榜单里,除 WETH/USDG/VIRTUAL 等明 显的通用资产外,其余全部匹配 "• Robinhood Token" 命名。
  2. 对候选地址做 eth_call name()/symbol(),102/102 都匹配该命名规律, symbol 都是可识别的真实美股/ETF ticker。
  3. 102/102 都能追溯到同一个工厂合约 + 同一个部署者 EOA 发出的 TokenCreated 事件。

decimals 只在 eth_call decimals() 真正成功时才写入(102/102 目前都是 18),失败或没有配置 RPC_URL 时保持 NULL 而不是假设 18——对应 stock_tokens.confidence 字段:high(三线索齐全 + decimals 已验证)/ medium(decimals 本轮未验证)/ needs_review(eth_call 失败,或 creator 按 created_tx_hash 反查 transactions 未命中,需要人工复核)。 creator 同理只在反查命中时才写入,未命中时保持 NULL 而不是零地址——零 地址在本数据集里是 mint/burn 哨兵值,写成 creator 会伪造出一个"零地址部 署"的假身份。

3. 表

DDL:schema/clickhouse/derived/007_stock_tokens.sql。 刷新脚本:scripts/derived/refresh_stock_tokens.sh (纯 Python 标准库实现,同 scripts/qa/check_clickhouse.py 的约定,不复用 indexer 自己的 Rust ClickHouse/RPC 客户端)。

  • {db}.stock_tokens(ReplacingMergeTree(version),ORDER BY address): 注册表。address/symbol/name/decimals/created_block/ created_tx_hash/factory/creator/mint_address/burn_address/ detection_rule/confidence/notes。refresh_stock_tokens.sh registry 幂等刷新:重跑只是新增一个 version,FINAL 会折叠。
  • {db}.stock_token_daily_activity(ReplacingMergeTree(version), ORDER BY (token, day)):按天的铸造/销毁/转账笔数+金额+当日活跃地址数。 只由 refresh_stock_tokens.sh daily 对已收尾的日子(默认日终 2 小时 之后)从 {db}.erc20_transfers FINAL 重新聚合写入,避免把还在增长的当天 数据当成最终值。金额是链上原始 UInt256,换算成人类可读数值用 stock_tokens.decimals,同 docs/queries.md §1.4 的约定,不在表里存浮点。
  • {db}.stock_token_holder_balances(VIEW,非物化):某代币当前持仓 = 收到的 - 发出的(Int256,排除零地址两端),每次查询都基于 erc20_transfers FINAL 现算,天然不受重组/去重影响,代价是全表扫描更 慢——按单个代币查最合适(见下面例 1/例 4),如果"一次查所有代币的持仓人" 变成高频路径,应该改成按 stock_token_daily_activity 的思路做增量物化。

4. 本地验证

生产只读研究数据即验证依据(见上文历次查询结果的原始数字)。此外在本地 ClickHouse scratch 库上用真实链上数据跑了一遍完整链路(stocktok_scratch_wt31 库,验证后已 DROP DATABASE 清理):

  1. 用真实节点 RPC 回填两段真实区块(34,760–34,790 覆盖 TSLA 创建、 143,818–144,215 覆盖 TSLA 从铸造到销毁的完整生命周期 铸造→转账→转账→销毁 4 笔真实转账,from/to 与生产环境的 mint_address/burn_address 完全一致)。
  2. refresh_stock_tokens.sh registry(带 RPC_URL)正确解出 TSLA 一行, decimals=18、confidence=high、mint_address/burn_address 与生产 全量统计的两个地址完全一致;不带 RPC_URL 重跑时 decimals 正确保持 NULL、confidence 降为 medium(money-safety 的 fail-closed 路径); 重跑两次 FINAL 计数仍是 1(幂等)。
  3. refresh_stock_tokens.sh daily --date 2026-06-22 正确算出 mint_count=1, burn_count=1, transfer_count=2, unique_holders=3,金额 均为 100000000000000000(0.1 TSLA @ 18 位小数),和真实的 4 笔转账逐笔 对得上。
  4. 对当天(还没收尾)跑 daily 会被拒绝并非零退出,确认"未收尾的日子拒绝 计算"这条 fail-closed 规则生效。

5. 示例查询

假设已执行 sed 's/{db}/robinhood/g' 建表。

例 1:持仓地址数最多的股票代币 Top 10

SELECT hex(token) AS token_hex, count() AS holder_count
FROM robinhood.stock_token_holder_balances
GROUP BY token
ORDER BY holder_count DESC
LIMIT 10;

例 2:TSLA 最近 30 天每日铸造/销毁

SELECT day, mint_count, toString(mint_volume) AS mint_volume_raw,
       burn_count, toString(burn_volume) AS burn_volume_raw
FROM robinhood.stock_token_daily_activity FINAL
WHERE token = unhex('322f0929c4625ed5bad873c95208d54e1c003b2d')  -- TSLA
  AND day >= today() - 30
ORDER BY day;

例 3:当前注册表,标出哪些还需要人工复核

SELECT symbol, name, decimals, confidence, notes
FROM robinhood.stock_tokens FINAL
ORDER BY confidence != 'needs_review' ASC, symbol;

例 4:某只股票代币按 decimals 换算后的历史转账(人工查看用,非记账)

SELECT block_number, hex(tx_hash) AS tx_hash_hex, hex(`from`) AS from_hex, hex(`to`) AS to_hex,
       toString(amount) AS amount_raw,
       amount / pow(10, (SELECT decimals FROM robinhood.stock_tokens FINAL WHERE address = t.token LIMIT 1)) AS amount_approx
FROM robinhood.erc20_transfers t FINAL
WHERE is_deleted = 0 AND token = unhex('af3d76f1834a1d425780943c99ea8a608f8a93f9')  -- AAPL
ORDER BY block_number DESC
LIMIT 50;

例 5:昨天发生过赎回(销毁)的股票代币

SELECT s.symbol, a.burn_count, toString(a.burn_volume) AS burn_volume_raw
FROM robinhood.stock_token_daily_activity a FINAL
INNER JOIN robinhood.stock_tokens s FINAL ON s.address = a.token
WHERE a.day = yesterday() AND a.burn_count > 0
ORDER BY a.burn_count DESC;

本页目录