Dapp TokenFarm开发(5)---合约开发
2.4 空投代币
2.4.0 编写合约
给TokenFarm.sol 添加如下空投函数
  // 3.空投代币
  function issueTokens() public {
    // 要求必须为合约拥有者才能空投代币
    require(msg.sender == owner, "caller must be the owner");
    // 给所有质押过的用户空投
    for (uint256 i = 0; i < stackers.length; i++) {
      address recipient = stackers[i];
      uint balance = stakingBalance[recipient];
      if (balance > 0){
        dappToken.transfer(recipient, balance);
      }
    }
  }
2.4.1 编写测试
继续编写,测试添加如下代码
        // 空投代币
        await tokenFarm.issueTokens({ from: owner })
        // 检查用户余额
        result = await dappToken.balanceOf(investor)
        assert.equal(result.toString(), tokens('100'), 'investor Dapp Tokens balance correst after staking')
        // 确保只有拥有者能调用空投函数
        await tokenFarm.issueTokens({ from: investor }).should.be.rejected;
2.4.2 测试
继续在终端修改,并测试
truffle migrate
truffle test
如下再度大成功!!!!!!!!!!!

2.5.3 封装空投代币函数
在根目录创建一个 scripts 文件夹在里面创建一个 issue-token.js
const TokenFarm = artifacts.require('TokenFarm')
module.exports =async function(callback) {
  let tokenFarm = await TokenFarm.deployed()
  await tokenFarm.issueTokens()
  
  console.log("Tokens issued!")
  callback()
};
继续在终端修改,获取uri,并测试
truffle compile 
truffle migrate
truffle test
truffle exec scripts/issue-token.js
如下成功空投

