Npm install -g truffle
Npm install -g EthereumJS TestRPC
Npm install -g supervisor
Truffle init
Npm init
Recommend:npm install --global --production windows-build-tools View
more detail:https://github.com/nodejs/node-gyp#installation能合约开发
pragma solidity ^0.4.21;
/**
* 官方文档众筹实现
* https://solidity.readthedocs.io/en/develop/types.html#structs
* 1 存储方式:memory、storage,状态变量默认是storage而local变量默认是memory
* 2 mapping类似java中字典key=>value,但是没有数组常用操作:push
* 3 require类似junit中断言
* 4 函数体操作状态变量必须有修饰符,view:对状态变量读操作,payable:支付操作
* 5 msg全局变量是配合web3使用
**/
contract CrowdFunding {
// 表结构:众筹项目
struct Fund {
// 众筹地址
address owner;
// 众筹描述
string desc;
// 众筹目标
uint goal;
// 已筹金币
uint coins;
// 是否结束
bool finished;
// 捐赠人数
uint recordCounts;
// 捐赠记录
mapping(uint => Record) records;
// 原本使用 Record[] records 数组定义
// 但是貌似目前版本尚不支持
// 于是将 数组 拆分成 长度 + 映射
// https://solidity.readthedocs.io/en/develop/types.html#mappings
}
// 表结构:捐赠记录
struct Record {
// 捐赠成员
address member;
// 捐赠金币
uint coin;
// 捐赠时间
uint time;
}
// 众筹地址列表
Fund[] funds;
function CrowdFunding() public payable {
}
// 获取众筹项目数量
function getFundCount() public view returns (uint) {
return funds.length;
}
// 获取众筹项目信息
// 参数:项目编号
// 返回:众筹地址 众筹描述 众筹目标 已筹金币 是否结束
function getFundInfo(uint fundIndex) public view returns (address, string, uint, uint, bool) {
Fund storage fund = funds[fundIndex];
return (fund.owner, fund.desc, fund.goal, fund.coins, fund.finished);
}
// 获取众筹捐赠人数
function getRecordCount(uint fundIndex) public view returns (uint) {
return funds[fundIndex].recordCounts;
}
// 获取众筹捐赠记录
// 参数:项目编号 记录编号
// 返回:捐赠成员 捐赠金币 捐赠时间
function getRecordInfo(uint fundIndex, uint recordIndex) public view returns (address, uint, uint) {
Record storage record = funds[fundIndex].records[recordIndex];
return (record.member, record.coin, record.time);
}
// 发起众筹:
function raiseFund(address raiser, string info, uint goal) public {
//funds.push(Fund(msg.sender, info, goal, 0, false, 0));
funds.push(Fund(raiser, info, goal, 0, false, 0));
}
// 捐赠众筹:
// https://solidity.readthedocs.io/en/latest/miscellaneous.html#modifiers
// payable for functions: Allows them to receive Ether together with a call.
function sendCoin(uint fundIndex) public payable {
// 默认属性
// msg.sender 转账账户
// msg.value 转账数目
// 智能合约默认单位 wei
// 1 ether = 10^18 wei
// 引用拷贝
Fund storage fund = funds[fundIndex];
require(!fund.finished);
// 转账 失败自动退出
fund.owner.transfer(msg.value);
// 更新众筹信息
fund.coins += msg.value;
fund.records[fund.recordCounts++] = Record(msg.sender, msg.value, now);
fund.finished = fund.coins >= fund.goal * 1 ether? true : false;
}
// fallback function:回退函数 防止抛出异常
// https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function
// if you want your contract to receive Ether, you have to implement a fallback function.
function() public payable { }
Truffle compile --reset
注意--reset是版本发生变化才生效,编译生成的合约\build\contracts\CrowdFunding.json
/**
* 众筹业务控model
* @author wolf
* @time 2018-05-01
*/
var Web3 = require('web3');
var contract = require("truffle-contract");
var provider = new Web3.providers.HttpProvider("http://localhost:8545");
//使用truffle-contract包的contract()方法
var CrowdFunding = contract(
copy编译后文件:/build/contracts/CrowdFunding.json
);
//UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: invalid address
//没有默认地址,会报错:务必设置为自己的钱包地址,如果不知道,查看自己的客户端启动时,观察打印到控制台的地址
CrowdFunding.setProvider(provider);
CrowdFunding.defaults({
from : "0xeeacbf78bb5eeba49acdc67c0fbd5dd46e67facf"
});
module.exports = function () {
this.web3 = new Web3(provider);
this.model = CrowdFunding;
}
Truffle migrate --reset
**Option 1:**
CrowdFunding.defaults({
from : "0xeeacbf78bb5eeba49acdc67c0fbd5dd46e67facf"
});
**Option2:**
CrowdService.web3.eth.defaultAccount=account;
/**
* 账户列表
* @param req
* @param res
*/
get_accountsList:function (req, res) {
res.send(CrowdService.web3.eth.accounts)
},
/**
* 查看区块数
* @param req
* @param res
*/
get_blocksList : function (req, res) {
res.send(CrowdService.web3.eth.blockNumber);
},
/**
* 查看默认账户/调用合约的账户
* @param req
* @param res
*/
post_defaultAccount: function (req, res) {
var account = req.body.account;
var retMsg = new Message();
if (Checks.isNull(account)) {
console.log("Current default: " + CrowdService.web3.eth.defaultAccount);
res.send(retMsg.success('合约调用默认账户:'+ CrowdService.web3.eth.defaultAccount));
} else {
CrowdService.web3.eth.defaultAccount=account;
res.send(retMsg.success('更新合约调用默认账户:'+ CrowdService.web3.eth.defaultAccount))
}
},
/**
* 查看账户余额
* @param req
* @param res
*/
post_accountBalance : function (req, res) {
var account = req.body.account;
retMsg = new Message();
if (Checks.isNull(account)) {
res.send(retMsg.fail('账户地址不能为空!'))
}
var balance = CrowdService.web3.eth.getBalance(account);
res.send(balance)
},
/**
* 发起众筹
* @param req
* @param res
*/
post_raiseFund: function (req, res) {
var raiser = req.body.raiser;
var info = req.body.info;
var goal = req.body.goal;
if (Checks.isNull(raiser)) {
raiser = CrowdService.web3.eth.accounts[0];
}
CrowdService.model.deployed().then(function (instance) {
return instance.raiseFund(raiser, info, goal, { gas: 1000000 });
}).then(function (result) {
console.log(result); //打印交易收据
});
res.send(JSON.stringify({"info" : info, "goal": goal, "code": "募集成功!"}));
},
/**
* 捐赠众筹
* @param req
* @param res
*/
post_donate: function (req, res) {
var retMsg = new Message();
// sendCoin(uint fundIndex, address donater, uint coin)
var fundIndex = req.body.fundIndex;
var donater = req.body.donater;
var coin = req.body.coin;
/*if (Checks.isNull(fundIndex) || Checks.isNull(donater) || Checks.isNull(coin)) {
res.send(JSON.stringify(retMsg.fail('众筹项目、捐赠账户、捐赠数量不能为空!!!')));
}*/
CrowdService.web3.eth.defaultAccount = donater;
CrowdService.model.deployed().then(function (instance) {
return instance.sendCoin(fundIndex,{value: CrowdService.web3.toWei(coin, 'ether'), from: donater, gas: 1000000 });
}).then(function (result) {
console.log(result); //打印交易收据
});
res.send(JSON.stringify(retMsg.success('捐赠成功!!!')));
},
/**
* 众筹列表
* @param req
* @param res
*/
post_fundsList: function (req, res) {
var total;
var list = new Array();
var g;
CrowdService.model.deployed().then(function (instance) {
g=instance;
return g.getFundCount();
}).then(function (total) {
//promise循环
var promoseArray=[];
for (index=0; index < total; index++) {
promoseArray.push(g.getFundInfo(index));
}
Promise.all(promoseArray).then(function (data) {
res.send(JSON.stringify(data));
})
});
},
/**
* 众筹详情
* @param req
* @param res
*/
post_fundInfo: function (req, res) {
var index = req.body.index;
CrowdService.model.deployed().then(function (instance) {
return instance.getFundInfo(index);
}).then(function (result) {
res.send(result);
});
},
/**
* 获取捐赠记录列表
* @param req
* @param res
*/
post_recordsList: function (req, res) {
var fundIndex = req.body.fundIndex;
var g;
CrowdService.model.deployed().then(function (instance) {
g = instance;
return g.getRecordCount(fundIndex);
}).then(function (count) {
console.log(count);
if (count <= 0) {
res.send("没有捐赠记录");
return;
}
var promiseArray=[];
for(x=0; x
/**
* 输出格式类
* @type {{code: number, msg: string, data: {total: number, pageNo: number, pageSize: number, object: {}, array: Array}}}
* @author wolf
* @time 2018/5/1
*/
function Message () {
this.result = {
"code": 0,
"msg": "操作成功",
"data": {"total": 0, "pageNo": 1, "pageSize": 10, "object": {}, "array": []}
};
}
Message.prototype.success = function (msg) {
this.result.msg = msg;
return this.result;
}
Message.prototype.fail = function (msg) {
this.result.code = -1;
this.result.msg = msg;
return this.result;
}
Message.prototype.listPage = function (total, pageNo, list) {
this.result.data.total = total;
this.result.data.pageNo = pageNo;
this.result.data.array = list;
return this.result;
}
Message.prototype.setData = function (object) {
this.result.data.object = object;
return this.result;
}
module.exports = Message;
var Migrations = artifacts.require("./Migrations.sol");
var Test = artifacts.require("./Test.sol");
var CrowdFunding = artifacts.require("./CrowdFunding.sol");
module.exports = function (deployer) {
deployer.deploy(Migrations);
deployer.deploy(Test);
deployer.deploy(CrowdFunding);
};
var promiseArray=[];
for(x=0; x
Message.prototype.success = function (msg) {
this.result.msg = msg;
return this.result;
}
/**
* 检查工具类
* @author wolf
* @time 2018/5/1
*/
function Checks() {}
/**
* 判断是否为空
* @param val
* @returns
*/
Checks.isNull = function(val) {
if (val == undefined || val == null || val == "" || val == ''
|| val == "undefined" || val == "null" || val == "NULL") {
return true;
}
return false;
}
module.exports = Checks;
// 转账 失败自动退出
fund.owner.transfer(msg.value);
// 更新众筹信息
fund.coins += msg.value;
fund.records[fund.recordCounts++] = Record(msg.sender, msg.value, now);
for crowdfunding.js:
CrowdService.model.deployed().then(function (instance) {
return instance.sendCoin(fundIndex,{value: CrowdService.web3.toWei(coin, 'ether'), from: donater, gas: 1000000 });
}).then(function (result) {
console.log(result); //打印交易收据
});