Merge branch 'master' into next-v5.0

This commit is contained in:
Hadrien Croubois
2023-01-14 18:51:03 -03:00
committed by Francisco Giordano
265 changed files with 5659 additions and 8542 deletions

View File

@ -1,6 +1,6 @@
const format = require('../format-lines');
const VALUE_SIZES = [ 224, 160 ];
const VALUE_SIZES = [224, 160];
const header = `\
pragma solidity ^0.8.0;
@ -271,7 +271,7 @@ function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos)
/* eslint-enable max-len */
// OPTIONS
const defaultOpts = (size) => ({
const defaultOpts = size => ({
historyTypeName: `Trace${size}`,
checkpointTypeName: `Checkpoint${size}`,
checkpointFieldName: '_checkpoints',
@ -300,11 +300,7 @@ module.exports = format(
legacyOperations(LEGACY_OPTS),
common(LEGACY_OPTS),
// New flavors
...OPTS.flatMap(opts => [
types(opts),
operations(opts),
common(opts),
]),
...OPTS.flatMap(opts => [types(opts), operations(opts), common(opts)]),
],
'}',
);

View File

@ -1,80 +0,0 @@
const format = require('../format-lines');
const VALUE_SIZES = [ 224, 160 ];
const header = `\
pragma solidity ^0.8.0;
import "../utils/Checkpoints.sol";
`;
const legacy = () => `\
contract CheckpointsMock {
using Checkpoints for Checkpoints.History;
Checkpoints.History private _totalCheckpoints;
function latest() public view returns (uint256) {
return _totalCheckpoints.latest();
}
function latestCheckpoint() public view returns (bool, uint256, uint256) {
return _totalCheckpoints.latestCheckpoint();
}
function length() public view returns (uint256) {
return _totalCheckpoints.length();
}
function push(uint256 value) public returns (uint256, uint256) {
return _totalCheckpoints.push(value);
}
function getAtBlock(uint256 blockNumber) public view returns (uint256) {
return _totalCheckpoints.getAtBlock(blockNumber);
}
function getAtProbablyRecentBlock(uint256 blockNumber) public view returns (uint256) {
return _totalCheckpoints.getAtProbablyRecentBlock(blockNumber);
}
}
`;
const checkpoint = length => `\
contract Checkpoints${length}Mock {
using Checkpoints for Checkpoints.Trace${length};
Checkpoints.Trace${length} private _totalCheckpoints;
function latest() public view returns (uint${length}) {
return _totalCheckpoints.latest();
}
function latestCheckpoint() public view returns (bool, uint${256 - length}, uint${length}) {
return _totalCheckpoints.latestCheckpoint();
}
function length() public view returns (uint256) {
return _totalCheckpoints.length();
}
function push(uint${256 - length} key, uint${length} value) public returns (uint${length}, uint${length}) {
return _totalCheckpoints.push(key, value);
}
function lowerLookup(uint${256 - length} key) public view returns (uint${length}) {
return _totalCheckpoints.lowerLookup(key);
}
function upperLookup(uint${256 - length} key) public view returns (uint${length}) {
return _totalCheckpoints.upperLookup(key);
}
}
`;
// GENERATE
module.exports = format(
header,
legacy(),
...VALUE_SIZES.map(checkpoint),
);

View File

@ -168,6 +168,18 @@ function get(
require(value != 0 || contains(map, key), errorMessage);
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
`;
const customMap = ({ name, keyType, valueType }) => `\
@ -193,7 +205,7 @@ function set(
}
/**
* @dev Removes a value from a set. O(1).
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
@ -216,7 +228,7 @@ function length(${name} storage map) internal view returns (uint256) {
}
/**
* @dev Returns the element stored at position \`index\` in the set. O(1).
* @dev Returns the element stored at position \`index\` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
@ -262,6 +274,26 @@ function get(
) internal view returns (${valueType}) {
return ${fromBytes32(valueType, `get(map._inner, ${toBytes32(keyType, 'key')}, errorMessage)`)};
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(${name} storage map) internal view returns (${keyType}[] memory) {
bytes32[] memory store = keys(map._inner);
${keyType}[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
`;
// GENERATE

