Solana - 如何使用Neon在Solana上部署Solidity智能合约 - Quicknode

  • QuickNode
  • 发布于 2025-01-30 16:59
  • 阅读 16

本文提供了一步步的指南,教你如何在Solana区块链上使用Neon EVM部署Solidity智能合约。内容涵盖环境设置、智能合约创建和测试,以及成功部署后的合约验证等多个方面,适合有一定Solidity和Solana基础的开发者学习和实践。

概述

在本指南中,你将学习如何使用 Solidity 在 Solana 区块链上部署智能合约,得益于 Neon EVM,这是一个用于以太坊虚拟机 (EVM) 智能合约的 Solana 运行时。它允许开发者在 Solana 上部署和执行 Solidity 智能合约。

我们将涵盖使用 Neon 进行 Solana 开发的基础知识,包括设置你的环境、创建一个 Solidity 智能合约,以及进行测试以确保其按预期工作。本指南结束时,你将掌握在 Solana 区块链上使用 Solidity 部署你自己智能合约的知识和技能。

你将要做的事情

  • 学习有关使用 Neon 的基础知识
  • 设置开发环境
  • 使用 Solidity 和 Neon 创建并部署一个 Scoreboard 智能合约
  • 运行测试以确保程序按预期工作
  • 验证已部署的智能合约

你将需要

依赖 版本
node.js >8.9.4

Solana 基础知识

在我们深入了解 Neon EVM 之前,下面是 Solana 一些重要概念的快速回顾:

  • 到处都是账户: 在 Solana 中,大多数元素,包括用户钱包、程序、数据日志和系统程序,都表示为账户。这些账户与传统操作系统中的文件相似,可被创建、修改和删除,并可以保存或处理数据。

  • 程序,而非智能合约: Solana 将智能合约称为“程序。”这些程序本质上是存储可执行代码的账户,负责处理交易并更新区块链状态。

  • Solana 程序的无状态性: 与以太坊的 EVM 合约不同,后者是有状态的,Solana 程序不在内部存储其状态。相反,Solana 程序利用账户来存储和管理状态数据。

  • 宽裕的账户存储: Solana 账户最多可以存储 10 MB 的数据,为不同类型的信息提供了充足的存储空间。

要深入探索 Solana,请参考 参考指南

Neon EVM 基础知识

Neon EVM 是一个整合在 Solana 可执行账户内的以太坊虚拟机,实质上构成了 Solana 智能合约中的整个 EVM 执行层。它允许开发者在 Solana 上部署和执行 Solidity 智能合约,同时享受 Solana 的可扩展性和低交易成本。与 L2 解决方案或侧链不同,Neon EVM 作为一个完整的 EVM 实现,能够无缝地在 Solana 网络上运行。

Neon EVM 使得使用 Solidity 和 Vyper 开发的 dApps 能够利用 Solana 的优势,如低费用、快速交易处理和并行事务执行能力。此解决方案确保与必需的以太坊 dApp 工具(如 Vyper、Solidity、MetaMask、Hardhat、Truffle 和 Remix)兼容,从而为以太坊应用程序迁移至 Solana 提供了便利。

开发

设置环境

首先,你需要将 Neon EVM DevNet 添加为你钱包中的网络。在本指南中,我们使用 MetaMask 作为钱包。

  • 访问 Neon 的 Chainlist 页面
  • 点击 连接钱包
  • Neon EVM DevNet 下点击 添加到 MetaMask
  • 按照说明进行操作

在 Neon EVM 上,有代理运营商负责在 Solana 上结算 Neon 交易。尽管可以更改,但我们将使用 Chainlist 分配的默认代理运营商。有关更多详细信息,请参见 该页面

Chainlist

然后,你需要从 devnet 获取一些 NEON 测试代币以供测试和开发使用。

  • 前往 Neon 的水龙头
  • 在连入 Neon EVM DevNet 的状态下连接你的钱包
  • 选择 NEON 作为代币
  • 输入你想要的数量(在撰写本文时,最大限制为 100 NEON)
  • 点击 发送测试代币

稍等片刻,你的钱包将获得 NEON 测试代币。

Faucet

Hardhat 配置

Hardhat 是一个用于编译、部署、测试和调试以太坊软件的开发环境。在本指南中,我们将使用 Hardhat 来编译、部署和测试智能合约。

让我们从创建项目开始。

在你想要的任何目录中打开终端,并运行以下代码。

这段代码创建一个名为 neon-scoreboard 的文件夹,初始化项目,安装 Hardhat ,然后依次运行 Hardhat

mkdir neon-scoreboard && cd neon-scoreboard
npm init --yes
npm install --save-dev hardhat
npx hardhat init

然后,根据你的偏好选择 JavaScript 或 TypeScript 并完成以下步骤。

