当前位置: 首页 > news >正文

Web3 solidity编写交易所合约 编写ETH和自定义代币存入逻辑 并带着大家手动测试

上文 Web3 叙述交易所授权置换概念 编写transferFrom与approve函数我们写完一个简单授权交易所的逻辑 但是并没有测试
其实也不是我不想 主要是 交易所也没实例化 现在也测试不了
我们先运行 ganache 启动一个虚拟的区块链环境
在这里插入图片描述
先发布 在终端执行

truffle migrate

如果你跟着我一步一步来的 那编译应该就会通过的
在这里插入图片描述
然后的话 我们要将交易所的合约也创建一下
在项目根目录下的 contracts 目录下 创建一个文件叫 Exchange.sol
然后 先编写出最基本的结构

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";contract Exchange {using SafeMath for uint256;
}

然后 这里 我们需要指定一个收费账号 因为 我们交易所大家可以直接理解为中介
但与互联网中介不同的在于 我们这个合约是纯公开透明的 但大家在这里交换代币 比如 预料到什么代币可能要涨了 赶紧转入一些 交易所从中间获取部分利益自然也是无可厚非的 而且 这个都是公开透明的

然后 还有一个费率的问题 例如 有些 我们每次交易 费率是百分之六 就比如你在虎牙送主播礼物其实主播只能拿到一小部分,大部分是平台的 你可以理解为被平台拿走的部分就叫费率 当然直播平台估计要到百分之五十以上 平台拿到的会比主播多 一般交易平台费率应该就会少一点 大概在百分之十以内

我们可以直接这样写

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";contract Exchange {using SafeMath for uint256;//收费账号地址address public feeAccout;//费率uint256 public feePercent;//实例化合约交易所constructor(address _feeAccout,uint256 _feePercent) {//用接到的参数给账号地址和费率赋值feeAccout = _feeAccout;feePercent = _feePercent;}
}

这里 我们先定义了两个变量 address 地址类型 feeAccout 设置了public表示这个变量是公开的 用于存储收费账号的地址
然后uint256数字类型的feePercent 记录费率使用
然后在合约实例化的constructor中从外面接受账号地址和费率的值 然后给上面两个变量赋值

但还有一个问题 我们的交易所不可能只存一种货币 不然我们那什么去跟别人兑换呢 是不是 或者是 你只存一种 对话来干嘛呢?
那么 我们交易所中就可以存一个这样的对象
我们先用js结构阐述

{"A代币地址":{"A用户地址": 300,"B用户地址": 400},"B代币地址": {"A用户地址": 500}
}

大概就是这样的一个结构 第一层对象是目前有存储的所有代币地址 他们对应的值 是 这个代币下 每个用户 值对应拥有的数量

在solidity中 我们可以这样写

mapping(address=> mapping(address=>uint256)) public tokens;

我们定义了一个对象 然后 键是一个address地址类型 值是一个对象 值中的对象 键也是address地址类型 值是uint256数字类型
然后设置public表示它是公开的 然后名字叫 tokens 名字可以看心情去定义

但是 光有数据自然是无法完成逻辑 我们还需要一个存款的方法
我们可以这样写
这里 我们定义了两个方法 第一个用来充值ETH 第二个则是gerToken的充值函数
然后我们用public声明函数公开
然后payable则声明这是个充值的函数

    //转入  ETHfunction depositEther() payable public {}//转入  gerTokenfunction depositToken() payable public {}

在这里插入图片描述
然后 我们在上面定义一个常量

// ETH 代币地址
address constant ETHER = address(0);

在这里插入图片描述
正常来讲 这个的值应该是一个地址 是我们 ETH代币对应的地址 但是 我们这里只是模拟 就随便写了一个 address(0)
这样也符合address的一个地址规范
然后 我们还得写一个事件来充当日志 记录充值操作
这里 我写的 叫 Deposit 这个 其实大家可以顺便取名字 你叫 A 叫B都可以
参考代码如下

event Deposit(address token,address user,uint256 amount,uint256 balance);//存入ETH

然后 我们的depositEther 存入 ETH 的函数逻辑就可以开始写了

//转入  ETH
function depositEther() payable public {tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender].add(msg.value);emit Deposit(ETHER,msg.sender, msg.value, tokens[ETHER][msg.sender]);
}

ETHER 就是我们刚刚创建的代币标识 值是address(0) 这个只是我们乱写的一个地址 因为我们目前只是测试
我们就假设我们的交易所 0就代表ETH 然后msg.sender 代表当前用户的地址 然后msg.value是需要操作的金额
之前我们说过 这个tokens是存储 代币地址 然后 用户持有数量的对象

