> 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/open-to-solana-users.md).

# 向 Solana 用户开放你的合约

在 Rome（Hadrian 测试网、Rubicon 主网）上部署一个 Solidity 合约，并向 Solana 钱包开放——合约需要什么、Solana 钱包用户如何调用它、各网络地址，以及启动 ch

一次部署，两类用户。Rome 上的合约既可由使用其 EVM 密钥的 MetaMask 用户访问，也可由使用其 Solana 密钥的 Solana 钱包用户（例如 Solflare）访问——同一地址，同一状态。本页给出端到端路径：部署、让合约支持 Solana、在应用中接入 Solana 通道，并发布到主网。

## 1. 部署到你想要的网络

Rome 链是标准的 EVM 目标：Hardhat、Foundry、viem 和 ethers 无需改动即可使用（完整教程见 [部署 Solidity 合约](/zh/kai-fa-zhe-zhi-nan/deploy-solidity.md)).

| 网络                                          | 链 ID     | RPC                                         | 区块浏览器                                                                                 | Gas 代币  | 如何获取 gas                                                                                                                |
| ------------------------------------------- | -------- | ------------------------------------------- | ------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------- |
| [**Rubicon**](/zh/wang-luo/rubicon.md) （主网） | `7531`   | `https://rubicon.mainnet.romeprotocol.xyz/` | [via-rubicon.mainnet.romeprotocol.xyz](https://via-rubicon.mainnet.romeprotocol.xyz/) | USDC    | 使用以下方式从以太坊（CCTP）或 Solana 跨链 USDC： [Rome Bridge](https://bridge-api.mainnet.romeprotocol.xyz/)；它会以 gas 的形式到账             |
| **Hadrian** （测试网）                           | `200010` | `https://hadrian.testnet.romeprotocol.xyz/` | [via-hadrian.testnet.romeprotocol.xyz](https://via-hadrian.testnet.romeprotocol.xyz/) | 测试 USDC | 从测试网跨链测试 USDC（[水龙头](/zh/zi-yuan/faucets.md)）或在以下位置从 Solana devnet 钱包封装： [Rome App](https://app.devnet.romeprotocol.xyz) |

在 EVM 侧，gas 是 18 位小数的 USDC；任何网络都没有 Rome 水龙头。写入操作消耗的 gas 比以太坊直觉所预期的更多，因为大部分成本来自创建 Solana 账户：从未使用过的收款方、一个新的代币账户、一个已部署的合约。请使用 `eth_estimateGas`，标准工具会这样做，且绝不要硬编码 21,000。在 Hadrian 上测得，部署一个 10 字节合约的估算和实际使用量为 1,147,921 gas，而向从未使用过的地址发起原生转账为 1,086,961；相比之下，向已存在地址转账仅为 21,000。Rome 按实际使用的 gas 收费，在这些测量中实际使用量从未超过估算值。首次部署前先准备一些 USDC。之后在浏览器上验证源码（[验证合约](/zh/kai-fa-zhe-zhi-nan/verify-contracts.md)；主网验证器是 `https://verify.mainnet.romeprotocol.xyz`).

先在 Hadrian 上开发，然后将相同构件重新部署到 Rubicon，并切换链 ID 与主网 wrapper 地址；合约本身在不同网络之间不会有任何变化。Rubicon 尚未收录在公共注册表中， `create-rome-app` 或 `rome-cli` ，因此读取其中链参数的工具无法直接定位它；请从以下位置手动填写这些值： [Rubicon](/zh/wang-luo/rubicon.md)。Rubicon 上的 gas 使用真实 USDC，价格约为 Hadrian 的十倍，因此在那里的部署需要真实资金。

## 2. 什么样的合约可支持 Solana

Solana 用户的 EVM 身份是其 **合成地址**, `keccak256(solana_pubkey)[12:]`：一个普通的 `msg.sender`，并带有普通的 nonce。大多数合约完全无需修改。关键的三点：

* **以 ERC-20 形式接收价值，而不是 `msg.value`.** Solana 用户的资金是钱包中的 SPL 代币，在 EVM 侧表现为该代币的 wrapper（`wUSDC`, `wETH`, `wSOL`）。该 synthetic 在静态时不持有任何资产，用户资产会以 wrapper 形式到账，因此请通过以下方式拉取： `transferFrom` 在以下之后 `approve` 并通过以下方式返回： `transfer`。每位用户在首次拉取前只需向 wrapper 授予一次 SPL 委托权限（[一次性：授予包装器](/zh/kai-fa-zhe-zhi-nan/dual-lane-app.md#one-time-grant-the-wrapper)）。 `payable` 入口点仅在 synthetic 已获得原生 gas 后才能工作（即 relay 路径的 `rome_composeExternalDepositV1`），而 fund-and-sweep 模式并不会这样做。现有的 ERC-20 金库、AMM 或借贷市场已经具备正确的结构。
* **请使用规范 wrapper。** 每条链对每个 mint 只有一个 wrapper；地址见 [合约地址](/zh/can-kao/contract-addresses.md) （Hadrian 的也在公开 [registry](https://github.com/rome-protocol/rome-registry)）中。请在构造函数中指向这些地址；不要自行部署。
* **使其适配钱包签名时的原子预算。** Solana 钱包只签署一笔 Solana 交易，因此 Solana 通道调用必须适配该限制：约 140 万计算单元、64 个账户、4 KB（[约束](/zh/he-xin-gai-nian/constraints.md)）。在 Hadrian 上测得：转账、approve 以及 Aave supply 都能放入；Uniswap V3 swap 也能放入但余量很小（约 124 万 CU）；Aave borrow 则无法放入，会在下一节走 relay 路径。请通过 Solana 回执中的 `computeUnitsConsumed`进行测量，并在请求交易时使用 `maxSupportedTransactionVersion: 1` （Rome 的各个 leg 是 v1 交易；否则该字段会显示为 0）。

你不需要的内容：Solana 程序、桥、第二次部署，或任何 Rome 专用 Solidity。如果合约还通过预编译调用 Solana 程序，请参见 [从 EVM 调用 Solana](/zh/kai-fa-zhe-zhi-nan/call-solana-from-evm.md).

## 3. 让 Solana 钱包来调用它

你应用中的 EVM 路径保持不变（MetaMask + `submitRomeTx`，或直接使用 viem/ethers）。Solana 路径有两种形态。

**SDK 通道——每次调用一笔 Solana v1 交易。** [`@rome-protocol/sdk`](https://github.com/rome-protocol/rome-sdk-ts) (`submitRomeTxV1`）会由代理为你的 EVM 调用组装一笔 Solana v1 交易（最多 64 个账户和 4 KB，不使用地址查找表；你的代码中也不需要 ComputeBudget 指令、treasure wallet 或账户发现）。钱包会用同一个密钥签名两次：首先是一个可读的授权消息（`Rome authorization` 第一行， `0x` ，下一行是 EVM 交易哈希），链通过 Ed25519 程序进行校验，然后再提交交易。应用会将已签名交易发送到 Solana RPC；调用会返回 EVM 交易哈希及其回执。在钱包签署交易之前，SDK 会先检查：payer 是唯一签名者，仅运行 Rome 程序和 Ed25519 验证器，Rome 指令携带的必须正是用户授权的调用，且不存在优先费用。其余情况一律拒绝。

如果某次调用无法放入一笔交易，composer 会拒绝它，SDK 会将其交给代理转发，并沿用同一份授权签名，因此用户仍只会看到一次授权提示。此时结果会带有 `route: "relay"`。关于转发调用和长调用的规则见 [代发调用和长调用](/zh/kai-fa-zhe-zhi-nan/call-evm-from-solana.md#relayed-calls-and-long-calls)。转发调用使用链的原生 gas 支付，因此 synthetic 需要有 gas 余额： `fundSyntheticGas(deps, amountWei)` 会在一笔由钱包签名的 v1 交易中，将链的 gas 代币（Hadrian 和 Rubicon 上为 USDC）从钱包的代币账户转入其中。

fund leg（`buildFundLeg`）以及 sweep 前的钱包代币账户创建都是普通的 Solana 指令； `submitSolanaInstructionsV1` 也会将它们作为 v1 交易发送，由同一钱包签名者签名，不涉及代理。sweep 自身的调用（`buildSweepLeg`, `HelperProgram.transfer_spl`会通过 `submitRomeTxV1` 和其他调用一样，代理会查找代币账户。 `submitRomeTxV1` 本身不会自动创建新的 synthetic 账户：在首次进行资产移动调用之前，请检查 `isSyntheticProvisioned(...)` 如果为 false，则提交 `buildCreatePdaCall(synthetic)` 通过 `submitRomeTxV1` 一次即可。完整的存入与取出代码示例见 [构建双通道应用](/zh/kai-fa-zhe-zhi-nan/dual-lane-app.md)；底层机制见 [从 Solana 调用 EVM](/zh/kai-fa-zhe-zhi-nan/call-evm-from-solana.md)。较早的 `submitRomeTxSolanaLane`，它在客户端构建一个 legacy Solana 交易，目前仍作为旧路径保留在 SDK 中。

**每个 `deps` 值来自何处。** SDK 的 `deps` 对象有五个必填字段（其余如 `fetchImpl` 以及超时设置，都是可选的）。其中四个来自链，一个来自钱包：

| `deps` 字段    | 来源                                                                 | 注册表获取器（`@rome-protocol/registry` v0.2.0）                              |
| ------------ | ------------------------------------------------------------------ | --------------------------------------------------------------------- |
| `proxyUrl`   | 链的 RPC URL                                                         | `getChain(chainId).rpcUrl`                                            |
| `chainId`    | 链 ID                                                               | `getChain(chainId).chainId`                                           |
| `programId`  | 该链运行的 Rome 程序 ID                                                   | `getChain(chainId).romeEvmProgramId`                                  |
| `connection` | 该链集群的 Solana RPC，已签名交易会发送到此处（Hadrian 使用 devnet，Rubicon 使用 mainnet） | `getChain(chainId).solana.rpc` （Hadrian 的公开 devnet URL）；主网请使用你自己的 RPC |
| `signer`     | 钱包的 `LaneSigner`，或 `Keypair` 在脚本中                                  | 无                                                                     |

leg 构建器采用不在 `deps`中的值。它们的 `mint` （称为 `usdcMint` ，在教程中称为 usdcMint）是 gas 代币的 Solana mint，来自 `getTokens(chainId)` （其中条目为 `kind: "gas"`，字段 `mintId`）。wUSDC wrapper 地址不是 leg 构建器的输入；它用于 ERC-20 调用，对应的条目是 `kind: "spl_wrapper"` 以及 symbol `wUSDC` （字段 `address`）。注册表涵盖 Hadrian。对于 Rubicon，请手动填写： `proxyUrl` `https://rubicon.mainnet.romeprotocol.xyz/`, `chainId` `7531`, `programId` `RomePq9X3iAoTr813HR7uRarafFDUJty6GdiEceYpzX`, `mint` `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`、下一节表格中的 wrapper，以及一个用于 `connection`. [Rubicon](/zh/wang-luo/rubicon.md) 的 Solana mainnet RPC。完整列表见

**代理的 external-V1 端点——不使用 SDK 的同一通道。** SDK 封装了原子组装、relay 以及 gas 存入（`fundSyntheticGas`）。原始 RPC 方法仍保留给不使用 SDK 的客户端，其中包括迭代式 compose，而 SDK 不会封装它。钱包会对该调用签署一条 Ed25519 消息（可读形式为 `Rome authorization\n0x<hash>` 或原始哈希），然后代理要么为钱包组装待签名的 Solana 交易（`rome_composeUnsignedAtomicV1`, `rome_composeUnsignedIterativeV1` + `rome_submitSignedV1Plan`），要么仅凭一次钱包签名自行完成整个执行（`rome_relayUnsignedV1`，在 `rome_composeExternalDepositV1` （SDK 的 `fundSyntheticGas`）为 synthetic 的 gas 余额充值；转发调用会从其中扣费，因此余额不足时请及时补充）。 [JSON-RPC 支持](/zh/can-kao/json-rpc.md)方法形态见 [从 Solana 调用 EVM](/zh/kai-fa-zhe-zhi-nan/call-evm-from-solana.md#the-external-v1-endpoints)；授权规则见

。凡是迭代式的调用都应使用 relay，而所有能放入的调用都应使用 SDK 通道。

## 4. 各网络的 wrapper 地址

| 网络               | `wUSDC` wrapper                              | 其他 wrapper                                                                                               |
| ---------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Rubicon (7531)   | `0x0952d233b0c254cd375f3bfb3e5869c1a906f9b3` | `wETH` `0x01e8b3573da1d4b7b4b1ce0932cf07c8af0c92e9`, `wSOL` `0xc4e29e0f726a906e93277cbbc37bf27a9848a113` |
| Hadrian (200010) | `0xbce339ba4c3a8de3bb8af1c5539e6ac11da3112d` | `wETH` `0x02aeace038269f9961c93d04dcacd6fb3adfa55f`, `wSOL` `0x39f36444fcb79b3e691544aee2a832ebef54ca9f` |

原生 gas 代币显示为 `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` 在代币列表中；它不是 ERC-20 合约。Wrapper 采用 SPL mint 的小数位，而不是 18 位：wUSDC 为 6，wETH 为 8，wSOL 为 9。

## 5. 上线检查清单

1. 已部署到 Hadrian；EVM 路径可通过 MetaMask 正常使用。
2. 所有涉及资产转移的入口点都基于 ERC-20，并指向该链的标准 wrapper。
3. 一个能够签署 v1 交易的 Solana 钱包（目前 Solflare 在 devnet 上可以；Phantom 还不行）可在 Hadrian 上完成完整往返：为 synthetic 提供基础配置（`create_pda`，一次）→ fund leg → grant → approve → call → sweep leg，使用 SDK 通道；如果调用是迭代式，则走 relay 路径。
4. 每个 Solana 通道调用的 `computeUnitsConsumed` 会从 Solana 回执中读取，并且必须低于原子预算，否则该调用会被路由到 relay。
5. 在应用的首次存入流程中，两条通道都包含 wrapper 授权： `isEnabled(user)` 会先检查，并在 `approve_spl` 为 false 时仅发送一次（[一次性：授予包装器](/zh/kai-fa-zhe-zhi-nan/dual-lane-app.md#one-time-grant-the-wrapper)).
6. 源码已在浏览器上验证。
7. 已使用主网 wrapper 地址重新部署到 Rubicon。Rubicon 不在注册表中，因此其 `deps` 值需手动填写，来源于 [Rubicon](/zh/wang-luo/rubicon.md)。使用你已确认可在主网上签署 v1 交易的钱包，以真实资金完成一次相同的往返。

## 下一步

* [构建双通道应用](/zh/kai-fa-zhe-zhi-nan/dual-lane-app.md) ——金库示例，逐步说明，两种钱包
* [从 Solana 调用 EVM](/zh/kai-fa-zhe-zhi-nan/call-evm-from-solana.md) —— synthetic 地址、账户发现、external-V1 端点
* [部署 Solidity 合约](/zh/kai-fa-zhe-zhi-nan/deploy-solidity.md) · [验证合约](/zh/kai-fa-zhe-zhi-nan/verify-contracts.md) · [合约地址](/zh/can-kao/contract-addresses.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/open-to-solana-users.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.
