> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qu.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 使用 Solidity 部署

> 在 Quai Network 上部署简单单链智能合约的指南。

## 介绍

本文展示如何使用 Hardhat 在 Quai Network 的任何链上部署 Solidity 智能合约。

## 前提条件

要在 Quai 上部署单链智能合约，我们需要一些工具包和依赖项。以下是我们将使用的所有依赖项概述：

|                                                                                                  |                                                 |
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------- |
| [**NodeJS**](https://nodejs.org/en/download/)                                                    | Javascript 运行时环境。请使用 LTS 版本。                    |
| [**hardhat-example**](https://github.com/dominant-strategies/hardhat-example)                    | 包含 Quai Network 示例合约和部署脚本的 Hardhat 项目。          |
| [**Quais.js**](https://www.npmjs.com/package/quais)                                              | 用于与 Quai Network 交互的 JavaScript 库。              |
| [**@quai/hardhat-deploy-metadata**](https://www.npmjs.com/package/@quai/hardhat-deploy-metadata) | 将合约元数据上传到 IPFS 的 Hardhat 插件，用于在 Quaiscan 上验证合约。 |
| [**@openzeppelin/contracts**](https://www.npmjs.com/package/@openzeppelin/contracts)             | 示例 ERC20 和 ERC721 合约使用的智能合约库。                   |

## 环境设置

### 安装示例仓库

首先克隆 `hardhat-example` 仓库，导航到本教程将使用的 `Solidity` 目录，并通过 `npm` 安装依赖项。

```bash theme={null}
git clone https://github.com/dominant-strategies/hardhat-example.git
cd hardhat-example/Solidity
npm install
```

### 智能合约

`Solidity/` 目录包含 2 个示例合约：`contracts/` 目录中的 `ERC20.sol` 和 `ERC721.sol`。这两个合约都是从 [Open Zeppelin 库](https://www.openzeppelin.com/contracts) 派生的实现。

本教程将使用 `ERC20.sol` 示例合约，但您也可以添加自己的合约或使用其他库的合约。

<Warning>
  Quai Network EVM 支持 Solidity 版本最高到 0.8.20。使用更新版本的 Solidity 可能会在部署智能合约时导致错误。
</Warning>

### 环境变量

我们在 `hardhat-example` 仓库的根目录中包含了一个示例环境文件 `.env.dist`，用于安全地管理代币详情、私钥和 RPC URL。

<Note>
  `.env.dist` 文件是一个模板文件，不应直接使用。您应该将 `.env.dist` 文件复制到新的 `.env` 文件。

  此文件位于 `hardhat-example` 仓库的根目录，作为 `Solidity/` 目录的配置文件。
</Note>

使用以下命令将根目录中的 `.env.dist` 文件复制到仓库根目录的新 `.env` 文件：

```bash theme={null}
cp ../.env.dist ../.env
```

打开 `.env` 文件并添加您的私钥、RPC URL 和要部署的合约的代币参数。`.env` 文件应如下所示：

```bash .env theme={null}
## 示例环境文件 - 根据需要更改所有值

# 部署地址的唯一私钥
CYPRUS1_PK="0x0000000000000000000000000000000000000000000000000000000000000000" # 以 0x00 开头的公钥

# 链 ID（本地：1337，Orchard 测试网：15000，主网：9）
CHAIN_ID="15000"

# RPC 端点
RPC_URL="https://orchard.rpc.quai.network"

# ERC20 参数
ERC20_NAME="TestERC20"
ERC20_SYMBOL="TE20"
ERC20_INITIALSUPPLY=1000000

# ERC721 参数
ERC721_NAME="TestERC721"
ERC721_SYMBOL="TE721"
ERC721_BASE_URI="ipfs://METADATA_CID/"
ERC721_MAX_TOKENS=1000
```

<Note>
  示例 `.env.dist` 默认指向 **Orchard 测试网**，因此您无需消耗真实 QUAI 即可部署。
  要部署到主网，请将 `CHAIN_ID` 更改为 `9`，将 `RPC_URL` 更改为
  `https://rpc.quai.network`。
</Note>

有关 RPC 端点的更多信息，请参阅[网络](/cn/build/networks)页面。

`hardhat-example` 仓库使用 [Quais SDK](/cn/sdk/introduction) 仅使用一个 RPC URL 配置网络连接。要了解有关 SDK 如何配置网络提供者的更多信息，请访问 [SDK 提供者示例](/cn/sdk/static/provider)部分。

填写私钥和 RPC URL 后，我们现在可以在 `hardhat.config.js` 中安全地使用它们了。

### Hardhat 配置

Hardhat 使用 `hardhat.config.js` 文件来配置智能合约部署。配置文件允许您定义部署网络、任务、编译器等。

`hardhat-example` 包含一个预构建的 `hardhat.config.js` 文件，其中包含用于在 Cyprus-1 上部署和验证智能合约的配置。

<Accordion title="示例 hardhat 配置文件" icon="file" iconType="solid">
  此示例配置文件作为 `hardhat-example` 仓库的一部分提供。

  ```javascript hardhat.config.js theme={null}
  /**
   * @type import('hardhat/config').HardhatUserConfig
   */

  require('@nomicfoundation/hardhat-toolbox')
  require('@quai/quais-upgrades')
  require('@quai/hardhat-deploy-metadata')

  const dotenv = require('dotenv')
  dotenv.config({ path: '../.env' })

  module.exports = {
    defaultNetwork: 'cyprus1',
    networks: {
      cyprus1: {
        url: process.env.RPC_URL,
        accounts: [process.env.CYPRUS1_PK],
        chainId: Number(process.env.CHAIN_ID),
      },
    },

    solidity: {
      compilers: [
        {
          version: '0.8.17',
          settings: {
            optimizer: { enabled: true, runs: 1000 },
            metadata: {
              bytecodeHash: 'ipfs',
              useLiteralContent: true,
            },
            evmVersion: 'london',
          },
        },
        {
          version: '0.8.20',
          settings: {
            optimizer: { enabled: true, runs: 1000 },
            metadata: {
              bytecodeHash: 'ipfs',
              useLiteralContent: true,
            },
            evmVersion: 'london',
          },
        },
      ],
    },

    paths: {
      sources: './contracts',
      cache: './cache',
      artifacts: './artifacts',
    },
    mocha: {
      timeout: 20000,
    },
  }
  ```

  <Info>
    Cyprus-1 是目前 Quai Network 上唯一活跃的区域，因此示例配置仅定义了一个
    `cyprus1` 网络。完整的区域端点列表请参阅[网络](/cn/build/networks)。
  </Info>

  <Warning>
    `metadata.bytecodeHash: 'ipfs'` 和 `useLiteralContent: true` 编译器设置是
    `@quai/hardhat-deploy-metadata` 生成可验证输出所必需的。删除它们将导致
    Quaiscan 验证失败。
  </Warning>
</Accordion>

部署合约时，`hardhat.config.js` 将从 `.env` 文件中提取您的私钥和 RPC URL。您还可以在 `solidity` 对象中指定 Solidity 版本和编译器设置。

## 部署和交互

<Steps>
  <Step title="使用 Hardhat 编译">
    使用 Hardhat 进行智能合约编译很简单，可以在 CLI 中使用 `npx` 完成。

    使用以下命令编译 `contracts/` 目录中的所有合约：

    ```bash theme={null}
    npx hardhat compile
    ```

    应该输出：

    ```bash theme={null}
    Downloading compiler 0.8.20

    Compiled 2 Solidity files successfully
    ```
  </Step>

  <Step title="配置部署脚本">
    在 `scripts/` 目录中，您会找到 ERC20 和 ERC721 合约的部署脚本：`deployERC20.js` 和 `deployERC721.js`。在本教程中，我们将部署一个 ERC20 合约。

    `deployERC20.js` 脚本从 `hardhat.config.js` 中提取您的网络配置，从仓库根目录的 `.env` 文件中提取您的代币参数，并使用它们来部署您的合约。

    代币参数通过 `tokenArgs` 数组使用：

    ```js theme={null}
    const tokenArgs = [process.env.ERC20_NAME, process.env.ERC20_SYMBOL, quais.parseUnits(process.env.ERC20_INITIALSUPPLY)]
    ```

    在部署合约之前，该脚本使用 `@quai/hardhat-deploy-metadata` 插件将已编译合约的元数据推送到 IPFS 并返回生成的 CID：

    ```js theme={null}
    const { deployMetadata } = require("hardhat")
    // ...
    const ipfsHash = await deployMetadata.pushMetadataToIPFS("ERC20")
    ```

    然后 CID 作为第四个参数传递给 `ContractFactory`，将其嵌入已部署的字节码中。Quaiscan 稍后通过该 CID 获取您的源代码进行验证 — 没有它，合约虽可部署，但无法验证。

    ```js theme={null}
    const provider = new quais.JsonRpcProvider(hre.network.config.url, undefined, { usePathing: true })
    const wallet = new quais.Wallet(hre.network.config.accounts[0], provider)
    const ERC20 = new quais.ContractFactory(ERC20Json.abi, ERC20Json.bytecode, wallet, ipfsHash)
    ```

    我们将在下一步中使用这些概念来正确修改代币参数和网络规范以部署我们的合约。

    <Tip>
      `deployERC721.js` 脚本遵循相同的结构，但具有不同的合约参数以及不同的
      ABI/字节码。您可以为要部署的任何合约复制此配置。
    </Tip>
  </Step>

  <Step title="部署您的合约">
    部署脚本接受一个 `--network` 标志来指定您要部署到的网络。示例配置仅定义了 `cyprus1`，我们将在此使用它。

    ```bash theme={null}
    npx hardhat run scripts/deployERC20.js --network cyprus1
    ```

    应该输出：

    ```bash theme={null}
    File added with CID: QmPCoBa1bCFmRoTD7GuexJqBAy7pqg8J4b8B48q5DgxUEV
    Original IPFS hash found in bytecode: QmPCoBa1bCFmRoTD7GuexJqBAy7pqg8J4b8B48q5DgxUEV
    Metadata JSON for ERC20 saved to /.../hardhat-example/Solidity/metadata/ERC20_metadata.json
    Transaction broadcasted: 0x235fdeb85db5b6cee8da9780e2246907e8342751849f5ce3514847a5dffd916f
    Contract deployed to:  0x00735E9B2c731Fd3eCC8129a3653ACb99dF969cC
    ```

    第一行打印的 `CID` 是您在 Quaiscan 上验证合约所需的 IPFS 哈希 — 请保存它。

    恭喜，您现在已经在 Quai Network 上部署了一个 ERC20 代币！

    <Warning>
      `ERC20.sol` 和 `ERC721.sol` 示例合约是每种代币的基本实现，仅供示例使用。强烈建议在将这些合约用于任何生产用途之前，根据您的具体用例进行修改。
    </Warning>
  </Step>

  <Step title="与合约交互">
    Hardhat 控制台目前不支持与 Quai Network 上的智能合约交互。

    要与合约交互，您可以使用 [Quais SDK](/cn/sdk/static/contract) 配置一个简单的脚本。下面的脚本为我们部署到 `0x00735E9B2c731Fd3eCC8129a3653ACb99dF969cC` 的 ERC20 代币配置了一个 [Contract](/cn/sdk/content/classes/Contract) 实例，以获取代币的名称、符号和总供应量。

    ```javascript getContractDetails.js theme={null}
    const quais = require('quais')
    const ERC20Json = require('../artifacts/contracts/ERC20.sol/ERC20.json')

    async function getContractDetails() {
      // 配置提供者、钱包和合约工厂
      const provider = new quais.JsonRpcProvider(hre.network.config.url, undefined, { usePathing: true })
      const wallet = new quais.Wallet(hre.network.config.accounts[0], provider)
      const ERC20 = new quais.Contract("0x00735E9B2c731Fd3eCC8129a3653ACb99dF969cC", ERC20Json.abi, wallet)

      const tokenName = await ERC20.name()
      const tokenSymbol = await ERC20.symbol()
      const tokenDecimals = await ERC20.decimals()
      const tokenTotalSupply = await ERC20.totalSupply()
    }

    getContractDetails()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error)
        process.exit(1)
      })
    ```
  </Step>
</Steps>

## 总结

现在您拥有了创建简单 Hardhat 项目、部署和与自己的智能合约交互所需的所有工具。

由于部署脚本已将您的合约元数据推送到 IPFS，您现在可以在 Quaiscan 上验证它 — 详见[在 Quaiscan 上验证合约](/cn/guides/development/verifycontract)了解下一步。