这里 我们操作 add 给用户在token对象中的对应ETH 加上msg.value的数值
然后 我们调用自己刚刚写的Deposit来记录这次交易
Deposit 第一个参数 ETHER 代币地址 msg.sender 当前用户 msg.value 操作数值 tokens[ETHER][msg.sender] 在tokens中找到代币地址对应的对象下的对应当前用户对应的数值 简单说 最后一个要的是用户该代币的总数

然后 ETH的充值操作已经完成了
那么 grToken也需要一个充值逻辑
但是 我们不应该直接在交易所中操作 而是要通过我们代币的合约 去操作
我们引入 grToken的合约文件
在这里插入图片描述
然后 depositToken 代码编写如下

//转入  gerToken
function depositToken(address _token, uint256 _amount) payable public {require(grToken(_token).transferFrom(msg.sender,address(this),_amount));tokens[_token][msg.sender] = tokens[_token][msg.sender].add(_amount);emit Deposit(_token,msg.sender, _amount, tokens[_token][msg.sender]);
}

这里 我们两个参数 _token代币地址 _amount需要充入金额
然后 我们的下一句可能有问题 所以套上了require来调用 之前我们讲过 require 如果代码错误 他会立刻停止程序 并将错误记录在区块链上
然后我们实例化grToken 合约对象 地址就 传入我们的_token调用其中的transferFrom函数 扣款用户就是msg.sender 当前操作这个函数的用户 收款地址address(this)我们交易所本身 数额就是方法接到的_amount参数
然后 操作完成之后 我们再次通过tokens 操作用户在对象中的代币数值
然后调用 我们刚刚定义的 Deposit 记录交易
然后 我们编译一下试试
终端输入

truffle compile

在这里插入图片描述
没有任何问题

但 我们部署之前 还需要写个脚本 你别合约好不容易写完了 但没有写脚本去使用它
我们在migrations目录下创建一个2_contract.js
编写代码如下

const grToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")
module.exports = async  function(deployer) {const accounts = await web3.eth.getAccounts();await deployer.deploy(grToken);await deployer.deploy(Exchange,accounts[0],3);
}

这里 我们导入了grToken代币合约和Exchange交易所合约
然后 调用web3的getAccounts拿到用户列表
然后发布两个合约
其中 Exchange本身需要两个参数 一个是 收款用户 就是交易所得到的小费给哪个用户 以及后面的费率
我们这里费率少一点 写个百分之三吧
然后 地址 我们直接在用户列表中找到下标为0的用户 因为发布时 燃料消耗的第一个用户 那么 小费自然也应该归他

我们终端执行

truffle migrate --reser

更新发布一下智能合约
在这里插入图片描述
这里 发布成功了 但是 我们还是得测试一下

首先 我们用MetaMask导入一下 我们ganache中的第一个用户
在这里插入图片描述
我们在项目根目录下的scripts 目录下创建 test.js
参考代码如下

const GrToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")const toWei = (bn) => {return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {return web3.utils.toWei(bn.toString(), "ether");
}module.exports = async function(callback) {const grTokenDai = await GrToken.deployed();const exchage = await Exchange.deployed();const accounts= await web3.eth.getAccounts()await exchage.depositEther({from: accounts[0],value: inWei(10)});callback()
}

我们先导入了 代币 grToken 和 交易所 Exchange的合约
然后 调用了Exchange的depositEther 来充值ETH 具体要存入的用户 依旧通过getAccounts拿取用户列表 然后操作第一个去存储
然后 我们终端执行

truffle exec .\scripts\test.js

在这里插入图片描述
然后查看 MetaMask 会发现用户的款确实扣了
在这里插入图片描述
在运行一次 就又少 10
在这里插入图片描述
当然 这里只是存入 但对用于来讲 最直观的就是看ETH少了
而且应该还会更少一些 因为 还有燃料需要消耗
还挺坑的 老实说

然后 我们可以查一下存款
scripts 目录下创建 test.js
编写代码如下

const GrToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")
const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';const toWei = (bn) => {return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {return web3.utils.toWei(bn.toString(), "ether");
}module.exports = async function(callback) {const grTokenDai = await GrToken.deployed();const exchage = await Exchange.deployed();const accounts= await web3.eth.getAccounts()await exchage.depositEther({from: accounts[0],value: inWei(10)});let res = await exchage.tokens(ETHER_ADDRESS,accounts[0])console.log(toWei(res));callback()
}

我们这里直接写死了0x0000000000000000000000000000000000000000 这个就是我们设置以太坊的地址
然后 通过交易所定义的 tokens 定义的get特性 通过ETH 的地址和账号地址查看存入的代币
然后 我们再次运行

truffle exec .\scripts\test.js

