Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 50 additions & 20 deletions docs/pages/cn/how-to/verify-contract.mdx
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
---
source_path: how-to/verify-contract.mdx
source_sha: 6cc73e10bb88685960bc61fa08f4942073bc61bc
source_sha: 203fffb80a0e333188b0fc2122787d3ff82df9d9
title: "验证智能合约"
description: "使用 forge verify-contract 在 Stablescan 上验证您的 Stable 合约源代码,以便用户可以读取和与其交互。"
diataxis: "how-to"
---

# 验证智能合约

验证会将您的合约源代码上传到区块浏览器,并证明其编译为已部署的字节码。验证后,用户无需重新托管您的代码,即可在 Stablescan 上读取状态、调用函数和审计源代码。本指南将介绍如何在 Stable 上验证 Foundry 部署的合约。
验证会将您的合约源代码上传到区块浏览器,并证明其编译为已部署的字节码。一旦验证,用户可以在 Stablescan 上读取状态、调用函数和审计源代码,而无需重新托管您的代码。本指南将介绍如何在 Stable 上验证 Foundry 部署的合约。

## 先决条件
Stablescan 在 Etherscan 的多链 (V2) API 上运行,因此验证和所有其他浏览器 API 调用都将发送到 `https://api.etherscan.io/v2/api` 并带有 `chainid` 参数:

- 已在 Stable 测试网或主网上部署的合约。如果您尚未部署,请参阅[部署智能合约](/cn/tutorial/smart-contract)。
- 已安装 Foundry(`forge` 在您的 PATH 中可用)。
- 来自 `forge create` 输出的已部署合约地址。
| **网络** | **链 ID** | **验证器 URL** |
| :-------------- | :----------- | :--------------------------------------------- |
| Stable 测试网 | `2201` | `https://api.etherscan.io/v2/api?chainid=2201` |
| Stable 主网 | `988` | `https://api.etherscan.io/v2/api?chainid=988` |

## 1. 确认已部署地址
:::warning
Stablescan 不提供自己的 API。对 `https://testnet.stablescan.xyz/api` 的请求返回 `{"status":"0","message":"NOTOK","result":"Invalid API URL endpoint"}`,浏览器会被重定向到 `/notavailable`。请改用上面提供的 Etherscan V2 URL。
:::

## 前提条件