请确保对于最后一个问题输入“y”,因为我们将安装特定版本的包。

运行 Hardhat 的示例控制台输出如下所示。

888    888                      888 888               888
888    888                      888 888               888
888    888                      888 888               888
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
888    888 .d888888 888    888  888 888  888 .d888888 888
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888

👷 欢迎使用 Hardhat v2.17.4 👷‍

✔ 你想做什么? · 创建一个 JavaScript 项目
✔ Hardhat 项目根目录: ·
✔ 你想添加 .gitignore 吗? (Y/n) · y
✔ 你想用 npm 安装这个示例项目的依赖项吗 (@nomicfoundation/hardhat-toolbox)? (Y/n) · y

然后,安装这些包。

npm install --save-dev chai@^4.3.6

完成这些步骤后,文件夹结构应如下所示。

├── README.md           // 项目的文档和信息。
├── contracts           // Solidity 智能合约的目录。
├── hardhat.config.js   // Hardhat 开发环境的配置文件。
├── node_modules        // 包含项目依赖项(已安装软件包)的目录。
├── package-lock.json   // 锁定文件,指定每个依赖项的确切版本。
├── package.json        // 包含项目元数据和依赖项信息的 JSON 文件。
├── scripts             // 自定义脚本或自动化代码的目录。
└── test                // 测试文件和测试相关代码的目录。

使用你最喜欢的代码编辑器打开 hardhat.config.js 文件,并按以下方式修改它。

该 Hardhat 配置文件允许开发者在 Neon Devnet 和本地 hardhat 网络上部署和测试智能合约。

require("@nomicfoundation/hardhat-toolbox");

const proxy_url = "https://devnet.neonevm.org";
const network_id = 245022926;

// 测试账户的私钥
// 注意:请用你自己的私钥替换,并确保其有非零 NEON 余额
const privateKeys = [\
  "PRIVATE_KEY",\
];

module.exports = {
  solidity: "0.8.4",
  defaultNetwork: "hardhat",
  networks: {
    hardhat: {},
    neonlabs: {
      url: proxy_url,
      accounts: privateKeys,
      network_id: network_id,
      chainId: network_id,
      allowUnlimitedContractSize: false,
      timeout: 1000000,
      isFork: true,
    },
  },
};

注意事项

PRIVATE_KEY 替换为你账户的私钥。如果你的私钥不以 0x 开头,请确保在私钥开头添加它。

提示

要获取你的私钥;

  • 点击浏览器上的 MetaMask 图标,一个别致的狐狸头。如果未见,检查浏览器的 扩展 页面。
  • 点击 符号,然后选择 账户详情
  • 然后,点击 显示私钥 并按照说明操作。

MetaMask 私钥

现在,我们准备编写我们的智能合约。

智能合约

contracts 文件夹中创建一个 Solidity 文件,运行以下命令。

请随意删除预写的 Lock.sol 文件。

echo > ./contracts/Scoreboard.sol

将以下内容复制到 Scoreboard.sol 文件中。

这是一个 Scoreboard 智能合约,允许用户管理和跟踪他们的游戏分数。用户可以创建账户、向当前分数添加积分、重置当前分数并检索当前和最高分数。该智能合约使用结构体存储用户数据,使用数组管理用户账户,并使用映射跟踪用户索引以便于访问。它还会发出事件以记录分数更新。

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

