什么是合约地址?如何查询和验证一个合约地址?

以太坊、Tron 与 Solana 上的合约地址详解,作者:ChainGate.

合约地址是智能合约在区块链上的地址。它在合约部署时产生,没有私钥,也是人们在代币旁边写「CA」时所指的那串字符。

在以太坊和所有 EVM 链上,它看起来和钱包地址一模一样:0x 后接 40 个十六进制字符。USDT、USDC 这样的代币本身就是合约,所以代币的地址就是合约地址。它和钱包地址的区别在于背后是什么:是代码和存储,而不是一个持有私钥的人。

这个词会在三个地方出现:往钱包里添加自定义代币时、区块浏览器把一个地址标注为合约时,以及有人发布一个新币的 CA 时。本指南解释这个地址标识的是什么、它是如何生成的、如何把它和钱包地址区分开、在哪里找到代币的真实地址,以及把资金转到合约地址会发生什么。

简要版

  • 合约地址指向代码,钱包地址指向持有密钥的人。在 EVM 链上两者格式相同,所以光看格式分不出谁是谁。区块浏览器或一次 eth_getCode 调用可以。
  • 在 EVM 链上,地址是 0x + 40 个十六进制字符,由部署者的地址和 nonce 推导而来,或者在 CREATE2 下由一个 salt 推导而来。Tron 使用以 T 开头的 34 个字符,Solana 使用 base58 格式的 mint 地址。
  • 从发行方的网站或文档复制代币地址,然后检查区块浏览器是否显示已验证的源码、大量持有者和较长的历史。骗子代币会沿用真币的名称和代码。
  • 大多数代币合约无法退回转到它自己地址上的代币。充值要转到钱包地址;与合约交互要通过 dApp 或一个知道其函数的钱包。

1. 什么是合约地址?

在以太坊以及按它的模式构建的链上,每个账户都有一个地址。账户分两种。外部账户(externally owned account)属于持有其私钥的人。合约账户存放一个程序以及该程序维护的数据,它的地址就是合约地址。ethereum.org 的文档说得很直接:合约账户没有私钥,它们由智能合约代码的逻辑控制。

合约由一笔交易一次性部署,在那一刻获得地址,并在链存在期间一直保留它。任何人都可以向这个地址发送交易来调用合约的某个函数。一次代币转账或在去中心化交易所上的一次兑换,就是一笔发给合约的交易。

代币是最常见的情况。USDT、USDC、WETH 以及其他所有 ERC-20 代币都是维护一张余额表的合约。因此代币的地址就是合约地址,也是钱包显示一个它还不认识的代币所需要的唯一信息。

2. 加密货币里的「CA」是什么意思?

CA 是 contract address(合约地址)的缩写。在 X、Telegram 和 Discord 上,关于新代币的帖子通常以 CA 加地址结尾,因为代币的名称和代码不是唯一的,而地址是唯一的。交易网站和钱包也用同样的缩写。

在 Solana 上,CA 是代币的 mint 地址,也就是定义代币供应量和小数位数的那个账户。在以太坊、BNB Chain、Base 和其他 EVM 网络上,它是 ERC-20 或 BEP-20 合约的地址。两种情况下,把这个地址粘贴到钱包或浏览器里,就能找到别人所说的那个代币。这也是假 CA 成为常见骗局的原因:一个同名的仿冒代币会有一个不同的地址。

3. 合约地址长什么样?

格式取决于链,而且和这条链用于钱包地址的格式相同。下面是两种广泛使用的稳定币的官方地址,取自发行方的页面:

网络代币合约地址格式
EthereumUSDT(ERC-20)0xdAC17F958D2ee523a2206206994597C13D831ec70x + 40 个十六进制字符
EthereumUSDC0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB480x + 40 个十六进制字符
BaseUSDC0x833589fCD6eDb6E08f4c7C32D4f71b54bdA029130x + 40 个十六进制字符
Arbitrum OneUSDC0xaf88d065e77c8cC2239327C5EDb3A432268e58310x + 40 个十六进制字符
Polygon PoSUSDC0x3c499c542cEF5E3811e1192ce70d8cC03d5c33590x + 40 个十六进制字符
TronUSDT(TRC-20)TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t以 T 开头的 34 个 base58check 字符
SolanaUSDC(mint 地址)EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v32 到 44 个 base58 字符

