Generate already lint code from procedural generation (#5060)
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const cp = require('child_process');
|
||||
// const cp = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const format = require('./format-lines');
|
||||
@ -23,11 +23,11 @@ function generateFromTemplate(file, template, outputPrefix = '') {
|
||||
...(version ? [version + ` (${file})`] : []),
|
||||
`// This file was procedurally generated from ${input}.`,
|
||||
'',
|
||||
require(template),
|
||||
require(template).trimEnd(),
|
||||
);
|
||||
|
||||
fs.writeFileSync(output, content);
|
||||
cp.execFileSync('prettier', ['--write', output]);
|
||||
// cp.execFileSync('prettier', ['--write', output]);
|
||||
}
|
||||
|
||||
// Contracts
|
||||
|
||||
@ -15,7 +15,7 @@ import {Math} from "./math/Math.sol";
|
||||
`;
|
||||
|
||||
const sort = type => `\
|
||||
/**
|
||||
/**
|
||||
* @dev Sort an array of ${type} (in memory) following the provided comparator function.
|
||||
*
|
||||
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
|
||||
@ -26,28 +26,28 @@ const sort = type => `\
|
||||
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
|
||||
* consume more gas than is available in a block, leading to potential DoS.
|
||||
*/
|
||||
function sort(
|
||||
function sort(
|
||||
${type}[] memory array,
|
||||
function(${type}, ${type}) pure returns (bool) comp
|
||||
) internal pure returns (${type}[] memory) {
|
||||
) internal pure returns (${type}[] memory) {
|
||||
${
|
||||
type === 'bytes32'
|
||||
? '_quickSort(_begin(array), _end(array), comp);'
|
||||
: 'sort(_castToBytes32Array(array), _castToBytes32Comp(comp));'
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @dev Variant of {sort} that sorts an array of ${type} in increasing order.
|
||||
*/
|
||||
function sort(${type}[] memory array) internal pure returns (${type}[] memory) {
|
||||
function sort(${type}[] memory array) internal pure returns (${type}[] memory) {
|
||||
${type === 'bytes32' ? 'sort(array, _defaultComp);' : 'sort(_castToBytes32Array(array), _defaultComp);'}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const quickSort = `
|
||||
const quickSort = `\
|
||||
/**
|
||||
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at \`begin\` (inclusive), and stops
|
||||
* at end (exclusive). Sorting follows the \`comp\` comparator.
|
||||
@ -123,34 +123,34 @@ function _swap(uint256 ptr1, uint256 ptr2) private pure {
|
||||
}
|
||||
`;
|
||||
|
||||
const defaultComparator = `
|
||||
/// @dev Comparator for sorting arrays in increasing order.
|
||||
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) {
|
||||
const defaultComparator = `\
|
||||
/// @dev Comparator for sorting arrays in increasing order.
|
||||
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) {
|
||||
return a < b;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const castArray = type => `\
|
||||
/// @dev Helper: low level cast ${type} memory array to uint256 memory array
|
||||
function _castToBytes32Array(${type}[] memory input) private pure returns (bytes32[] memory output) {
|
||||
/// @dev Helper: low level cast ${type} memory array to uint256 memory array
|
||||
function _castToBytes32Array(${type}[] memory input) private pure returns (bytes32[] memory output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const castComparator = type => `\
|
||||
/// @dev Helper: low level cast ${type} comp function to bytes32 comp function
|
||||
function _castToBytes32Comp(
|
||||
/// @dev Helper: low level cast ${type} comp function to bytes32 comp function
|
||||
function _castToBytes32Comp(
|
||||
function(${type}, ${type}) pure returns (bool) input
|
||||
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) {
|
||||
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) {
|
||||
assembly {
|
||||
output := input
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const search = `
|
||||
const search = `\
|
||||
/**
|
||||
* @dev Searches a sorted \`array\` and returns the first index that contains
|
||||
* a value greater or equal to \`element\`. If no such index exists (i.e. all
|
||||
@ -319,12 +319,12 @@ function upperBoundMemory(uint256[] memory array, uint256 element) internal pure
|
||||
}
|
||||
`;
|
||||
|
||||
const unsafeAccessStorage = type => `
|
||||
const unsafeAccessStorage = type => `\
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain \`pos\` is lower than the array length.
|
||||
*/
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
* WARNING: Only use if you are certain \`pos\` is lower than the array length.
|
||||
*/
|
||||
function unsafeAccess(${type}[] storage arr, uint256 pos) internal pure returns (StorageSlot.${capitalize(
|
||||
type,
|
||||
)}Slot storage) {
|
||||
@ -334,9 +334,10 @@ function unsafeAccess(${type}[] storage arr, uint256 pos) internal pure returns
|
||||
slot := arr.slot
|
||||
}
|
||||
return slot.deriveArray().offset(pos).get${capitalize(type)}Slot();
|
||||
}`;
|
||||
}
|
||||
`;
|
||||
|
||||
const unsafeAccessMemory = type => `
|
||||
const unsafeAccessMemory = type => `\
|
||||
/**
|
||||
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||
*
|
||||
@ -349,7 +350,7 @@ function unsafeMemoryAccess(${type}[] memory arr, uint256 pos) internal pure ret
|
||||
}
|
||||
`;
|
||||
|
||||
const unsafeSetLength = type => `
|
||||
const unsafeSetLength = type => `\
|
||||
/**
|
||||
* @dev Helper to set the length of an dynamic array. Directly writing to \`.length\` is forbidden.
|
||||
*
|
||||
@ -360,14 +361,18 @@ function unsafeSetLength(${type}[] storage array, uint256 len) internal {
|
||||
assembly {
|
||||
sstore(array.slot, len)
|
||||
}
|
||||
}`;
|
||||
}
|
||||
`;
|
||||
|
||||
// GENERATE
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
'library Arrays {',
|
||||
format(
|
||||
[].concat(
|
||||
'using SlotDerivation for bytes32;',
|
||||
'using StorageSlot for bytes32;',
|
||||
'',
|
||||
// sorting, comparator, helpers and internal
|
||||
sort('bytes32'),
|
||||
TYPES.filter(type => type !== 'bytes32').map(sort),
|
||||
@ -381,5 +386,7 @@ module.exports = format(
|
||||
TYPES.map(unsafeAccessStorage),
|
||||
TYPES.map(unsafeAccessMemory),
|
||||
TYPES.map(unsafeSetLength),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -17,10 +17,10 @@ import {Math} from "../math/Math.sol";
|
||||
`;
|
||||
|
||||
const errors = `\
|
||||
/**
|
||||
/**
|
||||
* @dev A value was attempted to be inserted on a past checkpoint.
|
||||
*/
|
||||
error CheckpointUnorderedInsertion();
|
||||
error CheckpointUnorderedInsertion();
|
||||
`;
|
||||
|
||||
const template = opts => `\
|
||||
@ -41,11 +41,7 @@ struct ${opts.checkpointTypeName} {
|
||||
* IMPORTANT: Never accept \`key\` as a user input, since an arbitrary \`type(${opts.keyTypeName}).max\` key set will disable the
|
||||
* library.
|
||||
*/
|
||||
function push(
|
||||
${opts.historyTypeName} storage self,
|
||||
${opts.keyTypeName} key,
|
||||
${opts.valueTypeName} value
|
||||
) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
||||
function push(${opts.historyTypeName} storage self, ${opts.keyTypeName} key, ${opts.valueTypeName} value) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
||||
return _insert(self.${opts.checkpointFieldName}, key, value);
|
||||
}
|
||||
|
||||
@ -108,15 +104,7 @@ function latest(${opts.historyTypeName} storage self) internal view returns (${o
|
||||
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
|
||||
* in the most recent checkpoint.
|
||||
*/
|
||||
function latestCheckpoint(${opts.historyTypeName} storage self)
|
||||
internal
|
||||
view
|
||||
returns (
|
||||
bool exists,
|
||||
${opts.keyTypeName} ${opts.keyFieldName},
|
||||
${opts.valueTypeName} ${opts.valueFieldName}
|
||||
)
|
||||
{
|
||||
function latestCheckpoint(${opts.historyTypeName} storage self) internal view returns (bool exists, ${opts.keyTypeName} ${opts.keyFieldName}, ${opts.valueTypeName} ${opts.valueFieldName}) {
|
||||
uint256 pos = self.${opts.checkpointFieldName}.length;
|
||||
if (pos == 0) {
|
||||
return (false, 0, 0);
|
||||
@ -144,11 +132,7 @@ function at(${opts.historyTypeName} storage self, uint32 pos) internal view retu
|
||||
* @dev Pushes a (\`key\`, \`value\`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
|
||||
* or by updating the last one.
|
||||
*/
|
||||
function _insert(
|
||||
${opts.checkpointTypeName}[] storage self,
|
||||
${opts.keyTypeName} key,
|
||||
${opts.valueTypeName} value
|
||||
) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
||||
function _insert(${opts.checkpointTypeName}[] storage self, ${opts.keyTypeName} key, ${opts.valueTypeName} value) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
||||
uint256 pos = self.length;
|
||||
|
||||
if (pos > 0) {
|
||||
@ -225,11 +209,10 @@ function _lowerBinaryLookup(
|
||||
/**
|
||||
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
|
||||
*/
|
||||
function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos)
|
||||
private
|
||||
pure
|
||||
returns (${opts.checkpointTypeName} storage result)
|
||||
{
|
||||
function _unsafeAccess(
|
||||
${opts.checkpointTypeName}[] storage self,
|
||||
uint256 pos
|
||||
) private pure returns (${opts.checkpointTypeName} storage result) {
|
||||
assembly {
|
||||
mstore(0, self.slot)
|
||||
result.slot := add(keccak256(0, 0x20), pos)
|
||||
@ -242,7 +225,11 @@ function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos)
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
'library Checkpoints {',
|
||||
format(
|
||||
[].concat(
|
||||
errors,
|
||||
OPTS.flatMap(opts => template(opts)),
|
||||
OPTS.map(opts => template(opts)),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -22,18 +22,13 @@ uint8 internal constant _KEY_MAX_GAP = 64;
|
||||
Checkpoints.${opts.historyTypeName} internal _ckpts;
|
||||
|
||||
// helpers
|
||||
function _bound${capitalize(opts.keyTypeName)}(
|
||||
${opts.keyTypeName} x,
|
||||
${opts.keyTypeName} min,
|
||||
${opts.keyTypeName} max
|
||||
) internal pure returns (${opts.keyTypeName}) {
|
||||
function _bound${capitalize(opts.keyTypeName)}(${opts.keyTypeName} x, ${opts.keyTypeName} min, ${
|
||||
opts.keyTypeName
|
||||
} max) internal pure returns (${opts.keyTypeName}) {
|
||||
return SafeCast.to${capitalize(opts.keyTypeName)}(bound(uint256(x), uint256(min), uint256(max)));
|
||||
}
|
||||
|
||||
function _prepareKeys(
|
||||
${opts.keyTypeName}[] memory keys,
|
||||
${opts.keyTypeName} maxSpread
|
||||
) internal pure {
|
||||
function _prepareKeys(${opts.keyTypeName}[] memory keys, ${opts.keyTypeName} maxSpread) internal pure {
|
||||
${opts.keyTypeName} lastKey = 0;
|
||||
for (uint256 i = 0; i < keys.length; ++i) {
|
||||
${opts.keyTypeName} key = _bound${capitalize(opts.keyTypeName)}(keys[i], lastKey, lastKey + maxSpread);
|
||||
@ -42,11 +37,7 @@ function _prepareKeys(
|
||||
}
|
||||
}
|
||||
|
||||
function _assertLatestCheckpoint(
|
||||
bool exist,
|
||||
${opts.keyTypeName} key,
|
||||
${opts.valueTypeName} value
|
||||
) internal {
|
||||
function _assertLatestCheckpoint(bool exist, ${opts.keyTypeName} key, ${opts.valueTypeName} value) internal {
|
||||
(bool _exist, ${opts.keyTypeName} _key, ${opts.valueTypeName} _value) = _ckpts.latestCheckpoint();
|
||||
assertEq(_exist, exist);
|
||||
assertEq(_key, key);
|
||||
@ -54,11 +45,9 @@ function _assertLatestCheckpoint(
|
||||
}
|
||||
|
||||
// tests
|
||||
function testPush(
|
||||
${opts.keyTypeName}[] memory keys,
|
||||
${opts.valueTypeName}[] memory values,
|
||||
${opts.keyTypeName} pastKey
|
||||
) public {
|
||||
function testPush(${opts.keyTypeName}[] memory keys, ${opts.valueTypeName}[] memory values, ${
|
||||
opts.keyTypeName
|
||||
} pastKey) public {
|
||||
vm.assume(values.length > 0 && values.length <= keys.length);
|
||||
_prepareKeys(keys, _KEY_MAX_GAP);
|
||||
|
||||
@ -71,7 +60,7 @@ function testPush(
|
||||
for (uint256 i = 0; i < keys.length; ++i) {
|
||||
${opts.keyTypeName} key = keys[i];
|
||||
${opts.valueTypeName} value = values[i % values.length];
|
||||
if (i > 0 && key == keys[i-1]) ++duplicates;
|
||||
if (i > 0 && key == keys[i - 1]) ++duplicates;
|
||||
|
||||
// push
|
||||
_ckpts.push(key, value);
|
||||
@ -98,11 +87,9 @@ function push(${opts.keyTypeName} key, ${opts.valueTypeName} value) external {
|
||||
_ckpts.push(key, value);
|
||||
}
|
||||
|
||||
function testLookup(
|
||||
${opts.keyTypeName}[] memory keys,
|
||||
${opts.valueTypeName}[] memory values,
|
||||
${opts.keyTypeName} lookup
|
||||
) public {
|
||||
function testLookup(${opts.keyTypeName}[] memory keys, ${opts.valueTypeName}[] memory values, ${
|
||||
opts.keyTypeName
|
||||
} lookup) public {
|
||||
vm.assume(values.length > 0 && values.length <= keys.length);
|
||||
_prepareKeys(keys, _KEY_MAX_GAP);
|
||||
|
||||
@ -124,7 +111,7 @@ function testLookup(
|
||||
upper = value;
|
||||
}
|
||||
// find the first key that is not smaller than the lookup key
|
||||
if (key >= lookup && (i == 0 || keys[i-1] < lookup)) {
|
||||
if (key >= lookup && (i == 0 || keys[i - 1] < lookup)) {
|
||||
lowerKey = key;
|
||||
}
|
||||
if (key == lowerKey) {
|
||||
@ -142,5 +129,10 @@ function testLookup(
|
||||
// GENERATE
|
||||
module.exports = format(
|
||||
header,
|
||||
...OPTS.flatMap(opts => [`contract Checkpoints${opts.historyTypeName}Test is Test {`, [template(opts)], '}']),
|
||||
...OPTS.flatMap(opts => [
|
||||
`contract Checkpoints${opts.historyTypeName}Test is Test {`,
|
||||
[template(opts).trimEnd()],
|
||||
'}',
|
||||
'',
|
||||
]),
|
||||
);
|
||||
|
||||
@ -54,7 +54,7 @@ import {EnumerableSet} from "./EnumerableSet.sol";
|
||||
`;
|
||||
/* eslint-enable max-len */
|
||||
|
||||
const defaultMap = () => `\
|
||||
const defaultMap = `\
|
||||
// To implement this library for multiple types with as little code repetition as possible, we write it in
|
||||
// terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,
|
||||
// and user-facing implementations such as \`UintToAddressMap\` are just wrappers around the underlying Map.
|
||||
@ -78,11 +78,7 @@ struct Bytes32ToBytes32Map {
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(
|
||||
Bytes32ToBytes32Map storage map,
|
||||
bytes32 key,
|
||||
bytes32 value
|
||||
) internal returns (bool) {
|
||||
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
|
||||
map._values[key] = value;
|
||||
return map._keys.add(key);
|
||||
}
|
||||
@ -148,7 +144,7 @@ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view retu
|
||||
*/
|
||||
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
|
||||
bytes32 value = map._values[key];
|
||||
if(value == 0 && !contains(map, key)) {
|
||||
if (value == 0 && !contains(map, key)) {
|
||||
revert EnumerableMapNonexistentKey(key);
|
||||
}
|
||||
return value;
|
||||
@ -181,11 +177,7 @@ struct ${name} {
|
||||
* Returns true if the key was added to the map, that is if it was not
|
||||
* already present.
|
||||
*/
|
||||
function set(
|
||||
${name} storage map,
|
||||
${keyType} key,
|
||||
${valueType} value
|
||||
) internal returns (bool) {
|
||||
function set(${name} storage map, ${keyType} key, ${valueType} value) internal returns (bool) {
|
||||
return set(map._inner, ${toBytes32(keyType, 'key')}, ${toBytes32(valueType, 'value')});
|
||||
}
|
||||
|
||||
@ -271,11 +263,13 @@ function keys(${name} storage map) internal view returns (${keyType}[] memory) {
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
'library EnumerableMap {',
|
||||
[
|
||||
format(
|
||||
[].concat(
|
||||
'using EnumerableSet for EnumerableSet.Bytes32Set;',
|
||||
'',
|
||||
defaultMap(),
|
||||
TYPES.map(details => customMap(details).trimEnd()).join('\n\n'),
|
||||
],
|
||||
defaultMap,
|
||||
TYPES.map(details => customMap(details)),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -43,7 +43,7 @@ pragma solidity ^0.8.20;
|
||||
`;
|
||||
/* eslint-enable max-len */
|
||||
|
||||
const defaultSet = () => `\
|
||||
const defaultSet = `\
|
||||
// To implement this library for multiple types with as little code
|
||||
// repetition as possible, we write it in terms of a generic Set type with
|
||||
// bytes32 values.
|
||||
@ -240,6 +240,11 @@ 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')],
|
||||
format(
|
||||
[].concat(
|
||||
defaultSet,
|
||||
TYPES.map(details => customSet(details)),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -21,25 +21,25 @@ pragma solidity ^0.8.20;
|
||||
`;
|
||||
|
||||
const errors = `\
|
||||
/**
|
||||
/**
|
||||
* @dev Value doesn't fit in an uint of \`bits\` size.
|
||||
*/
|
||||
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
|
||||
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @dev An int value doesn't fit in an uint of \`bits\` size.
|
||||
*/
|
||||
error SafeCastOverflowedIntToUint(int256 value);
|
||||
error SafeCastOverflowedIntToUint(int256 value);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @dev Value doesn't fit in an int of \`bits\` size.
|
||||
*/
|
||||
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
|
||||
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @dev An uint value doesn't fit in an int of \`bits\` size.
|
||||
*/
|
||||
error SafeCastOverflowedUintToInt(uint256 value);
|
||||
error SafeCastOverflowedUintToInt(uint256 value);
|
||||
`;
|
||||
|
||||
const toUintDownCast = length => `\
|
||||
@ -116,23 +116,24 @@ function toUint${length}(int${length} value) internal pure returns (uint${length
|
||||
}
|
||||
`;
|
||||
|
||||
const boolToUint = `
|
||||
/**
|
||||
const boolToUint = `\
|
||||
/**
|
||||
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
|
||||
*/
|
||||
function toUint(bool b) internal pure returns (uint256 u) {
|
||||
function toUint(bool b) internal pure returns (uint256 u) {
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
u := iszero(iszero(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// GENERATE
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
'library SafeCast {',
|
||||
errors,
|
||||
[...LENGTHS.map(toUintDownCast), toUint(256), ...LENGTHS.map(toIntDownCast), toInt(256), boolToUint],
|
||||
format(
|
||||
[].concat(errors, LENGTHS.map(toUintDownCast), toUint(256), LENGTHS.map(toIntDownCast), toInt(256), boolToUint),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -109,8 +109,12 @@ function deriveMapping(bytes32 slot, ${type} memory key) internal pure returns (
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
'library SlotDerivation {',
|
||||
format(
|
||||
[].concat(
|
||||
namespace,
|
||||
array,
|
||||
TYPES.map(type => (type.isValueType ? mapping(type) : mapping2(type))),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -90,8 +90,10 @@ function _assertDeriveMapping${name}(${type} memory key) internal {
|
||||
|
||||
// GENERATE
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
header,
|
||||
'contract SlotDerivationTest is Test, SymTest {',
|
||||
format(
|
||||
[].concat(
|
||||
'using SlotDerivation for bytes32;',
|
||||
'',
|
||||
array,
|
||||
@ -105,5 +107,7 @@ module.exports = format(
|
||||
})),
|
||||
),
|
||||
).map(type => (type.isValueType ? mapping(type) : boundedMapping(type))),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -86,6 +86,7 @@ const udvt = ({ type, name }) => `\
|
||||
* @dev UDVT that represent a slot holding a ${type}.
|
||||
*/
|
||||
type ${name}SlotType is bytes32;
|
||||
|
||||
/**
|
||||
* @dev Cast an arbitrary slot to a ${name}SlotType.
|
||||
*/
|
||||
@ -104,6 +105,7 @@ function tload(${name}SlotType slot) internal view returns (${type} value) {
|
||||
value := tload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Store \`value\` at location \`slot\` in transient storage.
|
||||
*/
|
||||
@ -119,9 +121,13 @@ function tstore(${name}SlotType slot, ${type} value) internal {
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
'library StorageSlot {',
|
||||
format(
|
||||
[].concat(
|
||||
TYPES.map(type => struct(type)),
|
||||
TYPES.flatMap(type => [get(type), type.isValueType ? '' : getStorage(type)]),
|
||||
TYPES.flatMap(type => [get(type), !type.isValueType && getStorage(type)].filter(Boolean)),
|
||||
TYPES.filter(type => type.isValueType).map(type => udvt(type)),
|
||||
TYPES.filter(type => type.isValueType).map(type => transient(type)),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
@ -54,12 +54,17 @@ function tstore(bytes32 slot, ${type} value) public {
|
||||
|
||||
// GENERATE
|
||||
module.exports = format(
|
||||
header.trimEnd(),
|
||||
header,
|
||||
'contract StorageSlotMock is Multicall {',
|
||||
format(
|
||||
[].concat(
|
||||
'using StorageSlot for *;',
|
||||
'',
|
||||
TYPES.filter(type => type.isValueType).map(type => storageSetValueType(type)),
|
||||
TYPES.filter(type => type.isValueType).map(type => storageGetValueType(type)),
|
||||
TYPES.filter(type => !type.isValueType).map(type => storageSetNonValueType(type)),
|
||||
TYPES.filter(type => type.isValueType).map(type => transient(type)),
|
||||
),
|
||||
).trimEnd(),
|
||||
'}',
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user