参考资料
- 使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP
- web3 1.0 API
开发环境
- Windows10
- web3 1.0
编写第一个Solidity智能合约
一个简单的例子是编写一个可以注册,保存社区成员信息和简单电子钱包功能的账户合约
pragma solidity ^0.4.24;
import "./SafeMath.sol";//开源的安全操作unit256的合约
contract Account{
using SafeMath for uint256;
//新成员创建事件
event NewMember(string _name, string _avator);
//成员信息结构
struct Member {
string name;//名字
string avatar;//头像
bool isExist;//是否注册
uint256 balance;//可周转余额
}
//地址到成员信息的mapping
mapping(address => Member) internal addressToMember;
//限制调用的条件
modifier onlyMemberOf(address _from){
require(addressToMember[_from].isExist);
_;
}
// 注册
function registerMember(string _name, string _avatar) public {
require(!isMemberOf());
addressToMember[msg.sender] = Member(_name, _avatar, true, 0);
emit NewMember(_name, _avatar);
}
// 判断是否注册
function isMemberOf() public view returns (bool) {
return addressToMember[msg.sender].isExist;
}
// 获取个人信息
function getMemberInfo() public view onlyMemberOf(msg.sender) returns (string name, string avatar, uint256 balance) {
return (addressToMember[msg.sender].name,addressToMember[msg.sender].avatar, addressToMember[msg.sender].balance);
}
//获取当前合约中的总余额
function getTotalBalance() public view returns (uint256) {
return address(this).balance;
}
//取出可周转余额
function withdraw(uint256 amount) public onlyMemberOf(msg.sender) returns (uint256) {
require(address(this).balance >= amount);
addressToMember[msg.sender].balance = addressToMember[msg.sender].balance.sub(amount);
msg.sender.transfer(amount);
return addressToMember[msg.sender].balance;
}
}
复制代码
在Remix上部署合约
- 安装Ganache
- 使用Ganache本地测试:安装MetaMask Chrome插件, 选择Custom RPC创建RPC连接到http://127.0.0.1:7545
- 或者要部署到私有节点,可以使用命令行,然后选择Custom RPC创建RPC连接到http://127.0.0.1:8545
$ geth --identity "MY Etherum" --rpc --rpccorsdomain "*" --datadir data --port "8545" --rpcapi "db,eth,net,web3,personal" --networkid 666 console
复制代码
- 打开Remix在线编译,在compile选择合适的编译版本编译,在run选择Deploy部署得到合约地址
- 可以在Remix上测试我们的合约(注册后getMemberInfo可以用户信息,isMemberOf为true)
- 合约部署和测试成功后,将ABI和Deployed Contracts复制保存到本地文件夹(注意Ganache得到的地址是临时的,下次打开就会失效)
配置Truffle+Vue项目
- 环境配置
在windows下需要先安装node.js, 建议使用Git Bash或者PowerShell执行命令:$ npm install -g -production windows-build-tools $ npm install -g ganache-cli $ npm install -g truffle $ npm install -g vue-cli 复制代码
- Vue项目安装
$ vue init webpack ecourse // vue init webpach + 你的项目名 $ cd ecourse $ npm install --save element-ui vue-router vuex [email protected] [email protected] 复制代码
- 添加文件及文件夹:① contracts放置.sol合约; ② store放置Vuex状态控制代码;③ util放置工具函数,util/constant放置上一步中编译好的合约地址和ABI,util/config放置一些配置
完善项目
具体的配置可以参考博客使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP,这里我主要指出使用web3 1.0 标准的不同配置
- getWeb3.js
import Web3 from 'web3'
let getWeb3 = new Promise(function (resolve, reject) {
var web3js = window.web3;
var web3Provider;
if (typeof web3js !== 'undefined') {
web3Provider = web3js.currentProvider;
} else {
web3Provider = new Web3.providers.HttpProvider('http://127.0.0.1:7545');
}
var web3 = new Web3(web3Provider);
resolve({
injectedWeb3: web3.eth.net.isListening(), // 新的api
web3() {
return web3
}
})
})
.then(result => {
return new Promise(function (resolve, reject) {
result.web3().eth.net.getId((err, networkId) => { // 新的api
if(err) {
reject(new Error('Unable to retrieve network ID'))
} else {
console.log('retrieve newworkId: ' + networkId)
result = Object.assign({}, result, {networkId})
resolve(result)
}
})
})
})
.then(result => {
return new Promise(function (resolve, reject) {
result.web3().eth.getCoinbase((err, coinbase) => {
if(err) {
reject(new Error('Unable to retrieve coinbase'))
} else {
coinbase = result.web3().utils.toChecksumAddress(coinbase);
console.log('retrieve coinbase: '+ coinbase);
result = Object.assign({}, result, {coinbase});
resolve(result)
}})
})
});
export default getWeb3
复制代码
- pollWeb3.js(web3 1.0 添加了新的api能够监听账户地址的变化,不需要使用setIntervel进行轮询)
import Web3 from 'web3'
import {store} from '../store/'
let web3 = window.web3;
web3 = new Web3(web3.currentProvider);
web3.currentProvider.publicConfigStore.on('update', ({selectedAddress, networkVersion}) => {
store.dispatch('pollWeb3', {
coinbase: selectedAddress
})
});
复制代码
- getContract.js
import Web3 from 'web3'
import {address, ABI} from './constant/ecourse_abi'
import {store} from '../store/'
let getContract = new Promise(function(resolve, reject) {
let web3 = new Web3(window.web3.currentProvider);
let ecourseContractInstance = new web3.eth.Contract(ABI, address);//新的api
if (!ecourseContractInstance) {
reject("no contract instance build")
}
resolve(ecourseContractInstance);
});
export default getContract
复制代码
Dapp调用合约函数
- App.vue(我们可以在入口文件注册web3和contract)
async beforeCreate() {
if(!this.$store.state.web3.web3Instance) {
await this.$store.dispatch('registerWeb3');
await this.$store.dispatch('getContractInstance');
}
},
复制代码
- web3 1.0调用函数使用methods
// 为避免报错,可以在调用合约函数之前,进行一个判断
if(typeof this.$store.state.contractInstance !== "function") {
await this.$store.dispatch('getContractInstance');
}
// 一个调用函数的例子
this.$store.state.contractInstance().methods.withdraw(this.formInline.balance)
.send({from:this.$store.state.web3.coinbase, gas: 300000})
.on('receipt', receipt => {
this.$message('取款成功');
})
.on('error', error => {
this.$message('取款失败');
})
// 另一个调用函数的例子
this.$store.state.contractInstance().methods.getMemberInfo()
.call({from: state.web3.coinbase}) //注意!!!!!from不能省略,因为metamask默认的msg.sender是accounts[0]
.then(res => {
console.log('account info: ' + res);
})
.catch(error => {
console.log(error);
})
复制代码
其他
- 之前没有学习过vue项目的,可以从一个最简单的Truffle PetShop项目学起,可以很快搭建并看到一个合约怎样调用。
- 学习solidity的很好的网站:cryptozombies,大概两天可以把所有lesson过一遍,基本上编写合约就没什么问题了
- 可以在truffle官网上找到很多框架,直接unbox使用,不过我觉得自己配置使用起来比较容易
我的项目地址:Github
有问题,可以随时提问