以太坊、Base、Arbitrum 和 Polygon 的条目来自 Circle 的 USDC 合约地址列表,USDT 的条目来自 Tether 的支持协议页面。USDC 在每条链上的地址都不同:名称相同并不代表是同一个合约。EVM 地址中的大小写字母构成一个校验和,由 EIP-55 定义;全小写的写法是同一个地址,浏览器和钱包两种都接受。

比特币没有合约地址。以 3 或 bc1 开头的比特币地址可以编码一个脚本,但地址上并没有一个可供调用的程序。这个概念属于以太坊、Tron 和 Solana 这类基于账户的链。

4. 合约地址与钱包地址:有什么区别?

在 EVM 链上两者看起来完全一样,所以区别在于是什么在控制这个地址。

钱包地址(外部账户)合约地址
由什么控制一个私钥,通常由助记词派生合约的代码;没有私钥
能否发起交易能不能。只有在交易或另一个合约调用它时才会运行
是否包含代码不包含,除非按 EIP-7702 委托给代码包含,还有自己的存储
如何创建免费:由公钥派生,不需要交易通过一笔支付 gas 的部署交易
典型用途收款、签署交易代币、交易所、借贷池、NFT 系列、跨链桥
在区块浏览器上显示为普通地址标注为合约,并有一个 Contract 标签

唯一的灰色地带是 EIP-7702,它自 2025 年 5 月的 Pectra 升级起在以太坊上生效。它允许钱包地址给自己挂上委托代码,从而批量执行调用或让别人代付手续费。密钥仍然控制着账户,账户仍然可以发送交易,所以它仍是一个附带代码的钱包地址。

要区分两者,在区块浏览器上打开这个地址:合约会有一个 Contract 标签、一个创建者地址,以及(如果源码已发布)已验证的代码。在代码里,JSON-RPC 方法 eth_getCode 会返回存储在该地址上的字节码,钱包地址则只返回 0x。Etherscan 指南展示了这些标签各在哪里。

5. 合约地址是如何生成的?

地址是算出来的,不是选出来的,每条链有自己的规则:

以太坊和 EVM 链(CREATE)
地址是对部署者地址及其 nonce(该地址已发送的交易数)做 Keccak-256 哈希后的最后 20 个字节。从同一个账户部署两次会得到两个不同的地址,因为 nonce 已经往前走了。
以太坊和 EVM 链(CREATE2)
一个合约可以在一个由它自己的地址、它选定的 salt 和创建代码的哈希算出的地址上部署另一个合约:keccak256(0xff ++ address ++ salt ++ keccak256(init_code))[12:]。地址在任何东西部署之前就已经确定,这就是一个合约能在许多条链上出现在同一个地址的原因。
Tron
Tron 地址是以 0x41 开头的 21 个字节,显示为以 T 开头的 34 个 base58check 字符。合约地址与钱包地址格式相同,由部署交易的 ID 和部署者的地址推导而来。
Solana
程序的地址是存放其可执行代码的账户的公钥。代币由其 mint 账户的地址标识,该账户归 Token Program 所有。持有该代币的钱包会为每个 mint 得到一个单独的代币账户。

这些规则见 ethereum.org 的账户文档、EIP-1014(针对 CREATE2)、Tron 账户参考和 Solana 代币文档。

6. 代币地址和合约地址是一回事吗?

在 EVM 链上,是的。代币地址就是该代币合约的合约地址,钱包、浏览器和交易所用这两个名字指同一串字符。往钱包里添加自定义代币就是粘贴这个地址;然后钱包会从合约本身读取代币符号和小数位数,所以地址错了显示的是一个错误的代币,而不是报错。

有两种情况需要额外的标识符。NFT 由系列的合约地址加上一个 token ID 来标识,因为整个系列都在一个合约里。在 Solana 上,代币地址是 mint 地址,而你持有的余额存放在一个与你的钱包关联的代币账户里,而不是在 mint 上。

7. 如何找到代币的合约地址?

从发行方控制的来源获取,然后在浏览器上确认。

发行方的网站或文档
稳定币发行方、协议和大多数项目都会按链公布自己的地址。Circle 和 Tether 分别为 USDC 和 USDT 维护着一个页面,上表中的条目就来自那里。
CoinMarketCap 和 CoinGecko
代币页面在 Contracts 一栏列出每条链上的合约地址,带有复制按钮和指向浏览器的链接。
区块浏览器
在 Etherscan、BscScan、Polygonscan、Tronscan 或 Solscan 上搜索代币名称。浏览器会标记出公认的那个代币并显示持有者数量;一个同名但只有十个持有者的副本是另一个代币。
你的钱包或交易所
钱包在代币详情页显示地址。交易所在充值和提币页面显示它,同时注明地址所属的网络。

