冻结与申诉
USDC 黑名单怎么查,和 USDT 差在哪三点
两份合约的查询函数差一个字母的大小写,这一个字母会让批量脚本静默返回空结果。更实质的差别在结构上:USDT 是 11075 字节的单体合约,USDC 只有 2186 字节,因为它是个代理壳——这直接决定了在 Etherscan 上查它要点哪个按钮。
两份合约都有黑名单功能,但查询函数的名字差一个字母的大小写。这一个字母会让你的批量查询脚本静默返回空结果,而不是报错。
下面是两份合约的逐项对照,全部来自公开只读调用,你可以自己复核每一条。
- USDT(以太坊)
0xdAC17F958D2ee523a2206206994597C13D831ec7 - USDC(以太坊)
0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
函数名和调用编码
| USDT | USDC | |
|---|---|---|
| 查询是否被拉黑 | isBlackListed |
isBlacklisted |
| 拼写差异 | BlackListed,L 大写 | Blacklisted,l 小写 |
| 调用编码 | 0xe47d6060 |
0xfe575a87 |
| 加入黑名单 | addBlackList |
blacklist |
| 移出黑名单 | removeBlackList |
unBlacklist |
函数名不同,函数签名的哈希也就不同,所以两者的调用编码完全没有关系。拿 USDT 那套编码去查 USDC 合约不会报错,只会返回空数据——手工在浏览器界面上点选函数不会遇到这个问题,写脚本才会踩。
权限结构:一个地址 vs 四个角色
USDT 合约的管理权限集中在单一的 owner 地址上。拉黑、解除、销毁余额、全局暂停,都由这一个地址发起。
USDC 把权限拆给了不同的角色,各自是不同的地址:
| 角色 | 负责 |
|---|---|
blacklister |
拉黑与解除拉黑 |
pauser |
暂停与恢复 |
masterMinter |
铸币权限管理 |
owner |
合约所有权 |
这四个只读函数在 USDC 上都能查,返回的是四个互不相同的地址。
还有一个能佐证角色分离确实生效的细节:用一个没有权限的地址去调用 USDC 的 blacklist,返回的错误信息是 Blacklistable: caller is not the blacklister——合约明确告诉你调用者不是 blacklister。而 USDT 在拒绝无权调用时不返回任何说明。
角色分离降低的是单一密钥被攻破的风险,属于治理成熟度的差别。它不改变"地址会因为合规程序被冻结"这件事的可能性。
更实质的差别:单体合约 vs 可升级代理
这一条比函数名的差异重要得多,但很少被提到。
对比两份合约在链上的字节码大小:
- USDT:11075 字节
- USDC:2186 字节
USDC 这么小,是因为它不是完整的实现,而是一个代理壳。真正的逻辑在另一份实现合约里,代理只负责把调用转发过去。存储槽里记着实现合约的地址,当前指向 0x43506849d7c04f9138d1a2050bbf3a0c054402dd。
USDT 没有这种结构,它是一份单体合约,代码就在那个地址上。
这个区别有两个实际后果。
第一,在 Etherscan 上查 USDC 的函数,路径和 USDT 不一样(见下一节)。
第二,两者的升级路径不同。USDC 可以直接把代理指向一份新的实现合约,持币人地址和余额不动,换的是逻辑。USDT 没有代理,它的做法是合约里带一个 deprecate 函数,把当前合约标记为废弃并指向新合约,需要生态各方跟着迁移。
对持币人来说,前者意味着规则可以在你不知情的情况下被替换掉,后者意味着迁移时你可能需要采取行动。两种都不是"不可更改",只是不可更改的方式不同。USDT 的那组开关写在"USDT 会被冻结吗"。
自己核对的方法(两者步骤不同)
查 USDT:在 Etherscan 打开合约地址,进 Contract 标签,点 Read Contract,函数列表里能看到 isBlackListed、owner、paused、deprecated。
查 USDC:同样进 Contract 标签,但要点 Read as Proxy,不是 Read Contract。
这一步是多数人卡住的地方。因为 USDC 是代理合约,Read Contract 只会显示代理壳自己的那几个函数,isBlacklisted、blacklister、pauser、masterMinter 全都不在里面。你会以为这些函数不存在。切到 Read as Proxy,Etherscan 会按实现合约的接口列出函数,那时才能查。

对照一下就清楚了:USDC 这边的子标签是 Read as Proxy 和 Past Implementations,USDT 那边是 Read Contract 和 Write Contract。图里还能看到 Etherscan 直接标出了当前实现合约地址 0x43506849…c054402dd 和 ZeppelinOS 标记,和前面从存储槽读出来的是同一个地址。
两侧都是只读调用,不花手续费,不需要连钱包。
零地址:一个可以用、一个不能用
全零地址 0x0000000000000000000000000000000000000000 在两份合约上的状态相反:
- 以太坊 USDT 上查,
isBlackListed返回true - USDC 上查,
isBlacklisted返回false
这个差异本身没什么实际影响,但它决定了你能不能用零地址做自查的对照样本。以太坊 USDT 上可以——先查零地址确认能查出 true,再查你关心的地址,这样你知道自己的操作方式是对的。做法写在"怎么查地址有没有被冻结"。
USDC 上没有这个便利。所有返回 false 的结果你都无法区分"确实没被拉黑"和"我查错了",只能靠仔细核对操作步骤。
顺带一提,波场的 USDT 合约上查零地址也返回 false,找对照样本得用别的办法,也写在上面那篇里。
查历史记录
两边都能查黑名单的历史操作记录,入口不同。
USDT 在以太坊上按事件签名哈希筛选,在合约页的 Events 标签里操作;波场上可以直接用 TronGrid 的事件接口,把 event_name 换成 AddedBlackList 或 RemovedBlackList。具体 URL 写在"USDT 会归零吗"。
USDC 的对应事件叫 Blacklisted 和 UnBlacklisted,在 Etherscan 的 Events 标签里按这两个名字筛。注意要在代理地址上查,因为事件是由代理地址发出的。
该拿这些差异做什么判断
技术层面的结论很短:两家都能冻结你的地址,函数名和查询路径不同,权限结构和升级方式不同。如果你换币的动机是"避免被冻结",换不解决问题。
至于实际持有哪个更合适,那是另一组判断,涉及发行方、储备、脱锚历史和使用场景,和这篇讲的冻结能力没有关系。把这两件事混在一起谈,恰恰是换币决策最常见的起点错误——冲着躲冻结去换币,换完发现躲掉的是另一种风险,而原来那个一点没少。