Ссылка: https://cryptozombies.io/ru/lesson/5/chapter/10

Давайте посмотрим на код SafeMath:

library SafeMath {
  function mul(uint256 a, uint256 b) internal pure returns (uint256) 
  {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }
  function div(uint256 a, uint256 b) internal pure returns (uint256) 
  {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    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) 
  {
    assert(b <= a);
    return a - b;
  }
  function add(uint256 a, uint256 b) internal pure returns (uint256)  
  {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

Во-первых, у нас есть ключевое слово library — библиотеки похожи на contracts, но с некоторыми отличиями. Для наших целей библиотеки позволяют нам использовать ключевое слово using, которое автоматически прикрепляет все методы библиотеки к другому типу данных:

using SafeMath for uint;
// now we can use these methods on any uint
uint test = 2;
test = test.mul(3); // test now equals 6
test = test.add(5); // test now equals 11

Обратите внимание, что функции mul и add требуют по 2 аргумента, но когда мы объявляем using SafeMath for uint, uint, для которого мы вызываем функцию (test), автоматически передается в качестве первого аргумента.

Давайте посмотрим на код add, чтобы увидеть, что делает SafeMath:

function add(uint256 a, uint256 b) internal pure returns (uint256) {
  uint256 c = a + b;
  assert(c >= a);
  return c;
}

По сути, add просто добавляет 2 uint, как +, но также содержит оператор assert, чтобы убедиться, что сумма больше a. Это защищает нас от переполнения.

assert похож на require, где он выдает ошибку, если false. Разница между assert и require заключается в том, что require вернет пользователю оставшуюся часть газа в случае сбоя функции, тогда как assert этого не сделает. Поэтому большую часть времени вы хотите использовать require в своем коде; assert обычно используется, когда что-то пошло не так с кодом (например, переполнение uint).

Проще говоря, SafeMath add, sub, mul и div — это функции, которые выполняют 4 основные математические операции, но выдают ошибку, если происходит переполнение или потеря значимости.