复制整串字符,并把网络一起记下来。Base 上的 USDC 地址在 Arbitrum 上毫无意义,在错误的链上查询时浏览器会显示一个空地址。

8. 如何验证一个合约地址是真的?

代币的名称和符号在合约里只是自由文本,所以任何人都能部署第二个 USDC。以下检查能把真合约和仿冒品区分开:

与发行方比对
地址必须与发行方网站或文档上的那个逐字符完全一致。不要只比对开头和结尾的几个字符;仿冒地址就是专门生成来让这几位相同的。
查看源码是否已验证
在 Etherscan 及类似浏览器上,Contract 标签会显示部署者是否发布了源码,以及浏览器是否重新编译并与字节码匹配。对任何广泛使用的代币来说,未验证的字节码都是一个警示信号。
检查持有者、存在时间和活跃度
真正的稳定币合约有数百万笔转账和多年的历史。上周才部署、只有寥寥几个持有者且没有已验证源码的合约是另一个代币,不管它叫什么名字。
读一读代币的规则
浏览器和代币扫描工具会标记那些所有者可以随意增发、暂停转账、修改费用或阻止卖出的合约。代理合约地址不变却可以更换实现,所以要查清是谁控制升级。
核对链
同一个项目在不同链上有不同的地址,所以要确保浏览器、钱包和来源指的都是同一条网络。

这篇 Etherscan 指南逐一介绍了这些检查用到的 Contract 标签以及 Read Contract 和 Write Contract 视图。

9. 可以把加密货币转到合约地址吗?

可以,结果取决于合约。往借贷池存款、在去中心化交易所买币或铸造 NFT,都是通过向合约发送一笔交易来完成的,通常附带一个函数调用,并通过一个知道合约接口的钱包或 dApp 来进行。

要避免的错误是把代币转到该代币自己的合约地址。ERC-20 标准定义了转账、授权和余额函数,却没有任何能让合约把代币退回的函数,所以误转到代币合约的币通常就没了,除非发行方内置了恢复函数并同意使用它。大多数从未设计为接收普通转账的合约也是如此:有的会拒绝,有的会默默接受。

交易所或个人向你要充值时,给你的是一个钱包地址。协议希望你交互时,dApp 会替你构建交易。如果你发现自己正在把代币的合约地址粘贴到转账的收款人栏里,停下来检查一下自己在做什么。

10. 合约地址在每条区块链上都一样吗?

不一样,除非部署者刻意这么做。上面的 USDC 表格显示同一资产在四条 EVM 链上有四个不同的地址,因为每次部署都是来自一个 nonce 不同的账户的一笔单独交易。跨链桥接版本的代币(常带有 .e 之类的后缀)有自己的地址,所以浏览器在一条网络上可能显示不止一个叫 USDC 的代币。

跨链相同的地址可以通过 CREATE2 实现,或者用一个全新账户在每条链上重放同一笔已签名的部署交易。Multicall3 是钱包和库常用的辅助合约,正因如此它在一百多条链上都位于 0xcA11bde05977b3631167028862bE2a173976CA11,它的部署列表就显示了这一点。大多数代币不是这样部署的,所以要在你正在使用的那条链上查地址。

如果你不确定钱包连接的是哪条网络,链 ID 列表把每个链 ID 对应到它所属的网络和浏览器。

11. 在代码中检查地址

允许用户粘贴代币地址或收款地址的应用,应该在构建交易之前先校验格式。ChainGate 的 SDK 可以校验比特币、以太坊、Litecoin、Dogecoin、Bitcoin Cash 以及你注册的任何 EVM 网络的地址,并会拒绝大小写混合校验和不匹配的 EVM 地址:

import { ChainGate, isValidEvmAddress } from 'chaingate';

const cg = new ChainGate({ apiKey: process.env.CHAINGATE_API_KEY });

// Format checks: true for a well-formed address, false otherwise
cg.networks.ethereum.isValidAddress('0xdAC17F958D2ee523a2206206994597C13D831ec7'); // true  (USDT contract)
cg.networks.ethereum.isValidAddress('0xD8DA6bf26964af9d7eed9e03e53415d37aa96045'); // false (EIP-55 checksum does not match)
isValidEvmAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48');                  // true  (USDC contract)

