【Solidity】代币
ERC20
ERC-20 全称 “Ethereum Request for Comment 20”,是一种标准接口,用于实现代币合约。ERC20 标准定义了一组函数和事件,使得代币可以在不同的应用和平台之间互操作。
ERC20 标准接口定义了一组必须实现的函数和事件:
interface IERC20 {// 返回代币的总供应量function totalSupply() external view returns (uint);// 返回指定地址的代币余额function balanceOf(address account) external view returns (uint);// 返回授权给 spender 的代币数量function allowance(address owner, address spender) external view returns (uint);// 将指定数量 amount 的代币从调用者的账户转移到另一个地址 recipientfunction transfer(address recipient, uint amount) external returns (bool);// 授权 spender 可以从调用者账户转移的代币数量 amountfunction approve(address spender, uint amount) external returns (bool);// 从 sender 账户转移指定数量的代币到 recipient, 需要预先通过 approve 授权function transferFrom(address sender,address recipient,uint amount) external returns (bool);
}
interface IERC20 {// 在代币转移时触发, 包括零值转移event Transfer(address indexed from, address indexed to, uint value);// 在调用 approve 时触发event Approval(address indexed owner, address indexed spender, uint value);
}
以下是一个简单的 ERC20 代币合约示例:
contract ERC20 is IERC20 {// 存储代币的名称、符号和小数位数string public name = "TestToken";string public symbol = "TTK";uint8 public decimals = 18;// 存储代币的总供应量uint public totalSupply;// 存储每个地址的代币余额; owner => balancemapping(address => uint) public balanceOf;// 存储每个地址对其他地址的授权额度; owner => spender => amountmapping(address => mapping(address => uint)) public allowance;// 定义两个事件, 用于记录代币转移和授权操作event Transfer(address indexed from, address indexed to, uint value);event Approval(address indexed owner,address indexed spender,uint value);// 将指定数量 amount 的代币从调用者的账户转移到另一个地址 recipientfunction transfer(address recipient,uint amount) external override returns (bool) {require(balanceOf[msg.sender] >= amount,"ERC20: transfer amount exceeds balance");balanceOf[msg.sender] -= amount;balanceOf[recipient] += amount;emit Transfer(msg.sender, recipient, amount);return true;}// 授权 spender 可以从调用者账户转移的代币数量 amountfunction approve(address spender,uint amount) external override returns (bool) {allowance[msg.sender][spender] = amount;emit Approval(msg.sender, spender, amount);return true;}// 从 sender 账户转移指定数量的代币到 recipient, 需要预先通过 approve 授权function transferFrom(address sender,address recipient,uint amount) external override returns (bool) {require(balanceOf[sender] >= amount,"ERC20: transfer amount exceeds balance");require(allowance[sender][msg.sender] >= amount,"ERC20: transfer amount exceeds allowance");balanceOf[sender] -= amount;balanceOf[recipient] += amount;allowance[sender][msg.sender] -= amount;emit Transfer(sender, recipient, amount);return true;}
}
使用 OpenZeppelin 库可以简化 ERC20 代币的实现。OpenZeppelin 提供了安全且经过审计的 ERC20 实现。
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract MyToken is ERC20 {constructor(string memory name,string memory symbol,uint256 initialSupply) ERC20(name, symbol) {_mint(msg.sender, initialSupply * 10 ** uint256(decimals()));}
}
除了上述核心方法,你可能还听过 mint & burn。它们通常用于 ERC20 代币合约中,以增加或减少代币的总供应量。
contract ERC20 is IERC20 {// ...// 创建 amount 数量的代币, 并将其分配给指定的地址function mint(uint amount) external {totalSupply += amount;balanceOf[msg.sender] += amount;emit Transfer(address(0), msg.sender, amount);}// 销毁 amount 数量的代币function burn(uint amount) external {require(balanceOf[msg.sender] >= amount,"ERC20: burn amount exceeds balance");totalSupply -= amount;balanceOf[msg.sender] -= amount;emit Transfer(msg.sender, address(0), amount);}
}
ERC721
ERC721 是以太坊上用于创建不可替代代币(NFT)的标准。与 ERC20 不同,ERC721 代币是独一无二的,每个代币都有自己的唯一标识符。
ERC721 标准定义了一组必须实现的函数和事件,使得代币可以在不同的应用和平台之间互操作。
interface IERC721 {// 返回某个地址拥有的代币数量function balanceOf(address owner) external view returns (uint256 balance);// 返回某个代币的所有者地址function ownerOf(uint256 tokenId) external view returns (address owner);// 安全地将代币从一个地址转移到另一个地址function safeTransferFrom(address from,address to,uint256 tokenId) external;// 将代币从一个地址转移到另一个地址function transferFrom(address from, address to, uint256 tokenId) external;// 批准某个地址可以转移指定的代币function approve(address to, uint256 tokenId) external;// 返回被批准可以转移指定代币的地址function getApproved(uint256 tokenId) external view returns (address operator);// 批准或撤销某个地址可以管理调用者所有的代币function setApprovalForAll(address operator, bool _approved) external;// 查询某个地址是否被批准可以管理另一个地址的所有代币function isApprovedForAll(address owner,address operator) external view returns (bool);
}
interface IERC721 {// 在代币转移时触发event Transfer(address indexed from,address indexed to,uint256 indexed tokenId);// 在调用 approve 时触发event Approval(address indexed owner,address indexed approved,uint256 indexed tokenId);// 在调用 setApprovalForAll 时触发event ApprovalForAll(address indexed owner,address indexed operator,bool approved);
}
WETH
WETH(Wrapped Ether)是以太坊(ETH)的包装版本,它遵循 ERC-20 代币标准。由于 ETH 本身并不符合 ERC-20 标准,因此在某些去中心化应用(DApp)和去中心化金融(DeFi)平台上使用时会有一些限制。WETH 的出现解决了这个问题,使 ETH 可以在这些平台上无缝使用。
contract WETH {// 代币名称、符号、小数位数string public name = "Wrapped Ether";string public symbol = "WETH";uint8 public decimals = 18;// 记录每个地址的 WETH 余额mapping(address => uint) public balanceOf;// 记录存入 ETH 的事件event Deposit(address indexed account, uint amount);// 记录提取 ETH 的事件event Withdrawal(address indexed account, uint amount);// 使合约可以接受 ETHreceive() external payable {deposit();}// 接受 ETH 并将其转换为 WETHfunction deposit() public payable {balanceOf[msg.sender] += msg.value;emit Deposit(msg.sender, msg.value);}// 将 WETH 转换回 ETH 并提取到调用者的地址function withdraw(uint amount) public {require(balanceOf[msg.sender] >= amount, "Insufficient balance");balanceOf[msg.sender] -= amount;payable(msg.sender).transfer(amount);emit Withdrawal(msg.sender, amount);}// 返回合约中存储的 ETH 总量function totalSupply() public view returns (uint) {return address(this).balance;}
}
我们可以直接使用 OpenZeppelin 的 ERC20 合约库来实现 WETH 合约:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract WETH is ERC20 {// 记录存入 ETH 的事件event Deposit(address indexed account, uint amount);// 记录提取 ETH 的事件event Withdrawal(address indexed account, uint amount);// 初始化 WETH 合约constructor() ERC20("Wrapped Ether", "WETH") {}// 使合约可以接受 ETHreceive() external payable {deposit();}// 接受 ETH 并将其转换为 WETHfunction deposit() public payable {_mint(msg.sender, msg.value);emit Deposit(msg.sender, msg.value);}// 将 WETH 转换回 ETH 并提取到调用者的地址function withdraw(uint amount) public {_burn(msg.sender, amount);payable(msg.sender).transfer(amount);emit Withdrawal(msg.sender, amount);}
}
-
部署 WETH 合约
-
调用 WETH 合约的 deposit 函数,设置传入的 ETH 数量,这里以 1 ETH 为例
-
调用 WETH 合约继承的 balanceOf 函数,传入部署 WETH 合约的地址,查看 WETH 余额
-
调用 WETH 合约继承的 totalSupply 函数,查看合约中存储的 ETH 总量
-
调用 WETH 合约的 withdraw 函数,传入提取的 WETH 数量,提取 ETH
-
调用 WETH 合约继承的 balanceOf 函数,查看 WETH 余额
-
调用 WETH 合约继承的 totalSupply 函数,查看合约中存储的 ETH 总量
相关文章:
【Solidity】代币
ERC20 ERC-20 全称 “Ethereum Request for Comment 20”,是一种标准接口,用于实现代币合约。ERC20 标准定义了一组函数和事件,使得代币可以在不同的应用和平台之间互操作。 ERC20 标准接口定义了一组必须实现的函数和事件: in…...
5 - Linux YUM仓库及NFS共享服务
目录 一、YUM概述 1.YUM简介 2.软件仓库的提供方式 3.RPM软件包的来源 4. yum 命令的运用 二、搭建ftp YUM仓库 三、NFS共享服务 1.NFS简述 2.模拟NFS 一、YUM概述 1.YUM简介 YUM(Yellow dog Updater Modified)是一个专门为了解决包的依赖关系…...
上传文件,文件类型限制语法,各种媒体视频文件的Content-Type
各种媒体视频文件的Content-Type “application/x-apple-diskimage”: “DMG”, “application/epubzip”: “EPUB”, “application/java-archive”: “JAR”, “video/x-matroska”: “MKV”, “text/html”: “HTML|HTM”, “text/css”: “CSS”, “text/javascript…...
类和对象(下)(2)
类和对象(下)(2) static成员 • ⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。 • 静态成员变量为当前类的所有对象所共享,不属于某个具体的对象,不存在对象中&#…...
软件测试 - 自动化测试(概念)(Java)(自动化测试分类、web自动化测试、驱动、selenium自动化测试工具的安装)
一、自动化的概念 ⾃动洒⽔机,主要通上⽔就可以⾃动化洒⽔并且可以⾃动的旋转。 ⾃动洗⼿液,免去了⼿动挤压可以⾃动感应出洗⼿液 超市⾃动闸⻔,不需要⼿动的开⻔关⻔ ⽣活中的⾃动化案例有效的减少了⼈⼒的消耗,同时也提⾼了⽣…...
wpf datagrid 实现双向绑定
前台 <DataGridAutoGenerateColumns"False"Background"White"CanUserAddRows"True"Grid.Row"1"RowEditEnding"DataGrid_OnRowEditEnding"RowHeight"60"SelectionUnit"CellOrRowHeader"x:Name"…...
使用循环在el-select下拉框中循环出-3至50
问: 使用循环在el-select下拉框中循环出-3至50 回答: <el-form-itemprop"adPosition"label"广告位置":rules"{required: true, message: 广告位置不能为空, trigger: change}" ><el-select v-model"addDataForm.adPosition"…...
全球海事航行通告解析辅助决策系统
“全球海事航行通告解析辅助决策系统”是一个针对海事行业设计的智能系统,旨在帮助海上导航和航运操作人员解析和应对全球发布的海事航行通告。 要做这样的系统我们必须要了解海事签派员的日常工作。 海事签派员,也称为船舶操作员或船运调度员࿰…...
Spring 解决bean的循环依赖
Spring循环依赖-博客园 1. 什么是循环依赖 2. 循环依赖能引发什么问题 循环依赖可能引发以下问题: 初始化顺序不确定:循环依赖导致无法确定哪个对象应该先被创建和初始化,从而造成初始化顺序的混乱。这可能导致错误的结果或意外的行为。死…...
鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main
阅读之前的说明 先说明,本篇很长,也很枯燥,若不是绝对的技术偏执狂是看不下去的.将通过一段简单代码去跟踪编译成ELF格式后的内容.看看ELF究竟长了怎样的一副花花肠子,用readelf命令去窥视ELF的全貌,最后用objdump命令…...
seq2seq编码器encoder和解码器decoder详解
编码器 在序列到序列模型中,编码器将输入序列(如一个句子)转换为一个隐藏状态序列,供解码器生成输出。编码层通常由嵌入层和RNN(如GRU/LSTM)等组成 Token:是模型处理文本时的基本单元,可以是词,子词,字符…...
前端使用 Konva 实现可视化设计器(21)- 绘制图形(椭圆)
本章开始补充一些基础的图形绘制,比如绘制:直线、曲线、圆/椭形、矩形。这一章主要分享一下本示例是如何开始绘制一个图形的,并以绘制圆/椭形为实现目标。 请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 Bug,…...
Python 将单词拆分为单个字母组成的列表对象
Python 将单词拆分为单个字母组成的列表对象 正文 正文 这里介绍一个简单算法,将英文单词拆分为其对应字母组成的列表。 str1 ACG lst1 [i for i in str1] lst2 list(str1)# Method 1 print(lst1) # Method 2 print(lst2) """ result: [A, C, G…...
欧洲 摩纳哥税务知识
摩纳哥是一个位于法国南部的城邦国家,以其豪华的生活环境和宽松的税收政策而闻名。自1869年以来,摩纳哥取消了个人所得税的征收,这使得它成为富裕人士和外籍人士的理想居住地。然而,这并不意味着摩纳哥的税收制度完全不存在。以下…...
域控制器的四大支柱分别是车载以太网、自适应Autosar
域控制器的四大支柱分别是车载以太网、自适应Autosar、高性能处理器和集中式E/E架构。 百度安全验证 。自适应Autosar采用Proxy/Skeleton的通信架构,同时采用中间件SOME/IP...
写给大数据开发:如何优化临时数据查询流程
你是否曾因为频繁的临时数据查询请求而感到烦恼?这些看似简单的任务是否正在蚕食你的宝贵时间,影响你的主要工作?如果是,那么这篇文章正是为你而写。 目录 引言:数据开发者的困境问题剖析:临时数据查询的…...
【MongoDB】Java连接MongoDB
连接URI 连接 URI提供驱动程序用于连接到 MongoDB 部署的指令集。该指令集指示驱动程序应如何连接到 MongoDB,以及在连接时应如何运行。下图解释了示例连接 URI 的各个部分: 连接的URI 主要分为 以下四个部分 第一部分 连接协议 示例中使用的 连接到具有…...
nginx支持的不同事件驱动模型
Nginx 支持的不同事件驱动模型 Nginx 是一款高性能的 Web 和反向代理服务器,它支持多种事件驱动模型来处理网络 I/O 操作。不同的操作系统及其版本支持不同的事件驱动模型,这些模型对于 Nginx 的并发处理能力和性能至关重要。下面详细介绍 Nginx 支持的…...
C++ TinyWebServer项目总结(7. Linux服务器程序规范)
进程 PID 进程的PID(Process ID)是操作系统中用于唯一标识一个进程的整数值。每个进程在创建时,操作系统都会分配一个唯一的PID,用来区分不同的进程。 PID的特点 唯一性: 在操作系统运行的某一时刻,每个…...
基于STM32单片机设计的秒表时钟计时器仿真系统——程序源码proteus仿真图设计文档演示视频等(文末工程资料下载)
基于STM32单片机设计的秒表时钟计时器仿真系统 演示视频 基于STM32单片机设计的秒表时钟计时器仿真系统 摘要 本设计基于STM32单片机,设计并实现了一个秒表时钟计时器仿真系统。系统通过显示器实时显示当前时间,并通过定时器实现秒表计时功能。显示小时…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...
Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...