因为我们测试操作了很多次 所以 这个数值是没问题的
在这里插入图片描述
大不了 我们再来一次
在这里插入图片描述
又存进去10 变成了 130
在这里插入图片描述
我们账号也其实少了很多
那么 ETH就好了

然后 我们来操作 grToken

但是 这个 我们需要先授权 允许交易所来操作我们的grToken

我们直接给scripts 目录下创建 test.js 写成这样

const GrToken = artifacts.require("grToken.sol")
const Exchange = artifacts.require("Exchange.sol")const toWei = (bn) => {return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {return web3.utils.toWei(bn.toString(), "ether");
}module.exports = async function(callback) {const grTokenDai = await GrToken.deployed();const exchage = await Exchange.deployed();const accounts= await web3.eth.getAccounts()await grTokenDai.approve(exchage.address,inWei(100000),{from: accounts[0]})await exchage.depositToken(grTokenDai.address,inWei(10000),{from: accounts[0]})let res = await exchage.tokens(grTokenDai.address,accounts[0])console.log(toWei(res));callback()
}

这里 我们先调用grTokenDai我们上文中写的 交易所授权函数approve 第一个参数 交易所地址 我们取exchage的address 授权的数量 是 100000授权账号是 第一个账号
然后 我们调用我们交易所写的depositToken 存入grToken代币
然后 第一个参数是grTokenDai的address地址 然后数量10000 存入的用户还是我们的第一个用户
然后 我们查看grtoken数量
因为grTokenDai.address
我们再次运行

truffle exec .\scripts\test.js

可以看到这个效果
在这里插入图片描述

相关文章:

Web3 solidity编写交易所合约 编写ETH和自定义代币存入逻辑 并带着大家手动测试

上文 Web3 叙述交易所授权置换概念 编写transferFrom与approve函数我们写完一个简单授权交易所的逻辑 但是并没有测试 其实也不是我不想 主要是 交易所也没实例化 现在也测试不了 我们先运行 ganache 启动一个虚拟的区块链环境 先发布 在终端执行 truffle migrate如果你跟着我…...

概念解析 | 生成式与判别式模型在低级图像恢复与点云重建中的角力:一场较量与可能性探索

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:生成式模型与判别式模型在低级图像恢复/点云重建任务中的优劣与特性。 生成式与判别式模型在低级图像恢复与点云重建中的角力:一场较量与可能性探索 1. 背景介绍 机器学习…...

【云原生】kubectl命令的详解

目录 一、陈述式资源管理方式1.1基本查看命令查看版本信息查看资源对象简写查看集群信息配置kubectl自动补全node节点查看日志 1.3基本信息查看查看 master 节点状态查看命名空间查看default命名空间的所有资源创建命名空间app删除命名空间app在命名空间kube-public 创建副本控…...

uniapp两个单页面之间进行传参

1.单页面传参&#xff1a;A --> B url: .....?code JSON.stringify(param), 2.单页面传参B–>Auni.$emit() uni.$on()...

uniapp运行项目到iOS基座

2022年9月&#xff0c;因收到苹果公司警告&#xff0c;目前开发者已无法在iOS真机设备使用未签名的标准基座&#xff0c;所以现在要运行到 IOS &#xff0c;也需要进行签名。 Windows系统&#xff0c;HBuilderX 3.6.20以下版本&#xff0c;无法像MacOSX那样对标准基座进行签名…...

HTTP——九、基于HTTP的功能追加协议

HTTP 一、基于HTTP的协议二、消除HTTP瓶颈的SPDY1、HTTP的瓶颈Ajax 的解决方法Comet 的解决方法SPDY的目标 2、SPDY的设计与功能3、SPDY消除 Web 瓶颈了吗 三、使用浏览器进行全双工通信的WebSocket1、WebSocket 的设计与功能2、WebSocket协议 四、期盼已久的 HTTP/2.01、HTTP/…...

Redis 在电商秒杀场景中的应用

Redis 在电商秒杀场景中的应用 一、简介1.1 简介1.2 场景应用 二、Redis 优势与挑战2.1 优势2.2 秒杀场景的挑战 三、应用场景分析3.1 库存预热代码示例 3.2 分布式锁3.3 消息队列 四、系统设计方案4.1 架构设计4.2 技术选型4.3 数据结构设计 五、Redis 性能优化5.1 集群部署5.…...

大麦订单生成器 大麦一键生成订单

后台一键生成链接&#xff0c;独立后台管理 教程&#xff1a;修改数据库config/Conn.php 不会可以看源码里有教程 下载源码程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3...

Java实现Google cloud storage 文件上传,Google oss

storage 控制台位置 创建一个bucket 点进bucket里面&#xff0c;权限配置里&#xff0c;公开访问&#xff0c;在互联网上公开&#xff0c;需要配置角色权限 新增一个访问权限 &#xff0c;账号这里可以模糊搜索&#xff0c; 角色配置 给allUser配置俩角色就可以出现 在互联…...

适配器模式(AdapterPattern)

适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09;是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式&#xff0c;它结合了两个独立接口的功能。 优缺点 优点&#xff1a; 单一职责原则。你可以将接口或数据转换代码从程序主要业务逻辑中分…...

Apache Kafka Learning

目录 一、Kafka 1、Message Queue是什么&#xff1f; 2、Kafka 基础架构 3、Kafka安装 4、Offset自动控制 5、Acks & Retries 6、幂等性 7、事务控制 8、数据同步机制 9、Kafka-Eagle 二、Maven项目测试 1、Topic API 2、生产者&消费者 一、Kafka Kafka是…...

手把手教你用idea实现Java连接MySQL数据库

目录 1.下载MySQL 2.下载mysql 的jdbc驱动 3.将驱动jar包导入idea 4.通过Java测试数据库是否连接成功 1.下载MySQL 首先如果没有mysql的需要先下载MySQL&#xff0c;可以看这个教程 MYSQL安装手把手&#xff08;亲测好用&#xff09;_程序小象的博客-CSDN博客 2.下载mysql…...

Ubuntu 22.04安装和使用ROS1可行吗

可行。 测试结果 ROS1可以一直使用下去的&#xff0c;这一点不用担心。Ubuntu会一直维护的。 简要介绍 Debian发行版^_^ AI&#xff1a;在Ubuntu 22.04上安装ROS1是可行的&#xff0c;但需要注意ROS1对Ubuntu的支持只到20.04。因此&#xff0c;如果要在22.04上安装ROS1&am…...

83 | Python可视化篇 —— Bokeh数据可视化

Bokeh 是一种交互式数据可视化库,它可以在 Python 中使用。它的设计目标是提供一个简单、灵活和强大的方式来创建现代数据可视化,同时保持良好的性能。Bokeh 支持多种图表类型,包括线图、散点图、柱状图、饼图、区域图、热力图等。此外,它还支持将这些图表组合在一起以创建…...

图像 检测 - RetinaNet: Focal Loss for Dense Object Detection (arXiv 2018)

图像 检测 - RetinaNet: Focal Loss for Dense Object Detection - 密集目标检测中的焦点损失&#xff08;arXiv 2018&#xff09; 摘要1. 引言2. 相关工作References 声明&#xff1a;此翻译仅为个人学习记录 文章信息 标题&#xff1a;RetinaNet: Focal Loss for Dense Obje…...

MySQL 与MongoDB区别

一、什么是MongoDB呢 ? MongoDB 是由C语言编写的&#xff0c;是一个基于分布式文件存储的开源数据库系统。在高负载的情况下&#xff0c;添加更多的节点&#xff0c;可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB 将数据存储为一…...

Kaggle First Place Winner Solution Study——多变量回归问题

本期分享一个Kaggle上playground系列多变量回归问题的第一名解决方案。试着分析、复现、学习一下金牌选手的数据分析思路。 赛题链接&#xff1a; Prediction of Wild Blueberry Yield | Kagglehttps://www.kaggle.com/competitions/playground-series-s3e14第一名解决方案链…...

分布式应用:Zookeeper 集群与kafka 集群部署

目录 一、理论 1.Zookeeper 2.部署 Zookeeper 集群 3.消息队列 4.Kafka 5.部署 kafka 集群 6.FilebeatKafkaELK 二、实验 1.Zookeeper 集群部署 2.kafka集群部署 3.FilebeatKafkaELK 三、问题 1.解压文件异常 2.kafka集群建立失败 3.启动 filebeat报错 4.VIM报错…...

Last-Mile Embodied Visual Navigation 论文阅读

论文阅读 题目&#xff1a;Last-Mile Embodied Visual Navigation 作者&#xff1a;JustinWasserman, Karmesh Yadav 来源&#xff1a;CoRL 时间&#xff1a;2023 代码地址&#xff1a;https://jbwasse2.github.io/portfolio/SLING Abstract 现实的长期任务&#xff08;例如…...

thunder gbm

文章目录 背景参考官网信息训练调参模型保存推理 背景 想在 GPU 上使用使用闪电般快速的提升方法&#xff1f;了解这个库就好了。在很多任务上&#xff0c;它都比 LightGBM 和 XGBoost 快。 ThunderGBM 的主要特征如下&#xff1a; 通常是其它库的 10 倍。 支持 Python&#x…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

一些实用的chrome扩展0x01

简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序&#xff0c;无论是测试应用程序、搜寻漏洞还是收集情报&#xff0c;它们都能提升工作流程。 FoxyProxy 代理管理工具&#xff0c;此扩展简化了使用代理&#xff08;如 Burp…...