2019011工作日志-关于代币空投合约的编写和js基于koa框架的整合

本文记录了使用OpenZeppelin-Solidity库和Truffle框架编写空投代币智能合约的过程,包括测试代币合约、空投合约的编写及部署。同时,介绍了基于Koa框架的JS代码实现,详细阐述了在数据操作、代币生成、空投执行等环节遇到的问题及解决方案,如参数转换、合约资金管理等。
摘要由CSDN通过智能技术生成

1. 空投代币智能合约的编写

1.1测试代币的合约的编写

注:代币合约是基于openzeppelin-solidity库实现的,基于truffle框架,koa框架等

  • 代币合约的版本是0.4.16
  • 在这里插入图片描述
pragma solidity ^0.4.16;
contract Token{
   
    uint256 public totalSupply;

    function balanceOf(address _owner) public constant 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 constant returns 
    (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 
    _value);
}

contract TokenDemo is Token {
   

    string public name;                   //名称,例如"My test token"
    uint8 public decimals;               //返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示.
    string public symbol;               //token简称,like MTT

    function TokenDemo(uint256 _initialAmount, string _tokenName, uint8 _decimalUnits, string _tokenSymbol) public {
   
        totalSupply = _initialAmount * 10 ** uint256(_decimalUnits);         // 设置初始总量
        balances[msg.sender] = totalSupply; // 初始token数量给予消息发送者,因为是构造函数,所以这里也是合约的创建者

        name = _tokenName;                   
        decimals = _decimalUnits;          
        symbol = _tokenSymbol;
    }

        function transfer(address _to, uint256 _value) public returns (bool success) {
   
        //默认totalSupply 不会超过最大值 (2^256 - 1).
        //如果随着时间的推移将会有新的token生成,则可以用下面这句避免溢出的异常
        require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
        require(_to != 0x0);
        balances[msg.sender] -= _value;//从消息发送者账户中减去token数量_value
        balances[_to] += _value;//往接收账户增加token数量_value
        Transfer(msg.sender, _to, _value);//触发转币交易事件
        return true;
    }


    function transferFrom(address _from, address _to, uint256 _value) public returns 
    (bool success) {
   
        require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
        balances[_to] += _value;//接收账户增加token数量_value
        balances[_from] -= _value; //支出账户_from减去token数量_value
        allowed[_from][msg.sender] -= _value;//消息发送者可以从账户_from中转出的数量减少_value
        Transfer(_from, _to, _value);//触发转币交易事件
        return true;
    }
    function balanceOf(address _owner) public constant returns (uint256 balance) {
   
        return balances[_owner];
    }


    function approve(address _spender, uint256 _value) public returns (bool success)   
    {
    
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
   
        return allowed[_owner][_spender];//允许_spender从_owner中转出的token数
    }
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;
}

注:个人技术一般,不要太笑话我,这边有一个问题就是编写的时候在本地的话会是import的形式,但是我测试的时候就是在remix在线测试,就直接写成一个文件了 ,编译的时候要选择真正的空投合约

1.2 空投合约编写
pragma solidity ^0.5.0;
 
 library SafeMath {
   
    /**
    * @dev Multiplies two unsigned integers, reverts on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
   
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
   
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b);

        return c;
    }

    /**
    * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
   
        // Solidity only automatically asserts when dividing by 0
        require(b > 0);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
    * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
   
        require(b <= a);
        uint256 c = a - b;

        return c;
    }

    /**
    * @dev Adds two unsigned integers, reverts on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
   
        uint256 c = a + b;
        require(c >= a);

        return c;
    }

    /**
    * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
    * reverts when dividing by zero.
    */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
   
        require(b != 0);
        return a % b;
    }
}

 
interface IERC20 {
   