contract Scoreboard {

    // 定义一个结构体以表示用户的分数数据
    struct UserScore {
        address player;
        uint8 currentScore;
        uint8 highestScore;
    }

    // 数组以存储用户分数数据
    UserScore[] public accountData;

    // 映射以跟踪数组中用户的索引
    mapping(address => uint256) public userIndex;

    // 事件以记录分数更新
    event ScoreUpdated(
        address indexed player,
        uint8 currentScore,
        uint8 highestScore
    );

    // 函数以在数组中创建一个新用户元素
    function createUser() public {

        // 确保用户在数组中不存在
        require(userIndex[msg.sender] == 0, "User already exists");

        // 创建一个新的 UserScore 结构并初始化
        UserScore memory newUser = UserScore({
            player: msg.sender,
            currentScore: 0,
            highestScore: 0
        });

        // 将新用户添加到数组并更新他们的索引
        accountData.push(newUser);
        userIndex[msg.sender] = accountData.length;
    }

    // 函数向用户当前分数添加积分
    function addPoints(uint8 numPoints) public {
        // 确保 numPoints 有效
        require(numPoints > 0 && numPoints < 100, "Invalid points");

        // 获取用户在数组中的索引
        uint256 index = userIndex[msg.sender];

        // 确保用户在数组中存在
        require(index != 0, "User does not exist");

        // 更新用户的当前分数和最高分数(如果需要)
        accountData[index - 1].currentScore += numPoints;
        if (
            accountData[index - 1].currentScore >
            accountData[index - 1].highestScore
        ) {
            accountData[index - 1].highestScore = accountData[index - 1]
                .currentScore;
        }

        // 发出事件以记录分数更新
        emit ScoreUpdated(
            msg.sender,
            accountData[index - 1].currentScore,
            accountData[index - 1].highestScore
        );
    }

    // 函数将用户的当前分数重置为零
    function resetScore() public {
        // 获取用户在数组中的索引
        uint256 index = userIndex[msg.sender];

        // 确保用户在数组中存在
        require(index != 0, "User does not exist");

        // 将用户的当前分数重置为零
        accountData[index - 1].currentScore = 0;

        // 发出事件以记录分数重置
        emit ScoreUpdated(
            msg.sender,
            accountData[index - 1].currentScore,
            accountData[index - 1].highestScore
        );
    }

    // 函数获取用户的当前分数
    function getCurrentScore() public view returns (uint8) {
        // 获取用户在数组中的索引
        uint256 index = userIndex[msg.sender];

        // 确保用户在数组中存在
        require(index != 0, "User does not exist");

        // 返回用户的当前分数
        return accountData[index - 1].currentScore;
    }

    // 函数获取用户的最高分数
    function getHighScore() public view returns (uint8) {
        // 获取用户在数组中的索引
        uint256 index = userIndex[msg.sender];

        // 确保用户在数组中存在
        require(index != 0, "User does not exist");

        // 返回用户的最高分数
        return accountData[index - 1].highestScore;
    }
}

测试

在部署之前,应测试智能合约以检查其是否按预期工作。

test 文件夹中创建一个 Javascript 文件,运行以下命令。

echo > ./test/Scoreboard.js

将以下内容添加到文件中。

// 导入用于测试的 Chai 断言库和用于以太坊交互的 Hardhat 的 ethers 库
const { expect } = require("chai");
const { ethers } = require("hardhat");

// 定义“Scoreboard 合约”的测试套件
describe("Scoreboard Contract", function () {
  let Scoreboard;
  let scoreboard;
  let owner;

  // 在每个测试用例之前设置通用配置
  beforeEach(async function () {
    // 获取以太坊签名者(账户)以进行测试
    [owner] = await ethers.getSigners();
    // 使用 ContractFactory 部署 Scoreboard 合约
    Scoreboard = await ethers.getContractFactory("Scoreboard");
    // 确保合约已部署且准备好进行测试
    scoreboard = await Scoreboard.deploy();
    await scoreboard.waitForDeployment();
  });

  // 测试用例:应该创建一个新用户
  it("Should create a new user", async function () {
    // 调用 createUser 函数创建新用户
    await scoreboard.createUser();
    // 从合约中获取用户的索引
    const userIndex = await scoreboard.userIndex(owner.address);
    // 期望用户的索引为 1(表示新用户)
    expect(userIndex).to.equal(1);
  });

  // 测试用例:应该向用户的分数中添加积分
  it("Should add points", async function () {
    // 创建新用户
    await scoreboard.createUser();
    // 向用户的分数添加 50 分
    await scoreboard.addPoints(50);
    // 检索当前分数和最高分数
    const currentScore = await scoreboard.getCurrentScore();
    const highestScore = await scoreboard.getHighScore();
    // 期望当前分数和最高分数均为 50
    expect(currentScore).to.equal(50);
    expect(highestScore).to.equal(50);
  });

  // 测试用例:应该重置用户的当前分数,同时保持最高分数
  it("Should reset the user's current score and maintain the high score", async function () {
    await scoreboard.createUser();
    await scoreboard.addPoints(50);
    // 重置用户的当前分数
    await scoreboard.resetScore();
    // 检索当前分数和最高分数
    const currentScore = await scoreboard.getCurrentScore();
    const highestScore = await scoreboard.getHighScore();
    // 期望当前分数为 0,最高分数保持为 50
    expect(currentScore).to.equal(0);
    expect(highestScore).to.equal(50);
  });
});

现在,使用以下代码执行测试。

npx hardhat test

输出控制台应类似于以下内容。

    Scoreboard 合约
    ✔ 应该创建一个新用户
    ✔ 应该添加积分
    ✔ 应该重置用户的当前分数并保持最高分数

    3 通过 (947ms)

部署

由于测试过程已成功完成,我们可以开始部署。

打开 scripts 文件夹下的 deploy.js 文件,并像下面这样修改它。

// 导入 Hardhat 运行时环境 (HRE) 模块
const hre = require("hardhat");

