一个简单的Token银行DApp - all-in

news/2025/11/20 23:43:14/文章来源:https://www.cnblogs.com/songlee/p/19249907

在上一篇文章(https://www.cnblogs.com/songlee/p/19244400)中,我们发行了自己的代币 MFT。

这里再创建一个存储MFT币的银行,合约代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";contract DBank {// 存储账户余额mapping(address => uint) private balance;// 不可变变量address private immutable token;constructor(address _token) {token = _token;} // 注意:所有amount应该是用户(或前端应用)直接向合约提供的最小单位数量(wei,或带10^18小数位的单位)//      单位转换在应用层进行modifier requireBalance(uint amount) {require(amount <= balance[msg.sender], "Your balance is not enough.");_;}// 查询余额function myBalance() public view returns (uint) {return balance[msg.sender];}// 存款 -----> 将个人账户的代币转移到 DBank 合约账户function deposit(uint amount) public {// 在代币合约中,将个人账户的 token 转移到 DBank 账户(合约地址)require(IERC20(token).transferFrom(msg.sender, address(this), amount), "deposit failed");// 记录balance[msg.sender] += amount;}// 取款 -----> 将 DBank 合约账户的代币转移到个人账户function withdraw(uint amount) external requireBalance(amount) {// 在代币合约中,将 DBank 合约账户的 token 转移到个人账户中// require(IERC20(token).transfer(msg.sender, amount), "withdraw failed");SafeERC20.safeTransfer(IERC20(token), msg.sender, amount);// 记录balance[msg.sender] -= amount;}// 转账 -----> 银行内的转账function bankTransfer(address to, uint amount) public requireBalance(amount) {// 直接记录balance[msg.sender] -= amount;balance[to] += amount;}
}

然后部署到测试网上,部署的过程不再赘述,这里部署后的合约地址是 0xcf33936D93CFda55e0e0B041B2C0a93817E2fdB1

二、使用react创建前端

这里我在VSCode中使用 Gemini AI 直接生成了一个页面,如下:
image

当然这还只是一个静态页面。我们需要使用一些 js 库去连接以太坊,与区块链进行交互。

常用的库比如ethers.jsweb3.jsviem.sh等,在Dapp的开发中使用这些库的API功能大部分都是相同的,你可以选择其中的一个即可。相对而言,更推荐 ethers.js、viem.sh,接口也更简洁。

这里我们选择 ethers.js 与区块链进行交互。

1、安装

npm install --save ethers

2、连接钱包,并操作合约

