前端调用Solidity智能合约连接MetaMask小狐狸钱包,并在Alchemy测试网发布

目录

1.DApp前端代码

2.solidity代码

3.编写部署代码

4.连接小狐狸钱包

[5.启动 Webpack 开发服务器](#5.启动 Webpack 开发服务器)

6.部署到Alchemy测试网


在前一往篇文章基础上操作:

https://blog.csdn.net/fyihdg/article/details/155675039https://blog.csdn.net/fyihdg/article/details/155675039 已经搭建好环境,写一个简单的前端代码,创建一个网页界面,让用户可以通过浏览器与区块链上的 Counter 合约交互,连接用户的MetaMask钱包 ,与一个已部署在以太坊测试网上的 Counter 智能合约交互,显示当前计数值,并提供一个按钮让用户调用 count() 函数来递增它,同时通过事件监听实时更新界面。

1.DApp前端代码

在vscode右键,新增 src目录,新建index.html,index.ts文件

index.html:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>

index.ts

javascript 复制代码
import { ethers } from "ethers";
import { abi } from '../artifacts/contracts/Counter.sol/Counter.json';

function getEth() {
    // @ts-ignore
    const eth = window.ethereum;
    if (!eth) {
        throw new Error("No ethereum provider found");
    }
    return eth;
}

async function requestAccess() {
    const eth = getEth();
    const result = await eth.request({ method: "eth_requestAccounts" }) as string[];
    return result && result.length > 0;
}

async function hasSigners() {
    const metamask = getEth();
    const signers = await metamask.request({ method: "eth_accounts" }) as string[];
    return signers.length > 0;
}

async function getContract() {
    // 1. 地址
    // 2. 方法名
    // 3. provider
    // 4. signer

    if (!await hasSigners() && !await requestAccess()) {
        throw new Error("No ethereum provider found");
    }
    const provider = new ethers.BrowserProvider(getEth());
    const address = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
    const contract = new ethers.Contract(
        address,
        abi,
        await provider.getSigner(),
    )
    const counter = document.createElement("div");
    async function getCount() {
        counter.innerHTML = await contract.getCount();
    }
    getCount();
    const btn = document.createElement("button");
    btn.innerHTML = "increment";
    btn.onclick = async function () {
        await contract.count();
    }

    contract.on(contract.filters.CounterInc(), async function ({ args }) {
        counter.innerHTML = args[0].toString() || await contract.getCount();
    })

    document.body.appendChild(counter);
    document.body.appendChild(btn);
}

async function main() {
    await getContract();
}

main();

在package.json文件所在目录下新建,webpack.common.js,webpack.dev.js,webpack.prod.js,.env文件

webpack.common.js

javascript 复制代码
const dotenv = require("dotenv");
dotenv.config();
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    entry: "./src/index.ts", // bundle"s entry point
    output: {
        path: path.resolve(__dirname, "dist"), // output directory
        filename: "[name].js", // name of the generated bundle
    },
    resolve: {
        extensions: [".js", ".ts", ".json"],
    },

    module: {
        rules: [
            {
                test: /\.ts$/,
                loader: "ts-loader",
                exclude: /node_modules/,
            },

            {
                test: /\.css$/i,
                use: ["style-loader", "css-loader"],
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html",
            inject: "body",
        }),
    ],
};

webpack.dev.js

javascript 复制代码
const webpack = require("webpack");
const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.common");

module.exports = merge(baseConfig,{
    mode:"development",
    plugins: [
        new webpack.DefinePlugin({
            'process.env.CONTRACT_ADDRESS': JSON.stringify(process.env.CONTRACT_ADDRESS),
            'process.env.DEBUG': JSON.stringify(process.env.DEBUG),
        }),
    ],

    devServer: {
        historyApiFallback: true,
        port:8080,
        hot:true
    }
});

webpack.prod.js

javascript 复制代码
const webpack = require("webpack");
const baseConfig = require("./webpack.common");
const { merge } = require("webpack-merge");


module.exports = merge(baseConfig,{
    mode: "production",
    plugins: [
        new webpack.DefinePlugin({
            'process.env.CONTRACT_ADDRESS': JSON.stringify(process.env.CONTRACT_ADDRESS),
            'process.env.DEBUG': JSON.stringify(process.env.DEBUG),
        }),
    ],
});

.env文件

javascript 复制代码
# .env  这个文件不能提交到git中
PRIVATE_KEY=私钥地址
ALCHEMY_API_KEY=ALCHEMY的key

package.json添加配置

javascript 复制代码
  "scripts": {
    "dev": "webpack serve --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js",
    "deploy:local": "npx hardhat run scripts/deploy-counter.ts --network localhost"
  }

2.solidity代码

在contracts目录下新建Counter.sol文件

javascript 复制代码
pragma solidity ^0.8.24;

import "hardhat/console.sol";

