跳转到内容

Web3.0-DApp开发

001 课程简介

002 初始web3.0

003 认识区块链

004 以太坊介绍

005 DApp简介

006 MetaMask

007 Ganache

008 Web3.js

中文文档: https://learnblockchain.cn/docs/web3.js

Web3.js是一个库,它有很多函数,使用它可以在以太坊生态系统中通过HTTP或IPC与本地或者以太坊远程节点交互,如查看链上信息等

各种高级语言编写的程序可以使用web3 interface来与EVM交互,在此过程中使用是的JSON-RPC(一个无状态且轻量级的远程过程调用(RPC)传送协议,其传递内容透过JSON为主)

您可以使用web3.is来读取和写入以太坊区块链,而不是使用ajax从Web服务器读取和写入数据。

img.png

所以web3.js依赖BigNumber Library1,且会自动进行引入。 核心代码

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>
    <script src="https://cdn.jsdelivr.net/npm/web3@4.16.0/dist/web3.min.js"></script>
    
</head>
<body>

    <h1 id="title"></h1>

    <input type="text" id="toAccount">
    <button id="send">发送</button>

    <script>
        // 连接到以太坊网络
        // const web3 = new Web3('https://mainnet.infura.io/v3/your-infura-project-id');
        var web3 = new Web3(Web3.givenProvider || 'http://localhost:7545');
        // var web3 = new Web3(Web3.givenProvider || "ws://localhost:7545");

        web3.eth.getBlockNumber().then(res=>{
            console.log(res);
        });

        web3.eth.getChainId().then(res=>{
            console.log(res);
        });

        web3.eth.getBalance("0xACaA8d29f7B3d5ECCd65b75xxxxxxxxxx").then(res=>{
            console.log(res);
            // 转换单位
            console.log(web3.utils.fromWei(res, "ether"));
        });

        // 使用 promise
        // web3.eth.sendTransaction({
        //     from: '0x270871c6dc7bA8e8Dxxxxxxxxxxxx',
        //     to: '0xACaA8d29f7B3d5ECCd65b7xxxxxxxxxx',
        //     value: web3.utils.toWei("1", "ether")
        // })
        // .then(function(receipt){
        //     console.log("转完了!")
        // });

        // 先授权
        // web3.eth.requestAccounts().then(res=>{
        //     console.log("授权", res);

        //     title.innerHTML = res[0];
        // });

        // 获取账号

        web3.eth.getAccounts().then(res=>{            
            console.log('-----',res,'---===');
            title.innerHTML = res[0];
        });


        send.onclick = function(){
            // 获取输入框的值
            var toAccount = document.getElementById("toAccount").value;
            console.log(toAccount);

            // 转账
            web3.eth.sendTransaction({
                from: title.innerHTML,
                to: toAccount,
                value: web3.utils.toWei("1", "ether")
            })
            .then(function(receipt){
                console.log("转完了!")
            });
        }


    </script>
    
</body>
</html>

009 编写智能合约 - 入门

智能合约

    1. Remix IDE

    RemixIDE是开发以太坊智能合约的在线IDE工具,部署简单的智能合约非常方便Remixt址:https://remix.ethereum.org/

  • 2.Truffle

    Truffle是一个世界级的智能合约开发框架,专门为智能合约而生, ·管理智能合约的生命周期 ·自动化合约测试 。可编程,可部署,可发布合约 ·不用过多的关注网络管理 。强大的交互式控制台

目录结构:

  • contracts/:存放solidity智能合约文件
  • migrations/:truffle使用migration system 来控制合约的部署。
  • test/:测试文件存放文字(javascript or solidity)
  • truffle-config.js:配置文件

solidity语言

3-1 数据位置

solidity数据存储位置有三类:storage,memory和calldata。不同存储位置的gas成本不同。storage类型的数据存在链上,类似计算机的硬盘,消耗gas多;memory和caldata类型的临时存在内存里,消耗gas少。大致用法:

  • 1,storage:合约里的状态变量默认都是storage,存储在链上。
  • 2,memory:函数里的参数和临时变量一般用memory,存储在内存中,不上链。
  • 3,caldata:和memory类似,存储在内存中,不上链。与memory的不同点在于calldata变量不能修改(immutable),一般用于函数的参数。

3-2 作用域

变量的作用域:Solidity中变量按作用域划分有三种,分别是状态变量(state variable),局部变量(local variable)和全局变量(global variable)。

  • 1,状态变量:状态变量是数据存储在链上的变量,所有合约内函数都可以访问,gas消耗高。状态变量在合约 内、函数外声明。可以在函数里更改状态变量的值:
  • 2,局部变量:局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。局部变量的数据存储在内存里,不上链,gas低。局部变量在函数内声明。
  • 3,全局变量:全局变量是全局范围工作的变量,都是solidity预留关键字。他们可以在函数内不声明直接使用(类似于msg.sender,block.number)

contract/StudentStorage.sol

javascript
pragma solidity >= 0.4.16 < 0.9.0;

contract StudentStorage {

    // 创建 2个变量,username,age
    string public name;
    uint public age;
    
    function setData(string memory _name, uint _age) public {
        // string memory a; // 局部变量,存储在内存中
        name = _name;
        age = _age;
    }

    // function test(uint x, uint y) public pure returns (uint) {
    //     return x + y;
    // }

    // view (视图函数,只访问不修改状态), pure(纯函数,不访问,也不修改)
    function getData() public view returns (string memory, uint) {
        return (name, age);
    }

}

执行编译

javascript
(base) PS D:\project\idea_work\own\ganache-demo\code> truffle compile

Compiling your contracts...
===========================
✓ Fetching solc version list from solc-bin. Attempt #1
✓ Downloading compiler. Attempt #1.
> Compiling .\contracts\StudentStorage.sol
> Compilation warnings encountered:

    Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> project:/contracts/StudentStorage.sol