2.5 取出代币(最终代码)
2.5.0 编写合约
TokenFarm 添加如下函数
pragma solidity ^0.5.0;
import "./DappToken.sol";
import "./DaiToken.sol";
contract TokenFarm {
  string public name = "Dapp Token Farm";
  DappToken public dappToken; // 合约 A
  DaiToken public daiToken; // 合约 B
  address public owner; // 合约拥有者
  address[] public stackers; // 质押过的名单(用于空投代币)
  mapping(address => uint256) public stakingBalance; // 正在质押总量
  mapping(address => bool) public hasStaked; // 已经质押过的地址
  mapping(address => bool) public isStaking; // 正在质押的地址
  // 构造函数 仅在代码部署的时候执行一次,部署完成无法再执行
  constructor(DappToken _dappToken, DaiToken _daiToken) public {
    dappToken = _dappToken; // 保存合约
    daiToken = _daiToken; // 保存合约
    owner = msg.sender; // 部署合约的时候设定拥有者
    // 该用户在合约中有一定的权限
  }
  // 1.质押代币
  function stakeTokens(uint _amount) public {
    // 要求质押的代币大于0
    require(_amount > 0,"amount cannot be 0");
    daiToken.transferFrom(msg.sender, address(this), _amount);
    // 更新质押数量
    stakingBalance[msg.sender] += _amount;
    // 更新已经质押过的名单
    if(!hasStaked[msg.sender]){
      stackers.push(msg.sender);
    }
    // 更新是否正在质押
    hasStaked[msg.sender] = true;
    isStaking[msg.sender] = true;
  }
  // 2.取出质押的代币
  function unstakeTokens() public {
    // 获取正在质押的总数
    uint balance = stakingBalance[msg.sender];
    // 要求正在质押总量大于0
    require(balance > 0, "staking banlance cannot be 0");
    // 将 DAI 发送回用户地址
    daiToken.transfer(msg.sender,balance);
    // 更新用户设置质押数量
    stakingBalance[msg.sender] = 0;
    // 更新用户质押状态
    isStaking[msg.sender] = false;
  }
  // 3.空投代币
  function issueTokens() public {
    // 要求必须为合约拥有者才能空投代币
    require(msg.sender == owner, "caller must be the owner");
    // 给所有质押过的用户空投
    for (uint256 i = 0; i < stackers.length; i++) {
      address recipient = stackers[i];
      uint balance = stakingBalance[recipient];
      if (balance > 0){
        dappToken.transfer(recipient, balance);
      }
    }
  }
}
2.5.1 编写测试
添加 取出质押代币的测试
const { assert } = require('chai');
const TokenFarm = artifacts.require("TokenFarm");
const DappToken = artifacts.require("DappToken");
const DaiToken = artifacts.require("DaiToken");
require('chai').use(require('chai-as-promised')).should()
function tokens(n) {
  // 用作数值转换 100 ether => 1*10^20 wei
  // 1ether = 10^18
  return web3.utils.toWei(n, 'Ether')
}
contract('TokenFarm', ([owner, investor]) => {
  let daiToken, dappToken, tokenFarm
  before(async () => {
    // 加载合约
    daiToken = await DaiToken.new()
    dappToken = await DappToken.new()
    tokenFarm = await TokenFarm.new(dappToken.address, daiToken.address)
    // 把所有的代币发送给tokenFarm
    await dappToken.transfer(tokenFarm.address, tokens('1000000'))
    // 发送100 给代币到用户
    await daiToken.transfer(investor, tokens('100'), { from: owner })
  })
  // 测试 daiToken 合约 name 属性 返回值是否为 'Mock DAI Token'
  describe('Mock Dai deployment', async () => {
    it('has a name', async () => {
      const name = await daiToken.name()
      assert.equal(name, 'Mock DAI Token')
    })
  })
  // 测试 DappToken 合约 name 属性 返回值是否为 'Dapp Token'
  describe('Dapp Token deployment', async () => {
    it('has a name', async () => {
      const name = await dappToken.name()
      assert.equal(name, 'DApp Token')
    })
  })
  // 测试 DappToken 合约 name 属性 返回值是否为 'Dapp Token Farm'
  describe('Token Farm deployment', async () => {
    it('has a name', async () => {
      const name = await tokenFarm.name()
      assert.equal(name, 'Dapp Token Farm')
    })
    // 测试tokenFarm 地址 是否有1000000*10^18 个 dappToken
    it('contract has tokens', async () => {
      let balance = await dappToken.balanceOf(tokenFarm.address)
      assert.equal(balance.toString(), tokens('1000000'))
    })
  })
  describe("Farming tokens", async () => {
    it('rewards investors for staking mDai tokens', async () => {
      let result
      // 检查用户是否有100个 DAI
      result = await daiToken.balanceOf(investor)
      assert.equal(result.toString(), tokens('100'), 'investor mDAI wallet balance correst before staking')
      // 用户授权100个 DAI,并质押到 TokenFarm
      await daiToken.approve(tokenFarm.address, tokens('100'), { from: investor })
      await tokenFarm.stakeTokens(tokens('100'), { from: investor })
      // 查询用户 DAI 余额是否为0
      result = await daiToken.balanceOf(investor)
      assert.equal(result.toString(), tokens('0'), 'investor mDAI wallet balance correst before staking')
      // 检查 TokenFarm 地址是否有100个 DAI
      result = await daiToken.balanceOf(tokenFarm.address)
      assert.equal(result.toString(), tokens('100'), 'TokenFarm mDAI wallet balance correst before staking')
      // 检查用户是否在 TokenFarm 质押 100 个 DAI
      result = await tokenFarm.stakingBalance(investor)
      assert.equal(result.toString(), tokens('100'), 'investor staking balance correst after staking')
      // 检查用户是否在质押
      result = await tokenFarm.isStaking(investor)
      assert.equal(result.toString(), 'true', 'investor staking status correst after staking')
      // 空投代币
      await tokenFarm.issueTokens({ from: owner })
      // 检查用户余额
      result = await dappToken.balanceOf(investor)
      assert.equal(result.toString(), tokens('100'), 'investor Dapp Tokens balance correst after staking')
      // 确保只有拥有者能调用空投函数
      await tokenFarm.issueTokens({ from: investor }).should.be.rejected;
      // 取出质押的代币 DAI
      await tokenFarm.unstakeTokens({ from: investor })
      // 检查用户 DAI 余额
      result = await daiToken.balanceOf(investor)
      assert.equal(result.toString(), tokens('100'), 'investor Mock Dai balance correst after staking')
      // 检查 TokenFarm 地址的 DAI 余额
      result = await daiToken.balanceOf(tokenFarm.address)
      assert.equal(result.toString(), tokens('0'), 'tokenFarm Mock Dai balance correst after staking')
      // 检查用户正在质押的DAI 余额
      result = await tokenFarm.stakingBalance(investor)
      assert.equal(result.toString(), tokens('0'), 'tokenFarm Mock Dai balance correst after staking')
      // 检查用户是否正在质押
      result = await tokenFarm.isStaking(investor)
      assert.equal(result.toString(), "false", 'tokenFarm status correst after staking')
    })
  })
})
2.5.2 测试
继续在终端修改,并测试
truffle migrate
truffle test
成功,我们的合约完成了

                    
                
                
            
        
浙公网安备 33010602011771号