代码段学习笔记
代码来源:Webase合约仓库
我只做了增加注释的工作用来记录相关知识点。
pragma solidity ^0.4.24;
import "./SafeMath.sol";
import "./Roles.sol";
import "./Address.sol";
contract IssuerRole {
using Roles for Roles.Role; 给Role合约里的role结构体附加Role里的三个函数功能
event IssuerAdded(address indexed account);
event IssuerRemoved(address indexed account);
Roles.Role private _issuers;
constructor () internal { //初始化合约,合约的发起者拥有权限
_addIssuer(msg.sender);
}
modifier onlyIssuer() { //修饰器 用来设置执行函数前的检查条件
require(isIssuer(msg.sender), "IssuerRole: caller does not have the Issuer role");
_; //执行函数的代码段
}
function isIssuer(address account) public view returns (bool) { //判断是否有权限
return _issuers.has(account);
}
function addIssuer(address account) public onlyIssuer { //只有有权限的角色才能赋予别人权限
_addIssuer(account);
}
function renounceIssuer() public { //移除权限 (这边代码有点怪:把自己权限删了?)
_removeIssuer(msg.sender);
}
function _addIssuer(address account) internal {
_issuers.add(account);
emit IssuerAdded(account);
}
function _removeIssuer(address account) internal {
_issuers.remove(account);
emit IssuerRemoved(account);
}
}
contract SuspenderRole {
using Roles for Roles.Role;
event SuspenderAdded(address indexed account);
event SuspenderRemoved(address indexed account);
Roles.Role private _suspenders;
constructor () internal {
_addSuspender(msg.sender);
}
modifier onlySuspender() {
require(isSuspender(msg.sender), "SuspenderRole: caller does not have the Suspender role");
_;
}
function isSuspender(address account) public view returns (bool) {
return _suspenders.has(account);
}
function addSuspender(address account) public onlySuspender {
_addSuspender(account);
}
function renounceSuspender() public {
_removeSuspender(msg.sender);
}
function _addSuspender(address account) internal {
_suspenders.add(account);
emit SuspenderAdded(account);
}
function _removeSuspender(address account) internal {
_suspenders.remove(account);
emit SuspenderRemoved(account);
}
}
contract Suspendable is SuspenderRole { / //继承合约
event Suspended(address account);
event UnSuspended(address account);
bool private _suspended;
constructor () internal {
_suspended = false;
}
/**
* @return True if the contract is suspended, false otherwise.
*/
function suspended() public view returns (bool) {
return _suspended;
}
/**
* @dev Modifier to make a function callable only when the contract is not suspended.
*/
modifier whenNotSuspended() {
require(!_suspended, "Suspendable: suspended");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is suspended.
*/
modifier whenSuspended() {
require(_suspended, "Suspendable: not suspended");
_;
}
/**
* @dev Called by a Suspender to suspend, triggers stopped state.
*/
function suspend() public onlySuspender whenNotSuspended {
_suspended = true;
emit Suspended(msg.sender);
}
/**
* @dev Called by a Suspender to unSuspend, returns to normal state.
*/
function unSuspend() public onlySuspender whenSuspended {
_suspended = false;
emit UnSuspended(msg.sender);
}
}
contract IBAC001Receiver { //抽象合约
/**
* @notice Handle the receipt of an NFT
* @dev The BAC001 smart contract calls this function on the recipient
*/
function onBAC001Received(address operator, address from, uint256 value, bytes data)
public returns (bytes4);
}
contract BAC001Holder is IBAC001Receiver {
function onBAC001Received(address, address, uint256, bytes) public returns (bytes4) {
return this.onBAC001Received.selector;
//表示获取当前合约中onBAC001Received函数的选择器(即函数签名)。Solidity编译器会根据函数名称和参数列表生成相应的函数选择器。这个选择器可以用来唯一地标识一个函数。
}
}
/**
* @title Standard BAC001 asset
*/
contract BAC001 is IssuerRole, Suspendable {
using SafeMath for uint256;
using Address for address;
mapping(address => uint256) private _balances; //地址映射代币余额
mapping(address => mapping(address => uint256)) private _allowed; //地址映射到被允许代表其花费代币的地址
//相当于一个二维映射,可以将这个二维映射看作是一个表格,其中每行表示代币的一个所有者(owner),每列表示被授权者(spender)。因此,通过在表格中指定一个所有者(owner)和一个被授权者(spender),可以获得被授权者(spender)可以花费的代币数量。比如_allowed[0x1111][0x2222] = 100;
uint256 private _totalAmount; //代币总量
string private _description;
string private _shortName;
uint8 private _minUnit; //代表代币的最小单位
// Equals to `bytes4(keccak256("onBAC001Received(address,address,uint256,bytes)"))`
bytes4 private constant _BAC001_RECEIVED = 0xc73d16ae; //函数签名是由函数名和函数参数类型组成的哈希值,用于唯一标识函数。 用于在代币转移过程中通知合约的接收方(通常是另一个智能合约),以便接收方可以采取相应的操作,如检查代币的有效性等。
event Send( address indexed from, address indexed to, uint256 value, bytes data);
event Approval( address indexed owner, address indexed spender, uint256 value);
constructor(string memory description, string memory shortName, uint8 minUnit, uint256 totalAmount) public {
_description = description;
_shortName = shortName;
_minUnit = minUnit;
_issue(msg.sender, totalAmount * (10 ** uint256(minUnit)), "");
}
function totalAmount() public view returns (uint256) {
return _totalAmount;
}
function balance(address owner) public view returns (uint256) {
return _balances[owner];
}
/**
* @dev Function to check the amount of assets that an owner allowed to a spender.
*/
function allowance(address owner, address spender) public view returns (uint256) {
return _allowed[owner][spender];
}
function send(address to, uint256 value, bytes data) public whenNotSuspended {
_send(msg.sender, to, value, data);
require(_checkOnBAC001Received(msg.sender, to, value, data), "BAC001: send to non BAC001Receiver implementer");
}
// function safeSend(address to, uint256 value, bytes data) public whenNotSuspended {
// send(to, value, data);
// require(_checkOnBAC001Received(msg.sender, to, value, data), "BAC001: send to non BAC001Receiver implementer");
// }
/**
* @dev Approve the passed address to spend the specified amount of assets on behalf of msg.sender.
*/
function approve(address spender, uint256 value) public whenNotSuspended returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
/**
* @dev Send assets from one address to another.
*/
function sendFrom(address from, address to, uint256 value, bytes data) public whenNotSuspended {
_send(from, to, value, data);
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
//add
require(_checkOnBAC001Received(from, to, value, data), "BAC001: send to non BAC001Receiver implementer");
}
safe todo
// function safeSendFrom(address from, address to, uint256 value, bytes data) public whenNotSuspended {
// sendFrom(from, to, value, data);
// require(_checkOnBAC001Received(from, to, value, data), "BAC001: send to non BAC001Receiver implementer");
// }
function batchSend(address[] to, uint256[] values, bytes data) public whenNotSuspended {
// MUST Throw on errors
require(to.length == values.length, "to and values array lenght must match.");
for (uint256 i = 0; i < to.length; ++i) {
require(to[i] != address(0x0), "destination address must be non-zero.");
send(to[i], values[i], data);
}
}
function _checkOnBAC001Received(address from, address to, uint256 value, bytes data)
internal returns (bool)
{
if (!to.isContract()) {
return true;
}
bytes4 retval = IBAC001Receiver(to).onBAC001Received(from, to, value, data);
return (retval == _BAC001_RECEIVED);
}
/**
* @dev Increase the amount of assets that an owner allowed to a spender.
*/
function increaseAllowance(address spender, uint256 addedValue) public whenNotSuspended returns (bool) {
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Decrease the amount of assets that an owner allowed to a spender.
* approve should be called when _allowed[msg.sender][spender] == 0. To decrement
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public whenNotSuspended returns (bool) {
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
return true;
}
function destroy(uint256 value, bytes data) public {
_destroy(msg.sender, value, data);
}
/**
* @dev Burns a specific amount of assets from the target address and decrements allowance.
*/
function destroyFrom(address from, uint256 value, bytes data) public {
_destroyFrom(from, value, data);
}
function description() public view returns (string memory) {
return _description;
}
/**
* @return the shortName of the asset.
*/
function shortName() public view returns (string memory) {
return _shortName;
}
/**
* @return the number of minUnit of the asset.
*/
function minUnit() public view returns (uint8) {
return _minUnit;
}
function issue(address to, uint256 value, bytes data) public onlyIssuer returns (bool) {
_issue(to, value, data);
return true;
}
/**
* @dev Send asset for a specified addresses.
*/
function _send(address from, address to, uint256 value, bytes data) internal {
require(to != address(0), "BAC001: send to the zero address");
_balances[from] = _balances[from].sub(value);
_balances[to] = _balances[to].add(value);
emit Send( from, to, value, data);
}
/**
* @dev Internal function that issues an amount of the asset and assigns it to
*/
function _issue(address account, uint256 value, bytes data) internal {
require(account != address(0), "BAC001: issue to the zero address");
_totalAmount = _totalAmount.add(value);
_balances[account] = _balances[account].add(value);
emit Send( address(0), account, value, data);
}
/**
* @dev Internal function that destroys an amount of the asset of a given
*/
function _destroy(address account, uint256 value, bytes data) internal {
require(account != address(0), "BAC001: destroy from the zero address");
_totalAmount = _totalAmount.sub(value);
_balances[account] = _balances[account].sub(value);
emit Send( account, address(0), value, data);
}
/**
* @dev Approve an address to spend another addresses' assets.
*/
function _approve(address owner, address spender, uint256 value) internal {
require(owner != address(0), "BAC001: approve from the zero address");
require(spender != address(0), "BAC001: approve to the zero address");
_allowed[owner][spender] = value;
emit Approval( owner, spender, value);
}
/**
* @dev Internal function that destroys an amount of the asset of a given
*/
function _destroyFrom(address account, uint256 value, bytes data) internal {
_destroy(account, value, data);
_approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
}
}
pragma solidity ^0.4.24;
//检查地址是否为合约地址和是否为零地址
library Address {
function isContract(address addr) internal view returns(bool) {
uint256 size;
assembly { size := extcodesize(addr) }
return size > 0;
}//在汇编代码中使用extcodesize指令来检查给定地址上的代码长度,如果长度大于0,则说明该地址是一个合约地址,返回true;否则,它是一个非合约地址,返回false。
function isEmptyAddress(address addr) internal pure returns(bool){
return addr == address(0);
}
}
pragma solidity ^0.4.24;
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}
pragma solidity ^0.4.24;
library Roles {
struct Role {
mapping (address => bool) bearer;
}
function add(Role storage role, address account) internal {
require(!has(role, account), "Roles: account already has role");
role.bearer[account] = true;
}
function remove(Role storage role, address account) internal {
require(has(role, account), "Roles: account does not have role");
role.bearer[account] = false;
}
function has(Role storage role, address account) internal view returns (bool) {
require(account != address(0), "Roles: account is the zero address");
return role.bearer[account];
}
}