> Artifacts written to D:\project\idea_work\own\ganache-demo\code\build\contracts
> Compiled successfully using:
   - solc: 0.8.21+commit.d9974bed.Emscripten.clang
(base) PS D:\project\idea_work\own\ganache-demo\code>

部署img_1.png 执行部署命令(直接执行部署也会执行编译):

truffle migrate img_2.png


测试,进入控制台

img_3.png

img_4.png

3-3 脚本测试

  • mocha测试
  • truffle脚本

010 编写智能合约 - 进阶

contracts/StudentListStorage.sol

solidity
pragma solidity >= 0.4.16 < 0.9.0;

contract StudentListStorage {

   // 结构体
    struct Student {
        uint id;
        string name;
        uint age;
    }

    // 动态数组
    Student[] public StudentList; // 自动gettter()

    // 创建 2个变量,username,age
    string  public name;
    uint public  age;
    
    // struct ,动态数组,映射,string
    function addList(string memory _name, uint _age) public returns (uint) {
        uint count = StudentList.length;
        uint index = count + 1;
        // string memory a; // 局部变量,存储在内存中
        StudentList.push(Student(index, _name, _age));
        return StudentList.length;
    }

    // function test(uint x, uint y) public pure returns (uint) {
    //     return x + y;
    // }

    // view (视图函数,只访问不修改状态), pure(纯函数,不访问,也不修改)
    function getList() public view returns (Student[] memory) {
        Student[] memory list = StudentList;
        return list;
    }


}

部署脚本: migrations/2_deploy.js

solidity
const Contracts = artifacts.require("./StudentListStorage.sol");

module.exports = async function (callback) {
    // console.log("111111");
    // console.log("---------");
    const studentStorage = await Contracts.deployed();


    await studentStorage.addList("hufl", 20);
    let res = await studentStorage.getList();
    console.log(res);

    console.log(await studentStorage.StudentList(2));
    callback();
    
}

测试脚本 scripts/test2.js

solidity

const Contracts = artifacts.require("./StudentListStorage.sol");

module.exports = async function (callback) {
    // console.log("111111");
    // console.log("---------");
    const studentStorage = await Contracts.deployed();


    await studentStorage.addList("hufl", 20);
    let res = await studentStorage.getList();
    console.log(res);

    console.log(await studentStorage.StudentList(2));
    callback();
    
}

执行测试脚本:

truffle exec scripts/test2.js

img_5.png

011 打通Web3.js到智能合约

ABI非常类似于 API(应用程序接口),一种人类可读的代码接口表示。ABI定义了用于与二进制合约交互的方法和结构,就像 API所做的那样,只是在较低的级别上。

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>
    <script src="https://cdn.jsdelivr.net/npm/web3@4.16.0/dist/web3.min.js"></script>
    
</head>
<body>

    <input type="text" id="myname">

    <input type="number" id="myage">

    <button id="add">add</button>

    <ul id="list">

    </ul>

    <script type="module">
        // 连接到以太坊网络
        var web3 = new Web3(Web3.givenProvider || 'http://localhost:7545');
     
        // 先授权
        // let account = await web3.eth.requestAccounts();
        // console.log(account);

        let accounts = await web3.eth.getAccounts();
        console.log(accounts[0]);

        let account = accounts[0];
        
        // 连接智能合约程序
       var studentListStorage =  await new web3.eth.Contract([
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "name": "StudentList",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "id",
          "type": "uint256"
        },
        {
          "internalType": "string",
          "name": "name",
          "type": "string"
        },
        {
          "internalType": "uint256",
          "name": "age",
          "type": "uint256"
        },
        {
          "internalType": "address",
          "name": "account",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "age",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "string",
          "name": "_name",
          "type": "string"
        },
        {
          "internalType": "uint256",
          "name": "_age",
          "type": "uint256"
        }
      ],
      "name": "addList",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "getList",
      "outputs": [
        {
          "components": [
            {
              "internalType": "uint256",
              "name": "id",
              "type": "uint256"
            },
            {
              "internalType": "string",
              "name": "name",
              "type": "string"
            },
            {
              "internalType": "uint256",
              "name": "age",
              "type": "uint256"
            },
            {
              "internalType": "address",
              "name": "account",
              "type": "address"
            }
          ],
          "internalType": "struct StudentListStorage.Student[]",
          "name": "",
          "type": "tuple[]"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    }
  ], "0xb18398aBd2Cd3280175C4227c177B1c4b8790e84"); // 合约地址

  console.log(studentListStorage)

  add.onclick = async function(){
     console.log(myname.value, myage.value)
     await studentListStorage
     .methods
     .addList(myname.value, myage.value)
     .send({
        from: account,
        gas: 300000
     })

     // 添加完后,获取列表
     getList()

     async function getList(){
        let res = await studentListStorage.methods.getList().call();
        console.log(res)

        list.innerHTML = res.map(item => `
           <li>${item.id}---${item.name} ----${item.age}</li> 
        `).join('')
     }
           
  }
       
</script>
    
</body>
</html>

012 加密货币

什么叫做代币? 代币可以在以太坊中表示任何东西

  • 在线平台中的信誉积分
  • 金融资产类似于公司股份的资产
  • 像美元一样的法定货币
  • 盎司黄金
  • 及更多..

ERC-20就是一套基于以太坊网络的标准代币发行协议。有了ERC-20,开发者们得以高效、可靠、低成本地创造专属自己项目的代币;我们甚至可以将ERC-20视为以太坊网络为早期区块链世界做出的最重要贡献.

https://github.com/ethereum/ElPs/blob/master/ElPs/eip-20.md
https://github.com/ethereum/ercs/blob/master/ERCS/erc-20.md

