1. 开发工具:
    truffle
    vue
    metamask

  2. 目录结构:

    demo
    ├── contracts
    │   ├── Demo.sol
    │   ├── Lib.sol
    │   └── Migrations.sol
    ├── migrations
    │   ├── 1_initial_migration.js
    │   └── 2_demo.js
    ├── package.json
    ├── public
    │   ├── favicon.ico
    │   └── index.html
    ├── src
    │   ├── App.vue
    │   ├── components
    │   │   └── Demo.vue
    │   └── main.js
    ├── test
    │   └── Demo.js
    └── truffle-config.js
  3. 环境搭建:

    1. 安装vue-cli
      npm install -g @vue/cli
    2. 创建项目:
      vue create demo
    3. 进入项目根目录:
      cd demo
    4. 安装truffle-contractweb3
      npm install truffle-contract web3
  4. truffle智能合约配置:

    1. 初始化项目:
      truffle init
    2. 修改配置文件:
      vim truffle-config.js
       // const HDWalletProvider = require('truffle-hdwallet-provider');
       // const mnemonic = 'relief submit stairs blossom blossom brush sheriff aisle dice swing number lyrics';
       module.exports = {
         networks: {
           // rinkeby: {
           //   provider: new HDWalletProvider(mnemonic, 'https://rinkeby.infura.io/v3/ca8b6a8c5394446db1ee24ba523cbffe'),
           //   network_id: '4'
           // },
           develop: {
             host: "127.0.0.1",
             port: 8545,
             network_id: 20,
             accounts: 5,
             defaultEtherBalance: 500,
             // blockTime: 3,
             gas: 4712388,
             gasPrice: 100000000000,
             // from: "0xef6a214542A5371F321a3e457EeC76DA2b4b3C34"
           }
         },
         compilers: {
           solc: {
             version: "0.8.0"
           }
         }
       };
    3. 开启测试网络:
      truffle develop --log
    4. 设置metamasktruffle develop网络(略)
    5. 安装 @openzeppelin/contracts
      npm install @openzeppelin/contracts
    6. 安装 truffle-hdwallet-provider(可选):
      npm install truffle-hdwallet-provider
    7. 创建solidity文件:
      1. 创建合约文件:
        vim contracts/Demo.sol
         // SPDX-License-Identifier: GPL-3.0
         import "./Lib.sol";
         import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
         pragma solidity ^0.8.0;
         contract Demo is ERC20 {
             event PrintNum(uint _num,uint _add);
             event DoTransfer(address _to,uint _amount);
             uint num;
             constructor() public ERC20('WETH', 'WETH') {
                 num = 1;
             }
             // eth-to-weth
             receive() external payable {
                 require(msg.value > 0);
                 _mint(msg.sender, msg.value);
             }
             // weth-to-eth
             function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                 if (recipient == address(this)) {
                     _burn(msg.sender, amount);
                     payable(msg.sender).transfer(amount);
                 } else {
                     _transfer(_msgSender(), recipient, amount);
                 }
                 return true;
             }
             function get() public view returns (uint) {
                 return num;
             }
             function add(uint _add) public {
                 emit PrintNum(num,_add);
                 num = Lib.add(num,_add);
             }
             function getBalance(address addr) public view returns (uint) {
                 return addr.balance;
             }
             function doTransfer(address payable _to) public payable{
                 _to.transfer(msg.value);
                 emit DoTransfer(_to,msg.value);
             }
         }
      2. 创建库文件:
        vim contracts/Lib.sol
         // SPDX-License-Identifier: GPL-3.0
         pragma solidity ^0.8.0;
         library Lib{
             function add(uint a,uint b) public pure returns(uint){
                 return a + b;
             }
         }
    8. 创建测试脚本:
      vim test/Demo.js
       const Demo = artifacts.require('./Demo.sol');
       contract('Demo', (accounts) => {
           it('get', async () => {
               const demo = await Demo.deployed()
               const num = await demo.get()
               console.log('num is:')
               console.log(num.toNumber())
               assert.equal(num, 1)
           })
           it('add', async () => {
               const demo = await Demo.deployed()
               await demo.add(2);
               const num = await demo.get()
               assert.equal(num, 3)
           })
           it('do transfer', async () => {
               const demo = await Demo.deployed()
               await demo.doTransfer('0xef6a214542A5371F321a3e457EeC76DA2b4b3C34', {value: 10 ** 18})
           })
           it('get balance', async () => {
               const demo = await Demo.deployed()
               const balance = await demo.getBalance('0xef6a214542A5371F321a3e457EeC76DA2b4b3C34')
               console.log('balance is:')
               console.log(balance.toString())
           })
           it('get weth balance', async () => {
               const demo = await Demo.deployed()
               const balance = await demo.balanceOf('0xef6a214542A5371F321a3e457EeC76DA2b4b3C34')
               console.log('weth balance is:')
               console.log(balance.toString())
           })
       });
    9. 测试合约:
      truffle test --show-events --network develop test/Demo.js
    10. 编译:
      truffle compile --network develop
    11. 创建部署脚本:
      vim migrations/2_demo.js
      var Demo = artifacts.require("./Demo.sol");
      var Lib = artifacts.require("./Lib.sol");
      module.exports = function(deployer) {
          deployer.deploy(Lib,{overwrite: false});
          deployer.link(Lib,Demo);
          deployer.deploy(Demo);
      };
    12. 部署合约:
      truffle migrate --reset --network develop
    13. 查看部署成功的合约地址:
      truffle networks
    14. 控制台console用法:
      1. 进入控制台:
        truffle console --network develop
      2. 实例化合约:
        let instance = await Demo.deployed()
      3. 调用合约方法:
         let num = await instance.get()
         console.log(num.toNumber())
         await instance.add(2)
         num = await instance.get()
         console.log(num.toNumber())
         await instance.doTransfer('0xef6a214542A5371F321a3e457EeC76DA2b4b3C34',{value: 10**18})
         let balance = await instance.getBalance('0xef6a214542A5371F321a3e457EeC76DA2b4b3C34')
         console.log(balance.toString())
      4. 退出控制台:
        .exit
    15. 使用区块链浏览器浏览本地区块数据(略):
      ethscan-私有链浏览器
  5. vue前端页面编写:

    1. App.vue
      vim src/App.vue
       <template>
         <div id="app">
           <Demo/>
         </div>
       </template>
       <script>
       import Demo from './components/Demo.vue';
       export default {
         name: 'app',
         components: {
           Demo
         }
       }
       </script>
    2. Demo.vue(重点):
      vim src/components/Demo.vue
       <template>
         <ul>
           <li>---</li>
           <li>current num: <input :value="currentNum" disabled></li>
           <li>---</li>
           <li><input v-model="newNum"></li>
           <li>
             <button @click="addNum">add num</button>
           </li>
           <li>---</li>
           <li>current balance: <input :value="balance" disabled></li>
           <li>address: <input v-model="toAddress"> amount: <input v-model="amount"></li>
           <li>
             <button @click="transferTo">do transfer</button>
           </li>
           <li>---</li>
           <li>address: <input v-model="toAddressByWeb3"> amount: <input v-model="amountByWeb3"></li>
           <li>
             <button @click="sendTransactionByWeb3">send transaction</button>
           </li>
           <li>---</li>
           <li>
             <button @click="getBalanceByWeb3">get balance</button>
           </li>
           <li>{{ balanceByWeb3 }}</li>
           <li>---</li>
           <li>
             <button @click="getBalanceOfWeth">get weth balance</button>
           </li>
           <li>{{ balanceOfWeth }}</li>
           <li>---</li>
           <li><input v-model="eth"></li>
           <li>
             <button @click="ethToWeth">eth to weth</button>
           </li>
           <li>---</li>
           <li><input v-model="weth"></li>
           <li>
             <button @click="wethToEth">weth to eth</button>
           </li>
         </ul>
       </template>
       <script>
       import Web3 from "web3";
       import contract from "truffle-contract";
       import demo from '../../build/contracts/Demo.json';
       export default {
         name: 'Demo',
         data() {
           return {
             web3: null,
             provider: null,
             account: null,
             contractInstance: null,
             currentNum: 0,
             newNum: 0,
             toAddress: "",
             amount: 0,
             balance: 0,
             toAddressByWeb3: "",
             amountByWeb3: 0,
             balanceByWeb3: 0,
             balanceOfWeth: 0,
             eth: 0,
             weth: 0,
           }
         },
         async created() {
           await this.initWeb3Account();
           await this.initContract();
           await this.getNum();
         },
         methods: {
           async initWeb3Account() {
             if (window.ethereum) {
               this.provider = window.ethereum;
               try {
                 await window.ethereum.enable();
               } catch (error) {
                 alert("User denied account access");
               }
             } else if (window.web3) {
               this.provider = window.web3.currentProvider;
             } else {
               this.provider = new Web3.providers.HttpProvider("http://127.0.0.1:8545");
             }
             this.web3 = new Web3(this.provider);
             this.web3.eth.getAccounts().then(accs => {
               this.account = accs[0];
             })
           },
           async initContract() {
             let demoContract = contract(demo);
             demoContract.setProvider(this.provider);
             this.contractInstance = await demoContract.deployed();
           },
           async getNum() {
             this.contractInstance.get().then(
                 res => {
                   this.currentNum = res;
                 }
             )
           },
           addNum() {
             this.contractInstance.add(this.newNum, {
               from: this.account
             }).then(() => {
               this.getNum();
             })
           },
           async getBalance() {
             let _this = this;
             this.contractInstance.getBalance(this.toAddress).then(
                 res => {
                   this.balance = _this.web3.utils.fromWei(res, 'ether');
                 }
             )
           },
           transferTo() {
             this.contractInstance.doTransfer(this.toAddress, {
               from: this.account,
               value: this.amount * 10 ** 18
             }).then(() => {
               this.getBalance();
             })
           },
           sendTransactionByWeb3() {
             this.web3.eth.sendTransaction({
               from: this.account,
               to: this.toAddressByWeb3,
               value: this.amountByWeb3 * 10 ** 18
             }, function (err, hash) {
               console.log(err, hash);
             })
           },
           getBalanceByWeb3() {
             let _this = this;
             this.web3.eth.getBalance(this.account).then(
                 function (wei) {
                   _this.balanceByWeb3 = _this.web3.utils.fromWei(wei, 'ether');
                 }
             )
           },
           async getBalanceOfWeth() {
             this.contractInstance.balanceOf(this.account).then(
                 res => {
                   this.balanceOfWeth = this.web3.utils.fromWei(res.toString(), 'ether');
                 }
             )
           },
           ethToWeth() {
             this.web3.eth.sendTransaction({
               from: this.account,
               to: this.contractInstance.address,
               value: this.web3.utils.toWei(this.eth.toString(), 'ether')
             }, function (err, hash) {
               console.log(err, hash);
             });
           },
           wethToEth() {
             this.contractInstance.transfer(this.contractInstance.address, this.web3.utils.toWei(this.weth.toString(), 'ether'), {
               from: this.account
             }).then(() => {
               this.getBalanceOfWeth();
             })
           },
         }
       }
       </script>
    3. 运行:
      npm run serve
文档更新时间: 2024-04-20 10:57   作者:lee