DAPP被称为分散式应用程序,DAPP是基于区块链技术的应用程序。dApp在不同计算机的P2P网络上运行,而不是在一台计算机上运行。dApps自P2P网络开始以来就已经存在。它实际上是一种软件程序,旨在以不受任何单个实体控制的方式在Internet上运行。分散式应用程序上的所有数据都存储在分布式分类帐中。
基于区块链的智能合约不仅能发挥智能合约低成本高效率的优势,而且可以避免恶意行为对合约的正常执行的干扰。将智能合约以代码化的形式写入区块链中,利用区块链技术实现数据存储、读取及执行过程可追踪透明化且不可篡改。此外利用区块链的共识算法构造的状态机系统能使智能合约高效的运行。
ERC20约定了一个代币合约需要实现的接口:
//接口标准
contract ERC20{
function totalSupply()constant returns(uint totalSupply);//总发行量
function balanceOf(address _owner)constant returns(uint balance);
//代币分发(注意,这个只有合约的Creator可以调用)
function transfer(address _to,uint _value)returns(bool success);
//这里是拥有者和拥有者之间的代币转移
function transferFrom(address _from,address _to,uint _value)returns(bool success);
function approve(address _spender,uint _value)returns(bool success);
function allowance(address _owner,address _spender)constant returns(uint remaining);
event Transfer(address indexed _from,address indexed _to,uint _value);
event Approval(address indexed _owner,address indexed _spender,uint _value);
//Token信息
string public constant name="4FunCoin";
string public constant symbol="4FC";
uint8 public constant decimals=18;//token的精度,大部分都是18
}
上面的代码是一个标准的ERC20标准的代码,规范给出了框架,我们只需要实现相应的函数就好了,这里给出函数说明。
接口函数说明
函数的形参是局部有效,所以前面使用下划线,与其他的变量区别开来.如_owner.
totalSupply()函数返回这个Token的总发行量;
balanceOf()查询某个地址的Token数量,结合mapping实现
transfer()owner使用这个进行发送代币
transferFrom()token的所有者用来发送token
allowance()控制代币的交易,如可交易账号及资产,控制Token的流通
approve()允许用户可花费的代币数;
事件函数说明
这里两个Event是重点,事件,可以被前端js代码捕获到并进行相应的处理:
event Transfer()Token的转账事件
event Approval()允许事件
ERC20代币合约实现
理解了上面的函数,下面的代码,就实现了Token合约的函数填充
pragma solidity^0.4.16;
interface tokenRecipient{function receiveApproval(address _from,uint256 _value,address _token,bytes _extraData)public;}//token的接受者这里声明接口,将会在我们的ABI里
contract TokenERC20{
/Token的属性说明*/
string public name=4FunCoin;
string public symbol=4FC;
uint8 public decimals=18;//18是建议的默认值
uint256 public totalSupply;//发行量
//建立映射地址对应了uint'便是他的余额
mapping(address=>uint256)public balanceOf;
//地址对应余额
mapping(address=>mapping(address=>uint256))public allowance;
//事件,用来通知客户端Token交易发生
event Transfer(address indexed from,address indexed to,uint256 value);
//事件,用来通知客户端代币被消耗
event Burn(address indexed from,uint256 value);
//这里是构造函数,实例创建时候执行
function TokenERC20(uint256 initialSupply,string tokenName,string tokenSymbol)public{
totalSupply=initialSupply10*uint256(decimals);//这里确定了总发行量
balanceOf[msg.sender]=totalSupply;//这里就比较重要,这里相当于实现了,把token全部给合约的Creator
name=tokenName;
symbol=tokenSymbol;
}
//token的发送函数
function _transfer(address _from,address _to,uint _value)internal{
require(_to!=0x0);//不是零地址
require(balanceOf[_from]>=_value);//有足够的余额来发送
require(balanceOf[_to]+_value>balanceOf[_to]);
uint previousBalances=balanceOf[_from]+balanceOf[_to];
balanceOf[_from]-=_value;//
balanceOf[_to]+=_value;
Transfer(_from,_to,_value);//这里触发了转账的事件,见上event
assert(balanceOf[_from]+balanceOf[_to]==previousBalances);//判断总额是否一致,避免过程出错
}
function transfer(address _to,uint256 _value)public{
_transfer(msg.sender,_to,_value);//这里已经储存了合约创建者的信息,这个函数是只能被合约创建者使用
}
function transferFrom(address _from,address _to,uint256 _value)public returns(bool success){
require(_value<=allowance_from);//这句很重要,地址对应的合约地址(也就是token余额)
allowance_from-=_value;
_transfer(_from,_to,_value);
return true;
}
function approve(address _spender,uint256 _value)public
returns(bool success){
allowancemsg.sender=_value;//这里是可花费总量
return true;
}
function approveAndCall(address _spender,uint256 _value,bytes _extraData)public returns(bool success){
tokenRecipient spender=tokenRecipient(_spender);
if(approve(_spender,_value)){
spender.receiveApproval(msg.sender,_value,this,_extraData);
return true;
}
}
//正如其名,这个是烧币(SB)的..,用于把创建者的token烧掉
function burn(uint256 _value)public returns(bool success){
require(balanceOf[msg.sender]>=_value);//必须要有这么多
balanceOf[msg.sender]-=_value;
totalSupply-=_value;
Burn(msg.sender,_value);
return true;
}
//这个是用户销毁token.....
function burnFrom(address _from,uint256 _value)public returns(bool success){
require(balanceOf[_from]>=_value);//一样要有这么多
require(_value<=allowance_from);//
balanceOf[_from]-=_value;
allowance_from-=_value;
totalSupply-=_value;
Burn(_from,_value);
return true;
}
}
上面的代码阅读难度不大,也写了大多处的注释,这里简单介绍几个要点:
构造函数
//这里是构造函数,实例创建时候执行
function TokenERC20(uint256 initialSupply,string tokenName,string tokenSymbol)public{
totalSupply=initialSupply10*uint256(decimals);//这里确定了总发行量
balanceOf[msg.sender]=totalSupply;//这里就比较重要,这里相当于实现了,把token全部给合约的Creator
name=tokenName;
symbol=tokenSymbol;
}
在Solidity里面,Contract我们可以直接理解成一个Class吧,如C++一样,这里面也存在一个构造函数而且他们的功能也是近乎相同,在合约创建的时候执行一次.(没错,合约整个生命周期里只能执行这样一次),所以他的作用就是实现合约信息的初始化,一旦数据写入区块数据,将是无法更改的了(永固性).
构造函数的是不能有返回值的(有也无法接受),但是可以带参数,像是此处代码,把发行量,token的名称和token的符号作为参数留出.在合约初始化时候我们便可以自行定义.
函数体中可见,我们对货币总量,名称和符号进行赋值,这样,这些值就永远的记录在了我们的合约的区块数据中了
映射(mapping)
//建立映射地址对应了uint'便是他的余额
mapping(address=>uint256)public balanceOf;
//地址对应余额
mapping(address=>mapping(address=>uint256))public allowance;