Use Prettier for JS files (#3913)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
pull/3933/head
Francisco 3 months ago committed by GitHub
parent 88754d0b36
commit a28aafdc85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .prettierrc
  2. 26
      .solcover.js
  3. 16
      docs/templates/helpers.js
  4. 10
      docs/templates/properties.js
  5. 7
      hardhat.config.js
  6. 4
      hardhat/ignore-unreachable-warnings.js
  7. 7
      hardhat/skip-foundry-tests.js
  8. 2
      package-lock.json
  9. 12
      package.json
  10. 176
      scripts/checks/compareGasReports.js
  11. 38
      scripts/checks/inheritance-ordering.js
  12. 16
      scripts/gen-nav.js
  13. 8
      scripts/generate/format-lines.js
  14. 10
      scripts/generate/run.js
  15. 10
      scripts/generate/templates/Checkpoints.js
  16. 5
      scripts/generate/templates/EnumerableSet.js
  17. 95
      scripts/generate/templates/SafeCast.js
  18. 36
      scripts/generate/templates/conversion.js
  19. 23
      scripts/helpers.js
  20. 12
      scripts/migrate-imports.js
  21. 2
      scripts/release/synchronize-versions.js
  22. 5
      scripts/release/update-changelog-release-date.js
  23. 2
      scripts/release/update-comment.js
  24. 6
      scripts/remove-ignored-artifacts.js
  25. 14
      scripts/update-docs-branch.js
  26. 18
      test/access/AccessControl.behavior.js
  27. 5
      test/access/AccessControl.test.js
  28. 28
      test/access/AccessControlCrossChain.test.js
  29. 12
      test/access/Ownable.test.js
  30. 20
      test/crosschain/CrossChainEnabled.test.js
  31. 89
      test/finance/PaymentSplitter.test.js
  32. 39
      test/finance/VestingWallet.behavior.js
  33. 18
      test/finance/VestingWallet.test.js
  34. 297
      test/governance/Governor.test.js
  35. 200
      test/governance/TimelockController.test.js
  36. 122
      test/governance/compatibility/GovernorCompatibilityBravo.test.js
  37. 19
      test/governance/extensions/GovernorComp.test.js
  38. 61
      test/governance/extensions/GovernorERC721.test.js
  39. 80
      test/governance/extensions/GovernorPreventLateQuorum.test.js
  40. 193
      test/governance/extensions/GovernorTimelockCompound.test.js
  41. 174
      test/governance/extensions/GovernorTimelockControl.test.js
  42. 92
      test/governance/extensions/GovernorVotesQuorumFraction.test.js
  43. 48
      test/governance/extensions/GovernorWithParams.test.js
  44. 106
      test/governance/utils/Votes.behavior.js
  45. 11
      test/governance/utils/Votes.test.js
  46. 2
      test/helpers/chainid.js
  47. 13
      test/helpers/create2.js
  48. 64
      test/helpers/crosschain.js
  49. 6
      test/helpers/customError.js
  50. 16
      test/helpers/eip712.js
  51. 27
      test/helpers/enums.js
  52. 4
      test/helpers/erc1967.js
  53. 177
      test/helpers/governance.js
  54. 48
      test/helpers/sign.js
  55. 10
      test/helpers/txpool.js
  56. 48
      test/metatx/MinimalForwarder.test.js
  57. 5
      test/migrate-imports.test.js
  58. 44
      test/proxy/Clones.behaviour.js
  59. 26
      test/proxy/Clones.test.js
  60. 15
      test/proxy/Proxy.behaviour.js
  61. 31
      test/proxy/beacon/BeaconProxy.test.js
  62. 10
      test/proxy/beacon/UpgradeableBeacon.test.js
  63. 18
      test/proxy/transparent/ProxyAdmin.test.js
  64. 41
      test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js
  65. 10
      test/proxy/utils/UUPSUpgradeable.test.js
  66. 14
      test/security/Pausable.test.js
  67. 2
      test/security/PullPayment.test.js
  68. 11
      test/security/ReentrancyGuard.test.js
  69. 291
      test/token/ERC1155/ERC1155.behavior.js
  70. 53
      test/token/ERC1155/ERC1155.test.js
  71. 16
      test/token/ERC1155/extensions/ERC1155Burnable.test.js
  72. 8
      test/token/ERC1155/extensions/ERC1155Pausable.test.js
  73. 16
      test/token/ERC1155/extensions/ERC1155Supply.test.js
  74. 2
      test/token/ERC1155/extensions/ERC1155URIStorage.test.js
  75. 38
      test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js
  76. 12
      test/token/ERC1155/utils/ERC1155Holder.test.js
  77. 97
      test/token/ERC20/ERC20.behavior.js
  78. 67
      test/token/ERC20/ERC20.test.js
  79. 19
      test/token/ERC20/extensions/ERC20Burnable.behavior.js
  80. 2
      test/token/ERC20/extensions/ERC20Burnable.test.js
  81. 2
      test/token/ERC20/extensions/ERC20Capped.behavior.js
  82. 95
      test/token/ERC20/extensions/ERC20FlashMint.test.js
  83. 18
      test/token/ERC20/extensions/ERC20Pausable.test.js
  84. 26
      test/token/ERC20/extensions/ERC20Snapshot.test.js
  85. 249
      test/token/ERC20/extensions/ERC20Votes.test.js
  86. 231
      test/token/ERC20/extensions/ERC20VotesComp.test.js
  87. 2
      test/token/ERC20/extensions/ERC20Wrapper.test.js
  88. 8
      test/token/ERC20/extensions/ERC4626.test.js
  89. 11
      test/token/ERC20/extensions/draft-ERC20Permit.test.js
  90. 7
      test/token/ERC20/presets/ERC20PresetMinterPauser.test.js
  91. 34
      test/token/ERC20/utils/SafeERC20.test.js
  92. 2
      test/token/ERC20/utils/TokenTimelock.test.js
  93. 197
      test/token/ERC721/ERC721.behavior.js
  94. 5
      test/token/ERC721/ERC721.test.js
  95. 13
      test/token/ERC721/extensions/ERC721Burnable.test.js
  96. 93
      test/token/ERC721/extensions/ERC721Consecutive.test.js
  97. 19
      test/token/ERC721/extensions/ERC721Pausable.test.js
  98. 2
      test/token/ERC721/extensions/ERC721Royalty.test.js
  99. 17
      test/token/ERC721/extensions/ERC721URIStorage.test.js
  100. 24
      test/token/ERC721/extensions/ERC721Votes.test.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,12 +1,13 @@
{
"printWidth": 120,
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid",
"overrides": [
{
"files": "*.sol",
"options": {
"singleQuote": false,
"printWidth": 120
"singleQuote": false
}
}
]

@ -1,15 +1,13 @@
module.exports = {
norpc: true,
testCommand: 'npm test',
compileCommand: 'npm run compile',
skipFiles: [
'mocks',
],
providerOptions: {
default_balance_ether: '10000000000000000000000000',
},
mocha: {
fgrep: '[skip-on-coverage]',
invert: true,
},
}
norpc: true,
testCommand: 'npm test',
compileCommand: 'npm run compile',
skipFiles: ['mocks'],
providerOptions: {
default_balance_ether: '10000000000000000000000000',
},
mocha: {
fgrep: '[skip-on-coverage]',
invert: true,
},
};

@ -2,26 +2,26 @@ const { version } = require('../../package.json');
module.exports['oz-version'] = () => version;
module.exports['readme-path'] = (opts) => {
module.exports['readme-path'] = opts => {
return 'contracts/' + opts.data.root.id.replace(/\.adoc$/, '') + '/README.adoc';
};
module.exports.names = (params) => params.map(p => p.name).join(', ');
module.exports.names = params => params.map(p => p.name).join(', ');
module.exports['typed-params'] = (params) => {
module.exports['typed-params'] = params => {
return params.map(p => `${p.type}${p.name ? ' ' + p.name : ''}`).join(', ');
};
const slug = module.exports.slug = (str) => {
const slug = (module.exports.slug = str => {
if (str === undefined) {
throw new Error('Missing argument');
}
return str.replace(/\W/g, '-');
};
});
const linksCache = new WeakMap();
function getAllLinks (items) {
function getAllLinks(items) {
if (linksCache.has(items)) {
return linksCache.get(items);
}
@ -34,11 +34,11 @@ function getAllLinks (items) {
return res;
}
module.exports['with-prelude'] = (opts) => {
module.exports['with-prelude'] = opts => {
const links = getAllLinks(opts.data.site.items);
const contents = opts.fn();
const neededLinks = contents
.match(/\{[-._a-z0-9]+\}/ig)
.match(/\{[-._a-z0-9]+\}/gi)
.map(m => m.replace(/^\{(.+)\}$/, '$1'))
.filter(k => k in links);
const prelude = neededLinks.map(k => `:${k}: ${links[k]}`).join('\n');

@ -1,7 +1,7 @@
const { isNodeType } = require('solidity-ast/utils');
const { slug } = require('./helpers');
module.exports.anchor = function anchor ({ item, contract }) {
module.exports.anchor = function anchor({ item, contract }) {
let res = '';
if (contract) {
res += contract.name + '-';
@ -37,13 +37,9 @@ module.exports['has-events'] = function ({ item }) {
module.exports['inherited-functions'] = function ({ item }) {
const { inheritance } = item;
const baseFunctions = new Set(
inheritance.flatMap(c => c.functions.flatMap(f => f.baseFunctions ?? [])),
);
const baseFunctions = new Set(inheritance.flatMap(c => c.functions.flatMap(f => f.baseFunctions ?? [])));
return inheritance.map((contract, i) => ({
contract,
functions: contract.functions.filter(f =>
!baseFunctions.has(f.id) && (f.name !== 'constructor' || i === 0),
),
functions: contract.functions.filter(f => !baseFunctions.has(f.id) && (f.name !== 'constructor' || i === 0)),
}));
};

@ -29,7 +29,7 @@ const argv = require('yargs/yargs')()
mode: {
alias: 'compileMode',
type: 'string',
choices: [ 'production', 'development' ],
choices: ['production', 'development'],
default: 'development',
},
ir: {
@ -46,8 +46,7 @@ const argv = require('yargs/yargs')()
alias: 'coinmarketcapApiKey',
type: 'string',
},
})
.argv;
}).argv;
require('@nomiclabs/hardhat-truffle5');
require('hardhat-ignore-warnings');
@ -106,7 +105,7 @@ if (argv.gas) {
outputFile: argv.gasReport,
coinmarketcap: argv.coinmarketcap,
};
};
}
if (argv.coverage) {
require('solidity-coverage');

@ -38,9 +38,7 @@ task(TASK_COMPILE_SOLIDITY_COMPILE, async (params, _, runSuper) => {
if (marked) {
result.output = {
...result.output,
errors: result.output.errors?.filter(
e => e.severity !== 'warning' || e.errorCode !== W_UNREACHABLE_CODE,
),
errors: result.output.errors?.filter(e => e.severity !== 'warning' || e.errorCode !== W_UNREACHABLE_CODE),
};
}
return result;

@ -1,7 +1,6 @@
const { subtask } = require('hardhat/config');
const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-tasks/task-names');
subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS)
.setAction(async (_, __, runSuper) =>
(await runSuper()).filter((path) => !path.endsWith('.t.sol')),
);
subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) =>
(await runSuper()).filter(path => !path.endsWith('.t.sol')),
);

2
package-lock.json generated

@ -34,7 +34,7 @@
"lodash.zip": "^4.2.0",
"merkletreejs": "^0.2.13",
"micromatch": "^4.0.2",
"prettier": "^2.3.0",
"prettier": "^2.8.1",
"prettier-plugin-solidity": "^1.1.0",
"rimraf": "^3.0.2",
"semver": "^7.3.5",

@ -14,14 +14,14 @@
"compile": "hardhat compile",
"coverage": "env COVERAGE=true hardhat coverage",
"docs": "npm run prepare-docs && oz-docs",
"docs:watch": "oz-docs watch contracts 'docs/templates' docs/config.js",
"docs:watch": "oz-docs watch contracts docs/templates docs/config.js",
"prepare-docs": "scripts/prepare-docs.sh",
"lint": "npm run lint:js && npm run lint:sol",
"lint:fix": "npm run lint:js:fix && npm run lint:sol:fix",
"lint:js": "eslint --ignore-path .gitignore .",
"lint:js:fix": "eslint --ignore-path .gitignore . --fix",
"lint:sol": "solhint '{contracts,test}/**/*.sol' && prettier -c '{contracts,test}/**/*.sol'",
"lint:sol:fix": "prettier --write '{contracts,test}/**/*.sol'",
"lint:js": "prettier --loglevel warn --ignore-path .gitignore '**/*.{js,ts}' --check && eslint --ignore-path .gitignore .",
"lint:js:fix": "prettier --loglevel warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint --ignore-path .gitignore . --fix",
"lint:sol": "prettier --loglevel warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write && solhint '{contracts,test}/**/*.sol'",
"lint:sol:fix": "prettier --loglevel warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write",
"clean": "hardhat clean && rimraf build contracts/build",
"prepare": "scripts/prepare.sh",
"prepack": "scripts/prepack.sh",
@ -75,7 +75,7 @@
"lodash.zip": "^4.2.0",
"merkletreejs": "^0.2.13",
"micromatch": "^4.0.2",
"prettier": "^2.3.0",
"prettier": "^2.8.1",
"prettier-plugin-solidity": "^1.1.0",
"rimraf": "^3.0.2",
"semver": "^7.3.5",

@ -7,7 +7,7 @@ const { argv } = require('yargs')
.options({
style: {
type: 'string',
choices: [ 'shell', 'markdown' ],
choices: ['shell', 'markdown'],
default: 'shell',
},
});
@ -16,52 +16,55 @@ const { argv } = require('yargs')
const BASE_TX_COST = 21000;
// Utilities
function sum (...args) {
function sum(...args) {
return args.reduce((a, b) => a + b, 0);
}
function average (...args) {
function average(...args) {
return sum(...args) / args.length;
}
function variation (current, previous, offset = 0) {
function variation(current, previous, offset = 0) {
return {
value: current,
delta: current - previous,
prcnt: 100 * (current - previous) / (previous - offset),
prcnt: (100 * (current - previous)) / (previous - offset),
};
}
// Report class
class Report {
// Read report file
static load (filepath) {
static load(filepath) {
return JSON.parse(fs.readFileSync(filepath, 'utf8'));
}
// Compare two reports
static compare (update, ref, opts = { hideEqual: true }) {
static compare(update, ref, opts = { hideEqual: true }) {
if (JSON.stringify(update.config.metadata) !== JSON.stringify(ref.config.metadata)) {
throw new Error('Reports produced with non matching metadata');
}
const deployments = update.info.deployments
.map(contract => Object.assign(
contract,
{ previousVersion: ref.info.deployments.find(({ name }) => name === contract.name) },
))
.map(contract =>
Object.assign(contract, { previousVersion: ref.info.deployments.find(({ name }) => name === contract.name) }),
)
.filter(contract => contract.gasData?.length && contract.previousVersion?.gasData?.length)
.flatMap(contract => [{
contract: contract.name,
method: '[bytecode length]',
avg: variation(contract.bytecode.length / 2 - 1, contract.previousVersion.bytecode.length / 2 - 1),
}, {
contract: contract.name,
method: '[construction cost]',
avg: variation(
...[contract.gasData, contract.previousVersion.gasData].map(x => Math.round(average(...x))),
BASE_TX_COST),
}])
.flatMap(contract => [
{
contract: contract.name,
method: '[bytecode length]',
avg: variation(contract.bytecode.length / 2 - 1, contract.previousVersion.bytecode.length / 2 - 1),
},
{
contract: contract.name,
method: '[construction cost]',
avg: variation(
...[contract.gasData, contract.previousVersion.gasData].map(x => Math.round(average(...x))),
BASE_TX_COST,
),
},
])
.sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`));
const methods = Object.keys(update.info.methods)
@ -77,21 +80,22 @@ class Report {
}))
.sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`));
return [].concat(deployments, methods)
return []
.concat(deployments, methods)
.filter(row => !opts.hideEqual || row.min?.delta || row.max?.delta || row.avg?.delta);
}
}
// Display
function center (text, length) {
function center(text, length) {
return text.padStart((text.length + length) / 2).padEnd(length);
}
function plusSign (num) {
function plusSign(num) {
return num > 0 ? '+' : '';
}
function formatCellShell (cell) {
function formatCellShell(cell) {
const format = chalk[cell?.delta > 0 ? 'red' : cell?.delta < 0 ? 'green' : 'reset'];
return [
format((!isFinite(cell?.value) ? '-' : cell.value.toString()).padStart(8)),
@ -100,7 +104,7 @@ function formatCellShell (cell) {
];
}
function formatCmpShell (rows) {
function formatCmpShell(rows) {
const contractLength = Math.max(8, ...rows.map(({ contract }) => contract.length));
const methodLength = Math.max(7, ...rows.map(({ method }) => method.length));
@ -113,54 +117,60 @@ function formatCmpShell (rows) {
{ txt: 'Avg', length: 30 },
{ txt: '', length: 0 },
];
const HEADER = COLS.map(entry => chalk.bold(center(entry.txt, entry.length || 0))).join(' | ').trim();
const SEPARATOR = COLS.map(({ length }) => length > 0 ? '-'.repeat(length + 2) : '').join('|').trim();
const HEADER = COLS.map(entry => chalk.bold(center(entry.txt, entry.length || 0)))
.join(' | ')
.trim();
const SEPARATOR = COLS.map(({ length }) => (length > 0 ? '-'.repeat(length + 2) : ''))
.join('|')
.trim();
return [
'',
HEADER,
...rows.map(entry => [
'',
chalk.grey(entry.contract.padEnd(contractLength)),
entry.method.padEnd(methodLength),
...formatCellShell(entry.min),
...formatCellShell(entry.max),
...formatCellShell(entry.avg),
'',
].join(' | ').trim()),
...rows.map(entry =>
[
'',
chalk.grey(entry.contract.padEnd(contractLength)),
entry.method.padEnd(methodLength),
...formatCellShell(entry.min),
...formatCellShell(entry.max),
...formatCellShell(entry.avg),
'',
]
.join(' | ')
.trim(),
),
'',
].join(`\n${SEPARATOR}\n`).trim();
]
.join(`\n${SEPARATOR}\n`)
.trim();
}
function alignPattern (align) {
function alignPattern(align) {
switch (align) {
case 'left':
case undefined:
return ':-';
case 'right':
return '-:';
case 'center':
return ':-:';
case 'left':
case undefined:
return ':-';
case 'right':
return '-:';
case 'center':
return ':-:';
}
}
function trend (value) {
return value > 0
? ':x:'
: value < 0
? ':heavy_check_mark:'
: ':heavy_minus_sign:';
function trend(value) {
return value > 0 ? ':x:' : value < 0 ? ':heavy_check_mark:' : ':heavy_minus_sign:';
}
function formatCellMarkdown (cell) {
function formatCellMarkdown(cell) {
return [
(!isFinite(cell?.value) ? '-' : cell.value.toString()),
(!isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString()),
(!isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%' + trend(cell.delta)),
!isFinite(cell?.value) ? '-' : cell.value.toString(),
!isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString(),
!isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%' + trend(cell.delta),
];
}
function formatCmpMarkdown (rows) {
function formatCmpMarkdown(rows) {
const COLS = [
{ txt: '' },
{ txt: 'Contract', align: 'left' },
@ -176,36 +186,48 @@ function formatCmpMarkdown (rows) {
{ txt: '%', align: 'right' },
{ txt: '' },
];
const HEADER = COLS.map(entry => entry.txt).join(' | ').trim();
const SEPARATOR = COLS.map(entry => entry.txt ? alignPattern(entry.align) : '').join('|').trim();
const HEADER = COLS.map(entry => entry.txt)
.join(' | ')
.trim();
const SEPARATOR = COLS.map(entry => (entry.txt ? alignPattern(entry.align) : ''))
.join('|')
.trim();
return [
'# Changes to gas costs',
'',
HEADER,
SEPARATOR,
rows.map(entry => [
'',
entry.contract,
entry.method,
...formatCellMarkdown(entry.min),
...formatCellMarkdown(entry.max),
...formatCellMarkdown(entry.avg),
'',
].join(' | ').trim()).join('\n'),
rows
.map(entry =>
[
'',
entry.contract,
entry.method,
...formatCellMarkdown(entry.min),
...formatCellMarkdown(entry.max),
...formatCellMarkdown(entry.avg),
'',
]
.join(' | ')
.trim(),
)
.join('\n'),
'',
].join('\n').trim();
]
.join('\n')
.trim();
}
// MAIN
const report = Report.compare(Report.load(argv._[0]), Report.load(argv._[1]));
switch (argv.style) {
case 'markdown':
console.log(formatCmpMarkdown(report));
break;
case 'shell':
default:
console.log(formatCmpShell(report));
break;
case 'markdown':
console.log(formatCmpMarkdown(report));
break;
case 'shell':
default:
console.log(formatCmpShell(report));
break;
}

@ -21,28 +21,32 @@ for (const artifact of artifacts) {
names[contractDef.id] = contractDef.name;
linearized.push(contractDef.linearizedBaseContracts);
contractDef.linearizedBaseContracts.forEach((c1, i, contracts) => contracts.slice(i + 1).forEach(c2 => {
graph.setEdge(c1, c2);
}));
contractDef.linearizedBaseContracts.forEach((c1, i, contracts) =>
contracts.slice(i + 1).forEach(c2 => {
graph.setEdge(c1, c2);
}),
);
}
}
/// graphlib.alg.findCycles will not find minimal cycles.
/// We are only interested int cycles of lengths 2 (needs proof)
graph.nodes().forEach((x, i, nodes) => nodes
.slice(i + 1)
.filter(y => graph.hasEdge(x, y) && graph.hasEdge(y, x))
.forEach(y => {
console.log(`Conflict between ${names[x]} and ${names[y]} detected in the following dependency chains:`);
linearized
.filter(chain => chain.includes(parseInt(x)) && chain.includes(parseInt(y)))
.forEach(chain => {
const comp = chain.indexOf(parseInt(x)) < chain.indexOf(parseInt(y)) ? '>' : '<';
console.log(`- ${names[x]} ${comp} ${names[y]} in ${names[chain.find(Boolean)]}`);
// console.log(`- ${names[x]} ${comp} ${names[y]}: ${chain.reverse().map(id => names[id]).join(', ')}`);
});
process.exitCode = 1;
}));
graph.nodes().forEach((x, i, nodes) =>
nodes
.slice(i + 1)
.filter(y => graph.hasEdge(x, y) && graph.hasEdge(y, x))
.forEach(y => {
console.log(`Conflict between ${names[x]} and ${names[y]} detected in the following dependency chains:`);
linearized
.filter(chain => chain.includes(parseInt(x)) && chain.includes(parseInt(y)))
.forEach(chain => {
const comp = chain.indexOf(parseInt(x)) < chain.indexOf(parseInt(y)) ? '>' : '<';
console.log(`- ${names[x]} ${comp} ${names[y]} in ${names[chain.find(Boolean)]}`);
// console.log(`- ${names[x]} ${comp} ${names[y]}: ${chain.reverse().map(id => names[id]).join(', ')}`);
});
process.exitCode = 1;
}),
);
}
if (!process.exitCode) {

@ -10,18 +10,18 @@ const files = glob.sync(baseDir + '/**/*.adoc').map(f => path.relative(baseDir,
console.log('.API');
function getPageTitle (directory) {
function getPageTitle(directory) {
switch (directory) {
case 'metatx':
return 'Meta Transactions';
case 'common':
return 'Common (Tokens)';
default:
return startCase(directory);
case 'metatx':
return 'Meta Transactions';
case 'common':
return 'Common (Tokens)';
default:
return startCase(directory);
}
}
const links = files.map((file) => {
const links = files.map(file => {
const doc = file.replace(baseDir, '');
const title = path.parse(file).name;

@ -1,14 +1,14 @@
function formatLines (...lines) {
function formatLines(...lines) {
return [...indentEach(0, lines)].join('\n') + '\n';
}
function *indentEach (indent, lines) {
function* indentEach(indent, lines) {
for (const line of lines) {
if (Array.isArray(line)) {
yield * indentEach(indent + 1, line);
yield* indentEach(indent + 1, line);
} else {
const padding = ' '.repeat(indent);
yield * line.split('\n').map(subline => subline === '' ? '' : padding + subline);
yield* line.split('\n').map(subline => (subline === '' ? '' : padding + subline));
}
}
}

@ -5,17 +5,15 @@ const fs = require('fs');
const path = require('path');
const format = require('./format-lines');
function getVersion (path) {
function getVersion(path) {
try {
return fs
.readFileSync(path, 'utf8')
.match(/\/\/ OpenZeppelin Contracts \(last updated v[^)]+\)/)[0];
return fs.readFileSync(path, 'utf8').match(/\/\/ OpenZeppelin Contracts \(last updated v[^)]+\)/)[0];
} catch (err) {
return null;
}
}
for (const [ file, template ] of Object.entries({
for (const [file, template] of Object.entries({
'utils/math/SafeCast.sol': './templates/SafeCast.js',
'utils/structs/EnumerableSet.sol': './templates/EnumerableSet.js',
'utils/structs/EnumerableMap.sol': './templates/EnumerableMap.js',
@ -27,7 +25,7 @@ for (const [ file, template ] of Object.entries({
const version = getVersion(output);
const content = format(
'// SPDX-License-Identifier: MIT',
...(version ? [ version + ` (${file})` ] : []),
...(version ? [version + ` (${file})`] : []),
`// This file was procedurally generated from ${input}.`,
'',
require(template),

@ -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;
@ -264,7 +264,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',
@ -293,11 +293,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)]),
],
'}',
);

@ -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')],
'}',
);

@ -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 '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 '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)],
'}',
);

@ -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`);
}
}

@ -1,18 +1,27 @@
function chunk (array, size = 1) {
function chunk(array, size = 1) {
return Array.range(Math.ceil(array.length / size)).map(i => array.slice(i * size, i * size + size));
}
function range (start, stop = undefined, step = 1) {
if (!stop) { stop = start; start = 0; }
return start < stop ? Array(Math.ceil((stop - start) / step)).fill().map((_, i) => start + i * step) : [];
function range(start, stop = undefined, step = 1) {
if (!stop) {
stop = start;
start = 0;
}
return start < stop
? Array(Math.ceil((stop - start) / step))
.fill()
.map((_, i) => start + i * step)
: [];
}
function unique (array, op = x => x) {
function unique(array, op = x => x) {
return array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i);
}
function zip (...args) {
return Array(Math.max(...args.map(arg => arg.length))).fill(null).map((_, i) => args.map(arg => arg[i]));
function zip(...args) {
return Array(Math.max(...args.map(arg => arg.length)))
.fill(null)
.map((_, i) => args.map(arg => arg[i]));
}
module.exports = {

@ -92,7 +92,7 @@ const pathUpdates = {
'token/ERC20/extensions/draft-IERC20Permit.sol': 'token/ERC20/extensions/IERC20Permit.sol',
};
async function main (paths = [ 'contracts' ]) {
async function main(paths = ['contracts']) {
const files = await listFilesRecursively(paths, /\.sol$/);
const updatedFiles = [];
@ -112,7 +112,7 @@ async function main (paths = [ 'contracts' ]) {
}
}
async function listFilesRecursively (paths, filter) {
async function listFilesRecursively(paths, filter) {
const queue = paths;
const files = [];
@ -133,7 +133,7 @@ async function listFilesRecursively (paths, filter) {
return files;
}
async function updateFile (file, update) {
async function updateFile(file, update) {
const content = await fs.readFile(file, 'utf8');
const updatedContent = update(content);
if (updatedContent !== content) {
@ -144,8 +144,8 @@ async function updateFile (file, update) {
}
}
function updateImportPaths (source) {
for (const [ oldPath, newPath ] of Object.entries(pathUpdates)) {
function updateImportPaths(source) {
for (const [oldPath, newPath] of Object.entries(pathUpdates)) {
source = source.replace(
path.join('@openzeppelin/contracts', oldPath),
path.join('@openzeppelin/contracts', newPath),
@ -159,7 +159,7 @@ function updateImportPaths (source) {
return source;
}
function getUpgradeablePath (file) {
function getUpgradeablePath(file) {
const { dir, name, ext } = path.parse(file);
const upgradeableName = name + 'Upgradeable';
return path.format({ dir, ext, name: upgradeableName });

@ -8,7 +8,7 @@ const cp = require('child_process');
setVersion('contracts/package.json');
function setVersion (file) {
function setVersion(file) {
const json = JSON.parse(fs.readFileSync(file));
json.version = process.env.npm_package_version;
fs.writeFileSync(file, JSON.stringify(json, null, 2) + '\n');

@ -25,9 +25,8 @@ if (!header.test(changelog)) {
process.exit(1);
}
const newHeader = pkg.version.indexOf(suffix) === -1
? `## ${version} (${new Date().toISOString().split('T')[0]})`
: `## ${version}`;
const newHeader =
pkg.version.indexOf(suffix) === -1 ? `## ${version} (${new Date().toISOString().split('T')[0]})` : `## ${version}`;
fs.writeFileSync('CHANGELOG.md', changelog.replace(header, newHeader));

@ -13,7 +13,7 @@ if (gitStatus.length > 0) {
const { version } = require('../../package.json');
// Get latest tag according to semver.
const [ tag ] = run('git', 'tag')
const [tag] = run('git', 'tag')
.split(/\r?\n/)
.filter(semver.coerce) // check version can be processed
.filter(v => semver.lt(semver.coerce(v), version)) // only consider older tags, ignore current prereleases

@ -6,7 +6,7 @@ const fs = require('fs');
const path = require('path');
const match = require('micromatch');
function readJSON (path) {
function readJSON(path) {
return JSON.parse(fs.readFileSync(path));
}
@ -15,11 +15,11 @@ const pkgFiles = readJSON('package.json').files;
// Get only negated patterns.
const ignorePatterns = pkgFiles
.filter(pat => pat.startsWith('!'))
// Remove the negation part. Makes micromatch usage more intuitive.
// Remove the negation part. Makes micromatch usage more intuitive.
.map(pat => pat.slice(1));
const ignorePatternsSubtrees = ignorePatterns
// Add **/* to ignore all files contained in the directories.
// Add **/* to ignore all files contained in the directories.
.concat(ignorePatterns.map(pat => path.join(pat, '**/*')))
.map(p => p.replace(/^\//, ''));

@ -1,7 +1,15 @@
const proc = require('child_process');
const read = cmd => proc.execSync(cmd, { encoding: 'utf8' }).trim();
const run = cmd => { proc.execSync(cmd, { stdio: 'inherit' }); };
const tryRead = cmd => { try { return read(cmd); } catch (e) { return undefined; } };
const run = cmd => {
proc.execSync(cmd, { stdio: 'inherit' });
};
const tryRead = cmd => {
try {
return read(cmd);
} catch (e) {
return undefined;
}
};
const releaseBranchRegex = /^release-v(?<version>(?<major>\d+)\.(?<minor>\d+)(?:\.(?<patch>\d+))?)$/;
@ -33,7 +41,7 @@ if (!matchingDocsBranches) {
if (others.length > 0) {
console.error(
`Found conflicting ${docsBranch} branches.\n` +
'Either local branch is outdated or there are multiple matching remote branches.',
'Either local branch is outdated or there are multiple matching remote branches.',
);
process.exit(1);
}

@ -7,7 +7,7 @@ const DEFAULT_ADMIN_ROLE = '0x00000000000000000000000000000000000000000000000000
const ROLE = web3.utils.soliditySha3('ROLE');
const OTHER_ROLE = web3.utils.soliditySha3('OTHER_ROLE');
function shouldBehaveLikeAccessControl (errorPrefix, admin, authorized, other, otherAdmin) {
function shouldBehaveLikeAccessControl(errorPrefix, admin, authorized, other, otherAdmin) {
shouldSupportInterfaces(['AccessControl']);
describe('default admin', function () {
@ -15,11 +15,11 @@ function shouldBehaveLikeAccessControl (errorPrefix, admin, authorized, other, o
expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.equal(true);
});
it('other roles\'s admin is the default admin role', async function () {
it("other roles's admin is the default admin role", async function () {
expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE);
});
it('default admin role\'s admin is itself', async function () {
it("default admin role's admin is itself", async function () {
expect(await this.accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE);
});
});
@ -125,7 +125,7 @@ function shouldBehaveLikeAccessControl (errorPrefix, admin, authorized, other, o
await this.accessControl.grantRole(OTHER_ROLE, otherAdmin, { from: admin });
});
it('a role\'s admin role can be changed', async function () {
it("a role's admin role can be changed", async function () {
expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE);
});
@ -140,14 +140,14 @@ function shouldBehaveLikeAccessControl (errorPrefix, admin, authorized, other, o
expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: otherAdmin });
});
it('a role\'s previous admins no longer grant roles', async function () {
it("a role's previous admins no longer grant roles", async function () {
await expectRevert(
this.accessControl.grantRole(ROLE, authorized, { from: admin }),
`${errorPrefix}: account ${admin.toLowerCase()} is missing role ${OTHER_ROLE}`,
);
});
it('a role\'s previous admins no longer revoke roles', async function () {
it("a role's previous admins no longer revoke roles", async function () {
await expectRevert(
this.accessControl.revokeRole(ROLE, authorized, { from: admin }),
`${errorPrefix}: account ${admin.toLowerCase()} is missing role ${OTHER_ROLE}`,
@ -164,14 +164,14 @@ function shouldBehaveLikeAccessControl (errorPrefix, admin, authorized, other, o
await this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: authorized });
});
it('revert if sender doesn\'t have role #1', async function () {
it("revert if sender doesn't have role #1", async function () {
await expectRevert(
this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: other }),
`${errorPrefix}: account ${other.toLowerCase()} is missing role ${ROLE}`,
);
});
it('revert if sender doesn\'t have role #2', async function () {
it("revert if sender doesn't have role #2", async function () {
await expectRevert(
this.accessControl.methods['$_checkRole(bytes32)'](OTHER_ROLE, { from: authorized }),
`${errorPrefix}: account ${authorized.toLowerCase()} is missing role ${OTHER_ROLE}`,
@ -180,7 +180,7 @@ function shouldBehaveLikeAccessControl (errorPrefix, admin, authorized, other, o
});
}
function shouldBehaveLikeAccessControlEnumerable (errorPrefix, admin, authorized, other, otherAdmin, otherAuthorized) {
function shouldBehaveLikeAccessControlEnumerable(errorPrefix, admin, authorized, other, otherAdmin, otherAuthorized) {
shouldSupportInterfaces(['AccessControlEnumerable']);
describe('enumerating', function () {

@ -1,7 +1,4 @@
const {
DEFAULT_ADMIN_ROLE,
shouldBehaveLikeAccessControl,
} = require('./AccessControl.behavior.js');
const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js');
const AccessControl = artifacts.require('$AccessControl');

@ -1,15 +1,13 @@
const { expectRevert } = require('@openzeppelin/test-helpers');
const { BridgeHelper } = require('../helpers/crosschain');
const {
DEFAULT_ADMIN_ROLE,
shouldBehaveLikeAccessControl,
} = require('./AccessControl.behavior.js');
const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js');
const crossChainRoleAlias = (role) => web3.utils.leftPad(
web3.utils.toHex(web3.utils.toBN(role).xor(web3.utils.toBN(web3.utils.soliditySha3('CROSSCHAIN_ALIAS')))),
64,
);
const crossChainRoleAlias = role =>
web3.utils.leftPad(
web3.utils.toHex(web3.utils.toBN(role).xor(web3.utils.toBN(web3.utils.soliditySha3('CROSSCHAIN_ALIAS')))),
64,
);
const AccessControlCrossChainMock = artifacts.require('$AccessControlCrossChainMock');
@ -39,23 +37,13 @@ contract('AccessControl', function (accounts) {
it('Crosschain calls not authorized to non-aliased addresses', async function () {
await expectRevert(
this.bridge.call(
accounts[0],
this.accessControl,
'$_checkRole(bytes32)',