require和assert区别(知识补充)
if(msg.sender != admin) { throw; }等价于require(msg.sender==admin),require()是新版的用法
以下场景使用 require() :
验证用户输入,即: require(input<20);
验证外部合约响应,即: require(external.send(amount));
执行合约前,验证状态条件,即: require(balance[msg.sender]>=amount)
一般地,尽量使用 require 函数
一般地,require 应该在函数最开始的地方使用。
以下场景使用 assert():
检查 overflow/underflow,即:c = a+b; assert(c > b)
检查非变量(invariants),即:assert(this.balance >= totalSupply);
验证改变后的状态
预防不应该发生的条件
一般地,尽量少使用 assert 调用
一般地,assert 应该在函数结尾处使用
基本上,require() 应该被用于函数中检查条件,assert() 用于预防不应该发生的情况,但不应该使条件错误。
Token代码详解
pragma solidity ^0.4.25;
声明使用的solidity语言版本
interface tokenRecipient{
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public;}
声明一个接口receiveApproval,可以和继承该接口的其他合约互相调用,interface是声明接口的关键字。
contract Token{
string public name;//代币名
string public symbol; //代币简称
uint8 public decimals = 2; // 定义token使用的小数点后几位,
//2即为后面两位数为小数点后的数
uint256 public totalSupply; //总发行量
address admin; //管理员地址
声明Token的各项基本属性
mapping(address => uint256) public balanceOf; // 用于返回某个地址的账户余额
声明一个映射类型的变量balanceOf,存储每个账户对应的余额(剩余Token数量)
mapping(address => mapping(address => uint256)) public allowance;
//返回_spender仍然被允许从_owner提取的金额
映射型变量allowance,表示存储账户允许第三方代理的余额数目(Token数),只要第三方进行的操作不超过这个余额数,想干什么就干什么。
event Transfer(address indexed from, address indexed to, uint256 value);
//货币转移,value:转移数量,from,to:转移地址
event Burn(address indexed from, uint256 value);//烧钱
触发该事件时,将参数信息传输给客户端,告知执行了该操作,即该事件发生。
modifier onlyAdmin(){
require(msg.sender == admin);
_;
}
判断是否是管理者
constructor(uint256 initialSupply, string tokenName, string tokenSymbol) public {
// require(admin == msg.sender);
totalSupply = initialSupply * 10 ** uint256(decimals);//小数点后两位00,无小数点
balanceOf[msg.sender] = totalSupply;
//初始化初始余额为初始供应量,msg.sender是全局变量,表示当前调用者的用户地址
name = tokenName;//初始化代币名称
symbol = tokenSymbol;//初始化简称
构造函数初始化

function _transfer(address _from, address _to, uint256 _value) internal {
//require用于执行合约前验证状态条件
require(_to != 0x0); // address can't be null
require(balanceOf[_from] >= _value);//检验可用余额是否充足
require(balanceOf[_to] + _value > balanceOf[_to]);//防止value是负数
uint previousBalances = balanceOf[_from] + balanceOf[_to];
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
emit Transfer(_from, _to, _value);
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);//检查非变量
}
转账函数,Transfer()这行代码会向区块链上的全部客户端广播一个事件,即从谁哪里转走多少钱给谁。
function transferTo(address _to, uint256 _value) public returns(bool success) {
require(_to != 0x0);
_transfer(msg.sender, _to, _value);//调用_transfer()
return true;
}
执行该函数,从admin账户转账给其他账户,指定被转账方
function transferFrom(address _from, address _to, uint256 _value) payable public returns(bool success){
require(_value <= allowance[_from][_to],"allowance is not enough");
allowance[_from][_to] -= _value;
_transfer(_from, _to, _value);
return true;
}
transferFrom方法用于允许代理第三方转移token,
require(_value <= allowance[_from][_to];
_from是授权方,_to是代理方,allowance即为授权方给代理方的可使用余额数,这行代码作用为检验代理的余额数是否足够交易的余额数执行操作。
若能正常执行,则代理的余额数减少,同时减少的这部分余额转账到另一个账户。
function approve(address _spender, uint256 _value) public returns (bool success){
allowance[msg.sender][_spender] = _value;//_spender能调用msg.sender多少token
return true;
}
approve是授权第三方(比如某个服务合约)从发送者账户转移代币,然后通过 transferFrom() 函数来执行具体的转移操作。
这行代码用于选择第三方账户和初始化第三方可代理授权方的Token数量。
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success){
tokenRecipient spender = tokenRecipient(_spender);
if(approve(_spender, _value)){
// inform contract
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
和approve()方法基本差别不大,但是调用了spender的**receiveApproval()**方法,但是前提是 spender实现了这个方法
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;//钱消失啦
totalSupply -= _value;//总供应量减少
emit Burn(msg.sender, _value);//说明该事件触发
return true;
}
烧钱操作,执行该函数后,msg.sender账户余额减少,减少的钱完全消失,Token总发行量也减少,当然前提是账户中有足够的钱来烧啦。
function burnFrom(address _from, uint256 _value) public returns (bool success){
require(balanceOf[msg.sender] >= _value);
require(_value <= allowance[_from][msg.sender]);
balanceOf[_from] -= _value;
allowance[_from][msg.sender] -= _value;
totalSupply -= _value;
emit Burn(_from, _value);
return true;
}
与上面函数不同,burn()可以理解为自己烧自己的钱。
burnFrom()为由代理第三方来烧授权方的钱,可烧钱的数量小于第三方代理的余额数。
执行该操作后,授权方(即_from总余额减少),第三方(_to代理余额数allowance减少),Token总发行量减少。
function getBalanceOf(address _account) public returns(uint256){
return balanceOf[_account];
}
function getAllowanceOf(address _from,address _to) public returns(uint256){
return allowance[_from][_to];
}
function test(address _from) public view returns (uint256) {
return balanceOf[_from];
}
}
返回账户余额数,可代理余额数。