-
Notifications
You must be signed in to change notification settings - Fork 11.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Safe Casting Library from uint256 to uintXX (#1926)
* Include Safe Casting Library with complete and exhaustive test-suite. * linting test file. * Typo in SafeCast import statement * Update test/utils/SafeCast.test.js * Rename `castUXX` to `toUintXX` from suggestion * Tackling the quick and easy suggestions regarding error string improvements etc. * typo and changelog update. * Improve SafeCast tests * Update test/utils/SafeCast.test.js * Update test/utils/SafeCast.test.js * incorrect import * add SafeCast to docs site * Update CHANGELOG.md * Update SafeCast.sol
- Loading branch information
Showing
5 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
pragma solidity ^0.5.0; | ||
|
||
import "../utils/SafeCast.sol"; | ||
|
||
contract SafeCastMock { | ||
using SafeCast for uint; | ||
|
||
function toUint128(uint a) public pure returns (uint128) { | ||
return a.toUint128(); | ||
} | ||
|
||
function toUint64(uint a) public pure returns (uint64) { | ||
return a.toUint64(); | ||
} | ||
|
||
function toUint32(uint a) public pure returns (uint32) { | ||
return a.toUint32(); | ||
} | ||
|
||
function toUint16(uint a) public pure returns (uint16) { | ||
return a.toUint16(); | ||
} | ||
|
||
function toUint8(uint a) public pure returns (uint8) { | ||
return a.toUint8(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
pragma solidity ^0.5.0; | ||
|
||
|
||
/** | ||
* @dev Wrappers over Solidity's uintXX casting operators with added overflow | ||
* checks. | ||
* | ||
* Downcasting from uint256 in Solidity does not revert on overflow. This can | ||
* easily result in undesired exploitation or bugs, since developers usually | ||
* assume that overflows raise errors. `SafeCast` restores this intuition by | ||
* reverting the transaction when such an operation overflows. | ||
* | ||
* Using this library instead of the unchecked operations eliminates an entire | ||
* class of bugs, so it's recommended to use it always. | ||
* | ||
* Can be combined with {SafeMath} to extend it to smaller types, by performing | ||
* all math on `uint256` and then downcasting. | ||
*/ | ||
library SafeCast { | ||
|
||
/** | ||
* @dev Returns the downcasted uint128 from uint256, reverting on | ||
* overflow (when the input is greater than largest uint128). | ||
* | ||
* Counterpart to Solidity's `uint128` operator. | ||
* | ||
* Requirements: | ||
* | ||
* - input must fit into 128 bits | ||
*/ | ||
function toUint128(uint256 value) internal pure returns (uint128) { | ||
require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); | ||
return uint128(value); | ||
} | ||
|
||
/** | ||
* @dev Returns the downcasted uint64 from uint256, reverting on | ||
* overflow (when the input is greater than largest uint64). | ||
* | ||
* Counterpart to Solidity's `uint64` operator. | ||
* | ||
* Requirements: | ||
* | ||
* - input must fit into 64 bits | ||
*/ | ||
function toUint64(uint256 value) internal pure returns (uint64) { | ||
require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); | ||
return uint64(value); | ||
} | ||
|
||
/** | ||
* @dev Returns the downcasted uint32 from uint256, reverting on | ||
* overflow (when the input is greater than largest uint32). | ||
* | ||
* Counterpart to Solidity's `uint32` operator. | ||
* | ||
* Requirements: | ||
* | ||
* - input must fit into 32 bits | ||
*/ | ||
function toUint32(uint256 value) internal pure returns (uint32) { | ||
require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); | ||
return uint32(value); | ||
} | ||
|
||
/** | ||
* @dev Returns the downcasted uint16 from uint256, reverting on | ||
* overflow (when the input is greater than largest uint16). | ||
* | ||
* Counterpart to Solidity's `uint16` operator. | ||
* | ||
* Requirements: | ||
* | ||
* - input must fit into 16 bits | ||
*/ | ||
function toUint16(uint256 value) internal pure returns (uint16) { | ||
require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); | ||
return uint16(value); | ||
} | ||
|
||
/** | ||
* @dev Returns the downcasted uint8 from uint256, reverting on | ||
* overflow (when the input is greater than largest uint8). | ||
* | ||
* Counterpart to Solidity's `uint8` operator. | ||
* | ||
* Requirements: | ||
* | ||
* - input must fit into 8 bits. | ||
*/ | ||
function toUint8(uint256 value) internal pure returns (uint8) { | ||
require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); | ||
return uint8(value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
const { BN, expectRevert } = require('@openzeppelin/test-helpers'); | ||
|
||
const { expect } = require('chai'); | ||
|
||
const SafeCastMock = artifacts.require('SafeCastMock'); | ||
|
||
contract('SafeCast', async () => { | ||
beforeEach(async function () { | ||
this.safeCast = await SafeCastMock.new(); | ||
}); | ||
|
||
function testToUint (bits) { | ||
describe(`toUint${bits}`, () => { | ||
const maxValue = new BN('2').pow(new BN(bits)).subn(1); | ||
|
||
it('downcasts 0', async function () { | ||
expect(await this.safeCast[`toUint${bits}`](0)).to.be.bignumber.equal('0'); | ||
}); | ||
|
||
it('downcasts 1', async function () { | ||
expect(await this.safeCast[`toUint${bits}`](1)).to.be.bignumber.equal('1'); | ||
}); | ||
|
||
it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { | ||
expect(await this.safeCast[`toUint${bits}`](maxValue)).to.be.bignumber.equal(maxValue); | ||
}); | ||
|
||
it(`reverts when downcasting 2^${bits} (${maxValue.addn(1)})`, async function () { | ||
await expectRevert( | ||
this.safeCast[`toUint${bits}`](maxValue.addn(1)), | ||
`SafeCast: value doesn't fit in ${bits} bits` | ||
); | ||
}); | ||
|
||
it(`reverts when downcasting 2^${bits} + 1 (${maxValue.addn(2)})`, async function () { | ||
await expectRevert( | ||
this.safeCast[`toUint${bits}`](maxValue.addn(2)), | ||
`SafeCast: value doesn't fit in ${bits} bits` | ||
); | ||
}); | ||
}); | ||
} | ||
|
||
[8, 16, 32, 64, 128].forEach(bits => testToUint(bits)); | ||
}); |