Generate already lint code from procedural generation (#5060)
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const cp = require('child_process');
|
// const cp = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const format = require('./format-lines');
|
const format = require('./format-lines');
|
||||||
@ -23,11 +23,11 @@ function generateFromTemplate(file, template, outputPrefix = '') {
|
|||||||
...(version ? [version + ` (${file})`] : []),
|
...(version ? [version + ` (${file})`] : []),
|
||||||
`// This file was procedurally generated from ${input}.`,
|
`// This file was procedurally generated from ${input}.`,
|
||||||
'',
|
'',
|
||||||
require(template),
|
require(template).trimEnd(),
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.writeFileSync(output, content);
|
fs.writeFileSync(output, content);
|
||||||
cp.execFileSync('prettier', ['--write', output]);
|
// cp.execFileSync('prettier', ['--write', output]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contracts
|
// Contracts
|
||||||
|
|||||||
@ -47,7 +47,7 @@ const sort = type => `\
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const quickSort = `
|
const quickSort = `\
|
||||||
/**
|
/**
|
||||||
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at \`begin\` (inclusive), and stops
|
* @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.
|
* at end (exclusive). Sorting follows the \`comp\` comparator.
|
||||||
@ -123,7 +123,7 @@ function _swap(uint256 ptr1, uint256 ptr2) private pure {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const defaultComparator = `
|
const defaultComparator = `\
|
||||||
/// @dev Comparator for sorting arrays in increasing order.
|
/// @dev Comparator for sorting arrays in increasing order.
|
||||||
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) {
|
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) {
|
||||||
return a < b;
|
return a < b;
|
||||||
@ -150,7 +150,7 @@ const castComparator = type => `\
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const search = `
|
const search = `\
|
||||||
/**
|
/**
|
||||||
* @dev Searches a sorted \`array\` and returns the first index that contains
|
* @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
|
* a value greater or equal to \`element\`. If no such index exists (i.e. all
|
||||||
@ -319,7 +319,7 @@ 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.
|
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
|
||||||
*
|
*
|
||||||
@ -334,9 +334,10 @@ function unsafeAccess(${type}[] storage arr, uint256 pos) internal pure returns
|
|||||||
slot := arr.slot
|
slot := arr.slot
|
||||||
}
|
}
|
||||||
return slot.deriveArray().offset(pos).get${capitalize(type)}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.
|
* @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.
|
* @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 {
|
assembly {
|
||||||
sstore(array.slot, len)
|
sstore(array.slot, len)
|
||||||
}
|
}
|
||||||
}`;
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
// GENERATE
|
// GENERATE
|
||||||
module.exports = format(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header.trimEnd(),
|
||||||
'library Arrays {',
|
'library Arrays {',
|
||||||
|
format(
|
||||||
|
[].concat(
|
||||||
'using SlotDerivation for bytes32;',
|
'using SlotDerivation for bytes32;',
|
||||||
'using StorageSlot for bytes32;',
|
'using StorageSlot for bytes32;',
|
||||||
|
'',
|
||||||
// sorting, comparator, helpers and internal
|
// sorting, comparator, helpers and internal
|
||||||
sort('bytes32'),
|
sort('bytes32'),
|
||||||
TYPES.filter(type => type !== 'bytes32').map(sort),
|
TYPES.filter(type => type !== 'bytes32').map(sort),
|
||||||
@ -381,5 +386,7 @@ module.exports = format(
|
|||||||
TYPES.map(unsafeAccessStorage),
|
TYPES.map(unsafeAccessStorage),
|
||||||
TYPES.map(unsafeAccessMemory),
|
TYPES.map(unsafeAccessMemory),
|
||||||
TYPES.map(unsafeSetLength),
|
TYPES.map(unsafeSetLength),
|
||||||
|
),
|
||||||
|
).trimEnd(),
|
||||||
'}',
|
'}',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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
|
* IMPORTANT: Never accept \`key\` as a user input, since an arbitrary \`type(${opts.keyTypeName}).max\` key set will disable the
|
||||||
* library.
|
* library.
|
||||||
*/
|
*/
|
||||||
function push(
|
function push(${opts.historyTypeName} storage self, ${opts.keyTypeName} key, ${opts.valueTypeName} value) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
||||||
${opts.historyTypeName} storage self,
|
|
||||||
${opts.keyTypeName} key,
|
|
||||||
${opts.valueTypeName} value
|
|
||||||
) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
|
||||||
return _insert(self.${opts.checkpointFieldName}, key, value);
|
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
|
* @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.
|
* in the most recent checkpoint.
|
||||||
*/
|
*/
|
||||||
function latestCheckpoint(${opts.historyTypeName} storage self)
|
function latestCheckpoint(${opts.historyTypeName} storage self) internal view returns (bool exists, ${opts.keyTypeName} ${opts.keyFieldName}, ${opts.valueTypeName} ${opts.valueFieldName}) {
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (
|
|
||||||
bool exists,
|
|
||||||
${opts.keyTypeName} ${opts.keyFieldName},
|
|
||||||
${opts.valueTypeName} ${opts.valueFieldName}
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uint256 pos = self.${opts.checkpointFieldName}.length;
|
uint256 pos = self.${opts.checkpointFieldName}.length;
|
||||||
if (pos == 0) {
|
if (pos == 0) {
|
||||||
return (false, 0, 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,
|
* @dev Pushes a (\`key\`, \`value\`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
|
||||||
* or by updating the last one.
|
* or by updating the last one.
|
||||||
*/
|
*/
|
||||||
function _insert(
|
function _insert(${opts.checkpointTypeName}[] storage self, ${opts.keyTypeName} key, ${opts.valueTypeName} value) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
||||||
${opts.checkpointTypeName}[] storage self,
|
|
||||||
${opts.keyTypeName} key,
|
|
||||||
${opts.valueTypeName} value
|
|
||||||
) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) {
|
|
||||||
uint256 pos = self.length;
|
uint256 pos = self.length;
|
||||||
|
|
||||||
if (pos > 0) {
|
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.
|
* @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)
|
function _unsafeAccess(
|
||||||
private
|
${opts.checkpointTypeName}[] storage self,
|
||||||
pure
|
uint256 pos
|
||||||
returns (${opts.checkpointTypeName} storage result)
|
) private pure returns (${opts.checkpointTypeName} storage result) {
|
||||||
{
|
|
||||||
assembly {
|
assembly {
|
||||||
mstore(0, self.slot)
|
mstore(0, self.slot)
|
||||||
result.slot := add(keccak256(0, 0x20), pos)
|
result.slot := add(keccak256(0, 0x20), pos)
|
||||||
@ -242,7 +225,11 @@ function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos)
|
|||||||
module.exports = format(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header.trimEnd(),
|
||||||
'library Checkpoints {',
|
'library Checkpoints {',
|
||||||
|
format(
|
||||||
|
[].concat(
|
||||||
errors,
|
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;
|
Checkpoints.${opts.historyTypeName} internal _ckpts;
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
function _bound${capitalize(opts.keyTypeName)}(
|
function _bound${capitalize(opts.keyTypeName)}(${opts.keyTypeName} x, ${opts.keyTypeName} min, ${
|
||||||
${opts.keyTypeName} x,
|
opts.keyTypeName
|
||||||
${opts.keyTypeName} min,
|
} max) internal pure returns (${opts.keyTypeName}) {
|
||||||
${opts.keyTypeName} max
|
|
||||||
) internal pure returns (${opts.keyTypeName}) {
|
|
||||||
return SafeCast.to${capitalize(opts.keyTypeName)}(bound(uint256(x), uint256(min), uint256(max)));
|
return SafeCast.to${capitalize(opts.keyTypeName)}(bound(uint256(x), uint256(min), uint256(max)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function _prepareKeys(
|
function _prepareKeys(${opts.keyTypeName}[] memory keys, ${opts.keyTypeName} maxSpread) internal pure {
|
||||||
${opts.keyTypeName}[] memory keys,
|
|
||||||
${opts.keyTypeName} maxSpread
|
|
||||||
) internal pure {
|
|
||||||
${opts.keyTypeName} lastKey = 0;
|
${opts.keyTypeName} lastKey = 0;
|
||||||
for (uint256 i = 0; i < keys.length; ++i) {
|
for (uint256 i = 0; i < keys.length; ++i) {
|
||||||
${opts.keyTypeName} key = _bound${capitalize(opts.keyTypeName)}(keys[i], lastKey, lastKey + maxSpread);
|
${opts.keyTypeName} key = _bound${capitalize(opts.keyTypeName)}(keys[i], lastKey, lastKey + maxSpread);
|
||||||
@ -42,11 +37,7 @@ function _prepareKeys(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _assertLatestCheckpoint(
|
function _assertLatestCheckpoint(bool exist, ${opts.keyTypeName} key, ${opts.valueTypeName} value) internal {
|
||||||
bool exist,
|
|
||||||
${opts.keyTypeName} key,
|
|
||||||
${opts.valueTypeName} value
|
|
||||||
) internal {
|
|
||||||
(bool _exist, ${opts.keyTypeName} _key, ${opts.valueTypeName} _value) = _ckpts.latestCheckpoint();
|
(bool _exist, ${opts.keyTypeName} _key, ${opts.valueTypeName} _value) = _ckpts.latestCheckpoint();
|
||||||
assertEq(_exist, exist);
|
assertEq(_exist, exist);
|
||||||
assertEq(_key, key);
|
assertEq(_key, key);
|
||||||
@ -54,11 +45,9 @@ function _assertLatestCheckpoint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tests
|
// tests
|
||||||
function testPush(
|
function testPush(${opts.keyTypeName}[] memory keys, ${opts.valueTypeName}[] memory values, ${
|
||||||
${opts.keyTypeName}[] memory keys,
|
opts.keyTypeName
|
||||||
${opts.valueTypeName}[] memory values,
|
} pastKey) public {
|
||||||
${opts.keyTypeName} pastKey
|
|
||||||
) public {
|
|
||||||
vm.assume(values.length > 0 && values.length <= keys.length);
|
vm.assume(values.length > 0 && values.length <= keys.length);
|
||||||
_prepareKeys(keys, _KEY_MAX_GAP);
|
_prepareKeys(keys, _KEY_MAX_GAP);
|
||||||
|
|
||||||
@ -98,11 +87,9 @@ function push(${opts.keyTypeName} key, ${opts.valueTypeName} value) external {
|
|||||||
_ckpts.push(key, value);
|
_ckpts.push(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testLookup(
|
function testLookup(${opts.keyTypeName}[] memory keys, ${opts.valueTypeName}[] memory values, ${
|
||||||
${opts.keyTypeName}[] memory keys,
|
opts.keyTypeName
|
||||||
${opts.valueTypeName}[] memory values,
|
} lookup) public {
|
||||||
${opts.keyTypeName} lookup
|
|
||||||
) public {
|
|
||||||
vm.assume(values.length > 0 && values.length <= keys.length);
|
vm.assume(values.length > 0 && values.length <= keys.length);
|
||||||
_prepareKeys(keys, _KEY_MAX_GAP);
|
_prepareKeys(keys, _KEY_MAX_GAP);
|
||||||
|
|
||||||
@ -142,5 +129,10 @@ function testLookup(
|
|||||||
// GENERATE
|
// GENERATE
|
||||||
module.exports = format(
|
module.exports = format(
|
||||||
header,
|
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 */
|
/* 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
|
// 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,
|
// 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.
|
// 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
|
* Returns true if the key was added to the map, that is if it was not
|
||||||
* already present.
|
* already present.
|
||||||
*/
|
*/
|
||||||
function set(
|
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
|
||||||
Bytes32ToBytes32Map storage map,
|
|
||||||
bytes32 key,
|
|
||||||
bytes32 value
|
|
||||||
) internal returns (bool) {
|
|
||||||
map._values[key] = value;
|
map._values[key] = value;
|
||||||
return map._keys.add(key);
|
return map._keys.add(key);
|
||||||
}
|
}
|
||||||
@ -181,11 +177,7 @@ struct ${name} {
|
|||||||
* Returns true if the key was added to the map, that is if it was not
|
* Returns true if the key was added to the map, that is if it was not
|
||||||
* already present.
|
* already present.
|
||||||
*/
|
*/
|
||||||
function set(
|
function set(${name} storage map, ${keyType} key, ${valueType} value) internal returns (bool) {
|
||||||
${name} storage map,
|
|
||||||
${keyType} key,
|
|
||||||
${valueType} value
|
|
||||||
) internal returns (bool) {
|
|
||||||
return set(map._inner, ${toBytes32(keyType, 'key')}, ${toBytes32(valueType, 'value')});
|
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(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header.trimEnd(),
|
||||||
'library EnumerableMap {',
|
'library EnumerableMap {',
|
||||||
[
|
format(
|
||||||
|
[].concat(
|
||||||
'using EnumerableSet for EnumerableSet.Bytes32Set;',
|
'using EnumerableSet for EnumerableSet.Bytes32Set;',
|
||||||
'',
|
'',
|
||||||
defaultMap(),
|
defaultMap,
|
||||||
TYPES.map(details => customMap(details).trimEnd()).join('\n\n'),
|
TYPES.map(details => customMap(details)),
|
||||||
],
|
),
|
||||||
|
).trimEnd(),
|
||||||
'}',
|
'}',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -43,7 +43,7 @@ pragma solidity ^0.8.20;
|
|||||||
`;
|
`;
|
||||||
/* eslint-enable max-len */
|
/* eslint-enable max-len */
|
||||||
|
|
||||||
const defaultSet = () => `\
|
const defaultSet = `\
|
||||||
// To implement this library for multiple types with as little code
|
// 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
|
// repetition as possible, we write it in terms of a generic Set type with
|
||||||
// bytes32 values.
|
// bytes32 values.
|
||||||
@ -240,6 +240,11 @@ function values(${name} storage set) internal view returns (${type}[] memory) {
|
|||||||
module.exports = format(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header.trimEnd(),
|
||||||
'library EnumerableSet {',
|
'library EnumerableSet {',
|
||||||
[defaultSet(), TYPES.map(details => customSet(details).trimEnd()).join('\n\n')],
|
format(
|
||||||
|
[].concat(
|
||||||
|
defaultSet,
|
||||||
|
TYPES.map(details => customSet(details)),
|
||||||
|
),
|
||||||
|
).trimEnd(),
|
||||||
'}',
|
'}',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -116,7 +116,7 @@ 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.
|
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
|
||||||
*/
|
*/
|
||||||
@ -132,7 +132,8 @@ const boolToUint = `
|
|||||||
module.exports = format(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header.trimEnd(),
|
||||||
'library SafeCast {',
|
'library SafeCast {',
|
||||||
errors,
|
format(
|
||||||
[...LENGTHS.map(toUintDownCast), toUint(256), ...LENGTHS.map(toIntDownCast), toInt(256), boolToUint],
|
[].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(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header.trimEnd(),
|
||||||
'library SlotDerivation {',
|
'library SlotDerivation {',
|
||||||
|
format(
|
||||||
|
[].concat(
|
||||||
namespace,
|
namespace,
|
||||||
array,
|
array,
|
||||||
TYPES.map(type => (type.isValueType ? mapping(type) : mapping2(type))),
|
TYPES.map(type => (type.isValueType ? mapping(type) : mapping2(type))),
|
||||||
|
),
|
||||||
|
).trimEnd(),
|
||||||
'}',
|
'}',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -90,8 +90,10 @@ function _assertDeriveMapping${name}(${type} memory key) internal {
|
|||||||
|
|
||||||
// GENERATE
|
// GENERATE
|
||||||
module.exports = format(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header,
|
||||||
'contract SlotDerivationTest is Test, SymTest {',
|
'contract SlotDerivationTest is Test, SymTest {',
|
||||||
|
format(
|
||||||
|
[].concat(
|
||||||
'using SlotDerivation for bytes32;',
|
'using SlotDerivation for bytes32;',
|
||||||
'',
|
'',
|
||||||
array,
|
array,
|
||||||
@ -105,5 +107,7 @@ module.exports = format(
|
|||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
).map(type => (type.isValueType ? mapping(type) : boundedMapping(type))),
|
).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}.
|
* @dev UDVT that represent a slot holding a ${type}.
|
||||||
*/
|
*/
|
||||||
type ${name}SlotType is bytes32;
|
type ${name}SlotType is bytes32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Cast an arbitrary slot to a ${name}SlotType.
|
* @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)
|
value := tload(slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Store \`value\` at location \`slot\` in transient storage.
|
* @dev Store \`value\` at location \`slot\` in transient storage.
|
||||||
*/
|
*/
|
||||||
@ -119,9 +121,13 @@ function tstore(${name}SlotType slot, ${type} value) internal {
|
|||||||
module.exports = format(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header.trimEnd(),
|
||||||
'library StorageSlot {',
|
'library StorageSlot {',
|
||||||
|
format(
|
||||||
|
[].concat(
|
||||||
TYPES.map(type => struct(type)),
|
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 => udvt(type)),
|
||||||
TYPES.filter(type => type.isValueType).map(type => transient(type)),
|
TYPES.filter(type => type.isValueType).map(type => transient(type)),
|
||||||
|
),
|
||||||
|
).trimEnd(),
|
||||||
'}',
|
'}',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -54,12 +54,17 @@ function tstore(bytes32 slot, ${type} value) public {
|
|||||||
|
|
||||||
// GENERATE
|
// GENERATE
|
||||||
module.exports = format(
|
module.exports = format(
|
||||||
header.trimEnd(),
|
header,
|
||||||
'contract StorageSlotMock is Multicall {',
|
'contract StorageSlotMock is Multicall {',
|
||||||
|
format(
|
||||||
|
[].concat(
|
||||||
'using StorageSlot for *;',
|
'using StorageSlot for *;',
|
||||||
|
'',
|
||||||
TYPES.filter(type => type.isValueType).map(type => storageSetValueType(type)),
|
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 => storageGetValueType(type)),
|
||||||
TYPES.filter(type => !type.isValueType).map(type => storageSetNonValueType(type)),
|
TYPES.filter(type => !type.isValueType).map(type => storageSetNonValueType(type)),
|
||||||
TYPES.filter(type => type.isValueType).map(type => transient(type)),
|
TYPES.filter(type => type.isValueType).map(type => transient(type)),
|
||||||
|
),
|
||||||
|
).trimEnd(),
|
||||||
'}',
|
'}',
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user