View File

@ -1,66 +0,0 @@
const format = require('../format-lines');
const TYPES = [
{ name: 'UintToAddressMap', keyType: 'uint256', valueType: 'address' },
{ name: 'AddressToUintMap', keyType: 'address', valueType: 'uint256' },
{ name: 'Bytes32ToBytes32Map', keyType: 'bytes32', valueType: 'bytes32' },
{ name: 'UintToUintMap', keyType: 'uint256', valueType: 'uint256' },
{ name: 'Bytes32ToUintMap', keyType: 'bytes32', valueType: 'uint256' },
];
const header = `\
pragma solidity ^0.8.0;
import "../utils/structs/EnumerableMap.sol";
`;
const customSetMock = ({ name, keyType, valueType }) => `\
// ${name}
contract ${name}Mock {
using EnumerableMap for EnumerableMap.${name};
event OperationResult(bool result);
EnumerableMap.${name} private _map;
function contains(${keyType} key) public view returns (bool) {
return _map.contains(key);
}
function set(${keyType} key, ${valueType} value) public {
bool result = _map.set(key, value);
emit OperationResult(result);
}
function remove(${keyType} key) public {
bool result = _map.remove(key);
emit OperationResult(result);
}
function length() public view returns (uint256) {
return _map.length();
}
function at(uint256 index) public view returns (${keyType} key, ${valueType} value) {
return _map.at(index);
}
function tryGet(${keyType} key) public view returns (bool, ${valueType}) {
return _map.tryGet(key);
}
function get(${keyType} key) public view returns (${valueType}) {
return _map.get(key);
}
function getWithMessage(${keyType} key, string calldata errorMessage) public view returns (${valueType}) {
return _map.get(key, errorMessage);
}
}
`;
// GENERATE
module.exports = format(
header,
...TYPES.map(details => customSetMock(details)),
);

View File