contract Counter {
    uint counter;

    event CounterInc(uint counter);

    function count() public {
        counter++;
        console.log("Now, counter is: ", counter);
        emit CounterInc(counter);
    }

    function getCount() public view returns (uint) {
        return counter;
    }
}

3.编写部署代码

在package.json所有目录下新增scripts目录,创建deploy-counter.ts文件

javascript 复制代码
import "@nomicfoundation/hardhat-ethers";
import { ethers } from "hardhat";

async function deploy() {
    const Counter = await ethers.getContractFactory("Counter");
    const counter = await Counter.deploy();
    await counter.waitForDeployment();
    console.log('counter address is', await counter.getAddress());
    return counter;
}

async function count(counter: any) {
    await counter.count();
    console.log('count is',await counter.getCount());
}

deploy().then(count);

4.连接小狐狸钱包

创建一个钱包,打开谷歌浏览器,输入地址:https://metamask.io/zh-CN/download

我选择添加扩展

然后点击:

就可以找到狐狸钱包了

我们选创建一个钱包

复制代码
要用 Google/Apple(因为没有备份可恢复),对于大多数加密货币用户:建议只用助记词方式,完全自主控制,不依赖任何第三方服务。Google/Apple 方式适合追求便捷的轻度用户,但要知道其中的信任依赖。

屏幕显示 12 个单词 → 立即手抄!,不要拍照,谁拿到你的助记词,谁就等于拥有了你的全部加密资产!

首先在根目录执行,启动一个 本地以太坊区块链节点(只在你电脑上运行),让前端 DApp 能通过 MetaMask 与本地合约交互,让你能在真实环境中测试 DApp,而无需花费真钱或等待测试网确认。记住这些只是测试工具,不要与真实钱包混淆!

  • 自动生成 20 个测试账户 ,每个账户包含:
    • 一个 私钥
    • 一个 地址
    • 10,000 个测试 ETH(仅限本地使用,没有真实价值)
javascript 复制代码
npx hardhat node

注意这个地址: http://127.0.0.1:8545/,配置网络:

导出测试的私钥

把控制台打印的私钥复制进来

导入后:

  • MetaMask 账户 = Hardhat 账户
  • 有钱 + 有权限 → 开发调试畅通无阻!

5.启动 Webpack 开发服务器

首先部署合约

javascript 复制代码
# 在另一个终端窗口部署合约
npx hardhat run scripts/deploy-counter.ts --network localhost 
javascript 复制代码
D:\csdn\Hardhat2.22.17>npx hardhat run scripts/deploy-counter.ts --network localhost
counter address is 0x5FbDB2315678afecb367f032d93F642f64180aa3
count is 1n

D:\csdn\Hardhat2.22.17>

启动 Webpack 开发服务器

javascript 复制代码
npx webpack serve --config webpack.dev.js
javascript 复制代码
D:\csdn\Hardhat2.22.17>npx webpack serve --config webpack.dev.js
[dotenv@17.2.3] injecting env (0) from .env -- tip: 🔐 encrypt with Dotenvx: https://dotenvx.com
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/, http://[::1]:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://198.18.0.1:8080/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fdfe:dcba:9876::1]:8080/
<i> [webpack-dev-server] Content not from webpack is served from 'D:\csdn\Hardhat2.22.17\public' directory
<i> [webpack-dev-server] 404s will fallback to '/index.html'
asset main.js 1.49 MiB [emitted] (name: main)
asset index.html 242 bytes [emitted]
runtime modules 27.9 KiB 12 modules
modules by path ./node_modules/ethers/lib.commonjs/ 889 KiB 118 modules
modules by path ./node_modules/ethers/node_modules/ 179 KiB 20 modules
modules by path ./node_modules/aes-js/lib.commonjs/*.js 66.8 KiB
  ./node_modules/aes-js/lib.commonjs/index.js 1.6 KiB [built] [code generated]
  + 8 modules
modules by path ./node_modules/webpack-dev-server/client/ 84.8 KiB
  modules by path ./node_modules/webpack-dev-server/client/*.js 53.3 KiB 4 modules
  modules by path ./node_modules/webpack-dev-server/client/utils/*.js 980 bytes 2 modules
  + 2 modules
modules by path ./node_modules/webpack/hot/*.js 5.17 KiB
  ./node_modules/webpack/hot/dev-server.js 1.94 KiB [built] [code generated]
  ./node_modules/webpack/hot/log.js 1.73 KiB [built] [code generated]
  + 2 modules
+ 5 modules
webpack 5.103.0 compiled successfully in 3441 ms

在浏览器中输入:http://localhost:8080

点击连接

点击'increment'按钮

点"确认"代表你在授权一个区块链交易!这是 MetaMask 交易确认弹窗

弹窗信息解读

✅ 网络:Hardhat Localhost(本地测试网)
✅ 请求来自:localhost:8080(你的前端DApp)
✅ 交互对象:合约地址(0x5FbDB...80aa3)
✅ 网络费:<US0.01(测试币,实际0)

const btn = document.createElement("button");
btn.innerHTML = "increment";
btn.onclick = async function () {
await contract.count(); // ⬅️ 这里触发的!
}

**// 点击确认后:

  1. ✅ 发送一个交易到 Counter 合约
  2. ✅ 调用 count() 函数
  3. ✅ 合约中的计数器 +1
  4. ✅ 触发 CounterInc 事件
  5. ✅ 前端监听到事件,更新显示**