ERC-20 的功能示例包括:

  • 将代币从一个帐户转到另一个帐户
  • 获取帐户的当前代币余额
  • 获取网络上可用代币的总供应量
  • 批准一个帐户中一定的代币金额由第三方帐户使用
 function name() public view returns (string)
 function symbol() public view returns (string)
 function decimals() public view returns (uint8)
 function totalSupply() public view returns (uint256)
 function balanceOf(address _owner) public view returns (uint256 balance)
 function transfer(address _to, uint256 _value) public returns (bool success)
 function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
 function approve(address _spender, uint256 _value) public returns (bool success)
 function allowance(address _owner, address _spender) public view returns (uint256 remaining)
 event Transfer(address indexed _from, address indexed _to, uint256 _value);
 event Approval(address indexed _owner, address indexed _spender, uint256 _value);
javascript
pragma solidity >= 0.4.16 < 0.9.0;

contract HflToken {

    string public name = "HFLToken";


}

img_6.png

013 转账

  • 编写自己的智能合约
solidity
pragma solidity >= 0.4.16 < 0.9.0;


contract HflToken {


    string public name = "HFLToken";

    string public symbol = "HFL";

    uint256 public decimals = 18;

    uint256 public totalSupply;

    // mapping(address => uint256) public balanceOf;
    mapping(address => uint256) public balanceOf;


    constructor() {
        // totalSupply = _initialSupply * 10 ** decimals;
        totalSupply = 1000000 * (10 ** decimals);
        // 部署账号
        balanceOf[msg.sender] = totalSupply;
    }
 
    // 触发 区块链日志 事件监听
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    function transfer(address _to,  uint256 _value) public returns (bool success) {
        require(_to!=address(0));
        // require(balanceOf[msg.sender] >= _value);
        // balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);  // 调用者余额减少
        // balanceOf[_to] = balanceOf[msg.sender].add(_value); // 接收者余额增加   
        _transfer(msg.sender, _to, _value);
        return true;
    }

    function _transfer(address _from, address _to,  uint256 _value) internal {
        require(_to!=address(0));
        require(balanceOf[_from] >= _value);
        // 从哪个账号发起的调用者
        balanceOf[_from] = balanceOf[_from] - _value;  // 调用者余额减少
        balanceOf[_to] = balanceOf[_to] + _value; // 接收者余额增加   

        // 触发事件
        emit Transfer(_from, _to, _value);
    }   





}

部署文件

js
const Contracts  = artifacts.require("HflToken.sol");

module.exports = function (deployer) {
   deployer.deploy(Contracts);
}

测试脚本

js

const Contracts = artifacts.require("./HflToken.sol");

const fromWei = (bn) => web3.utils.fromWei(bn, 'ether');

const toWei = (num) => web3.utils.toWei(num.toString(), 'ether');

module.exports = async function (callback) {

    const HflToken = await Contracts.deployed();
    // 测试第一个账号的余额
    let res1 = await HflToken.balanceOf("0x5bD9E71C4fe650e33F470CBdC4E0ecD76eE8Fb8B");
    console.log("第一个账号:", fromWei(res1));

    let res11 = await HflToken.balanceOf("0x74d2F3d35F4981ffd219725E601dF893D554057e");
    console.log("第二个账号:", fromWei(res11));

    console.log("---------转账开始---------");

    await HflToken.transfer("0x74d2F3d35F4981ffd219725E601dF893D554057e", toWei(10000), {
        from: "0x5bD9E71C4fe650e33F470CBdC4E0ecD76eE8Fb8B"
    });

    console.log("---------转账结束---------");

    let res2 = await HflToken.balanceOf("0x5bD9E71C4fe650e33F470CBdC4E0ecD76eE8Fb8B");
    console.log("第一个账号:", fromWei(res2));

    let res3 = await HflToken.balanceOf("0x74d2F3d35F4981ffd219725E601dF893D554057e");
    console.log("第二个账号:", fromWei(res3));

    // 测试第二个账号的余额
    callback();
    
}

命令行部署

truffle migrate --reset

命令行执行测试脚本

truffle exec ./scripts/transfer.js

查看效果: img_7.png

014 委托转账

核心方法: transferFrom方法

solidity
pragma solidity >= 0.4.16 < 0.9.0;


contract HflToken {


    string public name = "HFLToken";

    string public symbol = "HFL";

    uint256 public decimals = 18;
 
    uint256 public totalSupply;

    // mapping(address => uint256) public balanceOf;
    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance; //定量定额

    constructor() {
        // totalSupply = _initialSupply * 10 ** decimals;
        totalSupply = 1000000 * (10 ** decimals);
        // 部署账号
        balanceOf[msg.sender] = totalSupply;
    }
 
    // 触发 区块链日志 事件监听
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    function transfer(address _to,  uint256 _value) public returns (bool success) {
        require(_to!=address(0));
        // require(balanceOf[msg.sender] >= _value);
        // balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);  // 调用者余额减少
        // balanceOf[_to] = balanceOf[msg.sender].add(_value); // 接收者余额增加   
        _transfer(msg.sender, _to, _value);
        return true;
    }

    function _transfer(address _from, address _to,  uint256 _value) internal {
        require(_to!=address(0));
        require(balanceOf[_from] >= _value);
        // 从哪个账号发起的调用者
        balanceOf[_from] = balanceOf[_from] - _value;  // 调用者余额减少
        balanceOf[_to] = balanceOf[_to] + _value; // 接收者余额增加   

        // 触发事件
        emit Transfer(_from, _to, _value);
    }   


    function approve(address _spender, uint256 _value) public returns (bool success) {
        // msg.sender 当前网页登陆的账号
        // _spender 授权的账号 第三方的交易所的账号地址
        // _value 授权的金额
        require(_spender != address(0));
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        // // return true;
        // _approve(msg.sender, _spender, _value);
        return true;
    }

    function _approve(address _owner, address _spender, uint256 _value) internal {
        allowance[_owner][_spender] = _value;
    }


   // 被授权的交易所调用
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
       // _from 某个放款账号
       // _to 接收账号
       // msg.sender 交易所账户 地址       
        require(balanceOf[_from]  >= _value);
        require(allowance[_from][msg.sender]>=_value);
        // allowance[_from][msg.sender] = allowance[_from][msg.sender] - _value;
        _approve(_from, msg.sender, allowance[_from][msg.sender] - _value);
        _transfer(_from, _to, _value);
        return true;
    }
}

