Unverified Commit d17ae0b8 by Francisco Giordano Committed by GitHub

Signed SafeMath (#1559)

* signed safe math

* fix lint errors

* refactor overflow checks and add descriptions

* remove incorrect description

* add test for reversed arguments in multiplication test

* fix power operator

* improve multiplication test descriptions

* Update SafeMath.test.js

* add feature to changelog
parent fad30c3d
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* `ERC20`: `transferFrom` and `_burnFrom ` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524)) * `ERC20`: `transferFrom` and `_burnFrom ` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524))
* `ERC721`: added `_burn(uint256 tokenId)`, replacing the similar deprecated function (see below). ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) * `ERC721`: added `_burn(uint256 tokenId)`, replacing the similar deprecated function (see below). ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550))
* `ERC721`: added `_tokensOfOwner(address owner)`, allowing to internally retrieve the array of an account's owned tokens. ([#1522](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1522)) * `ERC721`: added `_tokensOfOwner(address owner)`, allowing to internally retrieve the array of an account's owned tokens. ([#1522](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1522))
* `SafeMath`: added overflow-safe operations for signed integers (`int256`). ([#1559](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1559))
### Improvements: ### Improvements:
* The compiler version required by `Array` was behind the rest of the libray so it was updated to `v0.4.24`. ([#1553](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1553)) * The compiler version required by `Array` was behind the rest of the libray so it was updated to `v0.4.24`. ([#1553](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1553))
......
...@@ -5,8 +5,10 @@ pragma solidity ^0.4.24; ...@@ -5,8 +5,10 @@ pragma solidity ^0.4.24;
* @dev Math operations with safety checks that revert on error * @dev Math operations with safety checks that revert on error
*/ */
library SafeMath { library SafeMath {
int256 constant private INT256_MIN = -2**255;
/** /**
* @dev Multiplies two numbers, reverts on overflow. * @dev Multiplies two unsigned integers, reverts on overflow.
*/ */
function mul(uint256 a, uint256 b) internal pure returns (uint256) { function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
...@@ -23,7 +25,26 @@ library SafeMath { ...@@ -23,7 +25,26 @@ library SafeMath {
} }
/** /**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero. * @dev Multiplies two signed integers, reverts on overflow.
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
// 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;
}
require(!(a == -1 && b == INT256_MIN)); // This is the only case of overflow not detected by the check below
int256 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) { function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0 // Solidity only automatically asserts when dividing by 0
...@@ -35,7 +56,19 @@ library SafeMath { ...@@ -35,7 +56,19 @@ library SafeMath {
} }
/** /**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero.
*/
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0); // Solidity only automatically asserts when dividing by 0
require(!(b == -1 && a == INT256_MIN)); // This is the only case of overflow
int256 c = a / b;
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) { function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a); require(b <= a);
...@@ -45,7 +78,17 @@ library SafeMath { ...@@ -45,7 +78,17 @@ library SafeMath {
} }
/** /**
* @dev Adds two numbers, reverts on overflow. * @dev Subtracts two signed integers, reverts on overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a));
return c;
}
/**
* @dev Adds two unsigned integers, reverts on overflow.
*/ */
function add(uint256 a, uint256 b) internal pure returns (uint256) { function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b; uint256 c = a + b;
...@@ -55,7 +98,17 @@ library SafeMath { ...@@ -55,7 +98,17 @@ library SafeMath {
} }
/** /**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo), * @dev Adds two signed integers, reverts on overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a));
return c;
}
/**
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero. * reverts when dividing by zero.
*/ */
function mod(uint256 a, uint256 b) internal pure returns (uint256) { function mod(uint256 a, uint256 b) internal pure returns (uint256) {
......
pragma solidity ^0.4.24; pragma solidity ^0.4.24;
import "../math/SafeMath.sol"; import "../math/SafeMath.sol";
contract SafeMathMock { contract SafeMathMock {
function mul(uint256 a, uint256 b) public pure returns (uint256) { function mulUints(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.mul(a, b); return SafeMath.mul(a, b);
} }
function div(uint256 a, uint256 b) public pure returns (uint256) { function mulInts(int256 a, int256 b) public pure returns (int256) {
return SafeMath.mul(a, b);
}
function divUints(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.div(a, b);
}
function divInts(int256 a, int256 b) public pure returns (int256) {
return SafeMath.div(a, b); return SafeMath.div(a, b);
} }
function sub(uint256 a, uint256 b) public pure returns (uint256) { function subUints(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.sub(a, b);
}
function subInts(int256 a, int256 b) public pure returns (int256) {
return SafeMath.sub(a, b); return SafeMath.sub(a, b);
} }
function add(uint256 a, uint256 b) public pure returns (uint256) { function addUints(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.add(a, b);
}
function addInts(int256 a, int256 b) public pure returns (int256) {
return SafeMath.add(a, b); return SafeMath.add(a, b);
} }
function mod(uint256 a, uint256 b) public pure returns (uint256) { function modUints(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.mod(a, b); return SafeMath.mod(a, b);
} }
} }
...@@ -3,4 +3,6 @@ const BigNumber = web3.BigNumber; ...@@ -3,4 +3,6 @@ const BigNumber = web3.BigNumber;
module.exports = { module.exports = {
ZERO_ADDRESS: '0x0000000000000000000000000000000000000000', ZERO_ADDRESS: '0x0000000000000000000000000000000000000000',
MAX_UINT256: new BigNumber(2).pow(256).minus(1), MAX_UINT256: new BigNumber(2).pow(256).minus(1),
MAX_INT256: new BigNumber(2).pow(255).minus(1),
MIN_INT256: new BigNumber(2).pow(255).times(-1),
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment