Solidity学习笔记2——Webase积分合约

这篇文章展示了如何使用Solidity编写智能合约,包括权限角色(IssuerRole,SuspenderRole)的实现,以及Suspendable合约用于控制合约暂停和恢复。合约中包含了事件(events)来记录状态变化,以及使用SafeMath库进行安全计算。此外,还涉及了合约之间的交互,如BAC001Holder合约实现IBAC001Receiver接口,用于处理代币接收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码段学习笔记

代码来源: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];
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值