015 交易所-存款

migrations/3_deploy.js

javascript

const Contracts  = artifacts.require("HflToken.sol");
const Exchange  = artifacts.require("Exchange.sol");

module.exports = async function (deployer) {

   const accounts = await web3.eth.getAccounts();
   const deployerAddress = accounts[0];
   
   await deployer.deploy(Contracts);
   await deployer.deploy(Exchange, deployerAddress, 10);
}

scripts/test-deposit.js

javascript

const HflToken = artifacts.require("./HflToken.sol");
const Exchange = artifacts.require("./Exchange.sol");

const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';


const fromWei = (bn) => web3.utils.fromWei(bn, 'ether');

const toWei = (num) => web3.utils.toWei(num.toString(), 'ether');

module.exports = async function (callback) {

    const hflToken = await HflToken.deployed();
    const exchange = await Exchange.deployed();
    const accounts = await web3.eth.getAccounts();


    // 往合约上存以太币
    // await exchange.depositEther({
    //     from: accounts[0], 
    //     value: toWei(10)}
    // );

    // let res = await exchange.tokens(ETHER_ADDRESS, accounts[0]);
    // console.log(fromWei(res));

    // 往合约上存代币
    // 授权
    // await hflToken.approve(exchange.address, toWei(100000), {
    //     from: accounts[0]
    // });
    
    // await exchange.depositToken(hflToken.address, toWei(100000), {
    //     from: accounts[0]
    // });

    let res = await exchange.tokens(hflToken.address, accounts[0]);
    console.log(fromWei(res));

    // 1. 查询交易所合约的ETH余额
    const ethBalanceWei = await web3.eth.getBalance(exchange.address);
    console.log("\n1. 交易所合约的ETH余额:", web3.utils.fromWei(ethBalanceWei, 'ether'), "ETH");

    // 2. 查询交易所合约持有的HFLToken总额 (通过查询代币合约)
    const exchangeHflBalanceWei = await hflToken.balanceOf(exchange.address);
    console.log("2. 交易所合约持有的HFL总额:", web3.utils.fromWei(exchangeHflBalanceWei, 'ether'), "HFL");

    callback();
    
}

016 交易所-取款

contracts/Exchange.sol 新增: withdrawEther(),withdrawToken()方法,event WithDraw()事件

solidity
pragma solidity >=0.4.16 <0.9.0;

import "./HflToken.sol";

