Michael.W基于Foundry精读Openzeppelin第12期——SafeCast.sol

  • Michael.W
  • 更新于 2023-07-23 17:40
  • 阅读 1180

SafeCast库提供了solidity的基础整数类型uintX和intX之间的类型安全转换的库方法。在不同的类型转换之间都加入溢出检查,如果一旦在转换过程中出现类型的溢出会立刻revert。

0. 版本

[openzeppelin]:v4.8.3,[forge-std]:v1.5.6

0.1 SafeCast.sol

Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/math/SafeCast.sol

SafeCast库提供了solidity的基础整数类型uintX和intX之间的类型安全转换的库方法。在不同的类型转换之间都加入溢出检查,如果一旦在转换过程中出现类型的溢出会立刻revert。

solidity中从uint256/int256向位数更小的整形做类型转换时可能会在小位数的整形上出现溢出,但是solidity是不会revert的。这种solidity的默认行为很容易产生bug。如果你的程序中有使用到uint256/int256向低位数整数的转换,推荐在每一处类型转换的地方使用SafeCast库。

1. 目标合约

封装SafeCast library成为一个可调用合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/utils/math/MockSafeCast.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/utils/math/SafeCast.sol";

contract MockSafeCast {
    using SafeCast for uint;
    using SafeCast for int;

    function toUint248(uint256 value) external pure returns (uint248) {
        return value.toUint248();
    }

    function toUint240(uint256 value) external pure returns (uint240) {
        return value.toUint240();
    }

    function toUint232(uint256 value) external pure returns (uint232){
        return value.toUint232();
    }

    function toUint224(uint256 value) external pure returns (uint224){
        return value.toUint224();
    }

    function toUint216(uint256 value) external pure returns (uint216){
        return value.toUint216();
    }

    function toUint208(uint256 value) external pure returns (uint208){
        return value.toUint208();
    }

    function toUint200(uint256 value) external pure returns (uint200){
        return value.toUint200();
    }

    function toUint192(uint256 value) external pure returns (uint192) {
        return value.toUint192();
    }

    function toUint184(uint256 value) external pure returns (uint184){
        return value.toUint184();
    }

    function toUint176(uint256 value) external pure returns (uint176){
        return value.toUint176();
    }

    function toUint168(uint256 value) external pure returns (uint168){
        return value.toUint168();
    }

    function toUint160(uint256 value) external pure returns (uint160){
        return value.toUint160();
    }

    function toUint152(uint256 value) external pure returns (uint152){
        return value.toUint152();
    }

    function toUint144(uint256 value) external pure returns (uint144){
        return value.toUint144();
    }

    function toUint136(uint256 value) external pure returns (uint136){
        return value.toUint136();
    }

    function toUint128(uint256 value) external pure returns (uint128) {
        return value.toUint128();
    }

    function toUint120(uint256 value) external pure returns (uint120) {
        return value.toUint120();
    }

    function toUint112(uint256 value) external pure returns (uint112) {
        return value.toUint112();
    }

    function toUint104(uint256 value) external pure returns (uint104) {
        return value.toUint104();
    }

    function toUint96(uint256 value) external pure returns (uint96){
        return value.toUint96();
    }

    function toUint88(uint256 value) external pure returns (uint88){
        return value.toUint88();
    }

    function toUint80(uint256 value) external pure returns (uint80){
        return value.toUint80();
    }

    function toUint72(uint256 value) external pure returns (uint72){
        return value.toUint72();
    }

    function toUint64(uint256 value) external pure returns (uint64){
        return value.toUint64();
    }

    function toUint56(uint256 value) external pure returns (uint56) {
        return value.toUint56();
    }

    function toUint48(uint256 value) external pure returns (uint48){
        return value.toUint48();
    }

    function toUint40(uint256 value) external pure returns (uint40){
        return value.toUint40();
    }

    function toUint32(uint256 value) external pure returns (uint32) {
        return value.toUint32();
    }

    function toUint24(uint256 value) external pure returns (uint24){
        return value.toUint24();
    }

    function toUint16(uint256 value) external pure returns (uint16){
        return value.toUint16();
    }

    function toUint8(uint256 value) external pure returns (uint8){
        return value.toUint8();
    }

    function toUint256(int256 value) internal pure returns (uint256) {
        return value.toUint256();
    }

    function toInt248(int256 value) internal pure returns (int248){
        return value.toInt248();
    }

    function toInt240(int256 value) internal pure returns (int240){
        return value.toInt240();
    }

    function toInt232(int256 value) internal pure returns (int232){
        return value.toInt232();
    }

    function toInt224(int256 value) internal pure returns (int224) {
        return value.toInt224();
    }

    function toInt216(int256 value) internal pure returns (int216) {
        return value.toInt216();
    }

    function toInt208(int256 value) internal pure returns (int208) {
        return value.toInt208();
    }

    function toInt200(int256 value) internal pure returns (int200) {
        return value.toInt200();
    }

    function toInt192(int256 value) internal pure returns (int192) {
        return value.toInt192();
    }

    function toInt184(int256 value) internal pure returns (int184) {
        return value.toInt184();
    }

    function toInt176(int256 value) internal pure returns (int176) {
        return value.toInt176();
    }

    function toInt168(int256 value) internal pure returns (int168) {
        return value.toInt168();
    }

    function toInt160(int256 value) internal pure returns (int160) {
        return value.toInt160();
    }

    function toInt152(int256 value) internal pure returns (int152) {
        return value.toInt152();
    }

    function toInt144(int256 value) internal pure returns (int144) {
        return value.toInt144();
    }

    function toInt136(int256 value) internal pure returns (int136) {
        return value.toInt136();
    }

    function toInt128(int256 value) internal pure returns (int128) {
        return value.toInt128();
    }

    function toInt120(int256 value) internal pure returns (int120) {
        return value.toInt120();
    }

    function toInt112(int256 value) internal pure returns (int112) {
        return value.toInt112();
    }

    function toInt104(int256 value) internal pure returns (int104) {
        return value.toInt104();
    }

    function toInt96(int256 value) internal pure returns (int96) {
        return value.toInt96();
    }

    function toInt88(int256 value) internal pure returns (int88) {
        return value.toInt88();
    }

    function toInt80(int256 value) internal pure returns (int80) {
        return value.toInt80();
    }

    function toInt72(int256 value) internal pure returns (int72) {
        return value.toInt72();
    }

    function toInt64(int256 value) internal pure returns (int64) {
        return value.toInt64();
    }

    function toInt56(int256 value) internal pure returns (int56) {
        return value.toInt56();
    }

    function toInt48(int256 value) internal pure returns (int48) {
        return value.toInt48();
    }

    function toInt40(int256 value) internal pure returns (int40) {
        return value.toInt40();
    }

    function toInt32(int256 value) internal pure returns (int32){
        return value.toInt32();
    }

    function toInt24(int256 value) internal pure returns (int24){
        return value.toInt24();
    }

    function toInt16(int256 value) internal pure returns (int16) {
        return value.toInt16();
    }

    function toInt8(int256 value) internal pure returns (int8){
        return value.toInt8();
    }

    function toInt256(uint256 value) internal pure returns (int256) {
        return value.toInt256();
    }
}