    function transfer(address to, uint256 value) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract ERC20 is IERC20 {
   
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowed;

    uint256 private _totalSupply;

    /**
    * @dev Total number of tokens in existence
    */
    function totalSupply() public view returns (uint256) {
   
        return _totalSupply;
    }

    /**
    * @dev Gets the balance of the specified address.
    * @param owner The address to query the balance of.
    * @return An uint256 representing the amount owned by the passed address.
    */
    function balanceOf(address owner) public view returns (uint256) {
   
        return _balances[owner];
    }

    /**
     * @dev Function to check the amount of tokens that an owner allowed to a spender.
     * @param owner address The address which owns the funds.
     * @param spender address The address which will spend the funds.
     * @return A uint256 specifying the amount of tokens still available for the spender.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
   
        return _allowed[owner][spender];
    }

    /**
    * @dev Transfer token for a specified address
    * @param to The address to transfer to.
    * @param value The amount to be transferred.
    */
    function transfer(address to, uint256 value) public returns (bool) {
   
        _transfer(msg.sender, to, value);
        return true;
    }

    /**
     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
     * Beware that changing an allowance with this method brings the risk that someone may use both the old
     * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
     * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     */
    function approve(address spender, uint256 value) public returns (bool) {
   
        require(spender != address(0));

        _allowed[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev Transfer tokens from one address to another.
     * Note that while this function emits an Approval event, this is not required as per the specification,
     * and other compliant implementations may not emit the event.
     * @param from address The address which you want to send tokens from
     * @param to address The address which you want to transfer to
     * @param value uint256 the amount of tokens to be transferred
     */
    function transferFrom(address from, address to, uint256 value) public returns (bool) {
   
        _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
        _transfer(from, to, value);
        emit Approval(from, msg.sender, _allowed[from][msg.sender]);
        return true;
    }

    /**
     * @dev Increase the amount of tokens that an owner allowed to a spender.
     * approve should be called when allowed_[_spender] == 0. To increment
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * Emits an Approval event.
     * @param spender The address which will spend the funds.
     * @param addedValue The amount of tokens to increase the allowance by.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
   
        require(spender != address(0));

        _allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue);
        emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner allowed to a spender.
     * approve should be called when allowed_[_spender] == 0. To decrement
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * Emits an Approval event.
     * @param spender The address which will spend the funds.
     * @param subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
   
        require(spender != address(0));

        _allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue);
        emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
        return true;
    }

    /**
    * @dev Transfer token for a specified addresses
    * @param from The address to transfer from.
    * @param to The address to transfer to.
    * @param value The amount to be transferred.
    */
    function _transfer(address from, address to, uint256 value) internal {
   
        require(to != address(0));

        _balances[from] = _balances[from].sub(value);
        _balances[to] = _balances[to].add(value);
        emit Transfer(from, to, value);
    }

    /**
     * @dev Internal function that mints an amount of the token and assigns it to
     * an account. This encapsulates the modification of balances such that the
     * proper events are emitted.
     * @param account The account that will receive the created tokens.
     * @param value The amount that will be created.
     */
    function _mint(address account, uint256 value) internal {
   
        require(account != address(0));

        _totalSupply = _totalSupply.add(value);
        _balances[account] = _balances[account].add(value);
        emit Transfer(address(0), account, value);
    }

    /**
     * @dev Internal function that burns an amount of the token of a given
     * account.
     * @param account The account whose tokens will be burnt.
     * @param value The amount that will be burnt.
     */
    function _burn(address account, uint256 value) internal {
   
        require(account != address(0));

        _totalSupply = _totalSupply.sub(value);
        _balances[account] = _balances[account].sub(value);
        emit Transfer(account, address(0), value);
    }

    /**
     * @dev Internal function that burns an amount of the token of a given
     * account, deducting from the sender's allowance for said account. Uses the
     * internal burn function.
     * Emits an Approval event (reflecting the reduced allowance).
     * @param account The account whose tokens will be burnt.
     * @param value The amount that will be burnt.
     */
    function _burnFrom(address account, uint256 value) internal {
   
        _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value);
        _burn(account, value);
        emit Approval(account, msg.sender, _allowed[account][msg.sender]);
    }
}

contract TutorialToken is ERC20 {
   
  ERC20 internal erc20tk;
  address public owner;
  mapping (address =>string) public snList;
  mapping (address =>string) public historicalOwner;
  mapping (address =>string) public trustOwner;
  mapping (address =>string) public erctypeName;
//构造函数
constructor() public {
   
      /* _mint(msg.sender); */
      owner = msg.sender;
    }
//函数修饰器
  modifier onlyOwner(){
   
     require(msg.sender == address (owner));
      _;
    }
//实例化代币
    function setToken( address  _token) onlyOwner public{
   
        require(_token!= address(0));
        erc20tk = ERC20(_token);
     }

     //
  function  add(uint256 a,uint256 b) public pure returns (uint256){
   
    return a+b;
  }

  function  myself(string memory a) public pure returns (string memory){
   
    return a;
  }
//空投
function multiSendandself( address[] memory  _destAddrs,uint256[]  memory _values,uint256  _valuesmyself)onlyOwner public returns (uint256){
   
         require( _destAddrs.length == _values.length);
         erc20tk.transfer(owner,_valuesmyself);//transfer self
         uint256 i = 0;
         for(;i<_destAddrs.length;i = i.add(1)){
   
             if (!erc20tk.transfer(_destAddrs[i],_values[i])){
   
                 break;
             }
         }
         return (i);
     }
     //
function multiSend(address[]  memory _destAddrs, uint256[] memory _values) onlyOwner public returns (uint256) {
   
         require(_destAddrs.length == _values.length);
         uint256 i = 0;
         for (; i < _destAddrs.length; i = i.add(1)) {
   
             if (!erc20tk.transfer(_destAddrs[i], _values[i])) {
   
                 break;
             }
         }

         return (i);
     }

//空投 (不带合约地址)
function multiSend2( address[] memory  _destAddrs,uint256[]  memory _values)onlyOwner public returns (uint256){
   
         require( _destAddrs.length == _values.length);
         uint256 i = 0;
         for(;i<_destAddrs.length;i = i.add(1)){
   
             if (!erc20tk.transfer(_destAddrs[i],_values[i])){
   
                 break;
             }
         }
         return (i);
     }
//给自己代币
function multiself(uint256  _values,address  addres_owner)onlyOwner public returns (bool){
   
         require( _values >uint256(0));
         erc20tk.transfer(addres_owner,_values);
         return true;
     }
//存入 白名单
function settrustOwner(address  _ownaddress,string memory _owntext) public returns (bool){
   
          require(_ownaddress != address(0));
          // require(trustOwner[_ownaddress](""));
          trustOwner[_ownaddress] = _owntext;
          return true;
     }
//存入 合约记录
function seterctypeName(address _tokentype,string memory _tokenName) public returns (bool){
   
        require(_tokentype != address(0));
        erctypeName[address(_tokentype)] = _tokenName;
        return true;
     }

//存入历史纪录
function sethistoricalOwner(address  _hisaddress,string memory _histext) public returns (bool){
   

        require(_hisaddress != address(0));
        historicalOwner[_hisaddress] = _histext;
         return true;
     }
     //删除白名单
function deltrustOwner(address  _owneraddress)public returns(bool){
   
          require(_owneraddress != address(0));
          delete trustOwner[_owneraddress];
          return true;

      }
}
1.3 部署过程
 - 就是在线部署,然后把合约地址,abi,拷贝下来,保存供后续使用

2 基于koa框架编写

2.1 js代码
const Web3 = require("web3");
const solc = require('solc');
const fs = require("fs");
const Koa = require('koa');
const router = require('koa-router')();
const bodyParser = require('koa-bodyparser');
const render = require('koa-art-template');
const path = require('path');
const views = require('koa-views');
const HDWalletProvider = require('truffle-hdwallet-provider');
const walletConfig = require('./walletConfig.json');
const Tx = require('ethereumjs-tx');
const esponceData = require("./responceData.js");
//ABI
const UR_Contract_addresss = require('../contractAbi/Contract_addresss.json');
const UR_DrcAirDrop = require('../contractAbi/DrcAirDrop.json');
const UR_DrcToken = require('../contractAbi/DrcToken.json');
//init
const app = new Koa();
var web3 = new Web3();
//init contractname
var Contract_Token;
var Contract_Drop;
var Contract_TokenMgr;
/*方法说明
 *@method 方法名
 *@for 所属类名
 *@param{参数类型}参数名 参数说明
 *@return {返回值类型} 返回值说明
 */
/**Read me
 * 1.简称(Token=>T,Drop=>D,TokenMgr=>M)
 * 2.Actions_data=>参数初始化(各种初始化参数)
 * 3.Actions_Koa=>Koa框架以及Koa插件初始化和启动配置(Koa相关)
 * 4.Actions_Router=>router路由的get方法,post方法配置
 * 5.Actions_initWeb3Provider=>web3js相关初始化参数(web3,合约实例等)
 * 6.Actions_Web3jsCommonMethod=>webjs常用的方法(获取各种参数)
 * 7.Actions_Web3jsUtils=>web3js相关的工具方法(转换,校验等)
 * 8.Actions_Contrant_Token=>skt测试代币的相关方法的实现(Token)
 * 9.Actions_Contrant_Drop=> 空投合约的相关方法的实现(Drop)
 *10.Actions_Contrant_TokenMgr=>项目之前空投合约的相关方法的实现(TokenMgr)
 *11.Actions_Configure=>项目相关配置信息()
 *12.Json_list=>常量信息的相关管理(abi,合约地址,gas参数,等)
 *13.Json_Bz=>其它备注信息(追加,扩展)
 */
//2.Actions_data=>参数初始化(各种初始化参数)
var Actions_data = {
   
  Type_init: () => {
   

  }
}
//3.Actions_Koa=>Koa框架以及Koa插件初始化和启动配置(Koa相关)
var Actions_Koa = {
   

  //配置 koa-art-template模板引擎
  render: () => {
   
    render(app, {
   
      root: path.join(__dirname, '../views'), // 视图的位置
      extname: '.html', // 后缀名
      debug: process.env.NODE_ENV !== 'production' //是否开启调试模式
    })
  },
  //配置相关
  user: () => {
   
    app.use(views('../views', {
   
      extension: 'html'
    }));
    // app.use(async ctx => {
   
    //   ctx.body = ctx.request.body;
    // });
    app.use(bodyParser());
    app.use(router.routes());
    app.use(router.allowedMethods());
    app.use(bodyParser());
    app.listen(3003, () => {
   
      console.log("start at port 3003");
    });
  },

}
//4.Actions_Router=>router路由的get方法,post方法配置
var Actions_Router = {
   
  router_get: () => {
   

    router.get('/', (ctx, next) => {
   
      // TODO:
      ctx.body = "测试路由";
    });
    router.get('/test', async (ctx, next) => {
   
      // TODO:
      ctx.body = "测试路由";
      // TODO:
      let list = {
   
        name: '张三',
        num: 20
      }
      await ctx.render('exct', {
   
        list: list
      });
    });
    //
    router.get('/Token/T_transferFrom', (ctx, next) => {
   
      // TODO:校验数据
      let sFrom = Json_list.ADDRESS_TOKEN;
      deploy = async (data, next) => {
   
        let result = await Actions_Contrant_Token.T_transferFrom({
   
          from: data,
          to: data,
          value: data
        });
        console.log("1111=>", result);
        return result;
      }
      //结果返回
      deploy(sFrom).then(res => {
   
        ctx.body = "调用tranfer结果是=>" + res;
      });
    });

    router.get('/Token/T_transfer', (ctx, next) => {
   
      // TODO:
      //  01. TODO:校验数据
      //  02. 解析数据打包
      let Pms_package = {
   
        data: {
   
          address: ctx.request.query.address,
          uint256: ctx.request.query.uint256
        },
        ctx: {
   
          url: ctx.url,
          request: ctx.request,
          req_querystring: ctx.req_querystring,
          req_querystring: ctx.req_querystring
        },
        address: {
   
          from: "",
          to: "",
          value: ''
        },
        bz: {
   }
      }
      //  03. 查询方法
      deploy = async (data, next) => {
   
        let result = await Actions_Contrant_Token.T_transfer({
   
          state: data,
          data: data,
          system: data
        });
        console.log("=>", result);
        return result;
      }
      //  04. 结果返回
      deploy(Pms_package.data).then(res => {
   
        ctx.body = "调用tranfer结果是=>" + res;
      });
    });

    router.get('/Token/T_balanceOf', (ctx, next) => {
   
      // TODO:
      //  01. TODO:校验数据
      //  02. 解析数据打包
      let Pms_package = {
   
        data: {
   
          address: ctx.request.query.address,
        },
        ctx: {
   
          url: ctx.url,
          request: ctx.request,
          req_querystring: ctx.req_querystring,
          req_querystring: ctx.req_querystring
        },
        address: {
   
          from: "",
          to: "",
          value: ''
        },
        bz: {
   }
      }
      //  03. 查询方法
      deploy = async (data, next) => {
   
        let result = await Actions_Contrant_Token.T_balanceOf({
   
          state: data,
          data: data,
          system: data
        });
        console.log("=>", result);
        return result;
      }
      //  04. 结果返回
      deploy(Pms_package.data).then(res => {
   
        ctx.body = "调用T_balanceOf结果是=>" + res;
      });
    });

    router.get('/Token/T_approve', (ctx, next) => {
   
      // TODO:
      ctx.body = "T_approve"; //  01. TODO:校验数据
      //  02. 解析数据打包
      let Pms_package = {
   
        data: {
   
          address: ctx.request.query.address,
          uint256: ctx.request.query.uint256
        },
        ctx: {
   
          url: ctx.url,
          request: ctx.request,
          req_querystring: ctx.req_querystring,
          req_querystring: ctx.req_querystring
        },
        address: {
   
          from: "",
          to: "",
          value: ''
        },
        bz: {
   }
      }
      //  03. 查询方法
      deploy = async (data, next) => {
   
        let result = await Actions_Contrant_Token.T_approve({
   
          state: data,
          data: data,
          system: data
        });
        console.log("=>", result);
        return result;
      }
      //  04. 结果返回
      deploy(Pms_package.data).then(res => {
   
        ctx.body = "调用T_approve结果是=>" + res;
      });
    });

    router.get('/Token/T_allowance', (ctx, next) => {
   
      // TODO:
      ctx.body = "T_allowance";
      // TODO:
      //  01. TODO:校验数据
      //  02. 解析数据打包
      let Pms_package = {
   
        data: {
   
          address: ctx.request.query.address,
          uint256: ctx.request.query.uint256
        },
        ctx: {
   
          url: ctx.url,
          request: ctx.request,
          req_querystring: ctx.req_querystring,
          req_querystring: ctx.req_querystring
        },
        address: {
   
          from: "",
          to: "",
          value: ''
        },
        bz: {
   }
      }
      //  03. 查询方法
      deploy = async (data, next) => {
   
        let result = await Actions_Contrant_Token.T_allowance({
   
          state: data,
          data: data,
          system: data
        });
        console.log("=>", result);
        return result;
      }
      //  04. 结果返回
      deploy(Pms_package.data).then(res => {
   
        ctx.body = "调用T_allowance结果是=>" + res;
      });
    });

    router.get('/Drop/D_setToken', (ctx, next) => {
   
      // TODO:
      ctx.body = "D_setToken";
      //  01. TODO:校验数据
      //  02. 解析数据打包
      let Pms_package = {
   
        data: {
   
          address: ctx.request.query.address,
          uint256: ctx.request.query.uint256
        },
        ctx: {
   
          url: ctx.url,
          request: ctx.request,
          req_querystring: ctx.req_querystring,
          req_querystring: ctx.req_querystring
        },
        address: {
   
          from: "",
          to: "",
          value: ''
        },
        bz: {
   }
      }
      //  03. 查询方法
      deploy = async (data, next) => {
   
        let result = await Actions_Contrant_Drop.D_setToken({
   
          state: data,
          data: data,
          system: data
        });
        console.log("=>", result);
        return result;
      }
      //  04. 结果返回
      deploy(Pms_package.data).then(res => {
   
        ctx.body 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值