> For the complete documentation index, see [llms.txt](https://docs.rome.builders/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rome.builders/zh/kai-fa-zhe-zhi-nan/deploy-solidity.md).

# 部署 Solidity 合约

使用 Hardhat 或 Foundry 在 Solana 上部署 Solidity 智能合约——Rome 网络配置、已注资账户以及分步部署。

本指南介绍如何使用 Hardhat 和 Foundry 在 Rome EVM 上部署 Solidity 智能合约。

## 前置条件

* 已安装 Node.js v22.13+（Hardhat）或 Foundry
* 一个已充值的 Rome EVM 地址（参见 [快速开始](/zh/kuai-su-kai-shi/quickstart.md))
* 将你的私钥导出为环境变量

```bash
export PRIVATE_KEY="0xYOUR_PRIVATE_KEY"
```

## 网络配置

| 网络              | RPC URL                                     | 链 ID     | 区块浏览器                                  |
| --------------- | ------------------------------------------- | -------- | -------------------------------------- |
| Hadrian（测试网）    | `https://hadrian.testnet.romeprotocol.xyz/` | `200010` | `via-hadrian.testnet.romeprotocol.xyz` |
| **Rubicon（主网）** | `https://rubicon.mainnet.romeprotocol.xyz/` | `7531`   | `via-rubicon.mainnet.romeprotocol.xyz` |

每个网络上的 gas 都以 USDC 计价。在 Hadrian 上，你可以通过桥接测试 USDC，或从 Solana devnet 钱包包装获取（[水龙头](/zh/zi-yuan/faucets.md)）；在 Rubicon 上，则通过使用……从以太坊桥接 USDC [Rome Bridge](https://bridge-api.mainnet.romeprotocol.xyz/)。使用你在 Hadrian 上测试过的相同工件部署到 Rubicon——只有链 ID 和包装器地址不同。

## Hardhat

### 设置

```bash
mkdir my-rome-project && cd my-rome-project
npx hardhat --init
```

接受默认设置（Hardhat 3、当前目录、TypeScript + viem 模板）；依赖项会自动安装。

### hardhat.config.ts

```typescript
import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem";
import { configVariable, defineConfig } from "hardhat/config";

export default defineConfig({
  plugins: [hardhatToolboxViemPlugin],
  solidity: {
    profiles: {
      default: { version: "0.8.28" },
      production: {
        version: "0.8.28",
        settings: { optimizer: { enabled: true, runs: 200 } },
      },
    },
  },
  networks: {
    hadrian: {
      type: "http",
      chainType: "l1",
      chainId: 200010,
      url: "https://hadrian.testnet.romeprotocol.xyz/",
      accounts: [configVariable("PRIVATE_KEY")],
    },
    rubicon: {
      type: "http",
      chainType: "l1",
      chainId: 7531,
      url: "https://rubicon.mainnet.romeprotocol.xyz/",
      accounts: [configVariable("PRIVATE_KEY")],
    },
  },
});
```

`configVariable("PRIVATE_KEY")` 从环境中解析（或从加密 keystore—— `npx hardhat keystore set PRIVATE_KEY`).

### 部署

```bash
npx hardhat run scripts/deploy.ts --network hadrian
```

### 在区块浏览器上验证

```bash
npx hardhat verify --network hadrian 0xCONTRACT_ADDRESS
```

需要来自……的 Sourcify 验证器配置 [验证合约](/zh/kai-fa-zhe-zhi-nan/verify-contracts.md) 在你的 `hardhat.config.ts`.

## Foundry

### 设置

```bash
forge init my-rome-project
cd my-rome-project
```

### 部署

```bash
# 测试网
forge create --rpc-url https://hadrian.testnet.romeprotocol.xyz/ \\
  --private-key $PRIVATE_KEY \\
  src/Counter.sol:Counter
```

### 调用已部署的合约

```bash
# 读取
cast call 0xCONTRACT_ADDRESS "number()" \\
  --rpc-url https://hadrian.testnet.romeprotocol.xyz/

# 写入
cast send 0xCONTRACT_ADDRESS "increment()" \\
  --rpc-url https://hadrian.testnet.romeprotocol.xyz/ \\
  --private-key $PRIVATE_KEY
```

## 使用 Rome Solidity SDK