contract Exchange {
    // 收费账户地址
    address public feeAccount;
    // 费率百分比
    uint256 public feePercent;

    // 存储以太坊地址
    address constant ETHER = address(0);

    // 存储用户地址和代币地址
    mapping(address => mapping(address => uint256)) public tokens;

    // 构造函数
    constructor(address _feeAccount, uint256 _feePercent) {
        feeAccount = _feeAccount;
        feePercent = _feePercent;
    }

    // 存以太币
    function depositEther() public payable {
        // msg.sender
        // msg.value
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] + msg.value;
        emit Deposit(ETHER, msg.sender, msg.value, tokens[ETHER][msg.sender]);
    }

    event Deposit(address token, address user, uint256 amount, uint256 balance);

    event WithDraw(address token, address user, uint256 amount, uint256 balance);

    // 存其他货币
    function depositToken(address _token, uint256 _amount) public {
        require(_token!=ETHER);
        // 调用某个方法强行从你账户往当前交易所账户转钱
        require(HflToken(_token).transferFrom(msg.sender, address(this), _amount));
        tokens[_token][msg.sender] = tokens[_token][msg.sender] + _amount;
        emit Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 提取以太币
    function withdrawEther(uint256 _amount) public {
        require(tokens[ETHER][msg.sender] >= _amount);
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
         payable(msg.sender).transfer(_amount);

        emit WithDraw(ETHER, msg.sender, _amount, tokens[ETHER][msg.sender]);
    }

    // 提取其他货币
    function withdrawToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        require(tokens[_token][msg.sender] >= _amount);

        tokens[_token][msg.sender] = tokens[_token][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        require(HflToken(_token).transfer(msg.sender, _amount));
        emit WithDraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    function balanceOf(
        address tokenAddress,
        address user
    ) public view returns (uint256) {
        // TODO
    }
}

scripts/test-withdraw.js

solidity

const HflToken = artifacts.require("./HflToken.sol");
const Exchange = artifacts.require("./Exchange.sol");

const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';


const fromWei = (bn) => web3.utils.fromWei(bn, 'ether');

const toWei = (num) => web3.utils.toWei(num.toString(), 'ether');

module.exports = async function (callback) {

    const hflToken = await HflToken.deployed();
    const exchange = await Exchange.deployed();
    const accounts = await web3.eth.getAccounts();

    // 测试取款以太币
    // await exchange.withdrawEther(toWei(5), {
    //     from: accounts[0]
    // });

    // let res1 = await exchange.tokens(ETHER_ADDRESS, accounts[0]);
    // console.log(fromWei(res1));

   // 测试取其他代币
    await exchange.withdrawToken(hflToken.address,toWei(50000), {
        from: accounts[0]
    });

     let res2 = await exchange.tokens(hflToken.address, accounts[0]);
    console.log(fromWei(res2));

    // // 1. 查询交易所合约的ETH余额
    // const ethBalanceWei = await web3.eth.getBalance(exchange.address);
    // console.log("\n1. 交易所合约的ETH余额:", web3.utils.fromWei(ethBalanceWei, 'ether'), "ETH");

    // // 2. 查询交易所合约持有的HFLToken总额 (通过查询代币合约)
    // const exchangeHflBalanceWei = await hflToken.balanceOf(exchange.address);
    // console.log("2. 交易所合约持有的HFL总额:", web3.utils.fromWei(exchangeHflBalanceWei, 'ether'), "HFL");

    callback();
    
}

017 交易所-流动池

https://github.com/hufanglei/web3-DApp/commit/fe584c72604ccca929377d07995cc01d298feee9

pragma solidity >=0.4.16 <0.9.0;

import "./HflToken.sol";

contract Exchange {
    // 收费账户地址
    address public feeAccount;
    // 费率百分比
    uint256 public feePercent;

    // 存储以太坊地址
    address constant ETHER = address(0);

    // 存储用户地址和代币地址
    mapping(address => mapping(address => uint256)) public tokens;

    // 订单结构体
    struct _Order {
        uint256 id;
        address user;
        address tokenGet;
        uint256 amountGet;

        address tokenGive;
        uint256 amountGive;

        uint256 timestamp;
    }

    // _Order[] public orderlist;

    mapping(uint256 => _Order) public orders;
    uint256 public orderCount;

    // 构造函数
    constructor(address _feeAccount, uint256 _feePercent) {
        feeAccount = _feeAccount;
        feePercent = _feePercent;
    }

    // 存以太币
    function depositEther() public payable {
        // msg.sender
        // msg.value
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] + msg.value;
        emit Deposit(ETHER, msg.sender, msg.value, tokens[ETHER][msg.sender]);
    }

    event Deposit(address token, address user, uint256 amount, uint256 balance);

    event WithDraw(
        address token,
        address user,
        uint256 amount,
        uint256 balance
    );

    event Order(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );


    // 存其他货币
    function depositToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        // 调用某个方法强行从你账户往当前交易所账户转钱
        require(
            HflToken(_token).transferFrom(msg.sender, address(this), _amount)
        );
        tokens[_token][msg.sender] = tokens[_token][msg.sender] + _amount;
        emit Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 提取以太币
    function withdrawEther(uint256 _amount) public {
        require(tokens[ETHER][msg.sender] >= _amount);
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        payable(msg.sender).transfer(_amount);

        emit WithDraw(ETHER, msg.sender, _amount, tokens[ETHER][msg.sender]);
    }

    // 提取其他货币
    function withdrawToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        require(tokens[_token][msg.sender] >= _amount);

        tokens[_token][msg.sender] = tokens[_token][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        require(HflToken(_token).transfer(msg.sender, _amount));
        emit WithDraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 查余额
    function balanceOf(
        address _token,
        address _user
    ) public view returns (uint256) {
        return tokens[_token][_user];
    }

    // makeOrder
    function makeOrder(address _tokenGet,
        uint256 _amountGet,
        address _tokenGive,
        uint256 _amountGive) public {
        orderCount = orderCount + 1;
        orders[orderCount] = _Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);

        // 发出订单
        emit Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);
    }

    // cancelOrder

    // fillOrder
}

018 交易所-取消订单

https://github.com/hufanglei/web3-DApp/commit/e10f379649da7e80a220d8236051fd71a60076f3 Exchange.sol

solidity
pragma solidity >=0.4.16 <0.9.0;

import "./HflToken.sol";

contract Exchange {
    // 收费账户地址
    address public feeAccount;
    // 费率百分比
    uint256 public feePercent;

    // 存储以太坊地址
    address constant ETHER = address(0);

    // 存储用户地址和代币地址
    mapping(address => mapping(address => uint256)) public tokens;


    // 订单结构体
    struct _Order {
        uint256 id;
        address user;
        address tokenGet;
        uint256 amountGet;

        address tokenGive;
        uint256 amountGive;

        uint256 timestamp;
    }

    // _Order[] public orderlist;

    mapping(uint256 => _Order) public orders;

    mapping(uint256 => bool) public orderCancel;

    uint256 public orderCount;

    // 构造函数
    constructor(address _feeAccount, uint256 _feePercent) {
        feeAccount = _feeAccount;
        feePercent = _feePercent;
    }

    // 存以太币
    function depositEther() public payable {
        // msg.sender
        // msg.value
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] + msg.value;
        emit Deposit(ETHER, msg.sender, msg.value, tokens[ETHER][msg.sender]);
    }

    event Deposit(address token, address user, uint256 amount, uint256 balance);

    event WithDraw(
        address token,
        address user,
        uint256 amount,
        uint256 balance
    );

    // 创建订单事件
    event Order(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );

    // 取消订单事件
    event Cancel(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );


    // 存其他货币
    function depositToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        // 调用某个方法强行从你账户往当前交易所账户转钱
        require(
            HflToken(_token).transferFrom(msg.sender, address(this), _amount)
        );
        tokens[_token][msg.sender] = tokens[_token][msg.sender] + _amount;
        emit Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 提取以太币
    function withdrawEther(uint256 _amount) public {
        require(tokens[ETHER][msg.sender] >= _amount);
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        payable(msg.sender).transfer(_amount);

        emit WithDraw(ETHER, msg.sender, _amount, tokens[ETHER][msg.sender]);
    }

    // 提取其他货币
    function withdrawToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        require(tokens[_token][msg.sender] >= _amount);

        tokens[_token][msg.sender] = tokens[_token][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        require(HflToken(_token).transfer(msg.sender, _amount));
        emit WithDraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 查余额
    function balanceOf(
        address _token,
        address _user
    ) public view returns (uint256) {
        return tokens[_token][_user];
    }

    // makeOrder
    function makeOrder(address _tokenGet,
        uint256 _amountGet,
        address _tokenGive,
        uint256 _amountGive) public {
        orderCount = orderCount + 1;
        orders[orderCount] = _Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);

        // 发出订单
        emit Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);
    }

    // cancelOrder
    function cancelOrder(uint256 _id) public {
        _Order memory myorder = orders[_id];
        require(myorder.id == _id);
        orderCancel[_id] = true;

        emit Cancel(myorder.id, msg.sender, myorder.tokenGet, myorder.amountGet, myorder.tokenGive, myorder.amountGive, block.timestamp);
    }

    // fillOrder
}

