Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Procedural SafeCast.sol generation #3245

Merged
merged 23 commits into from
May 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix lint
  • Loading branch information
Amxx committed Mar 7, 2022
commit f19f913c4d1804194c7b9e2e9ab4bcf513f71120
83 changes: 43 additions & 40 deletions scripts/generate/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,53 @@
const fs = require('fs');

const {
toInt,
toUint,
toIntDownCast,
toUintDownCast,
toInt,
toUint,
toIntDownCast,
toUintDownCast,
} = require('./templates');

function genSafeCast(path) {
content = [];
function genSafeCast (path) {
Amxx marked this conversation as resolved.
Show resolved Hide resolved
const content = [];

// Header
content.push([
`// SPDX-License-Identifier: MIT`,
`pragma solidity ^0.8.0;`,
``,
`/**`,
` * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow`,
` * checks.`,
` *`,
` * Downcasting from uint256/int256 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} and {SignedSafeMath} to extend it to smaller types, by performing`,
` * all math on \`uint256\` and \`int256\` and then downcasting.`,
` */`,
].join('\n'));
// Header
content.push([
'// SPDX-License-Identifier: MIT',
'pragma solidity ^0.8.0;',
'',
'/**',
' * @dev Wrappers over Solidity\'s uintXX/intXX casting operators with added overflow',
' * checks.',
' *',
' * Downcasting from uint256/int256 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} and {SignedSafeMath} to extend it to smaller types, by performing',
' * all math on `uint256` and `int256` and then downcasting.',
' */',
].join('\n'));

// Library
content.push(`library SafeCast {`);
for (size = 224; size > 0; size -= 8) {
content.push(toUintDownCast(size));
}
content.push(toUint(256));
for (size = 224; size > 0; size -= 8) {
content.push(toIntDownCast(size));
}
content.push(toInt(256));
content.push(`}`);
// Library
content.push('library SafeCast {');
for (let size = 224; size > 0; size -= 8) {
content.push(toUintDownCast(size));
content.push('');
}
content.push(toUint(256));
content.push('');
for (let size = 224; size > 0; size -= 8) {
content.push(toIntDownCast(size));
content.push('');
}
content.push(toInt(256));
content.push('}');

fs.writeFileSync(path, content.join('\n'));
fs.writeFileSync(path, content.join('\n'));
}

genSafeCast('./contracts/utils/math/SafeCast.sol')
genSafeCast('./contracts/utils/math/SafeCast.sol');
10 changes: 5 additions & 5 deletions scripts/generate/templates/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
toInt: require('./toInt'),
toUint: require('./toUint'),
toIntDownCast: require('./toIntDownCast'),
toUintDownCast: require('./toUintDownCast'),
}
toInt: require('./toInt'),
toUint: require('./toUint'),
toIntDownCast: require('./toIntDownCast'),
toUintDownCast: require('./toUintDownCast'),
};
24 changes: 12 additions & 12 deletions scripts/generate/templates/toInt.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
module.exports = length => [
` /**`,
` * @dev Converts an unsigned uint${length} into a signed int${length}.`,
` *`,
` * Requirements:`,
` *`,
` * - input must be less than or equal to maxInt${length}.`,
` */`,
` function toInt${length}(uint${length} value) internal pure returns (int${length}) {`,
` // Note: Unsafe cast below is okay because \`type(int${length}).max\` is guaranteed to be positive`,
` require(value <= uint${length}(type(int${length}).max), "SafeCast: value doesn't fit in an int${length}");`,
` return int${length}(value);`,
` }`,
' /**',
` * @dev Converts an unsigned uint${length} into a signed int${length}.`,
' *',
' * Requirements:',
' *',
` * - input must be less than or equal to maxInt${length}.`,
' */',
` function toInt${length}(uint${length} value) internal pure returns (int${length}) {`,
` // Note: Unsafe cast below is okay because \`type(int${length}).max\` is guaranteed to be positive`,
` require(value <= uint${length}(type(int${length}).max), "SafeCast: value doesn't fit in an int${length}");`,
` return int${length}(value);`,
' }',
].join('\n');
35 changes: 18 additions & 17 deletions scripts/generate/templates/toIntDownCast.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
module.exports = length => [
Amxx marked this conversation as resolved.
Show resolved Hide resolved
` /**`,
` * @dev Returns the downcasted int${length} from int256, reverting on`,
` * overflow (when the input is less than smallest int${length} or`,
` * greater than largest int${length}).`,
` *`,
` * Counterpart to Solidity's \`int${length}\` operator.`,
` *`,
` * Requirements:`,
` *`,
` * - input must fit into ${length} bits`,
` *`,
` * _Available since v3.1._`,
` */`,
` function toInt${length}(int256 value) internal pure returns (int${length}) {`,
` require(value >= type(int${length}).min && value <= type(int${length}).max, "SafeCast: value doesn't fit in ${length} bits");`,
` return int${length}(value);`,
` }`,
' /**',
` * @dev Returns the downcasted int${length} from int256, reverting on`,
` * overflow (when the input is less than smallest int${length} or`,
` * greater than largest int${length}).`,
' *',
` * Counterpart to Solidity's \`int${length}\` operator.`,
' *',
' * Requirements:',
' *',
` * - input must fit into ${length} bits`,
' *',
' * _Available since v3.1._',
' */',
` function toInt${length}(int256 value) internal pure returns (int${length}) {`,
// eslint-disable-next-line max-len
` require(value >= type(int${length}).min && value <= type(int${length}).max, "SafeCast: value doesn't fit in ${length} bits");`,
` return int${length}(value);`,
' }',
].join('\n');
22 changes: 11 additions & 11 deletions scripts/generate/templates/toUint.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
module.exports = length => [
` /**`,
` * @dev Converts a signed int${length} into an unsigned uint${length}.`,
` *`,
` * Requirements:`,
` *`,
` * - input must be greater than or equal to 0.`,
` */`,
` function toUint${length}(int${length} value) internal pure returns (uint${length}) {`,
` require(value >= 0, "SafeCast: value must be positive");`,
` return uint${length}(value);`,
` }`,
' /**',
` * @dev Converts a signed int${length} into an unsigned uint${length}.`,
' *',
' * Requirements:',
' *',
' * - input must be greater than or equal to 0.',
' */',
` function toUint${length}(int${length} value) internal pure returns (uint${length}) {`,
' require(value >= 0, "SafeCast: value must be positive");',
` return uint${length}(value);`,
' }',
].join('\n');
28 changes: 14 additions & 14 deletions scripts/generate/templates/toUintDownCast.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
module.exports = length => [
` /**`,
` * @dev Returns the downcasted uint${length} from uint256, reverting on`,
` * overflow (when the input is greater than largest uint${length}).`,
` *`,
` * Counterpart to Solidity's \`uint${length}\` operator.`,
` *`,
` * Requirements:`,
` *`,
` * - input must fit into ${length} bits`,
` */`,
` function toUint${length}(uint256 value) internal pure returns (uint${length}) {`,
` require(value <= type(uint${length}).max, "SafeCast: value doesn't fit in ${length} bits");`,
` return uint${length}(value);`,
` }`,
' /**',
` * @dev Returns the downcasted uint${length} from uint256, reverting on`,
` * overflow (when the input is greater than largest uint${length}).`,
' *',
` * Counterpart to Solidity's \`uint${length}\` operator.`,
' *',
' * Requirements:',
' *',
` * - input must fit into ${length} bits`,
' */',
` function toUint${length}(uint256 value) internal pure returns (uint${length}) {`,
` require(value <= type(uint${length}).max, "SafeCast: value doesn't fit in ${length} bits");`,
` return uint${length}(value);`,
' }',
].join('\n');