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