019 交易所-完成交易

https://github.com/hufanglei/web3-DApp/commit/75bcf3a18513bffe45eb2a513bc230ae80a3117a Exchange.sol

solidity
pragma solidity >=0.4.16 <0.9.0;

import "./HflToken.sol";

contract Exchange {
    // 收费账户地址
    address public feeAccount;
    // 费率百分比
    uint256 public feePercent;

    // 存储以太坊地址
    address constant ETHER = address(0);

    // 存储用户地址和代币地址
    mapping(address => mapping(address => uint256)) public tokens;


    // 订单结构体
    struct _Order {
        uint256 id;
        address user;
        address tokenGet;
        uint256 amountGet;

        address tokenGive;
        uint256 amountGive;

        uint256 timestamp;
    }

    // _Order[] public orderlist;

    mapping(uint256 => _Order) public orders;

    mapping(uint256 => bool) public orderCancel;

    mapping(uint256 => bool) public orderFill;

    uint256 public orderCount;

    // 构造函数
    constructor(address _feeAccount, uint256 _feePercent) {
        feeAccount = _feeAccount;
        feePercent = _feePercent;
    }

    // 存以太币
    function depositEther() public payable {
        // msg.sender
        // msg.value
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] + msg.value;
        emit Deposit(ETHER, msg.sender, msg.value, tokens[ETHER][msg.sender]);
    }

    event Deposit(address token, address user, uint256 amount, uint256 balance);

    event WithDraw(
        address token,
        address user,
        uint256 amount,
        uint256 balance
    );

    // 创建订单事件
    event Order(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );

    // 取消订单事件
    event Cancel(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );

   // 填充订单事件
    event Trade(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );

    // 存其他货币
    function depositToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        // 调用某个方法强行从你账户往当前交易所账户转钱
        require(
            HflToken(_token).transferFrom(msg.sender, address(this), _amount)
        );
        tokens[_token][msg.sender] = tokens[_token][msg.sender] + _amount;
        emit Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 提取以太币
    function withdrawEther(uint256 _amount) public {
        require(tokens[ETHER][msg.sender] >= _amount);
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        payable(msg.sender).transfer(_amount);

        emit WithDraw(ETHER, msg.sender, _amount, tokens[ETHER][msg.sender]);
    }

    // 提取其他货币
    function withdrawToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        require(tokens[_token][msg.sender] >= _amount);

        tokens[_token][msg.sender] = tokens[_token][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        require(HflToken(_token).transfer(msg.sender, _amount));
        emit WithDraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 查余额
    function balanceOf(
        address _token,
        address _user
    ) public view returns (uint256) {
        return tokens[_token][_user];
    }

    // makeOrder
    function makeOrder(address _tokenGet,
        uint256 _amountGet,
        address _tokenGive,
        uint256 _amountGive) public {
        orderCount = orderCount + 1;
        orders[orderCount] = _Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);

        // 发出订单
        emit Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);
    }

    // cancelOrder
    function cancelOrder(uint256 _id) public {
        _Order memory myorder = orders[_id];
        require(myorder.id == _id);
        orderCancel[_id] = true;

        emit Cancel(myorder.id, msg.sender, myorder.tokenGet, myorder.amountGet, myorder.tokenGive, myorder.amountGive, block.timestamp);
    }

    // fillOrder
    function fillOrder(uint256 _id) public {
        _Order memory myorder = orders[_id];
        require(myorder.id == _id);
        orderFill[_id] = true;

        // 账户余额 互换 && 小费收取
        /**
        xiaoming ,makeorder,
        100 KWT ==> 1 ether
        
        xiaoming ,少了1 ether
        xiaoming 多了100KWT

        -------------------------------

        msg.sender,  fillorder
        msg.sender,多了1 ether
        msg.sender 少了 100KWT
        */
   

        // require(_id > 0 && _id <= orderCount);
        // require(!orderCancel[_id]);

        // _Order memory myorder = orders[_id];
        // uint256 _feeAmount = ((myorder.amountGet * feePercent) / 100);

        uint256 feeAmount = myorder.amountGet * feePercent / 100;

        // tokens
        tokens[myorder.tokenGet][msg.sender] = tokens[myorder.tokenGet][msg.sender] - myorder.amountGet + feeAmount;
       
        tokens[myorder.tokenGet][feeAccount] = tokens[myorder.tokenGet][feeAccount] + feeAmount;

        tokens[myorder.tokenGet][myorder.user] = tokens[myorder.tokenGet][myorder.user] + myorder.amountGet;

        // 以太币
        tokens[myorder.tokenGive][msg.sender] = tokens[myorder.tokenGive][msg.sender] + myorder.amountGive;
        tokens[myorder.tokenGive][myorder.user] = tokens[myorder.tokenGive][myorder.user] - myorder.amountGive;

        emit Trade(myorder.id, myorder.user, myorder.tokenGet, myorder.amountGet, myorder.tokenGive, myorder.amountGive, block.timestamp);

    }

}

020 测试订单