对于与 Solana 程序交互的合约，请使用公共……中的接口 [`rome-solidity`](https://github.com/rome-protocol/rome-solidity) 仓库。它是从 GitHub 安装的，而不是从 npm 安装：

```bash
# Hardhat / npm
npm install github:rome-protocol/rome-solidity

# Foundry
forge install rome-protocol/rome-solidity
# 然后在 foundry.toml 的 [profile.default] 下：
# remappings = ["@rome-protocol/rome-solidity/=lib/rome-solidity/"]
```

超出……的合约 `interface.sol` 以及预言机接口（例如 ERC-20 包装器和工厂）会导入 OpenZeppelin。使用 npm 时，它会作为依赖项一并安装。使用 Foundry 时，还要运行 `forge install OpenZeppelin/openzeppelin-contracts` 并添加以下映射 `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/`.

使用 npm 时，该包会安装为 `@rome-protocol/rome-solidity`，因此下面的导入会解析自 `node_modules`。使用 Foundry 时，该映射会让同样的导入解析自 `lib/rome-solidity`.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {ICrossProgramInvocation, IHelperProgram}
    from "@rome-protocol/rome-solidity/contracts/interface.sol";

contract MyRomeContract {
    IHelperProgram constant Helper =
        IHelperProgram(0xFF00000000000000000000000000000000000009);
    ICrossProgramInvocation constant Cpi =
        ICrossProgramInvocation(0xFF00000000000000000000000000000000000008);

    // 将一个 SPL 代币从调用者的 PDA 转出
    function moveSpl(address to, uint64 tokens, bytes32 mint) external {
        Helper.transfer_spl(to, tokens, mint);
    }

    // 通过 CPI 调用任意 Solana 程序
    function callSolanaProgram(
        bytes32 programId,
        ICrossProgramInvocation.AccountMeta[] calldata accounts,
        bytes calldata data
    ) external {
        Cpi.invoke(programId, accounts, data);
    }
}
```

## 迁移现有协议

任何 Solidity 合约都可以在 Rome 上无需修改即可部署——无论是合规合约、DeFi 协议，还是现有的成熟应用。唯一不在你的合约中的内容是 **一次性包装器授权**：当用户通过你的合约转移 SPL 包装代币（如 wUSDC 等）时，必须在第一次……之前先授予该代币的包装器一次移动其代币的权限 `transferFrom`。如果没有它，转账将因 SPL 错误而回滚 `0x4`。在处理该调用为完成之前，请检查 `isEnabled(user)` 在包装器上，并查看 [每个钱包一次性授权](/zh/he-xin-gai-nian/token-interop.md#one-time-grant-per-wallet)；你的前端会发送授权，你的合约无需更改。下面有两个可以直接 fork 并使用上面相同 Hardhat / Foundry 流程部署的生产示例：

* [**compound-on-rome-comet**](https://github.com/rome-protocol/compound-on-rome-comet) — 经典的 Compound v3（Comet），标准 Foundry。
* [**rome-aave-v3**](https://github.com/rome-protocol/rome-aave-v3) — 经典的 Aave v3。

二者都无需修改合约即可获得 Solana 执行能力和 CPI 可组合性；其用户会在首次存款前完成上述一次性包装器授权。

## Gas

让你的工具自行估算 gas（`eth_estimateGas`；Hardhat， `forge create` 和 `cast` 都可以）并且永远不要硬编码 `21000`。在 Rome 上，写入操作的大部分成本来自创建 Solana 账户，例如已部署的合约、新的代币账户或从未使用过的接收方，估算值会将这些费用包含在内。对于会发起 Solana CPI 的调用，估算结果可能偏低，因此要留出余量。Rome 按实际使用的 gas 收费。在 Hadrian 上实测，部署一个 10 字节合约的估算和实际消耗都是 1,147,921 gas，而向现有地址发起原生转账的估算为 21,000，实际使用 10,001。真实合约的成本更高，因此请自行估算部署。The [JSON-RPC 页面](/zh/can-kao/json-rpc.md#gas-is-solana-derived-estimate-dont-hardcode) 上有实测表格。

## 部署限制

| 约束          | 限制              | 说明                        |
| ----------- | --------------- | ------------------------- |
| 合约最大大小      | 24 KB           | 与以太坊相同（EIP-170，24,576 字节） |
| 交易大小限制      | 每个 holder 80 KB | 大型部署会透明地拆分到多个 holder 账户中  |
| 计算预算        | 约 140 万 CU（原子）  | 对大型合约使用迭代模式               |
| Solidity 版本 | 推荐 0.8.28       | 更早版本也可用，但 0.8.28 与 SDK 匹配 |

## 常见错误

| 错误                                | 原因                                     | 解决方法                                                                                                                                                                                                                           |
| --------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `gas 资金不足`                        | EVM 地址没有 gas 代币                        | Hadrian：使用……桥接入测试 USDC [Rome Bridge](/zh/rome-shang-de-ying-yong/bridge-api.md) （见 [快速开始](/zh/kuai-su-kai-shi/quickstart.md)，第 2 步）；Rubicon：使用……将真实 USDC 桥接进来 [主网上的 Rome Bridge](https://bridge-api.mainnet.romeprotocol.xyz/) |
| `nonce 过低`                        | 钱包中的 nonce 过期                          | 重置 MetaMask 账户或手动指定 nonce                                                                                                                                                                                                      |
| `执行回退`                            | 合约逻辑执行失败                               | 使用……调试 `eth_call` 或 `forge test --fork-url`                                                                                                                                                                                    |
| `执行回退` 并出现 SPL 错误 `0x4` 在转移包装器代币时 | 用户尚未进行一次性包装器授权                         | 检查 `isEnabled(user)` 包装器上的……并发送 `approve_spl` 一次（[详情](/zh/he-xin-gai-nian/token-interop.md#one-time-grant-per-wallet))                                                                                                         |
| `交易出价过低`                          | gas 价格低于最低值                            | 提高交易中的 gas 价格                                                                                                                                                                                                                  |
| 在固定 gas 限额下，转账或部署失败               | 例如硬编码的限制，如 `21000` 低于创建 Solana 账户所需的成本 | 删除它并使用 `eth_estimateGas`                                                                                                                                                                                                       |

## 接下来

* [向 Solana 用户开放你的合约](/zh/kai-fa-zhe-zhi-nan/open-to-solana-users.md) — 让 Solana 钱包用户调用你刚部署的内容
* [从 EVM 调用 Solana](/zh/kai-fa-zhe-zhi-nan/call-solana-from-evm.md) — 使用 CPI 预编译与 Solana 程序交互
* [验证合约](/zh/kai-fa-zhe-zhi-nan/verify-contracts.md) — 将你的源代码发布到区块浏览器


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.rome.builders/zh/kai-fa-zhe-zhi-nan/deploy-solidity.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