@ -245,9 +245,6 @@ function values(${name} storage set) internal view returns (${type}[] memory) {
module.exports = format(
header.trimEnd(),
'library EnumerableSet {',
[
defaultSet(),
TYPES.map(details => customSet(details).trimEnd()).join('\n\n'),
],
[defaultSet(), TYPES.map(details => customSet(details).trimEnd()).join('\n\n')],
'}',
);

View File

@ -1,56 +0,0 @@
const format = require('../format-lines');
const TYPES = [
{ name: 'Bytes32Set', type: 'bytes32' },
{ name: 'AddressSet', type: 'address' },
{ name: 'UintSet', type: 'uint256' },
];
const header = `\
pragma solidity ^0.8.0;
import "../utils/structs/EnumerableSet.sol";
`;
const customSetMock = ({ name, type }) => `\
// ${name}
contract Enumerable${name}Mock {
using EnumerableSet for EnumerableSet.${name};
event OperationResult(bool result);
EnumerableSet.${name} private _set;
function contains(${type} value) public view returns (bool) {
return _set.contains(value);
}
function add(${type} value) public {
bool result = _set.add(value);
emit OperationResult(result);
}
function remove(${type} value) public {
bool result = _set.remove(value);
emit OperationResult(result);
}
function length() public view returns (uint256) {
return _set.length();
}
function at(uint256 index) public view returns (${type}) {
return _set.at(index);
}
function values() public view returns (${type}[] memory) {
return _set.values();
}
}
`;
// GENERATE
module.exports = format(
header,
...TYPES.map(details => customSetMock(details)),
);

97
scripts/generate/templates/SafeCast.js Executable file → Normal file
View File

@ -8,55 +8,55 @@ const LENGTHS = range(8, 256, 8).reverse(); // 248 → 8 (in steps of 8)
// This is used in the docs for each function.
const version = (selector, length) => {
switch (selector) {
case 'toUint(uint)': {
switch (length) {
case 8:
case 16:
case 32:
case 64:
case 128:
return '2.5';
case 96:
case 224:
return '4.2';
default:
assert(LENGTHS.includes(length));
return '4.7';
case 'toUint(uint)': {
switch (length) {
case 8:
case 16:
case 32:
case 64:
case 128:
return '2.5';
case 96:
case 224:
return '4.2';
default:
assert(LENGTHS.includes(length));
return '4.7';
}
}
}
case 'toInt(int)': {
switch (length) {
case 8:
case 16:
case 32:
case 64:
case 128:
return '3.1';
default:
assert(LENGTHS.includes(length));
return '4.7';
case 'toInt(int)': {
switch (length) {
case 8:
case 16:
case 32:
case 64:
case 128:
return '3.1';
default:
assert(LENGTHS.includes(length));
return '4.7';
}
}
case 'toUint(int)': {
switch (length) {
case 256:
return '3.0';
default:
assert(false);
return;
}
}
case 'toInt(uint)': {
switch (length) {
case 256:
return '3.0';
default:
assert(false);
return;
}
}
}
case 'toUint(int)': {
switch (length) {
case 256:
return '3.0';
default:
assert(false);
return;
}
}
case 'toInt(uint)': {
switch (length) {
case 256:
return '3.0';
default:
assert(false);
return;
}
}
default:
assert(false);
}
};
@ -158,11 +158,6 @@ function toUint${length}(int${length} value) internal pure returns (uint${length
module.exports = format(
header.trimEnd(),
'library SafeCast {',
[
...LENGTHS.map(toUintDownCast),
toUint(256),
...LENGTHS.map(toIntDownCast),
toInt(256),
],
[...LENGTHS.map(toUintDownCast), toUint(256), ...LENGTHS.map(toIntDownCast), toInt(256)],
'}',
);

View File

@ -1,50 +0,0 @@
const format = require('../format-lines');
const { range } = require('../../helpers');
const LENGTHS = range(8, 256, 8).reverse(); // 248 → 8 (in steps of 8)
const header = `\
pragma solidity ^0.8.0;
import "../utils/math/SafeCast.sol";
`;
const toInt = length => `\
function toInt${length}(uint${length} a) public pure returns (int${length}) {
return a.toInt${length}();
}
`;
const toUint = length => `\
function toUint${length}(int${length} a) public pure returns (uint${length}) {
return a.toUint${length}();
}
`;
const toIntDownCast = length => `\
function toInt${length}(int256 a) public pure returns (int${length}) {
return a.toInt${length}();
}
`;
const toUintDownCast = length => `\
function toUint${length}(uint256 a) public pure returns (uint${length}) {
return a.toUint${length}();
}
`;
// GENERATE
module.exports = format(
header,
'contract SafeCastMock {',
[
'using SafeCast for uint256;',
'using SafeCast for int256;',
'',
toUint(256),
...LENGTHS.map(toUintDownCast),
toInt(256),
...LENGTHS.map(toIntDownCast),
].flatMap(fn => fn.split('\n')).slice(0, -1),
'}',
);

View File

@ -1,26 +1,26 @@
function toBytes32 (type, value) {
function toBytes32(type, value) {
switch (type) {
case 'bytes32':
return value;
case 'uint256':
return `bytes32(${value})`;
case 'address':
return `bytes32(uint256(uint160(${value})))`;
default:
throw new Error(`Conversion from ${type} to bytes32 not supported`);
case 'bytes32':
return value;
case 'uint256':
return `bytes32(${value})`;
case 'address':
return `bytes32(uint256(uint160(${value})))`;
default:
throw new Error(`Conversion from ${type} to bytes32 not supported`);
}
}
function fromBytes32 (type, value) {
function fromBytes32(type, value) {
switch (type) {
case 'bytes32':
return value;
case 'uint256':
return `uint256(${value})`;
case 'address':
return `address(uint160(uint256(${value})))`;
default:
throw new Error(`Conversion from bytes32 to ${type} not supported`);
case 'bytes32':
return value;
case 'uint256':
return `uint256(${value})`;
case 'address':
return `address(uint160(uint256(${value})))`;
default:
throw new Error(`Conversion from bytes32 to ${type} not supported`);
}
}