// 定义一个名为 "main" 的异步部署合约的函数
async function main() {
  // 从签名者列表中获取部署账户
  const [deployer] = await ethers.getSigners();
  console.log("使用账户部署合约:", deployer.address);

  // 使用 Hardhat 的 ethers 库获取 "Scoreboard" 合约的 ContractFactory
  const Scoreboard = await hre.ethers.getContractFactory("Scoreboard");

  // 将 "Scoreboard" 合约部署到以太坊网络
  const scoreboard = await Scoreboard.deploy({ gasLimit: "0x10000000" });

  // 确保合约部署完成
  await scoreboard.waitForDeployment();
  console.log("已部署合约地址为: ", scoreboard.target);
}

// 执行 "main" 函数,捕获并处理任何错误
main().catch((error) => {
  console.error(error);
  // 设置进程退出代码为 1,以指示发生了错误
  process.exitCode = 1;
});

neonlabs 网络上运行部署脚本,该网络在配置文件 hardhat.config.js 中进行配置。

npx hardhat run scripts/deploy.js --network neonlabs

预期输出如下所示。当然,你的账户地址和已部署智能合约地址将不同。

使用账户部署合约: 0x58D09ecd499A1d6F2a0269f361Ee6DbbaBa44eF8
已部署合约地址为:  0x244BDb09C3B6B4c9faF2a71D5E876c73085559d2

现在,你的智能合约已成功部署!🎉 你可以通过搜索智能合约地址在 Neon 的区块浏览器 上进行检查。

最后,你可以在区块链浏览器上验证已部署的合约,以实现透明度和安全性。这使得每个人都可以查看你的已部署智能合约的代码。

验证智能合约

要验证智能合约,你需要修改 Hardhat 的配置文件。再次打开 hardhat.config.js

networks 对象定义之后,添加以下代码。

etherscan: {
    apiKey: {
      neonevm: "test",
    },
    customChains: [\
      {\
        network: "neonevm",\
        chainId: network_id,\
        urls: {\
          apiURL: "https://devnet-api.neonscan.org/hardhat/verify",\
          browserURL: "https://devnet.neonscan.org",\
        },\
      },\
    ],
  },

如果你感到困惑,请检查下面的代码,以查看更新的 hardhat.config.js 文件的完整内容。

require("@nomicfoundation/hardhat-toolbox");

const proxy_url = "https://devnet.neonevm.org";
const network_id = 245022926;

// 测试账户的私钥
// 注意:请用你自己的私钥替换,并确保其有非零 NEON 余额
const privateKeys = [\
  "PRIVATE_KEY",\
];

module.exports = {
  solidity: "0.8.4",
  defaultNetwork: "hardhat",
  networks: {
    hardhat: {},
    neonlabs: {
      url: proxy_url,
      accounts: privateKeys,
      network_id: network_id,
      chainId: network_id,
      allowUnlimitedContractSize: false,
      timeout: 1000000,
      isFork: true,
    },
  },
  etherscan: {
    apiKey: {
      neonevm: "test",
    },
    customChains: [\
      {\
        network: "neonevm",\
        chainId: network_id,\
        urls: {\
          apiURL: "https://devnet-api.neonscan.org/hardhat/verify",\
          browserURL: "https://devnet.neonscan.org",\
        },\
      },\
    ],
  },
};

当你的配置文件完成后,运行以下代码以验证你的智能合约。

DEPLOYED_SMART_CONTRACT_ADDRESS 替换为你已部署智能合约的地址。

npx hardhat verify DEPLOYED_SMART_CONTRACT_ADDRESS --network neonlabs

输出应如下。

成功提交合约来源代码
contracts/Scoreboard.sol:Scoreboard 地址 0x244BDb09C3B6B4c9faF2a71D5E876c73085559d2
在区块浏览器上进行验证。正在等待验证结果...

成功验证合约 Scoreboard 在区块浏览器上。
https://devnet.neonscan.org/address/0x244BDb09C3B6B4c9faF2a71D5E876c73085559d2#code

在验证过程完成后,任何人都可以查看已部署智能合约的代码并直接在 区块浏览器 上与智能合约进行交互。 验证智能合约

结论

就这样!你现在已经学习了如何使用 Solidity 在 Solana 区块链上部署智能合约。凭借这些知识,你可以开始在当前最快、最高效的区块链平台之一上构建去中心化应用程序。祝你编码愉快!

如果你有任何问题,请随时使用我们的专用频道在 Discord 上与我们联系,或使用下面的表单提供反馈。通过关注我们 Twitter 和我们的 Telegram 公告频道,保持关注最新动态。

想了解更多关于在 Solana 上使用 Solidity 开发的内容吗?查看 我们的 Solang 教程

我们 ❤️ 反馈!

让我们知道 如果你有任何反馈或新主题的请求。我们很乐意听取你的意见。

  • 原文链接: quicknode.com/guides/sol...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。