import {ethers} from 'ethers';
import dbankAbi from './ABI.json';function App() {const [balance, setBalance] = useState(0);const [account, setAccount] = useState(null);const [bankContract, setBankContract] = useState(0);const [depositAmount, setDepositAmount] = useState('');const [withdrawAmount, setWithdrawAmount] = useState('');const [transferAddress, setTransferAddress] = useState('');const [transferAmount, setTransferAmount] = useState('');const connectWallet = async() => {try {// 1、检查浏览器是否安装了以太坊钱包(如MetaMask)if (!window.ethereum) {alert('请安装MetaMask等以太坊钱包插件!');return;}// 2、请求连接钱包,获取账户const provider = new ethers.BrowserProvider(window.ethereum);const signer = await provider.getSigner();const accounts = await provider.send("eth_requestAccounts", []);setAccount(accounts[0]);// 3、访问合约const dbankAddress = "0xcf33936D93CFda55e0e0B041B2C0a93817E2fdB1";const theBankContract = new ethers.Contract(dbankAddress, dbankAbi, signer);setBankContract(theBankContract);// 首次调用合约的myBalance方法,显示余额const firstBalance = await theBankContract.myBalance();setBalance(ethers.formatUnits(firstBalance, 18));} catch (error) {console.error("连接钱包失败:", error);alert("连接钱包失败!");}}const getMyBalance = async() => {if (!bankContract) {console.log("银行合约未连接!");return;}try {// 调用合约的myBalance方法const myBalance = await bankContract.myBalance();setBalance(ethers.formatUnits(myBalance, 18));} catch (error) {console.error("获取余额失败:", error);alert("获取余额失败!");}}const deposit = async() => {if (!bankContract || !depositAmount) {alert("请输入存款金额!");return;}try {const tx = await bankContract.deposit(ethers.parseUnits(depositAmount, 18));await tx.wait(); // 等待交易被打包alert("存款成功!");setDepositAmount(''); // 清空输入框getMyBalance(); // 更新余额} catch (error) {console.error("存款失败:", error);alert("存款失败!");}}const withdraw = async() => {if (!bankContract || !withdrawAmount) {alert("请输入取款金额!");return;}try {const tx = await bankContract.withdraw(ethers.parseUnits(withdrawAmount, 18));await tx.wait(); // 等待交易被打包alert("取款成功!");setWithdrawAmount(''); // 清空输入框getMyBalance(); // 更新余额} catch (error) {console.error("取款失败:", error);alert("取款失败!");}}const bankTransfer = async() => {if (!bankContract || !transferAmount) {alert("请输入转账金额!");return;}try {const tx = await bankContract.bankTransfer(transferAddress,ethers.parseUnits(transferAmount, 18));await tx.wait(); // 等待交易被打包alert("转账成功!");setTransferAmount(''); // 清空输入框getMyBalance(); // 更新余额} catch (error) {console.error("转账失败:", error);alert("转账失败!");}}
}

优化后最终页面如下:
image

注意:请事先调用 MyFirstToken (MFT) 合约的approve接口,授权批准 DBank 合约账户可以从你的账户中多次提取,最高可达 25000 MFT币。
image

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/971525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用竞态条件绕过业务逻辑:一个价值500美元的漏洞挖掘

本文详细分析了Examlife保险平台成员创建系统中的竞态条件漏洞,攻击者可通过并发请求绕过重复账户限制,使用相同邮箱和员工ID创建多个保险档案,可能导致数据不一致和管理错误。文章包含漏洞原理、复现步骤和影响分析…

RecoveryTools

5d877c9b356c09b72e8e64bcb76471e8

信计2班 17 曾向嵩 文字识别系统

#coding=utf-8 import struct import os from PIL import Image DATA_PATH="D:\\Jesusss\\vs code\\my code\\文字识别系统\\data\\HWDB1.1trn_gnt" #gnt数据文件路径 IMG_PATH="D:\\Jesusss\\vs code\…

uploda-labs(1-21)靶场全解

uploda-labs-靶场 Pass-01(前端绕过) 先试试直接上传一句话木马.php文件 发现点击上传发现没有对后端响应但是我们抓包发现没有数据包 然后,我们上传.jpg或者png的时候发现可以上传成功也有返回流量包 我们猜测是前端…

251120一波三折的一天啊

今天去适应比赛的场地,以及资格审查,因为是延毕的博士,居然差点打不了,说要打个在读证明,也是服了,,。还好,至少打上了。 这个赛程也是很长了,打六天,打到周三。可能也是为了让大家不那么累吧,但是我感觉我…

Java自复习

static和final [static] 可修饰: 类:静态内部类 方法: 成员变量:静态变量(类变量) 代码块: 接口:接口中默认变量为:public static final [final] ---最终形态 修饰: 类:不可被继承 成员变量:常量,不可改变…

CentOS7系统安装Docker

CentOS7系统安装Docker官方文档:https://docs.docker.com/engine/install/centos/1. YUM 安装 1.1 安装最新版本 # (1) 卸载旧版本 docker $ sudo yum remove \docker \docker-client \docker-client-latest \docker-…

20232312 2025-2026-1 《网络与系统攻防技术》实验六实验报告

20232312 2025-2026-1 《网络与系统攻防技术》实验六实验报告 1.实验内容 实验内容包括以下几个主要部分:前期信息收集:使用Metasploit的辅助模块进行主机发现和端口扫描漏洞利用实践:针对多个常见服务漏洞进行实际…

软件工程学习日志2025.11.20

实验一:AI故事生成平台(2025.11.13) 学习目标 构建平台后端核心,实现基于关键词的自动故事生成功能。 技术实现数据模型设计Story数据模型 class Story: id: int # 主键 title: str # 故事标题 summary: str # …

Git 小白使用说明

🚀 Git 小白使用说明:从入门到规范 第一部分:基础设置与安全原则步骤/原则 核心目标 详细说明与 PyCharm 操作1. 安装与全局身份 确保 Git 正常运行并知道“您是谁”。 操作: 在 PyCharm 设置中检查 Git 路径。 提…

docker nginx 和宿主机原生 nginx 服务的性能压测对比

1、通过 yum install -y nginx 安装的原生 nginx 1.20.1➜ ~ service nginx restart Redirecting to /bin/systemctl restart nginx.service ➜ ~ curl localhost <!DOCTYPE html> <html> <head> …

kode-cli+glm4.6测评

kode-cli + glm4.6测评 官网 https://github.com/shareAI-lab/Kode-cli 开源,Apache-2.0 license用HTML、CSS和JavaScript(若更偏好p5.js也可选用),创建一个带有动画效果的天气卡片。要在卡片里呈现当前温度、具体位…

UEFI - FV/FFS/FDF 的关系 - 阿源

本文梳理和介绍了一下 固件卷 FV,FFS文件,FDF文件之间的组织关系,以及其在 EDKII 工程中的体现。目录1. 什么是固件卷 2. 是么是 FFS 文件 3. 什么是 FDF 文件一、UEFI 固件卷 如果一个磁盘是没有经过分区的简单状态…

体验 Grok4.1

用Grok4.1享赛博道祖人生。夸夸群绝不会想到,竟被格罗克这小子夺舍。我只说了句想要修仙,它瞬间就能把我捧成元婴,什么万里挑一的练武奇才都变得无味至极,因为它知我定是道祖转世。不懂风情之人会说这就是舔狗的马…

预算管理不用愁 - 智慧园区

又到年度预算季,不少企业管理者陷入“预算魔咒”: - 财务部门熬夜制表,业务部门敷衍填报,耗时1-2个月的预算,执行起来偏差超30%; - 销售、生产、研发各算各的账,资源互相争抢,协同效率低下; - 预算目标拍脑袋…

2025半期游忌

闲话 感觉做的时候感觉自己信心满满(感觉各科都是),结果呢,唉~,主科全部都演我 \(QwQ\)(甚至英语还考了 \(orz\) ,像极了我现在的心境) 正题 语文这次真的是被语文病句题被刺了,考的时候感觉 \(A\) 和 \(C\) …

Uni-App(Vue3 + TypeScript)方案结构详解 ------ 以 Lighting-UniApp 为例,提供源代码

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

第31天(简单题中等题 二分查找)

打卡第三十一天 1道简单题+2道中等题题目:思路:二分代码: class Solution { public:int singleNonDuplicate(vector<int>& nums) {int left = -1, right = nums.size() / 2;// left从-1开始,right从数组…

XHORSE XZBT40EN 4-Button Honda Civic 2016-2019 Special PCBs (5pcs/lot) for Reliable Key Fob Repairs

Problem: Struggling to Find Reliable Key Fob PCBs for Honda Civic 2016-2019? For automotive repair shops and Honda Civic owners, sourcing compatible, high-quality key fob PCBs can be a frustrating cha…

Java 和 Apache POI 处理 Excel 文件

一、引言 在企业应用中,Excel 是一种常见的数据存储和交换格式。Java 通过 Apache POI 库可以高效地读取、修改和写入 Excel 文件。本文介绍如何使用 Java 处理 Excel 文件,包括读取、写入和修改数据。 二、环境准备…