Solidity – Where Is the Single-parameter Version of Function Sub() Defined in SafeMath?

openzeppelinsafemathsolidityuint256

I'm going through the Ethernaut challenges to learn Solidity, and in challenge 3 ("Coin Flip"), they show the following code which subtracts 1 from the current block number:

enter image description here

I assumed that this "sub()" function was a built-in subtraction function, but it seems like it must be defined in OpenZeppelin's SafeMath.sol library, because when I comment out the use of SafeMath in this simple example, I get a compiler warning:

enter image description here

However, when I look in SafeMath.sol, I do not see a single-parameter version of the sub() function. There is only a two-parameter and three-parameter version of sub() defined there:

enter image description here

Where is this single-parameter version of the sub() function defined?

Best Answer

The function you have seen in SafeMath.sol :

function sub(uint256 a, uint256 b) internal pure returns (uint256) {
     return a - b;
}

Is the one that is implicitly called with block.number.sub(1). That is the case because SafeMath.sol is a library that is attached to the type uint256. You can see it in the Etherenaut challenge contract at this line :

using SafeMath for uint256;

It is described in the documentation, for the mismatching number of parameters, this is the relevant part to read :

The directive using A for B; can be used to attach functions (A) as member functions to any type (B). These functions will receive the object they are called on as their first parameter (like the self variable in Python).

But you can also use the library directly, the two syntax shown in this example are entirely equivalent :

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract Example {

    using SafeMath for uint256;

    function withAttachedFunction() public pure returns (uint256) {
        uint256 variable = 1;

        return variable.sub(1);
    }

    function withoutAttachedFunction() public pure returns (uint256) {
        uint256 variable = 1;

        return SafeMath.sub(variable, 1);
    }
}

Obviously, using the variable.sub(...) syntax is way more convenient, and it is the intended goal of the using X for Y; statement.

I hope that answers your question.