合约实战,代币合约,DAPP开发
1. ERC20标准
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
pragma solidity ^0.4.4; //定义接口 contract ERC20Interface{ string public name; string public symbol; uint8 public decimals; uint256 public totalSupply; /* function balanceOf(address _owner) view returns (uint256 balance); */ function transfer(address _to, uint256 _value) returns (bool success); function transferFrom(address _from, address _to, uint256 _value) returns (bool success); function approve(address _spender, uint256 _value) returns (bool success); function allowance(address _owner, address _spender) view returns (uint256 remaining); event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } contract ERC20 is ERC20Interface{ mapping(address => uint256) public balanceOf; //委托,允许他人操作的金额数 mapping(address => mapping(address => uint256)) allowed; //构造方法 constructor() public { name = "MyToken"; symbol = "weixuexi"; decimals = 0; totalSupply = 10000; balanceOf[msg.sender] = totalSupply; } /* function balanceOf(address _owner) view returns (uint256 balance){ return balanceOf[_owner]; } */ function transfer(address _to, uint256 _value) returns (bool success){ require(_to != address(0)); require(balanceOf[msg.sender] >= _value); require(balanceOf[_to] + _value > balanceOf[_to]); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; emit Transfer(msg.sender, _to, _value); } function transferFrom(address _from, address _to, uint256 _value) returns (bool success){ require(_from != address(0)); require(_to != address(0)); require(balanceOf[_from] >= _value); require(allowed[msg.sender][_from] >= _value); //当前合约能操作_from的钱数要大于_value require(balanceOf[_to] + _value > balanceOf[_to]); balanceOf[_from] -= _value; balanceOf[_to] += _value; emit Transfer(_from, _to, _value); success = true; } function approve(address _spender, uint256 _value) returns (bool success){ //当前账户允许—_spender操作的金额数 allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); success = true; } function allowance(address _owner, address _spender) view returns (uint256 remaining){ return allowed[_owner][_spender]; } }
2.DAPP去中心化应用开发【web项目】
web3.js
solidity
truffle https://truffleframework.com/docs/truffle/getting-started/installation
ganache
开发流程:
- 新建项目【初始化】
- 编写合约
- 合约编译、部署、测试
- 与合约交互
安装truffle:
npm install -g truffle
查看版本:truffle.cmd version
创建项目:
下载基本文件:
cd pet-shop
truffle init 【安装项目】
下载pet-shop包文件:
cd pet-shop
truffle unbox pet-shop
编写智能合约:Adoption.sol
pragma solidity ^0.4.23; contract Adoption { address[16] public adoptors; //领养这地址 function adopt(uint petId) public returns(uint) { adoptors[petId] = msg.sender; return petId; } function getAdoptors() public view returns (address[16]) { return adoptors; } }
编译: truffle.cmd compile【方式一,结合使用ganache】
truffle develop 【方式二,truffle集成了testrpc】; compile;
部署合约:migrate
部署合约脚本: 1_migration.js 改文件用于监听合约文件的动向,是否更新,变化
var MyContract = artifacts.require("MyContract"); module.exports = function(deployer) { // deployment steps deployer.deploy(MyContract); };
truffle.js:
module.exports = { // See <http://truffleframework.com/docs/advanced/configuration> // to customize your Truffle configuration! networks: { development: { host: "127.0.0.1", //主机 port: 7545, //端口,和ganache对应 network_id: "*" // Match any network id } } };
部署合约:[truffle] migrate
输出结果:Adoption.json [编译出的文件做出了更新]
这时,ganache中可以发现,已经出来了4个区块:
还有交易信息:
获取合约实例,调用函数:
pragma solidity ^0.4.23; contract Hello { //如果使用pure修饰,可以通过合约对象直接调用,否则需要使用call方法调用 function test() pure public returns (string) { return "hello world"; } }
/migrations/3_deploy_hello.js
var Hello = artifacts.require("./Hello.sol"); module.exports = function(deployer) { deployer.deploy(Hello); };
使用web3获取合约实例:
>truffle: let contract; //声明contract变量
contract = Hello.deployed().then(instance => contract=instance) //Hello 是上面迁移文件的合约实例
pragma solidity ^0.4.23; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/Adoption.sol"; contract TestAdoption { Adoption adoption = Adoption(DeployedAddresses.Adoption()); function testUserCatAdoptPet() public { uint returnId = adoption.adopt(8); uint expect = 8; Assert.equal(returnId, expect, "Adoption of pet Id 8 should be recorded"); } function testGetAdoptorAddByPetId() public { address expect = this; address adoptor = adoption.adoptors(8); Assert.equal(expect, adoptor, "get adopt by pet id"); } }
注意:修改完合约文件后,重新编译【compile】后,重新部署命令【migrate --reset】
调用合约方法:contract.test();
使用断言测试:Assert
同时会多出很多新的区块和交易
3.web3.js api的使用
进入truffle开发环境:truffle.cmd develop
获取账户余额:web3.eth.getBalace("").toString();
truffle(develop)> web3.eth.getBalance("0x627306090abab3a6e1400e9345bc60c78a8bef57").toString() '100000000000000000000'
获取所有账户:web3.eth.accounts;
truffle(develop)> null [ '0x627306090abab3a6e1400e9345bc60c78a8bef57', '0xf17f52151ebef6c7334fad080c5704d77216b732', '0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef', '0x821aea9a577a9b44299b9c15c88cf3087f3b5544', '0x0d1d4e623d10f9fba5db95830f7d3839406c6af2', '0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e', '0x2191ef87e392377ec08e7c08eb105ef5448eced5', '0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5', '0x6330a553fc93768f612722bb8c2ec78ac90b3bbc', '0x5aeda56215b167893e80b4fe645ba6d5bab767de' ]
获取当前账号:【数组中的第0个账号】
truffle(develop)> web3.eth.coinbase; '0x627306090abab3a6e1400e9345bc60c78a8bef57'
web3.fromWei(num, 单位);
truffle(develop)> web3.fromWei(5, 'ether') '0.000000000000000005'
web3.toWei(num,单位)
默认的区块:
truffle(develop)> web3.eth.defaultBlock 'latest'
交易:
truffle(develop)> web3.eth.sendTransaction({from:account1, to:account2, value:100000000000000000}) '0xb5065a9a03d75f08d7e704d352d08de5c8c4f8f19cc654cb1261d254f6194d90' truffle(develop)> web3.eth.getBalance(account1) BigNumber { s: 1, e: 19, c: [ 998999, 99999999979000 ] } truffle(develop)> web3.eth.getBalance(account2) BigNumber { s: 1, e: 20, c: [ 1001000 ] } truffle(develop)> web3.eth.getBalance(account1).toString() '99899999999999979000' truffle(develop)> web3.eth.getBalance(account2).toString() '100100000000000000000' truffle(develop)> web3.fromWei(web3.eth.getBalance(account1).toString(), 'ether') '99.899999999999979' truffle(develop)> web3.fromWei(web3.eth.getBalance(account2).toString(), 'ether') '100.1' truffle(develop)> web3.fromWei(web3.eth.getBalance(web3.eth.accounts[2]).toString(), 'ether') '100'
4. 代币合约的概念
pragma solidity ^0.4.4; contract EncryptedToken { uint256 INITAL_SUPPLY = 10000; mapping(address => uint) public balanceOf; constructor() { balanceOf[msg.sender] = INITAL_SUPPLY; } function transfer(address _to, uint256 _value) public { require(_to != address(0)); require(balanceOf[msg.sender] >= _value); require(balanceOf[_to] + _value > balanceOf[_to]); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; } }
var EncryptedToken = artifacts.require("./EncryptedToken.sol"); module.exports = function(deployer) { deployer.deploy(EncryptedToken); };
部署:
truffle.cmd develop
compile
migate
let c;
EncryptedToken.deployed().then(inc => c=inc);
c.balanceOf("0x627306090abab3a6e1400e9345bc60c78a8bef57") ; ->10000 //钱包地址
默认部署到第一个测试钱包中:
转账:c.transfer("0xf17f52151ebef6c7334fad080c5704d77216b732",1000)
truffle(develop)> c.balanceOf("0x627306090abab3a6e1400e9345bc60c78a8bef57")
BigNumber { s: 1, e: 3, c: [ 9000 ] }
5. web端
4.1 使用npm管理项目
npm init
安装web server:npm install lite-server
配置文件:bs-config.json
{ "server" : { "baseDir":["./src", "./build/contracts"] } }
package.json:
启动服务:npm run dev