区块链层面的操作:

// Counter.sol 合约中的函数
function count() public {
count += 1; // 状态变量+1
emit CounterInc(count); // 发出事件
}

**// 这个操作会:

  1. 🔄 修改区块链状态(count值改变)
  2. 📝 产生一个交易记录
  3. ⛓️ 被添加到区块中
  4. 🔥 消耗少量 Gas(测试币)**

至此,前端可以调用到合约了

6.部署到Alchemy测试网

打开网址:https://dashboard.alchemy.com/apps/vatwoz0eoicb1mih/setup

需要注意的是,最好弄一个gmail邮箱,qq邮箱容易被拦截。注册成功后

只选这个就行

下一步

去小狐狸复制私钥,选择这三个小点都可以:

.env文件,把私钥填写到:

从Endpoint URL复制:https://eth-sepolia.g.alchemy.com/v2/nr6k9FBd4Rvwi83XSr6xR

ALCHEMY_API_KEY就是:nr6k9FBd4Rvwi83XSr6xR

PRIVATE_KEY=填写刚刚复制的私钥,添加前辍0x

ALCHEMY_API_KEY=nr6k9FBd4Rvwi83XSr6xR

编辑hardhat.config.ts文件:

javascript 复制代码
import "hardhat-gas-reporter"
import "@nomicfoundation/hardhat-toolbox";
import "@nomicfoundation/hardhat-ethers";
import "@nomicfoundation/hardhat-verify";
const dotenv = require('dotenv');
dotenv.config();
type Config = import('hardhat/config').HardhatUserConfig

const config: Config = {
  solidity: "0.8.28",
  networks: {
    hardhat: {
      chainId: 31337
    },
    sepolia_eth: {
      url: `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`,
      accounts: [process.env.PRIVATE_KEY]
    }
    // 如果没有配置环境变量,这里先注释掉执行
    // sepolia_eth: {
    //   url: `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`,
    //   accounts: [process.env.PRIVATE_KEY]
    // }
  },
  gasReporter: {
    enabled: true
  }
};

export default config;

tsconfig.json文件,把这个"strict": true,注释掉

javascript 复制代码
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    //"strict": true,
    "skipLibCheck": true,
    "resolveJsonModule": true
  }
}

运行命令:

javascript 复制代码
npx hardhat run scripts/deploy-counter.ts --network sepolia_eth

成功了

javascript 复制代码
D:\csdn\Hardhat2.22.17>npx hardhat run scripts/deploy-counter.ts --network sepolia_eth
[dotenv@17.2.3] injecting env (2) from .env -- tip: 🔄 add secrets lifecycle management: https://dotenvx.com/ops
[dotenv@17.2.3] injecting env (0) from .env -- tip: 🔑 add access controls to secrets: https://dotenvx.com/ops
counter address is 0x920F394f09E6B17133e94c7AF0a86dF5A5cB357B
count is 0n

D:\csdn\Hardhat2.22.17>

输入网址查询:https://sepolia.etherscan.io/

成功上测试网了,注意,不是主网

主网是:https://etherscan.io/

相关推荐
测试人社区-千羽16 小时前
边缘计算场景下的智能测试挑战
人工智能·python·安全·开源·智能合约·边缘计算·分布式账本
TechubNews1 天前
Stripe 拟于本月 12 日上线稳定币支付功能
web3·区块链
古城小栈1 天前
Go语言原生智能合约开发与部署完全指南
golang·区块链·智能合约
ZFJ_张福杰2 天前
【区块链】区块链智能合约:从原理到应用的完整入门指南
区块链·智能合约
Web3VentureView2 天前
从“庞氏骗局”到“价值发现”:Web3 行业自我修正与新范式的曙光
大数据·金融·web3·去中心化·区块链
币圈菜头3 天前
GAEA × REVOX 合作 — 共建「情感 AI + Web3 应用」新生态
人工智能·web3·去中心化·区块链
聊天QQ:688238863 天前
PFC3D滑坡冲击仿真实战手札
web3
焦点链创研究所3 天前
从生态认证到价值重构:RootData 收录 BCT 背后的 Web3 数据生态协同逻辑
重构·web3
Rockbean3 天前
3分钟Solidity: 3.3 Enum枚举
web3·区块链·solidity