https://github.com/hufanglei/web3-DApp/commit/3358fd98daa300656270db04f1901dea4b906a57

Exchange.sol

solidity
pragma solidity >=0.4.16 <0.9.0;

import "./HflToken.sol";

contract Exchange {
    // 收费账户地址
    address public feeAccount;
    // 费率百分比
    uint256 public feePercent;

    // 存储以太坊地址
    address constant ETHER = address(0);

    // 存储用户地址和代币地址
    mapping(address => mapping(address => uint256)) public tokens;


    // 订单结构体
    struct _Order {
        uint256 id;
        address user;
        address tokenGet;
        uint256 amountGet;

        address tokenGive;
        uint256 amountGive;

        uint256 timestamp;
    }

    // _Order[] public orderlist;

    mapping(uint256 => _Order) public orders;

    mapping(uint256 => bool) public orderCancel;

    mapping(uint256 => bool) public orderFill;

    uint256 public orderCount;

    // 构造函数
    constructor(address _feeAccount, uint256 _feePercent) {
        feeAccount = _feeAccount;
        feePercent = _feePercent;
    }

    // 存以太币
    function depositEther() public payable {
        // msg.sender
        // msg.value
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] + msg.value;
        emit Deposit(ETHER, msg.sender, msg.value, tokens[ETHER][msg.sender]);
    }

    event Deposit(address token, address user, uint256 amount, uint256 balance);

    event WithDraw(
        address token,
        address user,
        uint256 amount,
        uint256 balance
    );

    // 创建订单事件
    event Order(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );

    // 取消订单事件
    event Cancel(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );

   // 填充订单事件
    event Trade(
        uint256 id,
        address user,
        address tokenGet,
        uint256 amountGet,
        address tokenGive,
        uint256 amountGive,
        uint256 timestamp
    );

    // 存其他货币
    function depositToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        // 调用某个方法强行从你账户往当前交易所账户转钱
        require(
            HflToken(_token).transferFrom(msg.sender, address(this), _amount)
        );
        tokens[_token][msg.sender] = tokens[_token][msg.sender] + _amount;
        emit Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 提取以太币
    function withdrawEther(uint256 _amount) public {
        require(tokens[ETHER][msg.sender] >= _amount);
        tokens[ETHER][msg.sender] = tokens[ETHER][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        payable(msg.sender).transfer(_amount);

        emit WithDraw(ETHER, msg.sender, _amount, tokens[ETHER][msg.sender]);
    }

    // 提取其他货币
    function withdrawToken(address _token, uint256 _amount) public {
        require(_token != ETHER);
        require(tokens[_token][msg.sender] >= _amount);

        tokens[_token][msg.sender] = tokens[_token][msg.sender] - _amount;
        // 从当前合约地址往用户地址转账
        require(HflToken(_token).transfer(msg.sender, _amount));
        emit WithDraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
    }

    // 查余额
    function balanceOf(
        address _token,
        address _user
    ) public view returns (uint256) {
        return tokens[_token][_user];
    }

    // makeOrder
    function makeOrder(address _tokenGet,
        uint256 _amountGet,
        address _tokenGive,
        uint256 _amountGive) public {

        require(balanceOf(_tokenGive, msg.sender) >= _amountGive, unicode"创建订单时余额不足");    

        orderCount = orderCount + 1;
        orders[orderCount] = _Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);

        // 发出订单
        emit Order(orderCount, msg.sender, _tokenGet, _amountGet, _tokenGive, _amountGive, block.timestamp);
    }

    // cancelOrder
    function cancelOrder(uint256 _id) public {
        _Order memory myorder = orders[_id];
        require(myorder.id == _id);
        orderCancel[_id] = true;

        emit Cancel(myorder.id, msg.sender, myorder.tokenGet, myorder.amountGet, myorder.tokenGive, myorder.amountGive, block.timestamp);
    }

    // fillOrder
    function fillOrder(uint256 _id) public {
        _Order memory myorder = orders[_id];
        require(myorder.id == _id);

        // 账户余额 互换 && 小费收取
        /**
        xiaoming ,makeorder,
        100 KWT ==> 1 ether
        
        xiaoming ,少了1 ether
        xiaoming 多了100KWT

        -------------------------------

        msg.sender,  fillorder
        msg.sender,多了1 ether
        msg.sender 少了 100KWT
        */
   

        // require(_id > 0 && _id <= orderCount);
        // require(!orderCancel[_id]);

        // _Order memory myorder = orders[_id];
        // uint256 _feeAmount = ((myorder.amountGet * feePercent) / 100);

        uint256 feeAmount = myorder.amountGet * feePercent / 100;

        require(balanceOf(myorder.tokenGive, myorder.user) >= myorder.amountGive, unicode"创建订单的用户的余额不足");    
        require(balanceOf(myorder.tokenGet, myorder.user) >= myorder.amountGive + feeAmount, unicode"填充订单的用户的余额不足");    


        // tokens
        tokens[myorder.tokenGet][msg.sender] = tokens[myorder.tokenGet][msg.sender] - myorder.amountGet - feeAmount;
       
        tokens[myorder.tokenGet][feeAccount] = tokens[myorder.tokenGet][feeAccount] + feeAmount;

        tokens[myorder.tokenGet][myorder.user] = tokens[myorder.tokenGet][myorder.user] + myorder.amountGet;

        // 以太币
        tokens[myorder.tokenGive][msg.sender] = tokens[myorder.tokenGive][msg.sender] + myorder.amountGive;
        tokens[myorder.tokenGive][myorder.user] = tokens[myorder.tokenGive][myorder.user] - myorder.amountGive;

        orderFill[_id] = true;

        emit Trade(myorder.id, myorder.user, myorder.tokenGet, myorder.amountGet, myorder.tokenGive, myorder.amountGive, block.timestamp);

    }




}

