首先,为什么使用SafeMath?

为避免程序结果产生溢出,开发者应在运算中使用SafeMath。

何为溢出?

以太坊虚拟机(EVM)为整数指定固定大小的数据类型。这意味着一个整型变量只能有一定范围的数字表示。例如,一个 uint8 ,只能存储在范围 [0,255] 的数字。试图存储 256 到一个 uint8 将变成 0。不加注意的话,只要没有检查用户输入又执行计算,导致数字超出存储它们的数据类型允许的范围,Solidity 中的变量就可以被用来组织攻击。

整数溢出的类型包括乘法溢出,加法溢出,减法溢出三种。

解决方案:1.在涉及到运算之前,先进行溢出判断,保证计算出的数据不超出此数据类型的表示范围。2.直接使用SafeMath库函数进行计算。

SafeMath的使用

第一步:导入SafeMath库文件

pragma solidity >=0.4.22 <0.6.0;

/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error
 */

library SafeMath {
    /**
     * @dev Multiplies two unsigned integers, reverts on overflow.
     */
    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);

        return c;
    }

    /**
     * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Adds two unsigned integers, reverts on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);

        return c;
    }

    /**
     * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
     * reverts when dividing by zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}

第二步,引用

pragma solidity >=0.4.22 <0.6.0;

import "./safemath.sol";

contract jisuan{
    uint a=2;
    uint b=5;
    uint c=8;
    //引入safemath库
    using SafeMath for uint256;
    
    //加法
    function addNum()public view returns(uint d){
        d=a.add(b);
    }
    //减法
    function subNum()public view returns(uint d){
        d=b.sub(a);
    }
    //乘法
    function mulNum()public view returns(uint d){
        d=a.mul(b);
    }
    //除法
    function divNum()public view returns(uint d){
        d=c.div(a);
    }
}

using for 的使用

1.与import的联系与区别

import是讲某个合约contract或者某个库lib导入到当前文件,它是using的前提;import后,当前文件内可以引用被引入文件内定义的library或contract。 
举个栗子: 
 


这里,如果没有先import,直接using,会报错。除非别的被import的文件再import了它。换句换说,就是

using的前提是需要直接或者间接的导入某个library.

using A for B,这里A通常是某个library里面定义的某个方法,B是某种数据类型,这句话是把A方法绑定到B类型上,相当于给B类型附加了一个A方法。(也有翻译为附着库的) 
在上面的例子中,将LibContract里定义的方法绑定到所有的数据类型。但是一般我们不会在所有的类型实例上都去调用LibContract的方法,应该是要按需using的,这里偷懒就写*。 
在通俗一点的例子就是, 
比如 using LibInt for uint,然后LibInt里面有定义一个toString方法。我们有一个uint a;那么可以这样调用a.toString(),toString方法在定义的时候,第一个参数会是一个uint类型的变量,表示调用者。

using A for B,  A的函数的第一个参数必须和B的数据类型一致。

还有这个方法是可以重载的,你可以定义好几个同名的方法,但是第一个参数的类型不同,调用的时候自动的根据调用类型选择某一种方法。
 

关于using for 可以参考:https://blog.csdn.net/qq_33764491/article/details/80604887

 

 

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