- 已经在 Stable 测试网或主网部署的合约。如果您尚未部署,请参阅[部署智能合约](/cn/tutorial/smart-contract)。
- 已安装 Foundry(`forge` 在您的 PATH 中可用)。如果 `--verifier custom` 未被识别,请运行 `foundryup`。
- 您 `forge create` 输出中的已部署合约地址。
- 来自 [https://etherscan.io/myapikey](https://etherscan.io/myapikey) 的 Etherscan API 密钥。一个密钥涵盖 V2 API 上的所有链,包括两个 Stable 网络。

## 1. 确认已部署的地址

确保您拥有之前部署的“部署到”地址。在[部署智能合约](/cn/tutorial/smart-contract)流程中,这是 `forge create` 后打印的值。
请确保您拥有之前部署的 `Deployed to` 地址。在[部署智能合约](/cn/tutorial/smart-contract)流程中,这是在 `forge create` 后打印的值。

```bash
cast code 0xDeployedContractAddress --rpc-url https://rpc.testnet.stable.xyz | head -c 20
Expand All @@ -30,54 +42,72 @@ cast code 0xDeployedContractAddress --rpc-url https://rpc.testnet.stable.xyz | h

非空字节码确认合约已部署在该地址。

## 2. 运行 forge verify-contract
## 2. 导出您的 API 密钥

Foundry 和 `curl` 都从您的 shell 读取密钥,因此请一次性导出。

```bash
export ETHERSCAN_API_KEY=YourApiKey

curl "https://api.etherscan.io/v2/api?chainid=2201&module=account&action=balance&address=0xDeployedContractAddress&tag=latest&apikey=$ETHERSCAN_API_KEY"
```

```text
{"status":"1","message":"OK","result":"0"}
```

`"status":"1"` 响应确认密钥在 Stable 测试网上可用。如果您收到 `Missing/Invalid API Key`,则密钥未设置或尚未激活。

## 3. 运行 forge verify-contract

Foundry 的验证流程将您的源代码提交给 Stablescan 验证器
Foundry 指向链 `2201` 的 Etherscan V2 端点

```bash
forge verify-contract \
0xDeployedContractAddress \
src/Counter.sol:Counter \
--chain-id 2201 \
--verifier blockscout \
--verifier-url https://testnet.stablescan.xyz/api \
--verifier custom \
--verifier-url "https://api.etherscan.io/v2/api?chainid=2201" \
--verifier-api-key $ETHERSCAN_API_KEY \
--watch
```

```text
Start verifying contract `0xDeployedContractAddress` deployed on 2201

Submitting verification of contract: Counter
Submitting verification for [src/Counter.sol:Counter] 0xDeployedContractAddress.
Submitted contract for verification:
Response: `OK`
GUID: `abc123...`
URL: https://testnet.stablescan.xyz/address/0xDeployedContractAddress
Contract verification status:
Response: `OK`
Details: `Pass - Verified`
Contract successfully verified
```

`--watch` 会一直阻塞直到验证完成,这样您就不需要轮询。在主网上,将链 ID 更改为 `988`,验证器 URL 更改为 `https://stablescan.xyz/api`。
`--watch` 会阻塞直到验证完成,这样您就不必轮询了。在主网上,将链 ID 切换到 `988`,验证器 URL 切换到 `https://api.etherscan.io/v2/api?chainid=988`。

:::note
**构造函数参数**:如果您的合约接受构造函数参数,请将 `--constructor-args $(cast abi-encode "constructor(uint256,address)" 42 0xSomeAddress)` 添加到命令中。如果没有此标志,任何带有非空构造函数的合约都将验证失败
**构造函数参数**:如果您的合约带有构造函数参数,请在命令中添加 `--constructor-args $(cast abi-encode "constructor(uint256,address)" 42 0xSomeAddress)`。如果没有此标志,任何带有非空构造函数的合约验证都将失败
:::

## 3. 在 Stablescan 上确认验证
## 4. 在 Stablescan 上确认验证

在浏览器上打开合约页面。

```text
https://testnet.stablescan.xyz/address/0xDeployedContractAddress
```

**合约**选项卡现在应该显示源代码一个绿色的“已验证”徽章,以及完整的 ABI。用户可以在**读取合约**下读取状态,并在**写入合约**下发送交易。
**Contract** 选项卡现在应该显示源代码一个绿色的“已验证”徽章和完整的 ABI。用户可以在 **Read Contract** 下读取状态,在 **Write Contract** 下发送交易。

## 故障排除

- **“字节码不匹配”**:您的源代码编译成与已部署代码不同的字节码。这通常是由于 Solidity 版本或优化器设置不匹配造成的。明确传递 `--compiler-version` 和 `--optimizer-runs` 以匹配您的 `foundry.toml`。
- **“GU ID 未找到”**:验证器尚未注册您的提交。使用 `--watch` 重新运行或手动检查响应中打印的 URL。
- **“Invalid API URL endpoint”**:您正在直接调用浏览器主机。将 `https://testnet.stablescan.xyz/api` 替换为 `https://api.etherscan.io/v2/api?chainid=2201`。
- **“Missing/Invalid API Key”**:`ETHERSCAN_API_KEY` 在当前 shell 中未设置,或者密钥刚刚创建且尚未激活。重新运行步骤 2 中的 `curl` 检查。
- **“Bytecode does not match”**:您的源代码编译为与已部署的字节码不同的字节码。最常见的原因是 Solidity 版本或优化器设置不匹配。明确传递 `--compiler-version` 和 `--optimizer-runs` 以匹配您的 `foundry.toml`。
- **“GUID not found”**:验证器尚未注册您的提交。使用 `--watch` 重新运行或手动检查响应中打印的 URL。
- **合约使用库**:为每个链接的库添加 `--libraries src/Lib.sol:Lib:0xDeployedLibAddress`。

## 下一步推荐
Expand Down
48 changes: 39 additions & 9 deletions docs/pages/en/how-to/verify-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,23 @@ diataxis: "how-to"

Verification uploads your contract's source code to the block explorer and proves it compiles to the deployed bytecode. Once verified, users can read state, call functions, and audit the source on Stablescan without re-hosting your code. This guide walks through verifying a Foundry-deployed contract on Stable.

Stablescan runs on Etherscan's multichain (V2) API, so verification and every other explorer API call go to `https://api.etherscan.io/v2/api` with a `chainid` parameter:

| **Network** | **Chain ID** | **Verifier URL** |
| :------------- | :----------- | :---------------------------------------------- |
| Stable testnet | `2201` | `https://api.etherscan.io/v2/api?chainid=2201` |
| Stable mainnet | `988` | `https://api.etherscan.io/v2/api?chainid=988` |

:::warning
Stablescan does not serve an API of its own. Requests to `https://testnet.stablescan.xyz/api` return `{"status":"0","message":"NOTOK","result":"Invalid API URL endpoint"}`, and a browser is redirected to `/notavailable`. Use the Etherscan V2 URLs above instead.
:::

## Prerequisites

- A contract already deployed on Stable testnet or mainnet. If you haven't deployed yet, see [Deploy a smart contract](/en/tutorial/smart-contract).
- Foundry installed (`forge` available in your PATH).
- Foundry installed (`forge` available in your PATH). Run `foundryup` if `--verifier custom` is not recognized.
- The deployed contract address from your `forge create` output.
- An Etherscan API key from [https://etherscan.io/myapikey](https://etherscan.io/myapikey). One key covers every chain on the V2 API, including both Stable networks.

## 1. Confirm the deployed address

Expand All @@ -28,41 +40,57 @@ cast code 0xDeployedContractAddress --rpc-url https://rpc.testnet.stable.xyz | h

A non-empty bytecode confirms the contract is deployed at that address.

## 2. Run forge verify-contract
## 2. Export your API key

Foundry and `curl` both read the key from your shell, so export it once.

```bash
export ETHERSCAN_API_KEY=YourApiKey

curl "https://api.etherscan.io/v2/api?chainid=2201&module=account&action=balance&address=0xDeployedContractAddress&tag=latest&apikey=$ETHERSCAN_API_KEY"
```

```text
{"status":"1","message":"OK","result":"0"}
```

A `"status":"1"` response confirms the key works against Stable testnet. If you get `Missing/Invalid API Key`, the key is unset or not yet active.

## 3. Run forge verify-contract

Foundry's verification flow submits your source to the Stablescan verifier.
Point Foundry at the Etherscan V2 endpoint for chain `2201`.

```bash
forge verify-contract \
0xDeployedContractAddress \
src/Counter.sol:Counter \
--chain-id 2201 \
--verifier blockscout \
--verifier-url https://testnet.stablescan.xyz/api \
--verifier custom \
--verifier-url "https://api.etherscan.io/v2/api?chainid=2201" \
--verifier-api-key $ETHERSCAN_API_KEY \
--watch
```

```text
Start verifying contract `0xDeployedContractAddress` deployed on 2201

Submitting verification of contract: Counter
Submitting verification for [src/Counter.sol:Counter] 0xDeployedContractAddress.
Submitted contract for verification:
Response: `OK`
GUID: `abc123...`
URL: https://testnet.stablescan.xyz/address/0xDeployedContractAddress
Contract verification status:
Response: `OK`
Details: `Pass - Verified`
Contract successfully verified
```

`--watch` blocks until verification finishes so you don't have to poll. On mainnet, swap the chain ID to `988` and the verifier URL to `https://stablescan.xyz/api`.
`--watch` blocks until verification finishes so you don't have to poll. On mainnet, swap the chain ID to `988` and the verifier URL to `https://api.etherscan.io/v2/api?chainid=988`.

:::note
**Constructor arguments**: If your contract takes constructor arguments, add `--constructor-args $(cast abi-encode "constructor(uint256,address)" 42 0xSomeAddress)` to the command. Without this flag, verification fails for any contract with a non-empty constructor.
:::

## 3. Confirm verification on Stablescan
## 4. Confirm verification on Stablescan

Open the contract page on the explorer.

Expand All @@ -74,6 +102,8 @@ The **Contract** tab should now show source code, a green "Verified" badge, and

## Troubleshooting

- **"Invalid API URL endpoint"**: you're calling the explorer host directly. Replace `https://testnet.stablescan.xyz/api` with `https://api.etherscan.io/v2/api?chainid=2201`.
- **"Missing/Invalid API Key"**: `ETHERSCAN_API_KEY` is unset in the current shell, or the key was just created and isn't active yet. Re-run the `curl` check in step 2.
- **"Bytecode does not match"**: your source compiles to different bytecode than what's deployed. Most often caused by mismatched Solidity version or optimizer settings. Pass `--compiler-version` and `--optimizer-runs` explicitly to match your `foundry.toml`.
- **"GUID not found"**: the verifier hasn't registered your submission yet. Re-run with `--watch` or manually check the URL printed in the response.
- **Contract uses libraries**: add `--libraries src/Lib.sol:Lib:0xDeployedLibAddress` for each linked library.
Expand Down
Loading