scripts/test-order.js

js

const HflToken = artifacts.require("./HflToken.sol");
const Exchange = artifacts.require("./Exchange.sol");

const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';


const fromWei = (bn) => web3.utils.fromWei(bn, 'ether');

const toWei = (num) => web3.utils.toWei(num.toString(), 'ether');

const wait = (seconds) => {
    const milliseconds = seconds * 1000;
    return new Promise(resolve => setTimeout(resolve, milliseconds));
}

module.exports = async function (callback) {

   try {
        const hflToken = await HflToken.deployed();
        const exchange = await Exchange.deployed();
        const accounts = await web3.eth.getAccounts();


        // 第一步 account0 ---> account1 10W
        await hflToken.transfer(accounts[1],toWei(100000), {
            from: accounts[0]
        });

        // 第二步 account0 ---> 交易所存入 10以太币
        await exchange.depositEther({
            from: accounts[0],
            value: toWei(10)
        });

        let res1 = await exchange.tokens(ETHER_ADDRESS, accounts[0]);
        // console.log("account[0]-在交易所的以太币", fromWei(res1));

        // 第二步 account0 ---> 交易所存入 10000 HFL
        await hflToken.approve(exchange.address, toWei(100000), {
            from: accounts[0]
        });

        await exchange.depositToken(hflToken.address, toWei(100000), {
            from: accounts[0]
        });

        let res2 = await exchange.tokens(hflToken.address, accounts[0]);
        // console.log("account[0]-在交易所的HFL币", fromWei(res2));

        // 第三步 account1 ---> 交易所存入 5以太币
        await exchange.depositEther({
            from: accounts[1],
            value: toWei(5)
        });

        let res3 = await exchange.tokens(ETHER_ADDRESS, accounts[1]);
        // console.log("account[1]-在交易所的以太币", fromWei(res3));

        // 第三步 account1 ---> 交易所存入 5000 HFL
        await hflToken.approve(exchange.address, toWei(50000), {
            from: accounts[1]
        });

        await exchange.depositToken(hflToken.address, toWei(50000), {
            from: accounts[1]
        });

        let res4 = await exchange.tokens(hflToken.address, accounts[1]);
        console.log("account[1]-在交易所的HFL币", fromWei(res4));

        let orderId = 0;
        let res;

        // 创建订单
        res = await exchange.makeOrder(hflToken.address, toWei(1000), ETHER_ADDRESS, toWei(0.1), {
            from: accounts[0]
        });
        // console.log("res",res);
        orderId = res.logs[0].args.id;
        console.log("创建一个订单,订单id为"+orderId);

        await wait(1);

        // 取消订单
        res = await exchange.makeOrder(hflToken.address, toWei(2000), ETHER_ADDRESS, toWei(0.2), {
            from: accounts[0]
        });
        // console.log("res",res);
        orderId = res.logs[0].args.id;

        await exchange.cancelOrder(orderId, {
            from: accounts[0]
        });
        console.log("取消一个订单,订单id为"+orderId);
        await wait(1);

        // 完成订单
        res = await exchange.makeOrder(hflToken.address, toWei(3000), ETHER_ADDRESS, toWei(0.3), {
            from: accounts[0]
        });

        orderId = res.logs[0].args.id;

        await exchange.fillOrder(orderId, {
            from: accounts[1]
        });
        console.log("完成一个订单,订单id为"+orderId);

        console.log("account[0]-在交易所的HFL币", fromWei(
            await exchange.tokens(hflToken.address, accounts[0])
        ));

        console.log("account[0]-在交易所的以太币", fromWei(
            await exchange.tokens(ETHER_ADDRESS, accounts[0])
        ));

        console.log("account[1]-在交易所的HFL币", fromWei(
            await exchange.tokens(hflToken.address, accounts[1])
        ));

        console.log("account[1]-在交易所的以太币", fromWei(
            await exchange.tokens(ETHER_ADDRESS, accounts[1])
        ));

         console.log("account[2]-在交易所的HFL币", fromWei(
            await exchange.tokens(hflToken.address, accounts[2])
        ));

   
   }catch(error){
       console.log(error) 
   }

    callback();
    
}

运行命令

  • 部署和编译 truffle migrate --reset
  • 测试 truffle exec .\scripts\test-order.js

运行结果: img_8.png

021 架构整合

https://github.com/hufanglei/hflContracts/commit/b83ef5a675eaf75428a8c823bb07244da13d74a7

022 React合约连接

https://github.com/hufanglei/hflContracts/commit/518d10ceb492552207dcba3b43d946e535f76a42https://github.com/hufanglei/hflContracts/commit/7067881169671f8d60683c17ce0a6463e9725940

023 资产信息

npm i --save redux react-redux

npm i --save @reduxjs/toolkit

024 React - Balance组件

025 React - antd引入

npm i antd --save

https://github.com/hufanglei/hflContracts/commit/929427f1a8073d7f82ad54b16f7e3719ada1ff94

026 React - Order组件

027 React - Order组件

img_9.pnghttps://github.com/hufanglei/hflContracts/commit/4d551e8e4899709bf1ab68d1df63989f8f77dacb

028 React - Order组件渲染

https://github.com/hufanglei/hflContracts/commit/302b894b1cf3bcb258a6ff255853f95dbc78f133img_10.png 操作步骤:

  • 运行ganache -d
  • 将账号1,2,3加入到metaMask钱包中
  • 运行truffle migrate --reset
  • metaMask钱包切换到第一个账户
  • 运行truffle exec .\scripts\test-order.js
  • 运行npm start
  • 点击 取消按钮,执行 取消订单
  • 点击 完成按钮,执行 完成订单

028 React - 事件订阅

  • 运行truffle exec .\scripts\test-order2.js

基于 MIT 许可发布