全部foundry测试合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/utils/math/SafeCast.t.sol

2. 代码精读

SafeCast库中函数众多,但是可以按照以下类别分组:

  • uint256向uintX的转换(X<256);
  • int256向intX的转换(X<256);
  • uint256和int256之间的互转。

这样,通过组合使用该库的库函数,就可以将uint256或int256安全地转换成各种小位数的有符号或无符号整形。

2.1 uint256 -> uintX (X<256)

以uint256 -> uint248举例:

function toUint248(uint256 value) internal pure returns (uint248) {
    // 判断输入的uint256的值&lt;=uint248类型的最大值,这样才能保证在类型转换的过程中不发生溢出
    // 如果不满足value>uint248类型的最大值,revert
    require(value &lt;= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
    // 类型转换,从uint256转换为uint248
    return uint248(value);
 }

foundry代码验证

contract SafeCastTest is Test {
    MockSafeCast msf = new MockSafeCast();

    function test_ToUint248() external {
        uint maxUint248 = type(uint248).max;
        assertEq(msf.toUint248(0), 0);
        assertEq(msf.toUint248(1), 1);
        assertEq(msf.toUint248(maxUint248), uint248(maxUint248));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 248 bits");
        msf.toUint248(maxUint248 + 1);
    }

    function test_ToUint240() external {
        uint maxUint240 = type(uint240).max;
        assertEq(msf.toUint240(0), 0);
        assertEq(msf.toUint240(1), 1);
        assertEq(msf.toUint240(maxUint240), uint240(maxUint240));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 240 bits");
        msf.toUint240(maxUint240 + 1);
    }

    function test_ToUint232() external {
        uint maxUint232 = type(uint232).max;
        assertEq(msf.toUint232(0), 0);
        assertEq(msf.toUint232(1), 1);
        assertEq(msf.toUint232(maxUint232), uint232(maxUint232));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 232 bits");
        msf.toUint232(maxUint232 + 1);
    }

    function test_ToUint224() external {
        uint maxUint224 = type(uint224).max;
        assertEq(msf.toUint224(0), 0);
        assertEq(msf.toUint224(1), 1);
        assertEq(msf.toUint224(maxUint224), uint224(maxUint224));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 224 bits");
        msf.toUint224(maxUint224 + 1);
    }

    function test_ToUint216() external {
        uint maxUint216 = type(uint216).max;
        assertEq(msf.toUint216(0), 0);
        assertEq(msf.toUint216(1), 1);
        assertEq(msf.toUint216(maxUint216), uint216(maxUint216));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 216 bits");
        msf.toUint216(maxUint216 + 1);
    }

    function test_ToUint208() external {
        uint maxUint208 = type(uint208).max;
        assertEq(msf.toUint208(0), 0);
        assertEq(msf.toUint208(1), 1);
        assertEq(msf.toUint208(maxUint208), uint208(maxUint208));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 208 bits");
        msf.toUint208(maxUint208 + 1);
    }

    function test_ToUint200() external {
        uint maxUint200 = type(uint200).max;
        assertEq(msf.toUint200(0), 0);
        assertEq(msf.toUint200(1), 1);
        assertEq(msf.toUint200(maxUint200), uint200(maxUint200));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 200 bits");
        msf.toUint200(maxUint200 + 1);
    }

    function test_ToUint192() external {
        uint maxUint192 = type(uint192).max;
        assertEq(msf.toUint192(0), 0);
        assertEq(msf.toUint192(1), 1);
        assertEq(msf.toUint192(maxUint192), uint192(maxUint192));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 192 bits");
        msf.toUint192(maxUint192 + 1);
    }

    function test_ToUint184() external {
        uint maxUint184 = type(uint184).max;
        assertEq(msf.toUint184(0), 0);
        assertEq(msf.toUint184(1), 1);
        assertEq(msf.toUint184(maxUint184), uint184(maxUint184));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 184 bits");
        msf.toUint184(maxUint184 + 1);
    }

    function test_ToUint176() external {
        uint maxUint176 = type(uint176).max;
        assertEq(msf.toUint176(0), 0);
        assertEq(msf.toUint176(1), 1);
        assertEq(msf.toUint176(maxUint176), uint176(maxUint176));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 176 bits");
        msf.toUint176(maxUint176 + 1);
    }

    function test_ToUint168() external {
        uint maxUint168 = type(uint168).max;
        assertEq(msf.toUint168(0), 0);
        assertEq(msf.toUint168(1), 1);
        assertEq(msf.toUint168(maxUint168), uint168(maxUint168));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 168 bits");
        msf.toUint168(maxUint168 + 1);
    }

    function test_ToUint160() external {
        uint maxUint160 = type(uint160).max;
        assertEq(msf.toUint160(0), 0);
        assertEq(msf.toUint160(1), 1);
        assertEq(msf.toUint160(maxUint160), uint160(maxUint160));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 160 bits");
        msf.toUint160(maxUint160 + 1);
    }

    function test_ToUint152() external {
        uint maxUint152 = type(uint152).max;
        assertEq(msf.toUint152(0), 0);
        assertEq(msf.toUint152(1), 1);
        assertEq(msf.toUint152(maxUint152), uint152(maxUint152));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 152 bits");
        msf.toUint152(maxUint152 + 1);
    }

    function test_ToUint144() external {
        uint maxUint144 = type(uint144).max;
        assertEq(msf.toUint144(0), 0);
        assertEq(msf.toUint144(1), 1);
        assertEq(msf.toUint144(maxUint144), uint144(maxUint144));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 144 bits");
        msf.toUint144(maxUint144 + 1);
    }

    function test_ToUint136() external {
        uint maxUint136 = type(uint136).max;
        assertEq(msf.toUint136(0), 0);
        assertEq(msf.toUint136(1), 1);
        assertEq(msf.toUint136(maxUint136), uint136(maxUint136));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 136 bits");
        msf.toUint136(maxUint136 + 1);
    }

    function test_ToUint128() external {
        uint maxUint128 = type(uint128).max;
        assertEq(msf.toUint128(0), 0);
        assertEq(msf.toUint128(1), 1);
        assertEq(msf.toUint128(maxUint128), uint128(maxUint128));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 128 bits");
        msf.toUint128(maxUint128 + 1);
    }

    function test_ToUint120() external {
        uint maxUint120 = type(uint120).max;
        assertEq(msf.toUint120(0), 0);
        assertEq(msf.toUint120(1), 1);
        assertEq(msf.toUint120(maxUint120), uint120(maxUint120));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 120 bits");
        msf.toUint120(maxUint120 + 1);
    }

    function test_ToUint112() external {
        uint maxUint112 = type(uint112).max;
        assertEq(msf.toUint112(0), 0);
        assertEq(msf.toUint112(1), 1);
        assertEq(msf.toUint112(maxUint112), uint112(maxUint112));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 112 bits");
        msf.toUint112(maxUint112 + 1);
    }

    function test_ToUint104() external {
        uint maxUint104 = type(uint104).max;
        assertEq(msf.toUint104(0), 0);
        assertEq(msf.toUint104(1), 1);
        assertEq(msf.toUint104(maxUint104), uint104(maxUint104));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 104 bits");
        msf.toUint104(maxUint104 + 1);
    }

    function test_ToUint96() external {
        uint maxUint96 = type(uint96).max;
        assertEq(msf.toUint96(0), 0);
        assertEq(msf.toUint96(1), 1);
        assertEq(msf.toUint96(maxUint96), uint96(maxUint96));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 96 bits");
        msf.toUint96(maxUint96 + 1);
    }

    function test_ToUint88() external {
        uint maxUint88 = type(uint88).max;
        assertEq(msf.toUint88(0), 0);
        assertEq(msf.toUint88(1), 1);
        assertEq(msf.toUint88(maxUint88), uint88(maxUint88));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 88 bits");
        msf.toUint88(maxUint88 + 1);
    }

    function test_ToUint80() external {
        uint maxUint80 = type(uint80).max;
        assertEq(msf.toUint80(0), 0);
        assertEq(msf.toUint80(1), 1);
        assertEq(msf.toUint80(maxUint80), uint80(maxUint80));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 80 bits");
        msf.toUint80(maxUint80 + 1);
    }

    function test_ToUint72() external {
        uint maxUint72 = type(uint72).max;
        assertEq(msf.toUint72(0), 0);
        assertEq(msf.toUint72(1), 1);
        assertEq(msf.toUint72(maxUint72), uint72(maxUint72));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 72 bits");
        msf.toUint72(maxUint72 + 1);
    }

    function test_ToUint64() external {
        uint maxUint64 = type(uint64).max;
        assertEq(msf.toUint64(0), 0);
        assertEq(msf.toUint64(1), 1);
        assertEq(msf.toUint64(maxUint64), uint64(maxUint64));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 64 bits");
        msf.toUint64(maxUint64 + 1);
    }

    function test_ToUint56() external {
        uint maxUint56 = type(uint56).max;
        assertEq(msf.toUint56(0), 0);
        assertEq(msf.toUint56(1), 1);
        assertEq(msf.toUint56(maxUint56), uint56(maxUint56));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 56 bits");
        msf.toUint56(maxUint56 + 1);
    }

    function test_ToUint48() external {
        uint maxUint48 = type(uint48).max;
        assertEq(msf.toUint48(0), 0);
        assertEq(msf.toUint48(1), 1);
        assertEq(msf.toUint48(maxUint48), uint48(maxUint48));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 48 bits");
        msf.toUint48(maxUint48 + 1);
    }

    function test_ToUint40() external {
        uint maxUint40 = type(uint40).max;
        assertEq(msf.toUint40(0), 0);
        assertEq(msf.toUint40(1), 1);
        assertEq(msf.toUint40(maxUint40), uint40(maxUint40));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 40 bits");
        msf.toUint40(maxUint40 + 1);
    }

    function test_ToUint32() external {
        uint maxUint32 = type(uint32).max;
        assertEq(msf.toUint32(0), 0);
        assertEq(msf.toUint32(1), 1);
        assertEq(msf.toUint32(maxUint32), uint32(maxUint32));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 32 bits");
        msf.toUint32(maxUint32 + 1);
    }

    function test_ToUint24() external {
        uint maxUint24 = type(uint24).max;
        assertEq(msf.toUint24(0), 0);
        assertEq(msf.toUint24(1), 1);
        assertEq(msf.toUint24(maxUint24), uint24(maxUint24));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 24 bits");
        msf.toUint24(maxUint24 + 1);
    }

    function test_ToUint16() external {
        uint maxUint16 = type(uint16).max;
        assertEq(msf.toUint16(0), 0);
        assertEq(msf.toUint16(1), 1);
        assertEq(msf.toUint16(maxUint16), uint16(maxUint16));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 16 bits");
        msf.toUint16(maxUint16 + 1);
    }

    function test_ToUint8() external {
        uint maxUint8 = type(uint8).max;
        assertEq(msf.toUint8(0), 0);
        assertEq(msf.toUint8(1), 1);
        assertEq(msf.toUint8(maxUint8), uint8(maxUint8));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 8 bits");
        msf.toUint8(maxUint8 + 1);
    }
}

2.2 int256 -> intX (X<256)

以int256 -> int248举例:

 function toInt248(int256 value) internal pure returns (int248 downcasted) {
    // downcasted为直接做有符号整数向小位数有符号整数的类型强转
    downcasted = int248(value);
    // 要求转换后的有符号整形同转换前相等,否则就是在转换的过程中产生了溢出
    require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
 }

注:当输入值value的值大于int248的最大值或小于int248的最小值时,进行类型转换时会产生溢出。

foundry代码验证

contract SafeCastTest is Test {
    MockSafeCast msf = new MockSafeCast();

    function test_ToInt248() external {
        int maxInt248 = type(int248).max;
        int minInt248 = type(int248).min;
        assertEq(msf.toInt248(0), 0);
        assertEq(msf.toInt248(1), 1);
        assertEq(msf.toInt248(maxInt248), int248(maxInt248));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 248 bits");
        msf.toInt248(maxInt248 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 248 bits");
        msf.toInt248(minInt248 - 1);
    }

    function test_ToInt240() external {
        int maxInt240 = type(int240).max;
        int minInt240 = type(int240).min;
        assertEq(msf.toInt240(0), 0);
        assertEq(msf.toInt240(1), 1);
        assertEq(msf.toInt240(maxInt240), int240(maxInt240));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 240 bits");
        msf.toInt240(maxInt240 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 240 bits");
        msf.toInt240(minInt240 - 1);
    }

    function test_ToInt232() external {
        int maxInt232 = type(int232).max;
        int minInt232 = type(int232).min;
        assertEq(msf.toInt232(0), 0);
        assertEq(msf.toInt232(1), 1);
        assertEq(msf.toInt232(maxInt232), int232(maxInt232));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 232 bits");
        msf.toInt232(maxInt232 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 232 bits");
        msf.toInt232(minInt232 - 1);
    }

    function test_ToInt224() external {
        int maxInt224 = type(int224).max;
        int minInt224 = type(int224).min;
        assertEq(msf.toInt224(0), 0);
        assertEq(msf.toInt224(1), 1);
        assertEq(msf.toInt224(maxInt224), int224(maxInt224));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 224 bits");
        msf.toInt224(maxInt224 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 224 bits");
        msf.toInt224(minInt224 - 1);
    }

    function test_ToInt216() external {
        int maxInt216 = type(int216).max;
        int minInt216 = type(int216).min;
        assertEq(msf.toInt216(0), 0);
        assertEq(msf.toInt216(1), 1);
        assertEq(msf.toInt216(maxInt216), int216(maxInt216));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 216 bits");
        msf.toInt216(maxInt216 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 216 bits");
        msf.toInt216(minInt216 - 1);
    }

    function test_ToInt208() external {
        int maxInt208 = type(int208).max;
        int minInt208 = type(int208).min;
        assertEq(msf.toInt208(0), 0);
        assertEq(msf.toInt208(1), 1);
        assertEq(msf.toInt208(maxInt208), int208(maxInt208));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 208 bits");
        msf.toInt208(maxInt208 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 208 bits");
        msf.toInt208(minInt208 - 1);
    }

    function test_ToInt200() external {
        int maxInt200 = type(int200).max;
        int minInt200 = type(int200).min;
        assertEq(msf.toInt200(0), 0);
        assertEq(msf.toInt200(1), 1);
        assertEq(msf.toInt200(maxInt200), int200(maxInt200));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 200 bits");
        msf.toInt200(maxInt200 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 200 bits");
        msf.toInt200(minInt200 - 1);
    }

    function test_ToInt192() external {
        int maxInt192 = type(int192).max;
        int minInt192 = type(int192).min;
        assertEq(msf.toInt192(0), 0);
        assertEq(msf.toInt192(1), 1);
        assertEq(msf.toInt192(maxInt192), int192(maxInt192));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 192 bits");
        msf.toInt192(maxInt192 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 192 bits");
        msf.toInt192(minInt192 - 1);
    }

    function test_ToInt184() external {
        int maxInt184 = type(int184).max;
        int minInt184 = type(int184).min;
        assertEq(msf.toInt184(0), 0);
        assertEq(msf.toInt184(1), 1);
        assertEq(msf.toInt184(maxInt184), int184(maxInt184));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 184 bits");
        msf.toInt184(maxInt184 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 184 bits");
        msf.toInt184(minInt184 - 1);
    }

    function test_ToInt176() external {
        int maxInt176 = type(int176).max;
        int minInt176 = type(int176).min;
        assertEq(msf.toInt176(0), 0);
        assertEq(msf.toInt176(1), 1);
        assertEq(msf.toInt176(maxInt176), int176(maxInt176));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 176 bits");
        msf.toInt176(maxInt176 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 176 bits");
        msf.toInt176(minInt176 - 1);
    }

    function test_ToInt168() external {
        int maxInt168 = type(int168).max;
        int minInt168 = type(int168).min;
        assertEq(msf.toInt168(0), 0);
        assertEq(msf.toInt168(1), 1);
        assertEq(msf.toInt168(maxInt168), int168(maxInt168));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 168 bits");
        msf.toInt168(maxInt168 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 168 bits");
        msf.toInt168(minInt168 - 1);
    }

    function test_ToInt160() external {
        int maxInt160 = type(int160).max;
        int minInt160 = type(int160).min;
        assertEq(msf.toInt160(0), 0);
        assertEq(msf.toInt160(1), 1);
        assertEq(msf.toInt160(maxInt160), int160(maxInt160));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 160 bits");
        msf.toInt160(maxInt160 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 160 bits");
        msf.toInt160(minInt160 - 1);
    }

    function test_ToInt152() external {
        int maxInt152 = type(int152).max;
        int minInt152 = type(int152).min;
        assertEq(msf.toInt152(0), 0);
        assertEq(msf.toInt152(1), 1);
        assertEq(msf.toInt152(maxInt152), int152(maxInt152));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 152 bits");
        msf.toInt152(maxInt152 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 152 bits");
        msf.toInt152(minInt152 - 1);
    }

    function test_ToInt144() external {
        int maxInt144 = type(int144).max;
        int minInt144 = type(int144).min;
        assertEq(msf.toInt144(0), 0);
        assertEq(msf.toInt144(1), 1);
        assertEq(msf.toInt144(maxInt144), int144(maxInt144));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 144 bits");
        msf.toInt144(maxInt144 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 144 bits");
        msf.toInt144(minInt144 - 1);
    }

    function test_ToInt136() external {
        int maxInt136 = type(int136).max;
        int minInt136 = type(int136).min;
        assertEq(msf.toInt136(0), 0);
        assertEq(msf.toInt136(1), 1);
        assertEq(msf.toInt136(maxInt136), int136(maxInt136));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 136 bits");
        msf.toInt136(maxInt136 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 136 bits");
        msf.toInt136(minInt136 - 1);
    }

    function test_ToInt128() external {
        int maxInt128 = type(int128).max;
        int minInt128 = type(int128).min;
        assertEq(msf.toInt128(0), 0);
        assertEq(msf.toInt128(1), 1);
        assertEq(msf.toInt128(maxInt128), int128(maxInt128));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 128 bits");
        msf.toInt128(maxInt128 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 128 bits");
        msf.toInt128(minInt128 - 1);
    }

    function test_ToInt120() external {
        int maxInt120 = type(int120).max;
        int minInt120 = type(int120).min;
        assertEq(msf.toInt120(0), 0);
        assertEq(msf.toInt120(1), 1);
        assertEq(msf.toInt120(maxInt120), int120(maxInt120));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 120 bits");
        msf.toInt120(maxInt120 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 120 bits");
        msf.toInt120(minInt120 - 1);
    }

    function test_ToInt112() external {
        int maxInt112 = type(int112).max;
        int minInt112 = type(int112).min;
        assertEq(msf.toInt112(0), 0);
        assertEq(msf.toInt112(1), 1);
        assertEq(msf.toInt112(maxInt112), int112(maxInt112));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 112 bits");
        msf.toInt112(maxInt112 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 112 bits");
        msf.toInt112(minInt112 - 1);
    }

    function test_ToInt104() external {
        int maxInt104 = type(int104).max;
        int minInt104 = type(int104).min;
        assertEq(msf.toInt104(0), 0);
        assertEq(msf.toInt104(1), 1);
        assertEq(msf.toInt104(maxInt104), int104(maxInt104));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 104 bits");
        msf.toInt104(maxInt104 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 104 bits");
        msf.toInt104(minInt104 - 1);
    }

    function test_ToInt96() external {
        int maxInt96 = type(int96).max;
        int minInt96 = type(int96).min;
        assertEq(msf.toInt96(0), 0);
        assertEq(msf.toInt96(1), 1);
        assertEq(msf.toInt96(maxInt96), int96(maxInt96));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 96 bits");
        msf.toInt96(maxInt96 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 96 bits");
        msf.toInt96(minInt96 - 1);
    }

    function test_ToInt88() external {
        int maxInt88 = type(int88).max;
        int minInt88 = type(int88).min;
        assertEq(msf.toInt88(0), 0);
        assertEq(msf.toInt88(1), 1);
        assertEq(msf.toInt88(maxInt88), int88(maxInt88));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 88 bits");
        msf.toInt88(maxInt88 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 88 bits");
        msf.toInt88(minInt88 - 1);
    }

    function test_ToInt80() external {
        int maxInt80 = type(int80).max;
        int minInt80 = type(int80).min;
        assertEq(msf.toInt80(0), 0);
        assertEq(msf.toInt80(1), 1);
        assertEq(msf.toInt80(maxInt80), int80(maxInt80));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 80 bits");
        msf.toInt80(maxInt80 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 80 bits");
        msf.toInt80(minInt80 - 1);
    }

    function test_ToInt72() external {
        int maxInt72 = type(int72).max;
        int minInt72 = type(int72).min;
        assertEq(msf.toInt72(0), 0);
        assertEq(msf.toInt72(1), 1);
        assertEq(msf.toInt72(maxInt72), int72(maxInt72));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 72 bits");
        msf.toInt72(maxInt72 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 72 bits");
        msf.toInt72(minInt72 - 1);
    }

    function test_ToInt64() external {
        int maxInt64 = type(int64).max;
        int minInt64 = type(int64).min;
        assertEq(msf.toInt64(0), 0);
        assertEq(msf.toInt64(1), 1);
        assertEq(msf.toInt64(maxInt64), int64(maxInt64));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 64 bits");
        msf.toInt64(maxInt64 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 64 bits");
        msf.toInt64(minInt64 - 1);
    }

    function test_ToInt56() external {
        int maxInt56 = type(int56).max;
        int minInt56 = type(int56).min;
        assertEq(msf.toInt56(0), 0);
        assertEq(msf.toInt56(1), 1);
        assertEq(msf.toInt56(maxInt56), int56(maxInt56));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 56 bits");
        msf.toInt56(maxInt56 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 56 bits");
        msf.toInt56(minInt56 - 1);
    }

    function test_ToInt48() external {
        int maxInt48 = type(int48).max;
        int minInt48 = type(int48).min;
        assertEq(msf.toInt48(0), 0);
        assertEq(msf.toInt48(1), 1);
        assertEq(msf.toInt48(maxInt48), int48(maxInt48));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 48 bits");
        msf.toInt48(maxInt48 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 48 bits");
        msf.toInt48(minInt48 - 1);
    }

    function test_ToInt40() external {
        int maxInt40 = type(int40).max;
        int minInt40 = type(int40).min;
        assertEq(msf.toInt40(0), 0);
        assertEq(msf.toInt40(1), 1);
        assertEq(msf.toInt40(maxInt40), int40(maxInt40));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 40 bits");
        msf.toInt40(maxInt40 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 40 bits");
        msf.toInt40(minInt40 - 1);
    }

    function test_ToInt32() external {
        int maxInt32 = type(int32).max;
        int minInt32 = type(int32).min;
        assertEq(msf.toInt32(0), 0);
        assertEq(msf.toInt32(1), 1);
        assertEq(msf.toInt32(maxInt32), int32(maxInt32));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 32 bits");
        msf.toInt32(maxInt32 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 32 bits");
        msf.toInt32(minInt32 - 1);
    }

    function test_ToInt24() external {
        int maxInt24 = type(int24).max;
        int minInt24 = type(int24).min;
        assertEq(msf.toInt24(0), 0);
        assertEq(msf.toInt24(1), 1);
        assertEq(msf.toInt24(maxInt24), int24(maxInt24));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 24 bits");
        msf.toInt24(maxInt24 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 24 bits");
        msf.toInt24(minInt24 - 1);
    }

    function test_ToInt16() external {
        int maxInt16 = type(int16).max;
        int minInt16 = type(int16).min;
        assertEq(msf.toInt16(0), 0);
        assertEq(msf.toInt16(1), 1);
        assertEq(msf.toInt16(maxInt16), int16(maxInt16));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 16 bits");
        msf.toInt16(maxInt16 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 16 bits");
        msf.toInt16(minInt16 - 1);
    }

    function test_ToInt8() external {
        int maxInt8 = type(int8).max;
        int minInt8 = type(int8).min;
        assertEq(msf.toInt8(0), 0);
        assertEq(msf.toInt8(1), 1);
        assertEq(msf.toInt8(maxInt8), int8(maxInt8));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in 8 bits");
        msf.toInt8(maxInt8 + 1);
        vm.expectRevert("SafeCast: value doesn't fit in 8 bits");
        msf.toInt8(minInt8 - 1);
    }
}

2.3 uint256和int256之间的互转

  • toUint256(int256 value): int256的value转换成uint256
    function toUint256(int256 value) internal pure returns (uint256) {
        // 要求value必须>=0,因为uint256无负数
        require(value >= 0, "SafeCast: value must be positive");
        // 只要value是正数,那么int256向uint256的转换就不会发生溢出。因为int256的正数域是uint256值域的一个真子集。所以可以安全地直接返回转换值
        return uint256(value);
    }
  • toInt256(uint256 value): uint256的value转换成int256
    function toInt256(uint256 value) internal pure returns (int256) {
        // 要求输入value的值必须&lt;=int256的最大值,这样就可以保证在uint256向int256转换的过程中不发生溢出
        require(value &lt;= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        // 返回int256的直接强转值
        return int256(value);
    }

foundry代码验证

contract MathTest is Test {
    MockSafeCast msf = new MockSafeCast();

    function test_toUint256() external {
        int maxInt256 = type(int).max;
        assertEq(msf.toUint256(0), 0);
        assertEq(msf.toUint256(1), 1);
        assertEq(msf.toUint256(maxInt256), uint(maxInt256));
        // revert with overflow
        vm.expectRevert("SafeCast: value must be positive");
        msf.toUint256(- 1);
    }

    function test_toInt256() external {
        uint maxInt256 = uint(type(int).max);
        assertEq(msf.toInt256(0), 0);
        assertEq(msf.toInt256(1), 1);
        assertEq(msf.toInt256(maxInt256), int(maxInt256));
        // revert with overflow
        vm.expectRevert("SafeCast: value doesn't fit in an int256");
        msf.toInt256(maxInt256 + 1);
    }
}

ps:\ 本人热爱图灵,热爱中本聪,热爱V神。 以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。 同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下! 如果需要转发,麻烦注明作者。十分感谢!

1.jpeg

公众号名称:后现代泼痞浪漫主义奠基人

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Michael.W
Michael.W
0x93E7...0000
狂热的区块链爱好者