// Bitcoin: validate and classify the address type
cg.networks.bitcoin.isValidAddress('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4');      // true
cg.networks.bitcoin.identifyAddressType('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'); // 'segwit-p2wpkh'

格式校验只能说明这串字符是一个格式正确的地址,不能说明那里是否有代码。要知道这一点,请在 RPC 端点上调用 eth_getCode:合约会返回它的字节码,钱包地址则返回 0x。地址校验文档列出了所有支持的网络以及 SDK 能识别的比特币地址类型。

12. 接下来看什么

合约地址告诉你在和哪个程序打交道,交易哈希告诉你发起了哪次调用,而 Etherscan 指南展示了如何在浏览器上读懂这两者。每次调用合约都要花 gas,Gas 追踪器显示现在在各网络上这要花多少。如果你希望用一个 SDK 就把比特币、以太坊和其他网络上的地址校验、余额和转账都处理好,ChainGate 就能做到。

常见问题

加密货币里的合约地址是什么?

智能合约在区块链上的地址:这是一个由交易部署的程序,有自己的存储,没有私钥。代币、去中心化交易所、借贷池和 NFT 系列都是合约,所以各自都有一个合约地址。在以太坊和其他 EVM 链上,它是 0x 后接 40 个十六进制字符,与钱包地址格式相同。

加密货币里的 CA 是什么意思?

CA 是 contract address(合约地址)的缩写。人们把它贴在代币名称旁边,因为名称和代码不是唯一的,而地址是唯一的。在 Solana 上,CA 是代币的 mint 地址;在以太坊、BNB Chain 或 Base 上,它是代币合约的地址。

合约地址和钱包地址是一回事吗?

不是。钱包地址由私钥控制,可以发起交易。合约地址由部署在它上面的代码控制,没有私钥,只有在交易调用它时才会动作。在 EVM 链上两者都是同样的 0x 格式,所以要在区块浏览器上区分它们(合约会有一个 Contract 标签),或者用 eth_getCode RPC 调用,它对钱包地址返回 0x。

合约地址长什么样?

以太坊、BNB Chain、Polygon、Arbitrum、Base 和其他 EVM 链:0x 加 40 个十六进制字符,例如 USDT 的地址 0xdAC17F958D2ee523a2206206994597C13D831ec7。Tron:以 T 开头的 34 个 base58check 字符,例如 USDT 的地址 TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t。Solana:32 到 44 个字符的 base58 mint 地址,例如 USDC 的地址 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v。

如何找到代币的合约地址?

从发行方的网站或文档获取,或者从 CoinMarketCap 或 CoinGecko 上代币页面的 Contracts 一栏获取,然后在同一条链的区块浏览器上确认:已验证的源码、大量持有者和长期的转账历史标志着真正的合约。钱包在代币详情页显示地址,交易所在充值页面显示。

如何知道一个地址是不是合约?

在区块浏览器上打开它。合约页面会显示一个 Contract 标签、创建者地址,以及(如果已发布)已验证的源码。在代码里,eth_getCode RPC 方法对合约返回字节码,对钱包地址返回 0x。

可以把代币转到合约地址吗?

只有当合约被设计为接收它们时才可以,比如借贷池或交易所,而且通常要通过一个会附上正确函数调用的 dApp。把代币转到该代币自己的合约地址通常会丢失,因为 ERC-20 标准没有把它们退回的函数。给交易所充值和给个人付款,永远都是转到钱包地址。

什么是代币地址?

代币的智能合约的合约地址。钱包、浏览器和交易所用代币地址和合约地址指同一串字符。在 Solana 上,代币地址是 mint 地址;NFT 由其系列的合约地址加上一个 token ID 来标识。

合约地址在所有链上都一样吗?

默认不一样。USDC 在以太坊、Base、Arbitrum 和 Polygon 上的地址各不相同,因为每次部署都是一笔单独的交易。项目可以通过 CREATE2 或重放同一笔已签名的部署交易在许多链上获得相同的地址,Multicall3 就是这么做的,但你始终应该在自己使用的那条链上查地址。

智能合约有私钥吗?

没有。合约账户由它的代码控制。如果代码包含所有者函数,所有者是一个单独的地址,通常是一个钱包或多签,它持有自己的密钥。已放弃所有权的合约没有任何人能再改动它。

使用 ChainGate 构建

把这些想法落地 —— ChainGate 提供钱包、交易与托管 RPC,一次安装即可覆盖以太坊以及 20 多条其他区块链。