From dafdce51ca8e8ae01990c30022d6bf9a8651fddf Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 14 Jul 2023 15:22:48 -0300 Subject: [PATCH 01/35] use isStorageVariable helper --- src/transformations/add-storage-gaps.ts | 12 +----------- src/transformations/purge-var-inits.ts | 3 ++- .../utils/get-initializer-items.ts | 7 ++----- .../utils/is-storage-variable.ts | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+), 17 deletions(-) create mode 100644 src/transformations/utils/is-storage-variable.ts diff --git a/src/transformations/add-storage-gaps.ts b/src/transformations/add-storage-gaps.ts index db8a4a84..77811eff 100644 --- a/src/transformations/add-storage-gaps.ts +++ b/src/transformations/add-storage-gaps.ts @@ -11,6 +11,7 @@ import { extractNatspec } from '../utils/extractNatspec'; import { decodeTypeIdentifier } from '../utils/type-id'; import { parseTypeId } from '../utils/parse-type-id'; import { ASTResolver } from '../ast-resolver'; +import { isStorageVariable } from './utils/is-storage-variable'; // By default, make the contract a total of 50 slots (storage + gap) const DEFAULT_SLOT_COUNT = 50; @@ -61,17 +62,6 @@ export function* addStorageGaps( } } -function isStorageVariable(varDecl: VariableDeclaration, resolver: ASTResolver): boolean { - switch (varDecl.mutability) { - case 'constant': - return false; - case 'immutable': - return !hasOverride(varDecl, 'state-variable-immutable', resolver); - default: - return true; - } -} - function getNumberOfBytesOfValueType(typeId: string, resolver: ASTResolver): number { const { head, tail } = parseTypeId(typeId); const details = head.match(/^t_(?[a-zA-Z]+)(?\d+)?/); diff --git a/src/transformations/purge-var-inits.ts b/src/transformations/purge-var-inits.ts index dd516ea4..0d946769 100644 --- a/src/transformations/purge-var-inits.ts +++ b/src/transformations/purge-var-inits.ts @@ -5,6 +5,7 @@ import { TransformerTools } from '../transform'; import { hasConstructorOverride, hasOverride } from '../utils/upgrades-overrides'; import { Transformation } from './type'; +import { isStorageVariable } from './utils/is-storage-variable'; export function* removeStateVarInits( sourceUnit: SourceUnit, @@ -16,7 +17,7 @@ export function* removeStateVarInits( } for (const varDecl of findAll('VariableDeclaration', contractNode)) { - if (varDecl.stateVariable && varDecl.value && !varDecl.constant) { + if (varDecl.value && isStorageVariable(varDecl, resolver)) { if (hasOverride(varDecl, 'state-variable-assignment', resolver)) { continue; } diff --git a/src/transformations/utils/get-initializer-items.ts b/src/transformations/utils/get-initializer-items.ts index 0a2a9f63..09388068 100644 --- a/src/transformations/utils/get-initializer-items.ts +++ b/src/transformations/utils/get-initializer-items.ts @@ -3,16 +3,13 @@ import { findAll } from 'solidity-ast/utils'; import { ASTResolver } from '../../ast-resolver'; import { getConstructor } from '../../solc/ast-utils'; import { hasOverride } from '../../utils/upgrades-overrides'; +import { isStorageVariable } from './is-storage-variable'; export function getInitializerItems(contract: ContractDefinition, resolver: ASTResolver) { const constructorNode = getConstructor(contract); const varInitNodes = [...findAll('VariableDeclaration', contract)].filter( - v => - v.stateVariable && - v.value && - !v.constant && - !hasOverride(v, 'state-variable-assignment', resolver), + v => v.value && isStorageVariable(v, resolver) && !hasOverride(v, 'state-variable-assignment', resolver) ); const modifiers = diff --git a/src/transformations/utils/is-storage-variable.ts b/src/transformations/utils/is-storage-variable.ts new file mode 100644 index 00000000..38eca6cd --- /dev/null +++ b/src/transformations/utils/is-storage-variable.ts @@ -0,0 +1,19 @@ +import { VariableDeclaration } from 'solidity-ast'; +import { ASTResolver } from '../../ast-resolver'; +import { hasOverride } from '../../utils/upgrades-overrides'; + +export function isStorageVariable(varDecl: VariableDeclaration, resolver: ASTResolver): boolean { + if (!varDecl.stateVariable || varDecl.constant) { + return false; + } else { + switch (varDecl.mutability) { + case 'constant': + // It's unclear if `varDecl.constant` and `varDecl.mutability === 'constant'` are equivalent so we use both just in case. + return false; + case 'immutable': + return !hasOverride(varDecl, 'state-variable-immutable', resolver); + default: + return true; + } + } +} From 3b1982238d5ded870de08c33fc6a3daad53acd94 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 14 Jul 2023 16:23:41 -0300 Subject: [PATCH 02/35] initial code for namespaced storage --- contracts/namespaces.sol | 22 ++ hardhat.config.js | 2 +- package-lock.json | 219 +++++++++++++----- package.json | 1 + src/cli.ts | 3 + src/index.ts | 9 +- src/transform-namespaces.test.ts | 33 +++ src/transform-namespaces.test.ts.md | 47 ++++ src/transform-namespaces.test.ts.snap | Bin 0 -> 560 bytes src/transform.ts | 59 ++++- src/transformations/add-namespace-struct.ts | 138 +++++++++++ .../utils/new-function-position.ts | 4 +- src/utils/erc7201.ts | 9 + tsconfig.json | 7 +- 14 files changed, 486 insertions(+), 67 deletions(-) create mode 100644 contracts/namespaces.sol create mode 100644 src/transform-namespaces.test.ts create mode 100644 src/transform-namespaces.test.ts.md create mode 100644 src/transform-namespaces.test.ts.snap create mode 100644 src/transformations/add-namespace-struct.ts create mode 100644 src/utils/erc7201.ts diff --git a/contracts/namespaces.sol b/contracts/namespaces.sol new file mode 100644 index 00000000..41a73d92 --- /dev/null +++ b/contracts/namespaces.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +contract U { + event B(); + + struct A { uint z; } + + // a + uint x; + // b + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + uint immutable y = 2; + uint z; + + function f() public { + z = 3; + } + + function g() public { + } +} diff --git a/hardhat.config.js b/hardhat.config.js index e504111b..7a7f6d60 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -9,6 +9,6 @@ internalTask(TASK_COMPILE_SOLIDITY_GET_COMPILER_INPUT, async (args, hre, runSupe module.exports = { solidity: { - compilers: [{ version: '0.6.7' }, { version: '0.8.8' }], + compilers: [{ version: '0.6.7' }, { version: '0.8.8' }, { version: '0.8.20' }], }, }; diff --git a/package-lock.json b/package-lock.json index c28007b8..43679364 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "ajv": "^8.0.0", "compare-versions": "^5.0.0", + "ethereum-cryptography": "^2.0.0", "lodash": "^4.17.20", "minimatch": "^6.0.0", "minimist": "^1.2.5", @@ -605,11 +606,24 @@ "node": ">=12.0.0" } }, + "node_modules/@noble/curves": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz", + "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "1.3.0" + } + }, "node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", "funding": [ { "type": "individual", @@ -618,9 +632,9 @@ ] }, "node_modules/@noble/secp256k1": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", - "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", "dev": true, "funding": [ { @@ -1239,7 +1253,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", - "dev": true, "funding": [ { "type": "individual", @@ -1248,10 +1261,9 @@ ] }, "node_modules/@scure/bip32": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", - "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz", + "integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==", "funding": [ { "type": "individual", @@ -1259,16 +1271,15 @@ } ], "dependencies": { - "@noble/hashes": "~1.1.1", - "@noble/secp256k1": "~1.6.0", + "@noble/curves": "~1.0.0", + "@noble/hashes": "~1.3.0", "@scure/base": "~1.1.0" } }, "node_modules/@scure/bip39": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", - "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz", + "integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==", "funding": [ { "type": "individual", @@ -1276,7 +1287,7 @@ } ], "dependencies": { - "@noble/hashes": "~1.1.1", + "@noble/hashes": "~1.3.0", "@scure/base": "~1.1.0" } }, @@ -3281,15 +3292,14 @@ } }, "node_modules/ethereum-cryptography": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", - "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.0.0.tgz", + "integrity": "sha512-g25m4EtfQGjstWgVE1aIz7XYYjf3kH5kG17ULWVB5dH6uLahsoltOhACzSxyDV+fhn4gbR4xRrOXGe6r2uh4Bg==", "dependencies": { - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.6.3", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" + "@noble/curves": "1.0.0", + "@noble/hashes": "1.3.0", + "@scure/bip32": "1.3.0", + "@scure/bip39": "1.2.0" } }, "node_modules/ethereumjs-abi": { @@ -3810,6 +3820,51 @@ } } }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, "node_modules/hardhat/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -3866,6 +3921,18 @@ "node": ">=0.8.0" } }, + "node_modules/hardhat/node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, "node_modules/hardhat/node_modules/find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -7125,16 +7192,23 @@ "tweetnacl-util": "^0.15.1" } }, + "@noble/curves": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz", + "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==", + "requires": { + "@noble/hashes": "1.3.0" + } + }, "@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "dev": true + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==" }, "@noble/secp256k1": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", - "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", "dev": true }, "@nodelib/fs.scandir": { @@ -7632,27 +7706,24 @@ "@scure/base": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", - "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", - "dev": true + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==" }, "@scure/bip32": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", - "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz", + "integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==", "requires": { - "@noble/hashes": "~1.1.1", - "@noble/secp256k1": "~1.6.0", + "@noble/curves": "~1.0.0", + "@noble/hashes": "~1.3.0", "@scure/base": "~1.1.0" } }, "@scure/bip39": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", - "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz", + "integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==", "requires": { - "@noble/hashes": "~1.1.1", + "@noble/hashes": "~1.3.0", "@scure/base": "~1.1.0" } }, @@ -9133,15 +9204,14 @@ "dev": true }, "ethereum-cryptography": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", - "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.0.0.tgz", + "integrity": "sha512-g25m4EtfQGjstWgVE1aIz7XYYjf3kH5kG17ULWVB5dH6uLahsoltOhACzSxyDV+fhn4gbR4xRrOXGe6r2uh4Bg==", "requires": { - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.6.3", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" + "@noble/curves": "1.0.0", + "@noble/hashes": "1.3.0", + "@scure/bip32": "1.3.0", + "@scure/bip39": "1.2.0" } }, "ethereumjs-abi": { @@ -9558,6 +9628,33 @@ "ws": "^7.4.6" }, "dependencies": { + "@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true + }, + "@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "requires": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "requires": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -9605,6 +9702,18 @@ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, + "ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "requires": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", diff --git a/package.json b/package.json index 72de95c3..a1eae419 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dependencies": { "ajv": "^8.0.0", "compare-versions": "^5.0.0", + "ethereum-cryptography": "^2.0.0", "lodash": "^4.17.20", "minimatch": "^6.0.0", "minimist": "^1.2.5", diff --git a/src/cli.ts b/src/cli.ts index c80fdf21..cf79e6d7 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -22,6 +22,7 @@ interface Options { skipWithInit: boolean; exclude: string[]; publicInitializers: string[]; + namespaced: boolean; } function readCommandFlags(resolveRootRelative: (p: string) => string): Options { @@ -32,11 +33,13 @@ function readCommandFlags(resolveRootRelative: (p: string) => string): Options { D: deleteOriginals = false, x: exclude = [], W: skipWithInit = false, + n: namespaced = false, } = minimist(process.argv.slice(2)); return { buildInfo, deleteOriginals, skipWithInit, + namespaced, initializablePath: initializablePath && resolveRootRelative(initializablePath), publicInitializers: ensureArray(publicInitializers).map(resolveRootRelative), exclude: ensureArray(exclude).map(p => diff --git a/src/index.ts b/src/index.ts index eccef998..d85a0d45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,7 @@ import { appendInitializableImport } from './transformations/append-initializabl import { fixNewStatement } from './transformations/fix-new-statement'; import { addRequiredPublicInitializer } from './transformations/add-required-public-initializers'; import { addStorageGaps } from './transformations/add-storage-gaps'; +import { addNamespaceStruct } from './transformations/add-namespace-struct'; import { renameInheritdoc } from './transformations/rename-inheritdoc'; import { transformConstructor, @@ -43,6 +44,7 @@ interface TranspileOptions { publicInitializers?: string[]; solcVersion?: string; skipWithInit?: boolean; + namespaced?: boolean; } function getExtraOutputPaths( @@ -93,7 +95,12 @@ export async function transpile( transform.apply(removeInheritanceListArguments); transform.apply(removeStateVarInits); transform.apply(removeImmutable); - transform.apply(addStorageGaps); + + if (options?.namespaced) { + transform.apply(addNamespaceStruct); + } else { + transform.apply(addStorageGaps); + } // build a final array of files to return const outputFiles: OutputFile[] = []; diff --git a/src/transform-namespaces.test.ts b/src/transform-namespaces.test.ts new file mode 100644 index 00000000..b4660d42 --- /dev/null +++ b/src/transform-namespaces.test.ts @@ -0,0 +1,33 @@ +import _test, { TestFn } from 'ava'; + +import { getBuildInfo } from './test-utils/get-build-info'; + +import { SolcInput, SolcOutput } from './solc/input-output'; +import { Transform } from './transform'; + +import { addNamespaceStruct } from './transformations/add-namespace-struct'; + +const test = _test as TestFn; + +interface Context { + solcInput: SolcInput; + solcOutput: SolcOutput; + transform: Transform; +} + +test.serial.before('compile', async t => { + const buildInfo = await getBuildInfo('0.8.20'); + + t.context.solcInput = buildInfo.input; + t.context.solcOutput = buildInfo.output as SolcOutput; +}); + +test.beforeEach('transform', async t => { + t.context.transform = new Transform(t.context.solcInput, t.context.solcOutput); +}); + +test('add namespace', t => { + const file = 'contracts/namespaces.sol'; + t.context.transform.apply(addNamespaceStruct); + t.snapshot(t.context.transform.results()[file]); +}); diff --git a/src/transform-namespaces.test.ts.md b/src/transform-namespaces.test.ts.md new file mode 100644 index 00000000..c636d7ac --- /dev/null +++ b/src/transform-namespaces.test.ts.md @@ -0,0 +1,47 @@ +# Snapshot report for `src/transform-namespaces.test.ts` + +The actual snapshot is saved in `transform-namespaces.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## add namespace + +> Snapshot 1 + + `// SPDX-License-Identifier: UNLICENSED␊ + pragma solidity ^0.8.20;␊ + ␊ + contract U {␊ + event B();␊ + ␊ + struct A { uint z; }␊ + ␊ + // b␊ + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable␊ + uint immutable y = 2;␊ + ␊ + /// @custom:storage-location erc7201:openzeppelin.storage.U␊ + struct UStorage {␊ + // a␊ + uint x;␊ + uint z;␊ + }␊ + ␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.U")) - 1))␊ + bytes32 private constant UStorageLocation = 0xe022f9b83eecd46e4fb4f58f3bf6221dceecce436d8ce41cf0ca78f72aa483aa;␊ + ␊ + function _getUStorage() private pure returns (UStorage storage $) {␊ + assembly {␊ + $.slot := UStorageLocation␊ + }␊ + }␊ + ␊ + function f() public {␊ + UStorage storage $ = _getUStorage();␊ + $.z = 3;␊ + }␊ + ␊ + function g() public {␊ + }␊ + }␊ + ` diff --git a/src/transform-namespaces.test.ts.snap b/src/transform-namespaces.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..69a860c7b30845dae01027ef6117bbd787991bda GIT binary patch literal 560 zcmV-00?++HRzV*&mAt00000000ARQNeE7KoF%xRVCm02cw7sKG+zWfD1xO+vE@lrIip;ducUZ z&(an4+VZYxAmWfuNx!sfa11G#gS|6v^!B~CPdrL8wo;FONei7&ig64QQ&KrH5=vsO zerH-eKE*L={L%i}ZoO|+_2ymc!`rKNuLtvQ*WaC)U?deew=qdAxS(PTi@VwFmz%r! z&9#*mxJ(gLmWWvB4gB=n(Dl8EWwA`^0-1&dJXm0g)`kH-cWnb!z0yT#;7{-Xr7*~L z0=olZ?vCn153X3Lbe4{@tyAX90%KB6DHU>ZFiEmMh6gn{Yb*pt2{|H7OI@Az414Bg z1RI!wKe5ip&Bqua$7F_DWD=-gBj4+fvz+9X@|+SO-FnMioa$f957XLZtsk3aui$?2 zvfm#1qu&)VhAaPa*u_Y=Bv}?yw_2@6NATixJr}kO4)kq%PZw=8slbQ45Ni_+n3pga z$)nWSv&$)X_vHCL{}_b<5sL>y8t`bqFGC(geCYfAn3*}FK`@L%^XoJ2F&u?_6R|MWX+XZ-_|O<(bW0{{TK5DCQq literal 0 HcmV?d00001 diff --git a/src/transform.ts b/src/transform.ts index e0be2071..fa3366b4 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -1,6 +1,6 @@ import { mapValues } from 'lodash'; -import { SourceUnit } from 'solidity-ast'; +import { SourceUnit, VariableDeclaration } from 'solidity-ast'; import { Node } from 'solidity-ast/node'; import { SolcInput, SolcOutput } from './solc/input-output'; import { srcDecoder, SrcDecoder } from './solc/src-decoder'; @@ -9,7 +9,7 @@ import { layoutGetter, LayoutGetter } from './solc/layout-getter'; import { Shift, shiftBounds } from './shifts'; import { applyTransformation } from './transformations/apply'; import { compareTransformations, compareContainment } from './transformations/compare'; -import { Transformation, WithSrc } from './transformations/type'; +import { Bounds, Transformation, WithSrc } from './transformations/type'; import { ASTResolver } from './ast-resolver'; type Transformer = (sourceUnit: SourceUnit, tools: TransformerTools) => Generator; @@ -26,6 +26,8 @@ export interface TransformerTools { resolver: ASTResolver; getData: (node: Node) => Partial; getLayout: LayoutGetter; + error: (node: Node, msg: string) => Error; + getRealEndIndex: (node: Node) => number; } // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -88,6 +90,8 @@ export class Transform { const { resolver, getLayout } = this; const readOriginal = this.readOriginal.bind(this); const getData = this.getData.bind(this); + const error = this.error.bind(this); + const getRealEndIndex = this.getRealEndIndex.bind(this); const tools: TransformerTools = { originalSource, originalSourceBuf, @@ -95,6 +99,8 @@ export class Transform { readOriginal, getData, getLayout, + error, + getRealEndIndex, }; for (const t of transform(ast, tools)) { @@ -133,6 +139,13 @@ export class Transform { } read(node: WithSrc): string { + const { source } = this.decodeSrc(node.src); + const { content } = this.state[source]; + const sb = this.getShiftedBounds(node); + return content.slice(sb.start, sb.start + sb.length).toString(); + } + + getShiftedBounds(node: WithSrc): Bounds { const { source, ...bounds } = this.decodeSrc(node.src); const { shifts, transformations, content } = this.state[source]; @@ -144,8 +157,46 @@ export class Transform { throw new Error(`Can't read from segment that has been partially transformed`); } - const sb = shiftBounds(shifts, bounds); - return content.slice(sb.start, sb.start + sb.length).toString(); + return shiftBounds(shifts, bounds); + } + + error(node: Node, msg: string): Error { + const { source, start } = this.decodeSrc(node.src); + const line = 1 + [...this.state[source].originalBuf.slice(0, start).toString('utf8').matchAll(/\n/g)].length; + const error = new Error(`${msg} (${source}:${line})`); + Error.captureStackTrace(error, this.error); // capture stack trace without this function + return error; + } + + getRealEndIndex(node: Node): number { + const { source, start, length } = this.decodeSrc(node.src); + if (node.nodeType !== 'VariableDeclaration') { + return start + length; + } else { + // VariableDeclaration node bounds don't include the semicolon + const buf = this.state[source].originalBuf; + let index = start + length; + while (true) { + const c = buf.toString('utf8', index, index + 1); + if (c === ';') { + return index; + } else if (/\S/.test(c)) { + throw this.error(node, 'Found unexpected content before semicolon'); + } + index += 1; + } + } + } + + getLeadingWhitespace(node: Node): string { + const { source } = this.decodeSrc(node.src); + const { start: nodeStart } = this.getShiftedBounds(node); + const buf = this.state[source].content; + let wsStart = nodeStart; + while (wsStart > 0 && /[ \t]/.test(buf.toString('utf8', wsStart - 1, wsStart))) { + wsStart -= 1; + } + return buf.toString('utf8', wsStart, nodeStart); } results(): { [file in string]: string } { diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts new file mode 100644 index 00000000..4be28d17 --- /dev/null +++ b/src/transformations/add-namespace-struct.ts @@ -0,0 +1,138 @@ +import { SourceUnit, VariableDeclaration } from 'solidity-ast'; +import { findAll } from 'solidity-ast/utils'; +import { getNodeBounds } from '../solc/ast-utils'; +import { TransformerTools } from '../transform'; +import { Transformation } from './type'; +import { newFunctionPosition } from './utils/new-function-position'; +import { formatLines } from './utils/format-lines'; +import { isStorageVariable } from './utils/is-storage-variable'; +import { erc7201Location } from '../utils/erc7201'; + +export function* addNamespaceStruct( + sourceUnit: SourceUnit, + tools: TransformerTools, +): Generator { + const { error, resolver, getRealEndIndex } = tools; + + for (const contract of findAll('ContractDefinition', sourceUnit)) { + let start = newFunctionPosition(contract, tools, false); + + let firstVariable: VariableDeclaration | undefined; + let lastVariable: VariableDeclaration | undefined; + let finished = false; + + const nonStorage: [number, VariableDeclaration][] = []; + + for (const n of contract.nodes) { + if (n.nodeType === 'VariableDeclaration') { + if (finished) { + throw error(n, 'All variables in the contract must be contiguous'); + } + + if (!isStorageVariable(n, resolver)) { + const varStart = lastVariable ? getRealEndIndex(lastVariable) + 1 : start; + nonStorage.push([varStart, n]); + } + + firstVariable ??= n; + lastVariable = n; + } else if (firstVariable) { + finished = true; + } else { + start = getRealEndIndex(n) + 1; + } + } + + for (const [s, v] of nonStorage) { + const bounds = { start: s, length: getRealEndIndex(v) + 1 - s }; + let removed = ''; + + yield { + kind: 'relocate-nonstorage-var-remove', + ...bounds, + transform: (source) => { + removed = source; + return ''; + }, + }; + + yield { + kind: 'relocate-nonstorage-var-reinsert', + start, + length: 0, + text: removed, + }; + } + + if (nonStorage.length > 0) { + yield { + kind: 'relocate-nonstorage-var-newline', + start, + length: 0, + text: '\n', + }; + } + + if (firstVariable && lastVariable) { + const namespace = contract.name + 'Storage'; + const id = 'openzeppelin.storage.' + contract.name; + + const end = getRealEndIndex(lastVariable) + 1; + + yield { + kind: 'add-namespace-struct', + start, + length: end - start, + transform: source => { + const [_, leading, rest] = source.match(/^((?:[ \t\v\f]*[\n\r]+)*)(.*)$/s)!; + return leading + formatLines(1, [ + `/// @custom:storage-location erc7201:${id}`, + `struct ${namespace} {`, + ...rest.split('\n'), + `}`, + ``, + `// keccak256(abi.encode(uint256(keccak256("${id}")) - 1))`, + `bytes32 private constant ${namespace}Location = ${erc7201Location(id)};`, + ``, + `function _get${namespace}() private pure returns (${namespace} storage $) {`, + [ + `assembly {`, + [ `$.slot := ${namespace}Location` ], + `}`, + ], + `}`, + ]).trimEnd(); + }, + }; + + for (const fnDef of findAll('FunctionDefinition', contract)) { + let foundReferences = false; + // TODO: variable references in modifiers? + if (fnDef.body) { + for (const ref of findAll('Identifier', fnDef.body)) { + const varDecl = resolver.tryResolveNode('VariableDeclaration', ref.referencedDeclaration!); + if (varDecl && isStorageVariable(varDecl, resolver)) { + if (varDecl.scope !== contract.id) { + throw error(varDecl, 'Namespaces assume all variables are private'); + } + foundReferences = true; + const { start } = getNodeBounds(ref); + yield { kind: 'add-namespace-ref', start, length: 0, text: '$.' } + } + } + + if (foundReferences) { + const { start: fnBodyStart } = getNodeBounds(fnDef.body); + yield { + kind: 'add-namespace-base-ref', + start: fnBodyStart + 1, + length: 0, + text: + `\n ${namespace} storage $ = _get${namespace}();`, + }; + } + } + } + } + } +} diff --git a/src/transformations/utils/new-function-position.ts b/src/transformations/utils/new-function-position.ts index 698a8962..2fe25315 100644 --- a/src/transformations/utils/new-function-position.ts +++ b/src/transformations/utils/new-function-position.ts @@ -7,6 +7,7 @@ import { matchBufferFrom } from '../../utils/match'; export function newFunctionPosition( contract: ContractDefinition, { readOriginal }: TransformerTools, + newline = true, ): number { const offset = getNodeBounds(contract).start; let searchStart = 0; @@ -17,7 +18,8 @@ export function newFunctionPosition( searchStart = pb.start + pb.length - offset; } - const brace = matchBufferFrom(readOriginal(contract, 'buffer'), /\{\n?/, searchStart); + const re = newline ? /\{\n?/ : /\{/; + const brace = matchBufferFrom(readOriginal(contract, 'buffer'), re, searchStart); if (!brace) { throw new Error(`Can't find start of contract ${contract.name}`); diff --git a/src/utils/erc7201.ts b/src/utils/erc7201.ts new file mode 100644 index 00000000..223dec5e --- /dev/null +++ b/src/utils/erc7201.ts @@ -0,0 +1,9 @@ +import { keccak256 } from 'ethereum-cryptography/keccak.js'; +import { utf8ToBytes, hexToBytes, bytesToHex } from 'ethereum-cryptography/utils.js'; + +export function erc7201Location(id: string): string { + const a = keccak256(utf8ToBytes(id)) + const b = BigInt('0x' + bytesToHex(a)) - 1n; + const c = hexToBytes(b.toString(16).padStart(64, '0')); + return '0x' + bytesToHex(keccak256(c)); +} diff --git a/tsconfig.json b/tsconfig.json index b54e0db0..00098796 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,15 +7,12 @@ "moduleResolution": "Node", "esModuleInterop": true, "resolveJsonModule": true, - "target": "es2018", + "target": "es2020", "declaration": true, "declarationMap": true, "sourceMap": true, "strict": true, - "outDir": "dist", - "lib": [ - "es2019" - ] + "outDir": "dist" }, "include": ["src"], "ts-node": { From ebe94f6eebb8ab3b9f44678edb2f15b79c165ad9 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 14 Jul 2023 16:28:27 -0300 Subject: [PATCH 03/35] lint --- src/transform.ts | 11 +++-- src/transformations/add-namespace-struct.ts | 45 ++++++++++--------- src/transformations/add-storage-gaps.ts | 3 +- .../utils/get-initializer-items.ts | 5 ++- src/utils/erc7201.ts | 2 +- src/utils/upgrades-overrides.ts | 4 +- 6 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/transform.ts b/src/transform.ts index fa3366b4..6948d980 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -1,6 +1,6 @@ import { mapValues } from 'lodash'; -import { SourceUnit, VariableDeclaration } from 'solidity-ast'; +import { SourceUnit } from 'solidity-ast'; import { Node } from 'solidity-ast/node'; import { SolcInput, SolcOutput } from './solc/input-output'; import { srcDecoder, SrcDecoder } from './solc/src-decoder'; @@ -147,7 +147,7 @@ export class Transform { getShiftedBounds(node: WithSrc): Bounds { const { source, ...bounds } = this.decodeSrc(node.src); - const { shifts, transformations, content } = this.state[source]; + const { shifts, transformations } = this.state[source]; const incompatible = (t: Transformation) => { const c = compareContainment(t, bounds); @@ -162,7 +162,9 @@ export class Transform { error(node: Node, msg: string): Error { const { source, start } = this.decodeSrc(node.src); - const line = 1 + [...this.state[source].originalBuf.slice(0, start).toString('utf8').matchAll(/\n/g)].length; + const line = + 1 + + [...this.state[source].originalBuf.slice(0, start).toString('utf8').matchAll(/\n/g)].length; const error = new Error(`${msg} (${source}:${line})`); Error.captureStackTrace(error, this.error); // capture stack trace without this function return error; @@ -176,7 +178,7 @@ export class Transform { // VariableDeclaration node bounds don't include the semicolon const buf = this.state[source].originalBuf; let index = start + length; - while (true) { + while (index < buf.length) { const c = buf.toString('utf8', index, index + 1); if (c === ';') { return index; @@ -185,6 +187,7 @@ export class Transform { } index += 1; } + throw this.error(node, 'could not find end of node'); } } diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index 4be28d17..b4cacb20 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -50,7 +50,7 @@ export function* addNamespaceStruct( yield { kind: 'relocate-nonstorage-var-remove', ...bounds, - transform: (source) => { + transform: source => { removed = source; return ''; }, @@ -84,24 +84,23 @@ export function* addNamespaceStruct( start, length: end - start, transform: source => { - const [_, leading, rest] = source.match(/^((?:[ \t\v\f]*[\n\r]+)*)(.*)$/s)!; - return leading + formatLines(1, [ - `/// @custom:storage-location erc7201:${id}`, - `struct ${namespace} {`, + const [, leading, rest] = source.match(/^((?:[ \t\v\f]*[\n\r]+)*)(.*)$/s)!; + return ( + leading + + formatLines(1, [ + `/// @custom:storage-location erc7201:${id}`, + `struct ${namespace} {`, ...rest.split('\n'), - `}`, - ``, - `// keccak256(abi.encode(uint256(keccak256("${id}")) - 1))`, - `bytes32 private constant ${namespace}Location = ${erc7201Location(id)};`, - ``, - `function _get${namespace}() private pure returns (${namespace} storage $) {`, - [ - `assembly {`, - [ `$.slot := ${namespace}Location` ], - `}`, - ], - `}`, - ]).trimEnd(); + `}`, + ``, + `// keccak256(abi.encode(uint256(keccak256("${id}")) - 1))`, + `bytes32 private constant ${namespace}Location = ${erc7201Location(id)};`, + ``, + `function _get${namespace}() private pure returns (${namespace} storage $) {`, + [`assembly {`, [`$.slot := ${namespace}Location`], `}`], + `}`, + ]).trimEnd() + ); }, }; @@ -110,14 +109,17 @@ export function* addNamespaceStruct( // TODO: variable references in modifiers? if (fnDef.body) { for (const ref of findAll('Identifier', fnDef.body)) { - const varDecl = resolver.tryResolveNode('VariableDeclaration', ref.referencedDeclaration!); + const varDecl = resolver.tryResolveNode( + 'VariableDeclaration', + ref.referencedDeclaration!, + ); if (varDecl && isStorageVariable(varDecl, resolver)) { if (varDecl.scope !== contract.id) { throw error(varDecl, 'Namespaces assume all variables are private'); } foundReferences = true; const { start } = getNodeBounds(ref); - yield { kind: 'add-namespace-ref', start, length: 0, text: '$.' } + yield { kind: 'add-namespace-ref', start, length: 0, text: '$.' }; } } @@ -127,8 +129,7 @@ export function* addNamespaceStruct( kind: 'add-namespace-base-ref', start: fnBodyStart + 1, length: 0, - text: - `\n ${namespace} storage $ = _get${namespace}();`, + text: `\n ${namespace} storage $ = _get${namespace}();`, }; } } diff --git a/src/transformations/add-storage-gaps.ts b/src/transformations/add-storage-gaps.ts index 77811eff..ff1601ed 100644 --- a/src/transformations/add-storage-gaps.ts +++ b/src/transformations/add-storage-gaps.ts @@ -1,8 +1,7 @@ -import { SourceUnit, ContractDefinition, VariableDeclaration } from 'solidity-ast'; +import { SourceUnit, ContractDefinition } from 'solidity-ast'; import { findAll, isNodeType } from 'solidity-ast/utils'; import { formatLines } from './utils/format-lines'; -import { hasOverride } from '../utils/upgrades-overrides'; import { getNodeBounds } from '../solc/ast-utils'; import { StorageLayout } from '../solc/input-output'; import { Transformation } from './type'; diff --git a/src/transformations/utils/get-initializer-items.ts b/src/transformations/utils/get-initializer-items.ts index 09388068..f40ec75d 100644 --- a/src/transformations/utils/get-initializer-items.ts +++ b/src/transformations/utils/get-initializer-items.ts @@ -9,7 +9,10 @@ export function getInitializerItems(contract: ContractDefinition, resolver: ASTR const constructorNode = getConstructor(contract); const varInitNodes = [...findAll('VariableDeclaration', contract)].filter( - v => v.value && isStorageVariable(v, resolver) && !hasOverride(v, 'state-variable-assignment', resolver) + v => + v.value && + isStorageVariable(v, resolver) && + !hasOverride(v, 'state-variable-assignment', resolver), ); const modifiers = diff --git a/src/utils/erc7201.ts b/src/utils/erc7201.ts index 223dec5e..249b856b 100644 --- a/src/utils/erc7201.ts +++ b/src/utils/erc7201.ts @@ -2,7 +2,7 @@ import { keccak256 } from 'ethereum-cryptography/keccak.js'; import { utf8ToBytes, hexToBytes, bytesToHex } from 'ethereum-cryptography/utils.js'; export function erc7201Location(id: string): string { - const a = keccak256(utf8ToBytes(id)) + const a = keccak256(utf8ToBytes(id)); const b = BigInt('0x' + bytesToHex(a)) - 1n; const c = hexToBytes(b.toString(16).padStart(64, '0')); return '0x' + bytesToHex(keccak256(c)); diff --git a/src/utils/upgrades-overrides.ts b/src/utils/upgrades-overrides.ts index 1f902c86..1a5399ba 100644 --- a/src/utils/upgrades-overrides.ts +++ b/src/utils/upgrades-overrides.ts @@ -73,5 +73,7 @@ function getOwnOverrides(node: Node): ValidationErrorKind[] { export function hasConstructorOverride(contract: ContractDefinition): boolean { const ctor = getConstructor(contract); - return ctor ? [...getOwnOverrides(ctor), ...getOwnOverrides(contract)].includes('constructor') : false; + return ctor + ? [...getOwnOverrides(ctor), ...getOwnOverrides(contract)].includes('constructor') + : false; } From e5dbedfb3df2377da03ff222f534352f2a69f534 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 14 Jul 2023 16:31:47 -0300 Subject: [PATCH 04/35] error on storage refs in modifiers --- src/transformations/add-namespace-struct.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index b4cacb20..0693b8f1 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -105,8 +105,17 @@ export function* addNamespaceStruct( }; for (const fnDef of findAll('FunctionDefinition', contract)) { + for (const ref of fnDef.modifiers.flatMap(m => [...findAll('Identifier', m)])) { + const varDecl = resolver.tryResolveNode( + 'VariableDeclaration', + ref.referencedDeclaration!, + ); + if (varDecl && isStorageVariable(varDecl, resolver)) { + throw error(ref, "Unsupported storage variable found in modifier"); + } + } + let foundReferences = false; - // TODO: variable references in modifiers? if (fnDef.body) { for (const ref of findAll('Identifier', fnDef.body)) { const varDecl = resolver.tryResolveNode( From 21ead5c4ca4bf0c22b96b00da521059e75b83d39 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 14 Jul 2023 16:36:31 -0300 Subject: [PATCH 05/35] lint --- src/transformations/add-namespace-struct.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index 0693b8f1..d1f74897 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -111,7 +111,7 @@ export function* addNamespaceStruct( ref.referencedDeclaration!, ); if (varDecl && isStorageVariable(varDecl, resolver)) { - throw error(ref, "Unsupported storage variable found in modifier"); + throw error(ref, 'Unsupported storage variable found in modifier'); } } From 17e639d988b324879f4dbce5ef173371ef2fa64c Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 14 Jul 2023 23:01:48 -0300 Subject: [PATCH 06/35] remove unused function --- src/transform.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/transform.ts b/src/transform.ts index 6948d980..06dc3a93 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -191,17 +191,6 @@ export class Transform { } } - getLeadingWhitespace(node: Node): string { - const { source } = this.decodeSrc(node.src); - const { start: nodeStart } = this.getShiftedBounds(node); - const buf = this.state[source].content; - let wsStart = nodeStart; - while (wsStart > 0 && /[ \t]/.test(buf.toString('utf8', wsStart - 1, wsStart))) { - wsStart -= 1; - } - return buf.toString('utf8', wsStart, nodeStart); - } - results(): { [file in string]: string } { return mapValues(this.state, s => s.content.toString()); } From b6886ebc02d9ea61ac5706be8bbe562746d106b9 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Wed, 16 Aug 2023 19:36:54 -0300 Subject: [PATCH 07/35] add line nr to error msg about containment --- src/transform.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/transform.ts b/src/transform.ts index 06dc3a93..a0507495 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -34,6 +34,7 @@ export interface TransformerTools { export interface TransformData {} interface TransformState { + id: number; ast: SourceUnit; transformations: Transformation[]; shifts: Shift[]; @@ -74,6 +75,7 @@ export class Transform { const contentBuf = Buffer.from(s.content); this.state[source] = { + id: output.sources[source].id, ast: output.sources[source].ast, original: s.content, originalBuf: contentBuf, @@ -104,8 +106,9 @@ export class Transform { }; for (const t of transform(ast, tools)) { - const { content, shifts, transformations } = this.state[source]; - insertSortedAndValidate(transformations, t); + const { id, content, shifts, transformations } = this.state[source]; + const error = (byteIndex: number, msg: string) => this.error({ src: `${byteIndex}:0:${id}` }, msg); + insertSortedAndValidate(transformations, t, error); const { result, shift } = applyTransformation(t, content, shifts, this); @@ -160,11 +163,9 @@ export class Transform { return shiftBounds(shifts, bounds); } - error(node: Node, msg: string): Error { + error(node: WithSrc, msg: string): Error { const { source, start } = this.decodeSrc(node.src); - const line = - 1 + - [...this.state[source].originalBuf.slice(0, start).toString('utf8').matchAll(/\n/g)].length; + const line = byteToLineNumber(this.state[source].originalBuf, start); const error = new Error(`${msg} (${source}:${line})`); Error.captureStackTrace(error, this.error); // capture stack trace without this function return error; @@ -200,14 +201,17 @@ export class Transform { } } -function insertSortedAndValidate(transformations: Transformation[], t: Transformation): void { +function insertSortedAndValidate(transformations: Transformation[], t: Transformation, error: (byteIndex: number, msg: string) => Error): void { transformations.push(t); transformations.sort(compareTransformations); // checks for overlaps for (let i = transformations.indexOf(t) + 1; i < transformations.length; i += 1) { const s = transformations[i]; const c = compareContainment(t, s); if (typeof c === 'number' && c < 0) { - throw new Error(`A bigger area has already been transformed (${s.kind} > ${t.kind})`); + throw error(s.start, `A bigger area has already been transformed (${s.kind} > ${t.kind})`); } } } +function byteToLineNumber(buf: Buffer, byteIndex: number): number { + return 1 + [...buf.slice(0, byteIndex).toString('utf8').matchAll(/\n/g)].length; +} From a83b0d96fe2d9bd1a17b0b6fbed96dae0e9f6370 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 19 Aug 2023 16:37:45 -0300 Subject: [PATCH 08/35] optimize ast resolver tryResolve --- package-lock.json | 1227 +++++++++++++++++++++++++++++++++++++++++-- package.json | 2 +- src/ast-resolver.ts | 9 +- 3 files changed, 1196 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43679364..17616fa4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "lodash": "^4.17.20", "minimatch": "^6.0.0", "minimist": "^1.2.5", - "solidity-ast": "^0.4.49" + "solidity-ast": "^0.4.50" }, "bin": { "upgrade-safe-transpiler": "dist/cli.js" @@ -1889,6 +1889,18 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -1907,6 +1919,43 @@ "node": ">=8" } }, + "node_modules/array.prototype.findlast": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.2.tgz", + "integrity": "sha512-p1YDNPNqA+P6cPX9ATsxg7DKir7gOmJ+jh5dEP3LlumMNYVC1F2Jgnyh6oI3n/qD9FeIkqR2jXfd73G68ImYUQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arrgv": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", @@ -2044,6 +2093,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2265,7 +2325,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -2730,6 +2789,21 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/del": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/del/-/del-7.0.0.tgz", @@ -2891,6 +2965,95 @@ "node": ">=6" } }, + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3568,6 +3731,14 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/fp-ts": { "version": "1.19.3", "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", @@ -3611,8 +3782,24 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -3620,6 +3807,14 @@ "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -3630,19 +3825,34 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -3712,6 +3922,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -3732,6 +3956,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -4040,7 +4275,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -4048,6 +4282,14 @@ "node": ">= 0.4.0" } }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4057,11 +4299,46 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, "engines": { "node": ">= 0.4" }, @@ -4251,6 +4528,19 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/io-ts": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", @@ -4269,6 +4559,30 @@ "node": ">=8" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4281,6 +4595,21 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-buffer": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", @@ -4304,6 +4633,31 @@ "node": ">=4" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-error": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", @@ -4353,6 +4707,17 @@ "npm": ">=3" } }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4362,6 +4727,20 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-path-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-3.0.0.tgz", @@ -4410,6 +4789,74 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", @@ -4422,6 +4869,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5102,7 +5565,31 @@ "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5641,6 +6128,22 @@ "node": ">=8.10.0" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -5811,6 +6314,23 @@ "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", "dev": true }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -5831,6 +6351,19 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5977,7 +6510,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -6085,9 +6617,12 @@ } }, "node_modules/solidity-ast": { - "version": "0.4.49", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.49.tgz", - "integrity": "sha512-Pr5sCAj1SFqzwFZw1HPKSq0PehlQNdM8GwKyAVYh2DOn7/cCK8LUKD1HeHnKtTgBW7hi9h4nnnan7hpAg5RhWQ==" + "version": "0.4.50", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.50.tgz", + "integrity": "sha512-WpIhaUibbjcBY4bg8TO2UXFWl8PQPhtH1QtMYJUqFUGxx0rRiEFsVLV+ow8XiWEnSPeu4xPp1/K43P4esxuK1Q==", + "dependencies": { + "array.prototype.findlast": "^1.2.2" + } }, "node_modules/source-map": { "version": "0.6.1", @@ -6189,15 +6724,57 @@ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/strip-ansi": { @@ -6464,6 +7041,67 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", @@ -6477,6 +7115,20 @@ "node": ">=4.2.0" } }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici": { "version": "5.16.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.16.0.tgz", @@ -6560,6 +7212,39 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -8156,6 +8841,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -8168,6 +8862,31 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "array.prototype.findlast": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.2.tgz", + "integrity": "sha512-p1YDNPNqA+P6cPX9ATsxg7DKir7gOmJ+jh5dEP3LlumMNYVC1F2Jgnyh6oI3n/qD9FeIkqR2jXfd73G68ImYUQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, "arrgv": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", @@ -8274,6 +8993,11 @@ } } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -8449,7 +9173,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -8796,6 +9519,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, "del": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/del/-/del-7.0.0.tgz", @@ -8919,6 +9651,80 @@ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true }, + "es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -9432,6 +10238,14 @@ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, "fp-ts": { "version": "1.19.3", "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", @@ -9465,8 +10279,18 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } }, "functional-red-black-tree": { "version": "1.0.1", @@ -9474,6 +10298,11 @@ "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -9481,16 +10310,25 @@ "dev": true }, "get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" } }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -9544,6 +10382,14 @@ "type-fest": "^0.20.2" } }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "requires": { + "define-properties": "^1.1.3" + } + }, "globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -9558,6 +10404,14 @@ "slash": "^3.0.0" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -9793,22 +10647,46 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } }, "hash-base": { "version": "3.1.0", @@ -9942,6 +10820,16 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "io-ts": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", @@ -9957,6 +10845,24 @@ "integrity": "sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==", "dev": true }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -9966,12 +10872,34 @@ "binary-extensions": "^2.0.0" } }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-buffer": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", "dev": true }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-error": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", @@ -10005,12 +10933,25 @@ "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", "dev": true }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-path-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-3.0.0.tgz", @@ -10041,12 +10982,66 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "requires": { + "which-typed-array": "^1.1.11" + } + }, "is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -10557,8 +11552,23 @@ "object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } }, "obliterator": { "version": "2.0.4", @@ -10909,6 +11919,16 @@ "picomatch": "^2.2.1" } }, + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -11016,12 +12036,33 @@ "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", "dev": true }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -11138,7 +12179,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -11224,9 +12264,12 @@ } }, "solidity-ast": { - "version": "0.4.49", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.49.tgz", - "integrity": "sha512-Pr5sCAj1SFqzwFZw1HPKSq0PehlQNdM8GwKyAVYh2DOn7/cCK8LUKD1HeHnKtTgBW7hi9h4nnnan7hpAg5RhWQ==" + "version": "0.4.50", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.50.tgz", + "integrity": "sha512-WpIhaUibbjcBY4bg8TO2UXFWl8PQPhtH1QtMYJUqFUGxx0rRiEFsVLV+ow8XiWEnSPeu4xPp1/K43P4esxuK1Q==", + "requires": { + "array.prototype.findlast": "^1.2.2" + } }, "source-map": { "version": "0.6.1", @@ -11316,6 +12359,36 @@ "strip-ansi": "^7.0.1" } }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, "strip-ansi": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", @@ -11501,12 +12574,66 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, "typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, "undici": { "version": "5.16.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.16.0.tgz", @@ -11569,6 +12696,30 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index a1eae419..220fdff0 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "lodash": "^4.17.20", "minimatch": "^6.0.0", "minimist": "^1.2.5", - "solidity-ast": "^0.4.49" + "solidity-ast": "^0.4.50" }, "devDependencies": { "@types/lodash": "^4.14.165", diff --git a/src/ast-resolver.ts b/src/ast-resolver.ts index e9e95ad0..95e4fb71 100644 --- a/src/ast-resolver.ts +++ b/src/ast-resolver.ts @@ -1,5 +1,5 @@ import { ContractDefinition } from 'solidity-ast'; -import { astDereferencer, ASTDereferencer, ASTDereferencerError } from 'solidity-ast/utils'; +import { astDereferencer, ASTDereferencer, ASTDereferencerError, ExtendedNodeType, ExtendedNodeTypeMap, isNodeType } from 'solidity-ast/utils'; import { NodeType, NodeTypeMap } from 'solidity-ast/node'; import { SolcOutput } from './solc/input-output'; @@ -15,7 +15,7 @@ export class ASTResolver { return this.tryResolveNode('ContractDefinition', id); } - resolveNode(nodeType: T, id: number): NodeTypeMap[T] { + resolveNode(nodeType: T, id: number): ExtendedNodeTypeMap[T] { const { node, sourceUnit } = this.deref.withSourceUnit(nodeType, id); const source = sourceUnit.absolutePath; if (this.exclude?.(source)) { @@ -27,7 +27,10 @@ export class ASTResolver { tryResolveNode(nodeType: T, id: number): NodeTypeMap[T] | undefined { try { - return this.resolveNode(nodeType, id); + const node = this.resolveNode('*', id); + if (isNodeType(nodeType, node)) { + return node; + } } catch (e) { if (e instanceof ASTDereferencerError) { return undefined; From 3b9532475e8b18a5ac9ef3fd313a598265e3bef7 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 19 Aug 2023 16:38:04 -0300 Subject: [PATCH 09/35] fix hardhat import --- src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index cf79e6d7..121391f5 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -11,7 +11,7 @@ import { findAlreadyInitializable } from './find-already-initializable'; async function getPaths() { const hardhat = require.resolve('hardhat', { paths: [process.cwd()] }); - const hre: HardhatRuntimeEnvironment = await import(hardhat); + const hre: HardhatRuntimeEnvironment = (await import(hardhat)).default; return hre.config.paths; } From 221b8d8c5273b4e0d013649f069ed3af67762e9b Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 19 Aug 2023 16:40:30 -0300 Subject: [PATCH 10/35] finish namespace implementation --- contracts/namespaces.sol | 28 +- src/cli.ts | 3 + src/index.ts | 12 +- src/transform-0.8.test.ts | 4 +- src/transform-namespaces.test.ts | 6 +- src/transform-namespaces.test.ts.md | 112 +++++++- src/transform-namespaces.test.ts.snap | Bin 560 -> 993 bytes src/transform.test.ts | 10 +- src/transformations/add-namespace-struct.ts | 239 ++++++++++-------- src/transformations/transform-constructor.ts | 179 +++++++------ .../utils/new-function-position.ts | 3 +- tsconfig.json | 2 +- 12 files changed, 389 insertions(+), 209 deletions(-) diff --git a/contracts/namespaces.sol b/contracts/namespaces.sol index 41a73d92..c354d4d2 100644 --- a/contracts/namespaces.sol +++ b/contracts/namespaces.sol @@ -1,17 +1,23 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; -contract U { +contract C1 { +} + +contract C2 { event B(); struct A { uint z; } + uint constant C = 3; // a uint x; // b /// @custom:oz-upgrades-unsafe-allow state-variable-immutable uint immutable y = 2; - uint z; + uint private z; + + string private s1 = ""; function f() public { z = 3; @@ -20,3 +26,21 @@ contract U { function g() public { } } + +contract C3 { + address private x; +} + +contract C4 { + address private x; + constructor() { + x = msg.sender; + } +} + +contract C5 { + address private x = msg.sender; +} + +contract C6 { +} diff --git a/src/cli.ts b/src/cli.ts index 121391f5..acfa521c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -23,6 +23,7 @@ interface Options { exclude: string[]; publicInitializers: string[]; namespaced: boolean; + namespaceExclude: string[]; } function readCommandFlags(resolveRootRelative: (p: string) => string): Options { @@ -34,12 +35,14 @@ function readCommandFlags(resolveRootRelative: (p: string) => string): Options { x: exclude = [], W: skipWithInit = false, n: namespaced = false, + N: namespaceExclude = [], } = minimist(process.argv.slice(2)); return { buildInfo, deleteOriginals, skipWithInit, namespaced, + namespaceExclude: ensureArray(namespaceExclude).map(resolveRootRelative), initializablePath: initializablePath && resolveRootRelative(initializablePath), publicInitializers: ensureArray(publicInitializers).map(resolveRootRelative), exclude: ensureArray(exclude).map(p => diff --git a/src/index.ts b/src/index.ts index d85a0d45..c8c229ff 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import path from 'path'; import fs from 'fs'; import { mapValues } from 'lodash'; +import minimatch from 'minimatch'; import { matcher } from './utils/matcher'; import { renamePath, isRenamed } from './rename'; @@ -45,6 +46,7 @@ interface TranspileOptions { solcVersion?: string; skipWithInit?: boolean; namespaced?: boolean; + namespaceExclude?: string[]; } function getExtraOutputPaths( @@ -78,6 +80,12 @@ export async function transpile( const excludeSet = new Set([...alreadyInitializable, ...Object.values(outputPaths)]); const excludeMatch = matcher(options?.exclude ?? []); + const namespaceInclude = (source: string) => { + const namespaced = options?.namespaced ?? false; + const namespaceExclude = options?.namespaceExclude ?? []; + return namespaced && !namespaceExclude.some(p => minimatch(source, p)); + }; + const transform = new Transform(solcInput, solcOutput, { exclude: source => excludeSet.has(source) || (excludeMatch(source) ?? isRenamed(source)), }); @@ -89,7 +97,7 @@ export async function transpile( transform.apply(fixImportDirectives); transform.apply(appendInitializableImport(outputPaths.initializable)); transform.apply(fixNewStatement); - transform.apply(transformConstructor); + transform.apply(transformConstructor(namespaceInclude)); transform.apply(removeLeftoverConstructorHead); transform.apply(addRequiredPublicInitializer(options?.publicInitializers)); transform.apply(removeInheritanceListArguments); @@ -97,7 +105,7 @@ export async function transpile( transform.apply(removeImmutable); if (options?.namespaced) { - transform.apply(addNamespaceStruct); + transform.apply(addNamespaceStruct(namespaceInclude)); } else { transform.apply(addStorageGaps); } diff --git a/src/transform-0.8.test.ts b/src/transform-0.8.test.ts index 83f61eb2..76aecba5 100644 --- a/src/transform-0.8.test.ts +++ b/src/transform-0.8.test.ts @@ -51,7 +51,7 @@ test('correctly index when utf8 characters', t => { test('preserves immutable if allowed', t => { const file = 'contracts/TransformAllowedImmutable.sol'; - t.context.transform.apply(transformConstructor); + t.context.transform.apply(transformConstructor()); t.context.transform.apply(removeLeftoverConstructorHead); t.context.transform.apply(removeStateVarInits); t.context.transform.apply(removeImmutable); @@ -60,7 +60,7 @@ test('preserves immutable if allowed', t => { test('custom contract size', t => { const file = 'contracts/TransformCustomSize.sol'; - t.context.transform.apply(transformConstructor); + t.context.transform.apply(transformConstructor()); t.context.transform.apply(removeLeftoverConstructorHead); t.context.transform.apply(removeStateVarInits); t.context.transform.apply(removeImmutable); diff --git a/src/transform-namespaces.test.ts b/src/transform-namespaces.test.ts index b4660d42..1295c4c5 100644 --- a/src/transform-namespaces.test.ts +++ b/src/transform-namespaces.test.ts @@ -5,7 +5,9 @@ import { getBuildInfo } from './test-utils/get-build-info'; import { SolcInput, SolcOutput } from './solc/input-output'; import { Transform } from './transform'; +import { removeStateVarInits } from './transformations/purge-var-inits'; import { addNamespaceStruct } from './transformations/add-namespace-struct'; +import { transformConstructor } from './transformations/transform-constructor'; const test = _test as TestFn; @@ -28,6 +30,8 @@ test.beforeEach('transform', async t => { test('add namespace', t => { const file = 'contracts/namespaces.sol'; - t.context.transform.apply(addNamespaceStruct); + t.context.transform.apply(transformConstructor(() => true)); + t.context.transform.apply(removeStateVarInits); + t.context.transform.apply(addNamespaceStruct(() => true)); t.snapshot(t.context.transform.results()[file]); }); diff --git a/src/transform-namespaces.test.ts.md b/src/transform-namespaces.test.ts.md index c636d7ac..ac085539 100644 --- a/src/transform-namespaces.test.ts.md +++ b/src/transform-namespaces.test.ts.md @@ -11,37 +11,133 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: UNLICENSED␊ pragma solidity ^0.8.20;␊ ␊ - contract U {␊ + contract C1 {␊ + function __C1_init() internal onlyInitializing {␊ + }␊ + ␊ + function __C1_init_unchained() internal onlyInitializing {␊ + }␊ + }␊ + ␊ + contract C2 {␊ + function __C2_init() internal onlyInitializing {␊ + __C2_init_unchained();␊ + }␊ + ␊ + function __C2_init_unchained() internal onlyInitializing {␊ + C2Storage storage $ = _getC2Storage();␊ + $.s1 = "";␊ + }␊ event B();␊ ␊ struct A { uint z; }␊ ␊ + uint constant C = 3;␊ // b␊ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable␊ uint immutable y = 2;␊ ␊ - /// @custom:storage-location erc7201:openzeppelin.storage.U␊ - struct UStorage {␊ + /// @custom:storage-location erc7201:openzeppelin.storage.C2␊ + struct C2Storage {␊ // a␊ uint x;␊ uint z;␊ + ␊ + string s1;␊ }␊ ␊ - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.U")) - 1))␊ - bytes32 private constant UStorageLocation = 0xe022f9b83eecd46e4fb4f58f3bf6221dceecce436d8ce41cf0ca78f72aa483aa;␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C2")) - 1))␊ + bytes32 private constant C2StorageLocation = 0xf05a05e0e3d15983ea921cad031aaea3040e9d631039045748753d29c5d248f9;␊ ␊ - function _getUStorage() private pure returns (UStorage storage $) {␊ + function _getC2Storage() private pure returns (C2Storage storage $) {␊ assembly {␊ - $.slot := UStorageLocation␊ + $.slot := C2StorageLocation␊ }␊ }␊ ␊ function f() public {␊ - UStorage storage $ = _getUStorage();␊ + C2Storage storage $ = _getC2Storage();␊ $.z = 3;␊ }␊ ␊ function g() public {␊ }␊ }␊ + ␊ + contract C3 {␊ + function __C3_init() internal onlyInitializing {␊ + }␊ + ␊ + function __C3_init_unchained() internal onlyInitializing {␊ + }␊ + /// @custom:storage-location erc7201:openzeppelin.storage.C3␊ + struct C3Storage {␊ + address x;␊ + }␊ + ␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C3")) - 1))␊ + bytes32 private constant C3StorageLocation = 0xaa7e0685867d809c517036b8f21e99d58bd04b1da2b202f167c355fdf82b4a94;␊ + ␊ + function _getC3Storage() private pure returns (C3Storage storage $) {␊ + assembly {␊ + $.slot := C3StorageLocation␊ + }␊ + }␊ + }␊ + ␊ + contract C4 {␊ + /// @custom:storage-location erc7201:openzeppelin.storage.C4␊ + struct C4Storage {␊ + address x;␊ + }␊ + ␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C4")) - 1))␊ + bytes32 private constant C4StorageLocation = 0x536a56e760d844b098efcc16711808e0b18bad9e07c2e82c78312ab719318df8;␊ + ␊ + function _getC4Storage() private pure returns (C4Storage storage $) {␊ + assembly {␊ + $.slot := C4StorageLocation␊ + }␊ + }␊ + constructor() {function __C4_init() internal onlyInitializing {␊ + __C4_init_unchained();␊ + }␊ + ␊ + function __C4_init_unchained() internal onlyInitializing {␊ + C4Storage storage $ = _getC4Storage();␊ + $.x = msg.sender;␊ + }␊ + }␊ + ␊ + contract C5 {␊ + function __C5_init() internal onlyInitializing {␊ + __C5_init_unchained();␊ + }␊ + ␊ + function __C5_init_unchained() internal onlyInitializing {␊ + C5Storage storage $ = _getC5Storage();␊ + $.x = msg.sender;␊ + }␊ + /// @custom:storage-location erc7201:openzeppelin.storage.C5␊ + struct C5Storage {␊ + address x;␊ + }␊ + ␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C5")) - 1))␊ + bytes32 private constant C5StorageLocation = 0xd94dd1cf5c0ce3bfbbd2555b11ad43bf11eeff03081ca744441b0fb7c0a6ecc2;␊ + ␊ + function _getC5Storage() private pure returns (C5Storage storage $) {␊ + assembly {␊ + $.slot := C5StorageLocation␊ + }␊ + }␊ + }␊ + ␊ + contract C6 {␊ + function __C6_init() internal onlyInitializing {␊ + }␊ + ␊ + function __C6_init_unchained() internal onlyInitializing {␊ + }␊ + }␊ ` diff --git a/src/transform-namespaces.test.ts.snap b/src/transform-namespaces.test.ts.snap index 69a860c7b30845dae01027ef6117bbd787991bda..10bea81ee979e08f894f401aab7ae0713d3072aa 100644 GIT binary patch literal 993 zcmV<710MWARzVlOKx+00000000BMSIchOMig~h6a@rikv|w1Sy&6n^W?*Vfu>3p28^J9QJ~#a zn8&3uFhvR+(zRrGkzIcy{n89o>P^>jRAd$u=XK}Yd(OQaeNI%G>s$BfA1G~^!bBQ_ zGC2V^l^U$eC)yI8jXfzWHVcyb&<_VC^DI%JWFR+e$2|$&TTesHa&Kp*gNtgAEnK}9AxEj6A^7e zL=Qz&x7GSh6oaP#?=L;*kRiP(b01$ouK9g~F41TVH81DrXI*(PlZ$-btES^Z z8gRWTb25RROw;@?e}F8ZcP9%gRSG>jnN(%{wmxGugl7H_+5p=$-niTI3YLo)LZL&7 z$wfYeY!1^Yq&Dj}tNKH_>DfAH>p*(ba@AR2xF2ly=M9R+P|brQTYP#Ox1hDWr6M?! z%Jw1Cxq-8Kdp)$CJbeP?X}61dh;+LPdumpKV-!sbd*>sz5&5M9*Gum&5x!5bkXQf) zW{8L*1~R5ZOM@Aa5+uVMLu>*@FpDu4A&)}A42`uglt)QC*j44WidHbDRRO4gvMMr% z&RP`M-H5An4kjv{Z45O+O!E?5T<-g_TKCwRD@l!{QmNI)q``cx-Q5Gmy9ewP2G&v- z*b$|QeNCx4G9B1fIq>5sikRa4dh{PljRb0lrRp9JdfwLn8zU#}Lz_;YZ8$(C1%eUC&-;7;; zD7(CkUBLn=0tf?aBF+_#BS^INBoY$g2(TiNk|qWmY6=n6VZ;cPDkL!@k>|LTUH&Y) z{780pec5BTelA?E>BtL@5EPZ!<`S0Q!w8%I(;@cm5 P-QSci&P(Wlx(xsTV$;^h literal 560 zcmV-00?++HRzV*&mAt00000000ARQNeE7KoF%xRVCm02cw7sKG+zWfD1xO+vE@lrIip;ducUZ z&(an4+VZYxAmWfuNx!sfa11G#gS|6v^!B~CPdrL8wo;FONei7&ig64QQ&KrH5=vsO zerH-eKE*L={L%i}ZoO|+_2ymc!`rKNuLtvQ*WaC)U?deew=qdAxS(PTi@VwFmz%r! z&9#*mxJ(gLmWWvB4gB=n(Dl8EWwA`^0-1&dJXm0g)`kH-cWnb!z0yT#;7{-Xr7*~L z0=olZ?vCn153X3Lbe4{@tyAX90%KB6DHU>ZFiEmMh6gn{Yb*pt2{|H7OI@Az414Bg z1RI!wKe5ip&Bqua$7F_DWD=-gBj4+fvz+9X@|+SO-FnMioa$f957XLZtsk3aui$?2 zvfm#1qu&)VhAaPa*u_Y=Bv}?yw_2@6NATixJr}kO4)kq%PZw=8slbQ45Ni_+n3pga z$)nWSv&$)X_vHCL{}_b<5sL>y8t`bqFGC(geCYfAn3*}FK`@L%^XoJ2F&u?_6R|MWX+XZ-_|O<(bW0{{TK5DCQq diff --git a/src/transform.test.ts b/src/transform.test.ts index 65f09ae0..8212b5aa 100644 --- a/src/transform.test.ts +++ b/src/transform.test.ts @@ -146,7 +146,7 @@ test('append initializable import custom', t => { test('transform constructor', t => { const file = 'contracts/TransformConstructor.sol'; - t.context.transform.apply(transformConstructor); + t.context.transform.apply(transformConstructor()); t.context.transform.apply(removeLeftoverConstructorHead); t.snapshot(t.context.transform.results()[file]); }); @@ -155,19 +155,19 @@ test('invalid constructors', t => { const tVarSubexpr = t.context.transformFile( 'contracts/invalid/TransformConstructorVarSubexpr.sol', ); - t.throws(() => tVarSubexpr.apply(transformConstructor), { + t.throws(() => tVarSubexpr.apply(transformConstructor()), { message: `Can't transpile non-trivial expression in parent constructor argument (y + 1)`, }); const tVarSubexprVar = t.context.transformFile( 'contracts/invalid/TransformConstructorVarSubexprVar.sol', ); - t.throws(() => tVarSubexprVar.apply(transformConstructor), { + t.throws(() => tVarSubexprVar.apply(transformConstructor()), { message: `Can't transpile non-trivial expression in parent constructor argument (y + 1)`, }); const tDupExpr = t.context.transformFile('contracts/invalid/TransformConstructorDupExpr.sol'); - t.throws(() => tDupExpr.apply(transformConstructor), { + t.throws(() => tDupExpr.apply(transformConstructor()), { message: `Can't transpile non-trivial expression in parent constructor argument (t.mint())`, }); }); @@ -181,7 +181,7 @@ test('fix new statement', t => { test('fix new statement in var init', t => { const file = 'contracts/TransformNewVarInit.sol'; - t.context.transform.apply(transformConstructor); + t.context.transform.apply(transformConstructor()); t.context.transform.apply(removeStateVarInits); t.context.transform.apply(removeLeftoverConstructorHead); t.context.transform.apply(addRequiredPublicInitializer([])); diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index d1f74897..1afb311b 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -8,138 +8,153 @@ import { formatLines } from './utils/format-lines'; import { isStorageVariable } from './utils/is-storage-variable'; import { erc7201Location } from '../utils/erc7201'; -export function* addNamespaceStruct( - sourceUnit: SourceUnit, - tools: TransformerTools, -): Generator { - const { error, resolver, getRealEndIndex } = tools; +export function getNamespaceStructName(contractName: string): string { + return contractName + 'Storage'; +} - for (const contract of findAll('ContractDefinition', sourceUnit)) { - let start = newFunctionPosition(contract, tools, false); +export function addNamespaceStruct(include?: (source: string) => boolean) { + return function* (sourceUnit: SourceUnit, tools: TransformerTools): Generator { + if (!include?.(sourceUnit.absolutePath)) { + return; + } - let firstVariable: VariableDeclaration | undefined; - let lastVariable: VariableDeclaration | undefined; - let finished = false; + const { error, resolver, getRealEndIndex } = tools; - const nonStorage: [number, VariableDeclaration][] = []; + for (const contract of findAll('ContractDefinition', sourceUnit)) { + let start = newFunctionPosition(contract, tools); - for (const n of contract.nodes) { - if (n.nodeType === 'VariableDeclaration') { - if (finished) { - throw error(n, 'All variables in the contract must be contiguous'); - } + let finished = false; - if (!isStorageVariable(n, resolver)) { - const varStart = lastVariable ? getRealEndIndex(lastVariable) + 1 : start; - nonStorage.push([varStart, n]); - } + const nonStorageVars: [number, VariableDeclaration][] = []; + const storageVars: VariableDeclaration[] = []; + + for (const n of contract.nodes) { + if (n.nodeType === 'VariableDeclaration' && (storageVars.length > 0 || isStorageVariable(n, resolver))) { + if (finished) { + throw error(n, 'All variables in the contract must be contiguous'); + } - firstVariable ??= n; - lastVariable = n; - } else if (firstVariable) { - finished = true; - } else { - start = getRealEndIndex(n) + 1; + if (!isStorageVariable(n, resolver)) { + const varStart = getRealEndIndex(storageVars.at(-1)!) + 1; + nonStorageVars.push([varStart, n]); + } else { + storageVars.push(n); + } + } else if (storageVars.length > 0) { + finished = true; + } else { + start = getRealEndIndex(n) + 1; + } } - } - for (const [s, v] of nonStorage) { - const bounds = { start: s, length: getRealEndIndex(v) + 1 - s }; - let removed = ''; - - yield { - kind: 'relocate-nonstorage-var-remove', - ...bounds, - transform: source => { - removed = source; - return ''; - }, - }; - - yield { - kind: 'relocate-nonstorage-var-reinsert', - start, - length: 0, - text: removed, - }; - } + for (const [s, v] of nonStorageVars) { + const bounds = { start: s, length: getRealEndIndex(v) + 1 - s }; + let removed = ''; + + yield { + kind: 'relocate-nonstorage-var-remove', + ...bounds, + transform: source => { + removed = source; + return ''; + }, + }; + + yield { + kind: 'relocate-nonstorage-var-reinsert', + start, + length: 0, + text: removed, + }; + } - if (nonStorage.length > 0) { - yield { - kind: 'relocate-nonstorage-var-newline', - start, - length: 0, - text: '\n', - }; - } + if (nonStorageVars.length > 0) { + yield { + kind: 'relocate-nonstorage-var-newline', + start, + length: 0, + text: '\n', + }; + } - if (firstVariable && lastVariable) { - const namespace = contract.name + 'Storage'; - const id = 'openzeppelin.storage.' + contract.name; - - const end = getRealEndIndex(lastVariable) + 1; - - yield { - kind: 'add-namespace-struct', - start, - length: end - start, - transform: source => { - const [, leading, rest] = source.match(/^((?:[ \t\v\f]*[\n\r]+)*)(.*)$/s)!; - return ( - leading + - formatLines(1, [ - `/// @custom:storage-location erc7201:${id}`, - `struct ${namespace} {`, - ...rest.split('\n'), - `}`, - ``, - `// keccak256(abi.encode(uint256(keccak256("${id}")) - 1))`, - `bytes32 private constant ${namespace}Location = ${erc7201Location(id)};`, - ``, - `function _get${namespace}() private pure returns (${namespace} storage $) {`, - [`assembly {`, [`$.slot := ${namespace}Location`], `}`], - `}`, - ]).trimEnd() - ); - }, - }; - - for (const fnDef of findAll('FunctionDefinition', contract)) { - for (const ref of fnDef.modifiers.flatMap(m => [...findAll('Identifier', m)])) { - const varDecl = resolver.tryResolveNode( - 'VariableDeclaration', - ref.referencedDeclaration!, - ); - if (varDecl && isStorageVariable(varDecl, resolver)) { - throw error(ref, 'Unsupported storage variable found in modifier'); - } + if (storageVars.length > 0) { + for (const v of storageVars) { + const { start, length } = getNodeBounds(v); + yield { + kind: 'remove-var-modifier', + start, + length, + transform: source => source.replace(/\s*\bprivate\b/g, ''), + }; } - let foundReferences = false; - if (fnDef.body) { - for (const ref of findAll('Identifier', fnDef.body)) { + const namespace = getNamespaceStructName(contract.name); + const id = 'openzeppelin.storage.' + contract.name; + + const end = getRealEndIndex(storageVars.at(-1)!) + 1; + + yield { + kind: 'add-namespace-struct', + start, + length: end - start, + transform: source => { + const [, leading, rest] = source.match(/^((?:[ \t\v\f]*[\n\r]+)*)(.*)$/s)!; + return ( + leading + + formatLines(1, [ + `/// @custom:storage-location erc7201:${id}`, + `struct ${namespace} {`, + ...rest.split('\n'), + `}`, + ``, + `// keccak256(abi.encode(uint256(keccak256("${id}")) - 1))`, + `bytes32 private constant ${namespace}Location = ${erc7201Location(id)};`, + ``, + `function _get${namespace}() private pure returns (${namespace} storage $) {`, + [`assembly {`, [`$.slot := ${namespace}Location`], `}`], + `}`, + ]).trimEnd() + ); + }, + }; + + for (const fnDef of findAll('FunctionDefinition', contract)) { + for (const ref of fnDef.modifiers.flatMap(m => [...findAll('Identifier', m)])) { const varDecl = resolver.tryResolveNode( 'VariableDeclaration', ref.referencedDeclaration!, ); if (varDecl && isStorageVariable(varDecl, resolver)) { - if (varDecl.scope !== contract.id) { - throw error(varDecl, 'Namespaces assume all variables are private'); - } - foundReferences = true; - const { start } = getNodeBounds(ref); - yield { kind: 'add-namespace-ref', start, length: 0, text: '$.' }; + throw error(ref, 'Unsupported storage variable found in modifier'); } } - if (foundReferences) { - const { start: fnBodyStart } = getNodeBounds(fnDef.body); - yield { - kind: 'add-namespace-base-ref', - start: fnBodyStart + 1, - length: 0, - text: `\n ${namespace} storage $ = _get${namespace}();`, - }; + let foundReferences = false; + if (fnDef.body) { + for (const ref of findAll('Identifier', fnDef.body)) { + const varDecl = resolver.tryResolveNode( + 'VariableDeclaration', + ref.referencedDeclaration!, + ); + if (varDecl && isStorageVariable(varDecl, resolver)) { + if (varDecl.scope !== contract.id) { + throw error(varDecl, 'Namespaces assume all variables are private'); + } + foundReferences = true; + const { start } = getNodeBounds(ref); + yield { kind: 'add-namespace-ref', start, length: 0, text: '$.' }; + } + } + + if (foundReferences) { + const { start: fnBodyStart } = getNodeBounds(fnDef.body); + yield { + kind: 'add-namespace-base-ref', + start: fnBodyStart + 1, + length: 0, + text: `\n ${namespace} storage $ = _get${namespace}();`, + }; + } } } } diff --git a/src/transformations/transform-constructor.ts b/src/transformations/transform-constructor.ts index 2706751a..7631d61f 100644 --- a/src/transformations/transform-constructor.ts +++ b/src/transformations/transform-constructor.ts @@ -11,6 +11,9 @@ import { formatLines } from './utils/format-lines'; import { hasConstructorOverride } from '../utils/upgrades-overrides'; import { getInitializerItems } from './utils/get-initializer-items'; import { parseNewExpression } from '../utils/new-expression'; +import { getNamespaceStructName } from './add-namespace-struct'; +import { ASTResolver } from '../ast-resolver'; +import { isStorageVariable } from './utils/is-storage-variable'; function getArgsList(constructor: FunctionDefinition, helper: TransformHelper): string { return helper.read(constructor.parameters).replace(/^\((.*)\)$/s, '$1'); @@ -78,86 +81,114 @@ export function* removeLeftoverConstructorHead(sourceUnit: SourceUnit): Generato // and must run removeLeftoverConstructorHead after. For example // This: constructor(uint a) /* modifiers */ public // Results in: constructor(uint a) /* modifiers */ public { function __Name_init(uint a) /* modifiers */ -export function* transformConstructor( - sourceUnit: SourceUnit, - tools: TransformerTools, -): Generator { - const { resolver, getData } = tools; +export function transformConstructor(namespaced?: (source: string) => boolean) { + return function* ( + sourceUnit: SourceUnit, + tools: TransformerTools, + ): Generator { + const { resolver, getData } = tools; - for (const contractNode of findAll('ContractDefinition', sourceUnit)) { - if (contractNode.contractKind !== 'contract' || hasConstructorOverride(contractNode)) { - continue; - } + const namespaces = namespaced?.(sourceUnit.absolutePath) ?? false; + + for (const contractNode of findAll('ContractDefinition', sourceUnit)) { + if (contractNode.contractKind !== 'contract' || hasConstructorOverride(contractNode)) { + continue; + } - const { name } = contractNode; - const { - constructorNode, - varInitNodes, - modifiers, - emptyUnchained: emptyConstructor, - } = getInitializerItems(contractNode, resolver); - - const initializer = ( - helper: TransformHelper, - argsList = '', - unchainedArgsList = '', - argNames: string[] = [], - ) => [ - `function __${name}_init(${argsList}) internal onlyInitializing {`, - buildSuperCallsForChain(contractNode, tools, helper), - emptyConstructor ? [] : [`__${name}_init_unchained(${argNames.join(', ')});`], - `}`, - ``, - [ - `function`, - `__${name}_init_unchained(${unchainedArgsList})`, - `internal onlyInitializing`, - ...modifiers.map(m => helper.read(m)), - `{`, - ].join(' '), - varInitNodes.map(v => { - const newExpr = parseNewExpression(v.value!); - if (!newExpr) { - return `${v.name} = ${helper.read(v.value!)};`; - } else { - const { typeName, newCall, initializeCall } = newExpr; - const createdContract = resolver.resolveContract(typeName.referencedDeclaration); - if (createdContract) { - getData(createdContract).isUsedInNewStatement = true; + const { name } = contractNode; + const { + constructorNode, + varInitNodes, + modifiers, + emptyUnchained: emptyConstructor, + } = getInitializerItems(contractNode, resolver); + + const namespace = getNamespaceStructName(name); + const constructorUsesStorage = + constructorNode !== undefined && + usesStorageVariables(constructorNode, resolver); + + const initializer = ( + helper: TransformHelper, + argsList = '', + unchainedArgsList = '', + argNames: string[] = [], + ) => [ + `function __${name}_init(${argsList}) internal onlyInitializing {`, + buildSuperCallsForChain(contractNode, tools, helper), + emptyConstructor ? [] : [`__${name}_init_unchained(${argNames.join(', ')});`], + `}`, + ``, + [ + `function`, + `__${name}_init_unchained(${unchainedArgsList})`, + `internal onlyInitializing`, + ...modifiers.map(m => helper.read(m)), + `{`, + ].join(' '), + namespaced && varInitNodes.length > 0 && !constructorUsesStorage + ? [`${namespace} storage $ = _get${namespace}();`] + : [], + varInitNodes.map(v => { + const prefix = namespaced ? '$.' : ''; + const newExpr = parseNewExpression(v.value!); + if (!newExpr) { + return `${prefix}${v.name} = ${helper.read(v.value!)};`; + } else { + const { typeName, newCall, initializeCall } = newExpr; + const createdContract = resolver.resolveContract(typeName.referencedDeclaration); + if (createdContract) { + getData(createdContract).isUsedInNewStatement = true; + } + return `${prefix}${v.name} = ${newCall(helper)};\n ${initializeCall(v.name, helper)};`; } - return `${v.name} = ${newCall(helper)};\n ${initializeCall(v.name, helper)};`; - } - }), - `}`, - ]; + }), + `}`, + ]; - if (constructorNode) { - const { start: bodyStart } = getNodeBounds(constructorNode.body!); - const argNames = constructorNode.parameters.parameters.map(p => p.name); + if (constructorNode) { + const { start: bodyStart } = getNodeBounds(constructorNode.body!); + const argNames = constructorNode.parameters.parameters.map(p => p.name); - yield { - start: bodyStart + 1, - length: 0, - kind: 'transform-constructor', - transform: (_, helper) => { - const argsList = getArgsList(constructorNode, helper); - const unchainedArgsList = getUnchainedArguments(constructorNode, helper, modifiers); - - return formatLines( - 1, - initializer(helper, argsList, unchainedArgsList, argNames).slice(0, -1), - ).trim(); - }, - }; - } else { - const start = newFunctionPosition(contractNode, tools); + yield { + start: bodyStart + 1, + length: 0, + kind: 'transform-constructor', + transform: (_, helper) => { + const argsList = getArgsList(constructorNode, helper); + const unchainedArgsList = getUnchainedArguments(constructorNode, helper, modifiers); - yield { - start, - length: 0, - kind: 'transform-constructor', - transform: (source, helper) => formatLines(1, initializer(helper)), - }; + return formatLines( + 1, + initializer(helper, argsList, unchainedArgsList, argNames).slice(0, -1), + ).trim(); + }, + }; + } else { + const start = newFunctionPosition(contractNode, tools); + + yield { + start, + length: 0, + kind: 'transform-constructor', + transform: (source, helper) => formatLines(1, initializer(helper)), + }; + } + } + } +} + +function usesStorageVariables(fnDef: FunctionDefinition, resolver: ASTResolver): boolean { + if (fnDef.body) { + for (const ref of findAll('Identifier', fnDef.body)) { + const varDecl = resolver.tryResolveNode( + 'VariableDeclaration', + ref.referencedDeclaration!, + ); + if (varDecl && isStorageVariable(varDecl, resolver)) { + return true; + } } } + return false; } diff --git a/src/transformations/utils/new-function-position.ts b/src/transformations/utils/new-function-position.ts index 2fe25315..21751989 100644 --- a/src/transformations/utils/new-function-position.ts +++ b/src/transformations/utils/new-function-position.ts @@ -7,7 +7,6 @@ import { matchBufferFrom } from '../../utils/match'; export function newFunctionPosition( contract: ContractDefinition, { readOriginal }: TransformerTools, - newline = true, ): number { const offset = getNodeBounds(contract).start; let searchStart = 0; @@ -18,7 +17,7 @@ export function newFunctionPosition( searchStart = pb.start + pb.length - offset; } - const re = newline ? /\{\n?/ : /\{/; + const re = /\{\n?/; const brace = matchBufferFrom(readOriginal(contract, 'buffer'), re, searchStart); if (!brace) { diff --git a/tsconfig.json b/tsconfig.json index 00098796..ceea58e6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "moduleResolution": "Node", "esModuleInterop": true, "resolveJsonModule": true, - "target": "es2020", + "target": "es2022", "declaration": true, "declarationMap": true, "sourceMap": true, From 421624c2c50f62bc0a1ecb2a6f7b6fd9d7924170 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 19 Aug 2023 17:02:52 -0300 Subject: [PATCH 11/35] fix bug in transform-constructor --- src/transformations/transform-constructor.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/transformations/transform-constructor.ts b/src/transformations/transform-constructor.ts index 7631d61f..9f37cc87 100644 --- a/src/transformations/transform-constructor.ts +++ b/src/transformations/transform-constructor.ts @@ -81,14 +81,14 @@ export function* removeLeftoverConstructorHead(sourceUnit: SourceUnit): Generato // and must run removeLeftoverConstructorHead after. For example // This: constructor(uint a) /* modifiers */ public // Results in: constructor(uint a) /* modifiers */ public { function __Name_init(uint a) /* modifiers */ -export function transformConstructor(namespaced?: (source: string) => boolean) { +export function transformConstructor(isNamespaced?: (source: string) => boolean) { return function* ( sourceUnit: SourceUnit, tools: TransformerTools, ): Generator { const { resolver, getData } = tools; - const namespaces = namespaced?.(sourceUnit.absolutePath) ?? false; + const useNamespaces = isNamespaced?.(sourceUnit.absolutePath) ?? false; for (const contractNode of findAll('ContractDefinition', sourceUnit)) { if (contractNode.contractKind !== 'contract' || hasConstructorOverride(contractNode)) { @@ -126,11 +126,11 @@ export function transformConstructor(namespaced?: (source: string) => boolean) { ...modifiers.map(m => helper.read(m)), `{`, ].join(' '), - namespaced && varInitNodes.length > 0 && !constructorUsesStorage + useNamespaces && varInitNodes.length > 0 && !constructorUsesStorage ? [`${namespace} storage $ = _get${namespace}();`] : [], varInitNodes.map(v => { - const prefix = namespaced ? '$.' : ''; + const prefix = useNamespaces ? '$.' : ''; const newExpr = parseNewExpression(v.value!); if (!newExpr) { return `${prefix}${v.name} = ${helper.read(v.value!)};`; From 759d4e2792b6406e98de2cca8be1ab0d547b1cc8 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 19 Aug 2023 17:02:57 -0300 Subject: [PATCH 12/35] update solidity-ast --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17616fa4..eef7d4af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "lodash": "^4.17.20", "minimatch": "^6.0.0", "minimist": "^1.2.5", - "solidity-ast": "^0.4.50" + "solidity-ast": "^0.4.51" }, "bin": { "upgrade-safe-transpiler": "dist/cli.js" @@ -6617,9 +6617,9 @@ } }, "node_modules/solidity-ast": { - "version": "0.4.50", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.50.tgz", - "integrity": "sha512-WpIhaUibbjcBY4bg8TO2UXFWl8PQPhtH1QtMYJUqFUGxx0rRiEFsVLV+ow8XiWEnSPeu4xPp1/K43P4esxuK1Q==", + "version": "0.4.51", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.51.tgz", + "integrity": "sha512-Mql4HTY3ce2t8YW6cGjq8dKKRT9D38D3TB/lOfIhgbfXx/cCFG2clXgqWuOfXGX9t6fhOPFvcVZhj2b6n30VBA==", "dependencies": { "array.prototype.findlast": "^1.2.2" } @@ -12264,9 +12264,9 @@ } }, "solidity-ast": { - "version": "0.4.50", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.50.tgz", - "integrity": "sha512-WpIhaUibbjcBY4bg8TO2UXFWl8PQPhtH1QtMYJUqFUGxx0rRiEFsVLV+ow8XiWEnSPeu4xPp1/K43P4esxuK1Q==", + "version": "0.4.51", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.51.tgz", + "integrity": "sha512-Mql4HTY3ce2t8YW6cGjq8dKKRT9D38D3TB/lOfIhgbfXx/cCFG2clXgqWuOfXGX9t6fhOPFvcVZhj2b6n30VBA==", "requires": { "array.prototype.findlast": "^1.2.2" } diff --git a/package.json b/package.json index 220fdff0..af52efd9 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "lodash": "^4.17.20", "minimatch": "^6.0.0", "minimist": "^1.2.5", - "solidity-ast": "^0.4.50" + "solidity-ast": "^0.4.51" }, "devDependencies": { "@types/lodash": "^4.14.165", From aca56c2620f6ff790af9dc7ace52e1e0d959c6ee Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 19 Aug 2023 17:05:10 -0300 Subject: [PATCH 13/35] 0.3.26-0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index eef7d4af..a2240026 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.25", + "version": "0.3.26-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.25", + "version": "0.3.26-0", "license": "MIT", "dependencies": { "ajv": "^8.0.0", diff --git a/package.json b/package.json index af52efd9..ff1d0237 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.25", + "version": "0.3.26-0", "description": "Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe.", "main": "dist/index.js", "types": "dist/index.d.ts", From 5a82888b3c40996ff4773816b8ac5f2efcadbec2 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Sat, 19 Aug 2023 18:35:44 -0300 Subject: [PATCH 14/35] lint --- src/ast-resolver.ts | 9 ++++++++- src/transform.ts | 9 +++++++-- src/transformations/add-namespace-struct.ts | 7 +++++-- src/transformations/transform-constructor.ts | 20 ++++++++------------ 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/ast-resolver.ts b/src/ast-resolver.ts index 95e4fb71..960e4cdc 100644 --- a/src/ast-resolver.ts +++ b/src/ast-resolver.ts @@ -1,5 +1,12 @@ import { ContractDefinition } from 'solidity-ast'; -import { astDereferencer, ASTDereferencer, ASTDereferencerError, ExtendedNodeType, ExtendedNodeTypeMap, isNodeType } from 'solidity-ast/utils'; +import { + astDereferencer, + ASTDereferencer, + ASTDereferencerError, + ExtendedNodeType, + ExtendedNodeTypeMap, + isNodeType, +} from 'solidity-ast/utils'; import { NodeType, NodeTypeMap } from 'solidity-ast/node'; import { SolcOutput } from './solc/input-output'; diff --git a/src/transform.ts b/src/transform.ts index a0507495..d08972cc 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -107,7 +107,8 @@ export class Transform { for (const t of transform(ast, tools)) { const { id, content, shifts, transformations } = this.state[source]; - const error = (byteIndex: number, msg: string) => this.error({ src: `${byteIndex}:0:${id}` }, msg); + const error = (byteIndex: number, msg: string) => + this.error({ src: `${byteIndex}:0:${id}` }, msg); insertSortedAndValidate(transformations, t, error); const { result, shift } = applyTransformation(t, content, shifts, this); @@ -201,7 +202,11 @@ export class Transform { } } -function insertSortedAndValidate(transformations: Transformation[], t: Transformation, error: (byteIndex: number, msg: string) => Error): void { +function insertSortedAndValidate( + transformations: Transformation[], + t: Transformation, + error: (byteIndex: number, msg: string) => Error, +): void { transformations.push(t); transformations.sort(compareTransformations); // checks for overlaps for (let i = transformations.indexOf(t) + 1; i < transformations.length; i += 1) { diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index 1afb311b..3bbf5fa1 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -29,7 +29,10 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { const storageVars: VariableDeclaration[] = []; for (const n of contract.nodes) { - if (n.nodeType === 'VariableDeclaration' && (storageVars.length > 0 || isStorageVariable(n, resolver))) { + if ( + n.nodeType === 'VariableDeclaration' && + (storageVars.length > 0 || isStorageVariable(n, resolver)) + ) { if (finished) { throw error(n, 'All variables in the contract must be contiguous'); } @@ -159,5 +162,5 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { } } } - } + }; } diff --git a/src/transformations/transform-constructor.ts b/src/transformations/transform-constructor.ts index 9f37cc87..2b2fda2c 100644 --- a/src/transformations/transform-constructor.ts +++ b/src/transformations/transform-constructor.ts @@ -82,10 +82,7 @@ export function* removeLeftoverConstructorHead(sourceUnit: SourceUnit): Generato // This: constructor(uint a) /* modifiers */ public // Results in: constructor(uint a) /* modifiers */ public { function __Name_init(uint a) /* modifiers */ export function transformConstructor(isNamespaced?: (source: string) => boolean) { - return function* ( - sourceUnit: SourceUnit, - tools: TransformerTools, - ): Generator { + return function* (sourceUnit: SourceUnit, tools: TransformerTools): Generator { const { resolver, getData } = tools; const useNamespaces = isNamespaced?.(sourceUnit.absolutePath) ?? false; @@ -105,8 +102,7 @@ export function transformConstructor(isNamespaced?: (source: string) => boolean) const namespace = getNamespaceStructName(name); const constructorUsesStorage = - constructorNode !== undefined && - usesStorageVariables(constructorNode, resolver); + constructorNode !== undefined && usesStorageVariables(constructorNode, resolver); const initializer = ( helper: TransformHelper, @@ -140,7 +136,10 @@ export function transformConstructor(isNamespaced?: (source: string) => boolean) if (createdContract) { getData(createdContract).isUsedInNewStatement = true; } - return `${prefix}${v.name} = ${newCall(helper)};\n ${initializeCall(v.name, helper)};`; + return `${prefix}${v.name} = ${newCall(helper)};\n ${initializeCall( + v.name, + helper, + )};`; } }), `}`, @@ -175,16 +174,13 @@ export function transformConstructor(isNamespaced?: (source: string) => boolean) }; } } - } + }; } function usesStorageVariables(fnDef: FunctionDefinition, resolver: ASTResolver): boolean { if (fnDef.body) { for (const ref of findAll('Identifier', fnDef.body)) { - const varDecl = resolver.tryResolveNode( - 'VariableDeclaration', - ref.referencedDeclaration!, - ); + const varDecl = resolver.tryResolveNode('VariableDeclaration', ref.referencedDeclaration!); if (varDecl && isStorageVariable(varDecl, resolver)) { return true; } From 487d57fe40ffb90deb1b97bbd6d715206aa61adb Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Wed, 23 Aug 2023 19:12:24 -0300 Subject: [PATCH 15/35] handle comments after variables --- contracts/namespaces.sol | 7 +++++ src/transform-namespaces.test.ts.md | 24 ++++++++++++++ src/transform-namespaces.test.ts.snap | Bin 993 -> 1105 bytes src/transform.ts | 43 ++++++++++++++++++++------ 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/contracts/namespaces.sol b/contracts/namespaces.sol index c354d4d2..a6e2220b 100644 --- a/contracts/namespaces.sol +++ b/contracts/namespaces.sol @@ -44,3 +44,10 @@ contract C5 { contract C6 { } + +contract C7 { + uint x; // a comment + + uint y; + // a separate comment +} diff --git a/src/transform-namespaces.test.ts.md b/src/transform-namespaces.test.ts.md index ac085539..a57768a5 100644 --- a/src/transform-namespaces.test.ts.md +++ b/src/transform-namespaces.test.ts.md @@ -140,4 +140,28 @@ Generated by [AVA](https://avajs.dev). function __C6_init_unchained() internal onlyInitializing {␊ }␊ }␊ + ␊ + contract C7 {␊ + function __C7_init() internal onlyInitializing {␊ + }␊ + ␊ + function __C7_init_unchained() internal onlyInitializing {␊ + }␊ + /// @custom:storage-location erc7201:openzeppelin.storage.C7␊ + struct C7Storage {␊ + uint x; // a comment␊ + ␊ + uint y;␊ + }␊ + ␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C7")) - 1))␊ + bytes32 private constant C7StorageLocation = 0x931371859ca5c5440d3850c7cf9c14adb9d1257b7ddd15562d561cd48871d379;␊ + ␊ + function _getC7Storage() private pure returns (C7Storage storage $) {␊ + assembly {␊ + $.slot := C7StorageLocation␊ + }␊ + }␊ + // a separate comment␊ + }␊ ` diff --git a/src/transform-namespaces.test.ts.snap b/src/transform-namespaces.test.ts.snap index 10bea81ee979e08f894f401aab7ae0713d3072aa..e2ed2898158123c3be44eb16145f0d0875d22a1d 100644 GIT binary patch literal 1105 zcmV-X1g`r*RzV6eyrY{w6!QR=~z3tN1MJolb+Na|B!vci7wAOD6btuh#E z=TNT4;3wKb>T^Bu?~BTR{N$Xj^dGN&{O0Jpqq=ckfB)+A6kYxL=J(!ZY9aT~ zyKsX=z8;e6G*7FOE=uzX%3Not$g|l+XiIgL&eMFfeCfXP#Jks_<-JaGaII#! z-$XarfciDK{+;QgVk78%m3stEZ738Qr02z<}n172riRq{vq~JPgB3>|vsy1hafNML*eT05d)- z=Dq1;RB8vlH_g3Hpr^B}_$w@+E9l+mGSw!7UOFC6tNQ72jdc^6g+=HR*yiNRaC=KbZU{*Z1)_L#KCM24yLy0XA9 z9O2sp3ylR}V2+4bG0-t3Ry)jy)}R^Y7-APOf?15YkX%W@9F47Tl&d5j?5c8GMQa$7 zX$h!=YFg$Voir%0yOCGzJ&a8@+h|$}F)J!`cD^6Wdfa`ZSCSgZ)MTkW#0K+6?d~ox z+Ff90V_*#%13O@=V*h2UI?xVm%MNVc4&f*$!TXg7K9|5*TYAE=7u;;4aGDek+e*R#3hOvu4CRPaQ3Xg*?|Jzjb%^ZTk_(|i4I_w zZ?Vh27`wbJyS#~A!6GdpkP&u@bAw|AiM4@5LKIej4N*qB7_hVy6tz+@LbZ`3W<&*! z8`lzM*$gaw6A#9zWa>5%)Yy^{QKq{HOM$R z;OvhM{!Eb#h~xo?jWRn-diNqvP zBDPvs!8vwJ32dcJVoSJoCU%4hX`~C55h9{aM8rC-lq8PH=9{>D)(i4LFYLzBc$6(T X@G#NkLn0o?xbOS}gHmf}P7nY9#abg2 literal 993 zcmV<710MWARzVlOKx+00000000BMSIchOMig~h6a@rikv|w1Sy&6n^W?*Vfu>3p28^J9QJ~#a zn8&3uFhvR+(zRrGkzIcy{n89o>P^>jRAd$u=XK}Yd(OQaeNI%G>s$BfA1G~^!bBQ_ zGC2V^l^U$eC)yI8jXfzWHVcyb&<_VC^DI%JWFR+e$2|$&TTesHa&Kp*gNtgAEnK}9AxEj6A^7e zL=Qz&x7GSh6oaP#?=L;*kRiP(b01$ouK9g~F41TVH81DrXI*(PlZ$-btES^Z z8gRWTb25RROw;@?e}F8ZcP9%gRSG>jnN(%{wmxGugl7H_+5p=$-niTI3YLo)LZL&7 z$wfYeY!1^Yq&Dj}tNKH_>DfAH>p*(ba@AR2xF2ly=M9R+P|brQTYP#Ox1hDWr6M?! z%Jw1Cxq-8Kdp)$CJbeP?X}61dh;+LPdumpKV-!sbd*>sz5&5M9*Gum&5x!5bkXQf) zW{8L*1~R5ZOM@Aa5+uVMLu>*@FpDu4A&)}A42`uglt)QC*j44WidHbDRRO4gvMMr% z&RP`M-H5An4kjv{Z45O+O!E?5T<-g_TKCwRD@l!{QmNI)q``cx-Q5Gmy9ewP2G&v- z*b$|QeNCx4G9B1fIq>5sikRa4dh{PljRb0lrRp9JdfwLn8zU#}Lz_;YZ8$(C1%eUC&-;7;; zD7(CkUBLn=0tf?aBF+_#BS^INBoY$g2(TiNk|qWmY6=n6VZ;cPDkL!@k>|LTUH&Y) z{780pec5BTelA?E>BtL@5EPZ!<`S0Q!w8%I(;@cm5 P-QSci&P(Wlx(xsTV$;^h diff --git a/src/transform.ts b/src/transform.ts index d08972cc..3398626d 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -174,23 +174,48 @@ export class Transform { getRealEndIndex(node: Node): number { const { source, start, length } = this.decodeSrc(node.src); + const buf = this.state[source].originalBuf; + + let end: number | undefined; + if (node.nodeType !== 'VariableDeclaration') { - return start + length; + end = start + length; } else { - // VariableDeclaration node bounds don't include the semicolon - const buf = this.state[source].originalBuf; - let index = start + length; - while (index < buf.length) { - const c = buf.toString('utf8', index, index + 1); + // VariableDeclaration node bounds don't include the semicolon so we manually look for it + for (let i = start + length; i < buf.length; i++) { + const c = buf.toString('utf8', i, i + 1); if (c === ';') { - return index; + end = i; + break; } else if (/\S/.test(c)) { throw this.error(node, 'Found unexpected content before semicolon'); } - index += 1; } - throw this.error(node, 'could not find end of node'); + if (end === undefined) { + throw this.error(node, 'could not find end of node'); + } } + + let foundComment = false; + + for (let i = end + 1; i < buf.length; i++) { + // look ahead 2 bytes to search for '//' + const next = buf.toString('utf8', i, i + 2); + if (foundComment) { + if (/[^\n\r]/.test(next[0])) { + end = i; + } else { + break; + } + } else if (next === '//') { + end = i + 1; + foundComment = true; + } else if (/[^ \t]/.test(next[0])) { + break; + } + } + + return end; } results(): { [file in string]: string } { From 628341946ab588d4b0d0161eaceecf4ff88c9ed5 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Wed, 23 Aug 2023 19:12:39 -0300 Subject: [PATCH 16/35] 0.3.26-1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2240026..94efde65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.26-0", + "version": "0.3.26-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.26-0", + "version": "0.3.26-1", "license": "MIT", "dependencies": { "ajv": "^8.0.0", diff --git a/package.json b/package.json index ff1d0237..bbfdb3fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.26-0", + "version": "0.3.26-1", "description": "Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe.", "main": "dist/index.js", "types": "dist/index.d.ts", From 54a1b0de53573abd28855a4f4238f076c4b66021 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 24 Aug 2023 15:19:55 +0200 Subject: [PATCH 17/35] add test --- contracts/namespaces.sol | 9 +++++++++ src/transform-namespaces.test.ts.md | 27 ++++++++++++++++++++++++++ src/transform-namespaces.test.ts.snap | Bin 1105 -> 1219 bytes 3 files changed, 36 insertions(+) diff --git a/contracts/namespaces.sol b/contracts/namespaces.sol index a6e2220b..f3c1903f 100644 --- a/contracts/namespaces.sol +++ b/contracts/namespaces.sol @@ -51,3 +51,12 @@ contract C7 { uint y; // a separate comment } + +contract C8 { + address private x; + address private y = address(this); + + constructor() { + x = msg.sender; + } +} diff --git a/src/transform-namespaces.test.ts.md b/src/transform-namespaces.test.ts.md index a57768a5..50e0257d 100644 --- a/src/transform-namespaces.test.ts.md +++ b/src/transform-namespaces.test.ts.md @@ -164,4 +164,31 @@ Generated by [AVA](https://avajs.dev). }␊ // a separate comment␊ }␊ + ␊ + contract C8 {␊ + /// @custom:storage-location erc7201:openzeppelin.storage.C8␊ + struct C8Storage {␊ + address x;␊ + address y;␊ + }␊ + ␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C8")) - 1))␊ + bytes32 private constant C8StorageLocation = 0xb93ad5010b0e46eab6ce47e44cb42c85a263d4e8daf058e8a66e4f114144f212;␊ + ␊ + function _getC8Storage() private pure returns (C8Storage storage $) {␊ + assembly {␊ + $.slot := C8StorageLocation␊ + }␊ + }␊ + ␊ + constructor() {function __C8_init() internal onlyInitializing {␊ + __C8_init_unchained();␊ + }␊ + ␊ + function __C8_init_unchained() internal onlyInitializing {␊ + $.y = address(this);␊ + C8Storage storage $ = _getC8Storage();␊ + $.x = msg.sender;␊ + }␊ + }␊ ` diff --git a/src/transform-namespaces.test.ts.snap b/src/transform-namespaces.test.ts.snap index e2ed2898158123c3be44eb16145f0d0875d22a1d..ce6ed101a821bb96b6f5eaff4e764d9d3d0340d4 100644 GIT binary patch literal 1219 zcmV;!1U&meRzVmd%NRu$LKtiKPC{nTs zs>d~0xb2q9O=u8{`IO0*rrfxpA7(Hyn$)6kJzRC}z31Gz=5u1Q!e07M|3H;i8H}}a zDA!}~6Kx^&xt{ooqVk_UJEtrC=bN9u+xlUvZr^;r_2aicz1iDCr@y`bV|bEU$UO{? z9pqJ-q)_go-#?xlAAR_E`r-Zdq}1nQjeL=%F0E$hFFaBsiVwE8ZIM@{wiP-e=yn^0 zmP~V7rA3a;&W^}gny1z70Ht{aWv(++vjHNnDZ_@m{dFgKZiFeP!$c0XGaGiF! zTSi1%5YeuP>h`dH8O6a9+Rz>hHAm99biw@D*IaCibi$m-7cH~Kz-`QE< zsDI%qgbn>#ubcOMRZfEkenGcr8Ze-ng9YGuH@L`GIy@YOo!I?GfeEI0*hBB^G=LfJ z7dOM{ukK;~5V_Xci8k4Y1|S8*_(& z!FujPD6OQJ>=zTrZ(uTkEX_yFs?iZ$w(QYqkB$sm>xa%9!}Y;x|E59FY*fd=la+Xe zJubmoeMv>Mt4%tB+!hXY>(}d{$H|>1Q0@!{Xo$#QFyGJ2D)5Y=Nts>+k1ctAVZh14 z`a^`T6D%|qfPpz8V#PqmlvwRBBU*!Im}7`t#0X|F=0b8M1#>jE!cnf0_+Xutt1Nne zF`1TtN~oq~?$K@w0|!ff)!xI{WV5BAhKN~Fq5Z>6TOQWkwQ41)kxWgN+CDP4dF1Z; z0q5%ntR)84k{DQzRK@;Fs_H2Rwju|%DTiyLvl1|~k zTOu)wj7lhhICerAhq)n6Q$sOLNF*&2B5{eLhU=KO5}Z9taMqLH>$YqVe1%@T*{DZ! z`AT&8SBoz18eQHNUBMzPB9IYwigSZw1&OsGh=eGt02`u=b}?XSDJW{CVuWfVNz8}} zF>Z}6e>S?jXLQ$X*@$laJ2$-!M^OeOx6AV9FRUqe_nKmJX}6kU(tgO4v5BzQ z0yBv*jtU_RA=>fKCj=l#FvBX;B$9_l3{H%+SVsXFZI!QhR=%4NdzpOKZTWI?j#_9O z^|2(*bTa0#4S!>Lt5 z(}+0^%IWa=raX)wa7Kbfve)Xc7=U)Z5I=EF6005(zU}XRR literal 1105 zcmV-X1g`r*RzV6eyrY{w6!QR=~z3tN1MJolb+Na|B!vci7wAOD6btuh#E z=TNT4;3wKb>T^Bu?~BTR{N$Xj^dGN&{O0Jpqq=ckfB)+A6kYxL=J(!ZY9aT~ zyKsX=z8;e6G*7FOE=uzX%3Not$g|l+XiIgL&eMFfeCfXP#Jks_<-JaGaII#! z-$XarfciDK{+;QgVk78%m3stEZ738Qr02z<}n172riRq{vq~JPgB3>|vsy1hafNML*eT05d)- z=Dq1;RB8vlH_g3Hpr^B}_$w@+E9l+mGSw!7UOFC6tNQ72jdc^6g+=HR*yiNRaC=KbZU{*Z1)_L#KCM24yLy0XA9 z9O2sp3ylR}V2+4bG0-t3Ry)jy)}R^Y7-APOf?15YkX%W@9F47Tl&d5j?5c8GMQa$7 zX$h!=YFg$Voir%0yOCGzJ&a8@+h|$}F)J!`cD^6Wdfa`ZSCSgZ)MTkW#0K+6?d~ox z+Ff90V_*#%13O@=V*h2UI?xVm%MNVc4&f*$!TXg7K9|5*TYAE=7u;;4aGDek+e*R#3hOvu4CRPaQ3Xg*?|Jzjb%^ZTk_(|i4I_w zZ?Vh27`wbJyS#~A!6GdpkP&u@bAw|AiM4@5LKIej4N*qB7_hVy6tz+@LbZ`3W<&*! z8`lzM*$gaw6A#9zWa>5%)Yy^{QKq{HOM$R z;OvhM{!Eb#h~xo?jWRn-diNqvP zBDPvs!8vwJ32dcJVoSJoCU%4hX`~C55h9{aM8rC-lq8PH=9{>D)(i4LFYLzBc$6(T X@G#NkLn0o?xbOS}gHmf}P7nY9#abg2 From 9326e847faa438211eca5b4c8fa2f96247298985 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 24 Aug 2023 18:23:56 -0300 Subject: [PATCH 18/35] Update hardhat.config.js Co-authored-by: Hadrien Croubois --- hardhat.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardhat.config.js b/hardhat.config.js index 7a7f6d60..3d7d617d 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -9,6 +9,6 @@ internalTask(TASK_COMPILE_SOLIDITY_GET_COMPILER_INPUT, async (args, hre, runSupe module.exports = { solidity: { - compilers: [{ version: '0.6.7' }, { version: '0.8.8' }, { version: '0.8.20' }], + compilers: ['0.6.7', '0.8.8', '0.8.20'].map(version => ({ version })), }, }; From 40051e3fea341b2a78df540ec5cfca4a71b3336d Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 24 Aug 2023 18:42:27 -0300 Subject: [PATCH 19/35] Update src/transformations/utils/new-function-position.ts --- src/transformations/utils/new-function-position.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/transformations/utils/new-function-position.ts b/src/transformations/utils/new-function-position.ts index 21751989..698a8962 100644 --- a/src/transformations/utils/new-function-position.ts +++ b/src/transformations/utils/new-function-position.ts @@ -17,8 +17,7 @@ export function newFunctionPosition( searchStart = pb.start + pb.length - offset; } - const re = /\{\n?/; - const brace = matchBufferFrom(readOriginal(contract, 'buffer'), re, searchStart); + const brace = matchBufferFrom(readOriginal(contract, 'buffer'), /\{\n?/, searchStart); if (!brace) { throw new Error(`Can't find start of contract ${contract.name}`); From 9865f0578c0f9b1cd5a9a3f2571ddd5fc1a6dd17 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 12:01:54 -0300 Subject: [PATCH 20/35] disable compilation warnings --- hardhat.config.js | 3 + package-lock.json | 348 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 352 insertions(+) diff --git a/hardhat.config.js b/hardhat.config.js index 3d7d617d..ad641376 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -1,6 +1,8 @@ const { internalTask } = require('hardhat/config'); const { TASK_COMPILE_SOLIDITY_GET_COMPILER_INPUT } = require('hardhat/builtin-tasks/task-names'); +require('hardhat-ignore-warnings'); + internalTask(TASK_COMPILE_SOLIDITY_GET_COMPILER_INPUT, async (args, hre, runSuper) => { const input = await runSuper(); input.settings.outputSelection['*']['*'].push('storageLayout'); @@ -11,4 +13,5 @@ module.exports = { solidity: { compilers: ['0.6.7', '0.8.8', '0.8.20'].map(version => ({ version })), }, + warnings: 'off', }; diff --git a/package-lock.json b/package-lock.json index 94efde65..8d562766 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "eslint-config-prettier": "^8.0.0", "eslint-plugin-prettier": "^4.0.0", "hardhat": "^2.0.9", + "hardhat-ignore-warnings": "^0.2.9", "prettier": "^2.1.2", "rimraf": "^3.0.2", "ts-node": "^10.4.0", @@ -4055,6 +4056,29 @@ } } }, + "node_modules/hardhat-ignore-warnings": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.9.tgz", + "integrity": "sha512-q1oj6/ixiAx+lgIyGLBajVCSC7qUtAoK7LS9Nr8UVHYo8Iuh5naBiVGo4RDJ6wxbDGYBkeSukUGZrMqzC2DWwA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/hardhat/node_modules/@noble/hashes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", @@ -5543,6 +5567,18 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-interval-tree": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "dependencies": { + "shallowequal": "^1.1.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/nofilter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", @@ -6485,6 +6521,12 @@ "sha.js": "bin.js" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6624,6 +6666,187 @@ "array.prototype.findlast": "^1.2.2" } }, + "node_modules/solidity-comments": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "node_modules/solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -10643,6 +10866,28 @@ } } }, + "hardhat-ignore-warnings": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.9.tgz", + "integrity": "sha512-q1oj6/ixiAx+lgIyGLBajVCSC7qUtAoK7LS9Nr8UVHYo8Iuh5naBiVGo4RDJ6wxbDGYBkeSukUGZrMqzC2DWwA==", + "dev": true, + "requires": { + "minimatch": "^5.1.0", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -11537,6 +11782,15 @@ "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", "dev": true }, + "node-interval-tree": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "requires": { + "shallowequal": "^1.1.0" + } + }, "nofilter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", @@ -12160,6 +12414,12 @@ "safe-buffer": "^5.0.1" } }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12271,6 +12531,94 @@ "array.prototype.findlast": "^1.2.2" } }, + "solidity-comments": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "requires": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "dev": true, + "optional": true + }, + "solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "dev": true, + "optional": true + }, + "solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "dev": true, + "optional": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index bbfdb3fe..925aa595 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "eslint-config-prettier": "^8.0.0", "eslint-plugin-prettier": "^4.0.0", "hardhat": "^2.0.9", + "hardhat-ignore-warnings": "^0.2.9", "prettier": "^2.1.2", "rimraf": "^3.0.2", "ts-node": "^10.4.0", From e70cbede12f3d07457a6a1cf0c6be72fee374fad Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 19:30:27 -0300 Subject: [PATCH 21/35] add missing transformation to namespaces test --- src/transform-namespaces.test.ts | 3 ++- src/transform-namespaces.test.ts.md | 4 ++-- src/transform-namespaces.test.ts.snap | Bin 1219 -> 1210 bytes 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/transform-namespaces.test.ts b/src/transform-namespaces.test.ts index 1295c4c5..727afba0 100644 --- a/src/transform-namespaces.test.ts +++ b/src/transform-namespaces.test.ts @@ -7,7 +7,7 @@ import { Transform } from './transform'; import { removeStateVarInits } from './transformations/purge-var-inits'; import { addNamespaceStruct } from './transformations/add-namespace-struct'; -import { transformConstructor } from './transformations/transform-constructor'; +import { removeLeftoverConstructorHead, transformConstructor } from './transformations/transform-constructor'; const test = _test as TestFn; @@ -31,6 +31,7 @@ test.beforeEach('transform', async t => { test('add namespace', t => { const file = 'contracts/namespaces.sol'; t.context.transform.apply(transformConstructor(() => true)); + t.context.transform.apply(removeLeftoverConstructorHead); t.context.transform.apply(removeStateVarInits); t.context.transform.apply(addNamespaceStruct(() => true)); t.snapshot(t.context.transform.results()[file]); diff --git a/src/transform-namespaces.test.ts.md b/src/transform-namespaces.test.ts.md index 50e0257d..3bca7244 100644 --- a/src/transform-namespaces.test.ts.md +++ b/src/transform-namespaces.test.ts.md @@ -99,7 +99,7 @@ Generated by [AVA](https://avajs.dev). $.slot := C4StorageLocation␊ }␊ }␊ - constructor() {function __C4_init() internal onlyInitializing {␊ + function __C4_init() internal onlyInitializing {␊ __C4_init_unchained();␊ }␊ ␊ @@ -181,7 +181,7 @@ Generated by [AVA](https://avajs.dev). }␊ }␊ ␊ - constructor() {function __C8_init() internal onlyInitializing {␊ + function __C8_init() internal onlyInitializing {␊ __C8_init_unchained();␊ }␊ ␊ diff --git a/src/transform-namespaces.test.ts.snap b/src/transform-namespaces.test.ts.snap index ce6ed101a821bb96b6f5eaff4e764d9d3d0340d4..914d8b8a817a55db669f99c9b3089458789339e6 100644 GIT binary patch literal 1210 zcmV;r1V#HnRzVe*$-8jIfzz#7y zjRv=hbRUZd00000000BUSj%qXHWW=;3<_k|_6LX{i+Ev&Pmzi-KwHl&0tABsL4kJD zfR8Ijh%6bBoW>qxF`qL1$gWE}vg3zR%T+MtA`u@V&%O7Y%PW75Op@8V;?rMH#$^H{ z?Ho$=2#T?`5ErQ)7q?kieERI1F7@v}y!qzn+oO5=>dn!2U;q96`8m4&<=t=HtJp$X zK=;x?TEB{fF!K?~cd09*#6BvLtqKIYocqp6XHDKR&iuTISl8Xh6`% zW8_;jNo^TtDZ05CkefJ-%d-xO(-QJjCn!sk>7^fwbrR3wbXdLgc>Kb{}SNcrHu|5(Caeu{smN2|4-3dbTfoNFs3^6682Fvo(?*^Nrg}I>KiY{0 zGrGuT-N|^EYX?Plk`_9Gu1=EdPk(?ep?k0MSepd8@n|$D=TFaPtcK9kA3`f&>zh~R zc0Ggj!iSJsNin&|#*ofnJccArd)2DmfUaBi?6hY``mOb!zuvXtu5u9lg_aL>IgR}YT^P%U-lNV5)bULVuNT;*d&rC}w7)9eezV{wm^Ze3) ztEKgC5q^lU&{zNl=77HAQG46sw28yqT#to1=8L}3Nk5M{Ir0ZU6kQ7aWAR2xY` zMwE|nZFKqG=<=4)-L_>Xy4!l^2Nn^$c@eR@v{@0c>w{(X%b$UwR#nM^|~9e!}Pjs%fDyipoYdli_1P}{aqq! z5XlyZ9Pt#4 z4Nj`|HH+GygxZ?}*N0x23aTj;R2>ye$g~rfV1t1NpiN+bOW@oZPOTD}2F!6#PW$gQ z1xg12aGxwW;oKLp^=VP75*e1-YMp$@#wRrA|?cWI+TPJ8oT3o2HemA7%R Yc6Zl!XnEDEgNmGg08bts1~(G`08qJ8P5=M^ literal 1219 zcmV;!1U&meRzVmd%NRu$LKtiKPC{nTs zs>d~0xb2q9O=u8{`IO0*rrfxpA7(Hyn$)6kJzRC}z31Gz=5u1Q!e07M|3H;i8H}}a zDA!}~6Kx^&xt{ooqVk_UJEtrC=bN9u+xlUvZr^;r_2aicz1iDCr@y`bV|bEU$UO{? z9pqJ-q)_go-#?xlAAR_E`r-Zdq}1nQjeL=%F0E$hFFaBsiVwE8ZIM@{wiP-e=yn^0 zmP~V7rA3a;&W^}gny1z70Ht{aWv(++vjHNnDZ_@m{dFgKZiFeP!$c0XGaGiF! zTSi1%5YeuP>h`dH8O6a9+Rz>hHAm99biw@D*IaCibi$m-7cH~Kz-`QE< zsDI%qgbn>#ubcOMRZfEkenGcr8Ze-ng9YGuH@L`GIy@YOo!I?GfeEI0*hBB^G=LfJ z7dOM{ukK;~5V_Xci8k4Y1|S8*_(& z!FujPD6OQJ>=zTrZ(uTkEX_yFs?iZ$w(QYqkB$sm>xa%9!}Y;x|E59FY*fd=la+Xe zJubmoeMv>Mt4%tB+!hXY>(}d{$H|>1Q0@!{Xo$#QFyGJ2D)5Y=Nts>+k1ctAVZh14 z`a^`T6D%|qfPpz8V#PqmlvwRBBU*!Im}7`t#0X|F=0b8M1#>jE!cnf0_+Xutt1Nne zF`1TtN~oq~?$K@w0|!ff)!xI{WV5BAhKN~Fq5Z>6TOQWkwQ41)kxWgN+CDP4dF1Z; z0q5%ntR)84k{DQzRK@;Fs_H2Rwju|%DTiyLvl1|~k zTOu)wj7lhhICerAhq)n6Q$sOLNF*&2B5{eLhU=KO5}Z9taMqLH>$YqVe1%@T*{DZ! z`AT&8SBoz18eQHNUBMzPB9IYwigSZw1&OsGh=eGt02`u=b}?XSDJW{CVuWfVNz8}} zF>Z}6e>S?jXLQ$X*@$laJ2$-!M^OeOx6AV9FRUqe_nKmJX}6kU(tgO4v5BzQ z0yBv*jtU_RA=>fKCj=l#FvBX;B$9_l3{H%+SVsXFZI!QhR=%4NdzpOKZTWI?j#_9O z^|2(*bTa0#4S!>Lt5 z(}+0^%IWa=raX)wa7Kbfve)Xc7=U)Z5I=EF6005(zU}XRR From fff0862e469b87e98d7db03d4516201849811ec2 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 19:51:12 -0300 Subject: [PATCH 22/35] simplify using flatMap --- src/transformations/transform-constructor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/transformations/transform-constructor.ts b/src/transformations/transform-constructor.ts index 2b2fda2c..b4b9bc90 100644 --- a/src/transformations/transform-constructor.ts +++ b/src/transformations/transform-constructor.ts @@ -125,21 +125,21 @@ export function transformConstructor(isNamespaced?: (source: string) => boolean) useNamespaces && varInitNodes.length > 0 && !constructorUsesStorage ? [`${namespace} storage $ = _get${namespace}();`] : [], - varInitNodes.map(v => { + varInitNodes.flatMap(v => { const prefix = useNamespaces ? '$.' : ''; const newExpr = parseNewExpression(v.value!); if (!newExpr) { - return `${prefix}${v.name} = ${helper.read(v.value!)};`; + return [`${prefix}${v.name} = ${helper.read(v.value!)};`]; } else { const { typeName, newCall, initializeCall } = newExpr; const createdContract = resolver.resolveContract(typeName.referencedDeclaration); if (createdContract) { getData(createdContract).isUsedInNewStatement = true; } - return `${prefix}${v.name} = ${newCall(helper)};\n ${initializeCall( - v.name, - helper, - )};`; + return [ + `${prefix}${v.name} = ${newCall(helper)};`, + `${initializeCall(v.name, helper)};`, + ]; } }), `}`, From f0b7185bef3bb509ee0aaaa0b468dc3d50fd4bf8 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 24 Aug 2023 22:40:17 -0300 Subject: [PATCH 23/35] Apply verkle changes Co-authored-by: Hadrien Croubois --- src/transformations/add-namespace-struct.ts | 2 +- src/utils/erc7201.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index 3bbf5fa1..3630ae3a 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -110,7 +110,7 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { ...rest.split('\n'), `}`, ``, - `// keccak256(abi.encode(uint256(keccak256("${id}")) - 1))`, + `// keccak256(abi.encode(uint256(keccak256("${id}")) - 1)) & ~bytes32(uint256(0xff))`, `bytes32 private constant ${namespace}Location = ${erc7201Location(id)};`, ``, `function _get${namespace}() private pure returns (${namespace} storage $) {`, diff --git a/src/utils/erc7201.ts b/src/utils/erc7201.ts index 249b856b..7571a7f8 100644 --- a/src/utils/erc7201.ts +++ b/src/utils/erc7201.ts @@ -5,5 +5,7 @@ export function erc7201Location(id: string): string { const a = keccak256(utf8ToBytes(id)); const b = BigInt('0x' + bytesToHex(a)) - 1n; const c = hexToBytes(b.toString(16).padStart(64, '0')); - return '0x' + bytesToHex(keccak256(c)); + const d = keccak256(c); + d[31] = 0; + return '0x' + bytesToHex(d); } From 3e6c7c6aaedcee98bfea598ddf5186cede756735 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 24 Aug 2023 22:41:36 -0300 Subject: [PATCH 24/35] Update src/transform.ts Co-authored-by: Hadrien Croubois --- src/transform.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transform.ts b/src/transform.ts index 3398626d..95c2ac43 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -243,5 +243,5 @@ function insertSortedAndValidate( } } function byteToLineNumber(buf: Buffer, byteIndex: number): number { - return 1 + [...buf.slice(0, byteIndex).toString('utf8').matchAll(/\n/g)].length; + return buf.slice(0, byteIndex).toString('utf8').split('\n').length; } From 4e6430f0a578b663e8f17b5640470587b2648e4f Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 22:46:00 -0300 Subject: [PATCH 25/35] update test snapshots --- src/transform-namespaces.test.ts.md | 24 ++++++++++++------------ src/transform-namespaces.test.ts.snap | Bin 1210 -> 1213 bytes 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/transform-namespaces.test.ts.md b/src/transform-namespaces.test.ts.md index 3bca7244..fdcd077c 100644 --- a/src/transform-namespaces.test.ts.md +++ b/src/transform-namespaces.test.ts.md @@ -46,8 +46,8 @@ Generated by [AVA](https://avajs.dev). string s1;␊ }␊ ␊ - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C2")) - 1))␊ - bytes32 private constant C2StorageLocation = 0xf05a05e0e3d15983ea921cad031aaea3040e9d631039045748753d29c5d248f9;␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C2")) - 1)) & ~bytes32(uint256(0xff))␊ + bytes32 private constant C2StorageLocation = 0xf05a05e0e3d15983ea921cad031aaea3040e9d631039045748753d29c5d24800;␊ ␊ function _getC2Storage() private pure returns (C2Storage storage $) {␊ assembly {␊ @@ -75,8 +75,8 @@ Generated by [AVA](https://avajs.dev). address x;␊ }␊ ␊ - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C3")) - 1))␊ - bytes32 private constant C3StorageLocation = 0xaa7e0685867d809c517036b8f21e99d58bd04b1da2b202f167c355fdf82b4a94;␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C3")) - 1)) & ~bytes32(uint256(0xff))␊ + bytes32 private constant C3StorageLocation = 0xaa7e0685867d809c517036b8f21e99d58bd04b1da2b202f167c355fdf82b4a00;␊ ␊ function _getC3Storage() private pure returns (C3Storage storage $) {␊ assembly {␊ @@ -91,8 +91,8 @@ Generated by [AVA](https://avajs.dev). address x;␊ }␊ ␊ - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C4")) - 1))␊ - bytes32 private constant C4StorageLocation = 0x536a56e760d844b098efcc16711808e0b18bad9e07c2e82c78312ab719318df8;␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C4")) - 1)) & ~bytes32(uint256(0xff))␊ + bytes32 private constant C4StorageLocation = 0x536a56e760d844b098efcc16711808e0b18bad9e07c2e82c78312ab719318d00;␊ ␊ function _getC4Storage() private pure returns (C4Storage storage $) {␊ assembly {␊ @@ -123,8 +123,8 @@ Generated by [AVA](https://avajs.dev). address x;␊ }␊ ␊ - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C5")) - 1))␊ - bytes32 private constant C5StorageLocation = 0xd94dd1cf5c0ce3bfbbd2555b11ad43bf11eeff03081ca744441b0fb7c0a6ecc2;␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C5")) - 1)) & ~bytes32(uint256(0xff))␊ + bytes32 private constant C5StorageLocation = 0xd94dd1cf5c0ce3bfbbd2555b11ad43bf11eeff03081ca744441b0fb7c0a6ec00;␊ ␊ function _getC5Storage() private pure returns (C5Storage storage $) {␊ assembly {␊ @@ -154,8 +154,8 @@ Generated by [AVA](https://avajs.dev). uint y;␊ }␊ ␊ - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C7")) - 1))␊ - bytes32 private constant C7StorageLocation = 0x931371859ca5c5440d3850c7cf9c14adb9d1257b7ddd15562d561cd48871d379;␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C7")) - 1)) & ~bytes32(uint256(0xff))␊ + bytes32 private constant C7StorageLocation = 0x931371859ca5c5440d3850c7cf9c14adb9d1257b7ddd15562d561cd48871d300;␊ ␊ function _getC7Storage() private pure returns (C7Storage storage $) {␊ assembly {␊ @@ -172,8 +172,8 @@ Generated by [AVA](https://avajs.dev). address y;␊ }␊ ␊ - // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C8")) - 1))␊ - bytes32 private constant C8StorageLocation = 0xb93ad5010b0e46eab6ce47e44cb42c85a263d4e8daf058e8a66e4f114144f212;␊ + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.C8")) - 1)) & ~bytes32(uint256(0xff))␊ + bytes32 private constant C8StorageLocation = 0xb93ad5010b0e46eab6ce47e44cb42c85a263d4e8daf058e8a66e4f114144f200;␊ ␊ function _getC8Storage() private pure returns (C8Storage storage $) {␊ assembly {␊ diff --git a/src/transform-namespaces.test.ts.snap b/src/transform-namespaces.test.ts.snap index 914d8b8a817a55db669f99c9b3089458789339e6..bdceb893280c8c131cc4746c8de527b6fbcdea89 100644 GIT binary patch literal 1213 zcmV;u1VZ~kRzVog3Vnn0Njr9A#|OE#tFWC5S#$hP-}mbuKSd_V>|OEsZz$t3fq`}o zrFsCxP+N$LR1b^WtSml1Ij2kg+nc9vj=npZwy(ZD`u^*`-khJK>!08M+P;b{qy@Au z9i(L(#gJd1Up`)4_C9>P{_y^InCt#PqasUU7nfu7JMO3s#ogm$o26y0ZHamWeL6>&{^O5(!kLVK`c^%NCJ6Cwt^)4z(?O%HSB=&reM}nzd&e1zN^2!V@ zvPpY1?C07+(H^CRj-aiRB>Te)&?U6*bslSzKsz1`M&h$QcWiL*9ail+5FFG?F9=fajNu@<~&@>JOS&64V z;|{FVcT@yt+Qc15ZRX%?x_vtIGI_E^%ac|MwGr{pAJCs>TtdO4rshUE= zJihn7T#Cuuw5z#a-Xgyb3ylR}V2+4TG0-6;Ry)jy)}R^Y7(y2?f?0^UkX%W@91X2- zlq-z8>v&zo*FufqCSCIp$hpn6?Ee_g;@%3w7qgEdHE?7t+jhD2d2L}8mm@gIpCiegTW*MdH44t-V! zeXS+nKnWE{r?5vfk(dQWMU+4oI-!ii+z_X!p_oP_kd_G%xkypN^%m%}ozQ0up}%g+ z2J}~e$E$-H#GS9ioqw^o^X75qb#WIg&>{dCV5c}YI8+c>>%&Wk!V0h<%4in?mX?B| zRw_oQHj;#lD7Pi^8vJv<79KjDPN%;OH$>!4iN|H?<%rh>p&A1PKdQkK` z1*8u0ZXLiyO=cAbS}yjtd~@l3mW!>Hivuig$Yim?WbwtAESfV})G^tG+&N++VX*~f zB4ZpCLKs4{ZDEPr$r9O+CF{1-e(z?{DPXAc zXGc7TX$7sSc?G0az@m2M&E=t228n785>*Eh6Ef`tCfH!$0caCg;1W2uhEuDArU7#t zl+*sks6go;0PYhkC!9xg3rN&Xkf??rS+`}!Je*$-8jIfzz#7y zjRv=hbRUZd00000000BUSj%qXHWW=;3<_k|_6LX{i+Ev&Pmzi-KwHl&0tABsL4kJD zfR8Ijh%6bBoW>qxF`qL1$gWE}vg3zR%T+MtA`u@V&%O7Y%PW75Op@8V;?rMH#$^H{ z?Ho$=2#T?`5ErQ)7q?kieERI1F7@v}y!qzn+oO5=>dn!2U;q96`8m4&<=t=HtJp$X zK=;x?TEB{fF!K?~cd09*#6BvLtqKIYocqp6XHDKR&iuTISl8Xh6`% zW8_;jNo^TtDZ05CkefJ-%d-xO(-QJjCn!sk>7^fwbrR3wbXdLgc>Kb{}SNcrHu|5(Caeu{smN2|4-3dbTfoNFs3^6682Fvo(?*^Nrg}I>KiY{0 zGrGuT-N|^EYX?Plk`_9Gu1=EdPk(?ep?k0MSepd8@n|$D=TFaPtcK9kA3`f&>zh~R zc0Ggj!iSJsNin&|#*ofnJccArd)2DmfUaBi?6hY``mOb!zuvXtu5u9lg_aL>IgR}YT^P%U-lNV5)bULVuNT;*d&rC}w7)9eezV{wm^Ze3) ztEKgC5q^lU&{zNl=77HAQG46sw28yqT#to1=8L}3Nk5M{Ir0ZU6kQ7aWAR2xY` zMwE|nZFKqG=<=4)-L_>Xy4!l^2Nn^$c@eR@v{@0c>w{(X%b$UwR#nM^|~9e!}Pjs%fDyipoYdli_1P}{aqq! z5XlyZ9Pt#4 z4Nj`|HH+GygxZ?}*N0x23aTj;R2>ye$g~rfV1t1NpiN+bOW@oZPOTD}2F!6#PW$gQ z1xg12aGxwW;oKLp^=VP75*e1-YMp$@#wRrA|?cWI+TPJ8oT3o2HemA7%R Yc6Zl!XnEDEgNmGg08bts1~(G`08qJ8P5=M^ From f6deaa0abef025d3706f2b5e6c4539dbe16b22b7 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 22:55:43 -0300 Subject: [PATCH 26/35] fix namespace var placement in constructor --- src/transform-namespaces.test.ts.md | 2 +- src/transform-namespaces.test.ts.snap | Bin 1213 -> 1213 bytes src/transformations/add-namespace-struct.ts | 3 ++- src/transformations/transform-constructor.ts | 6 +++++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/transform-namespaces.test.ts.md b/src/transform-namespaces.test.ts.md index fdcd077c..083b863c 100644 --- a/src/transform-namespaces.test.ts.md +++ b/src/transform-namespaces.test.ts.md @@ -186,8 +186,8 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ function __C8_init_unchained() internal onlyInitializing {␊ - $.y = address(this);␊ C8Storage storage $ = _getC8Storage();␊ + $.y = address(this);␊ $.x = msg.sender;␊ }␊ }␊ diff --git a/src/transform-namespaces.test.ts.snap b/src/transform-namespaces.test.ts.snap index bdceb893280c8c131cc4746c8de527b6fbcdea89..5e7da0770f5f048732122847f84d902d66acd92c 100644 GIT binary patch literal 1213 zcmV;u1VZ~kRzVbt&$(T6UBcnYIP$6ZENt ze2XTjE#gs%uCM##I!@!_q>bXVfGpJs8l}nf!jHu|iDz*-C^tQ{cI>_OBR4uu!5wtU z!@5PZ#v*#CMf0{=zivfum%-Jg2VK&qSH;N37f@dQeT&Y~^#F?1%<|HCd)v*4pFcic z+A;ryI}aQBX})gJ&x>s0Bk&{ogeKkwH0v!5UUYqk@GZ_yu?I7<=(p*Q-(MdA;!(X5a=-lZn)+T{YJRDAn`P1_qt06S?m(bF%^}|bd zJD$OM5kttVq?nwI#*ofnJccAryXC5GpRRlM9JJ>^`lI!#v#{a5x7nYSR+In6WeW{f8ppbUyhmgeZBhMVoRi0eFup-HA|LnTF%QGw3RtG=w(J=Cfw znp-k4No<=4WcJMJ?F$Cm7i^^rR+BPVgCxfOOA>1+6t*E0RuzhWNo0`cOL@E&^;vW3 zvpVW)Edd8gs6aY}J)?=lEHEmf1j5h>WgO;)I86=3G$MhtOo+%uiW;tWP@nCkK5Iz* zZC@(X-yj|@4{Crr-@u)JG2D4`+<6`Df(2RxAOq|a=LUxgB5OUogea^48={PMAz*1K zC~Bo*glZ#6$cS<~aOZn*=M8b+_N9XRc8=gLEJ^s`B}sMZVI@g52Fr}gYcuY>pC0Ce zZVst~tXD^HQIlE43q2QydtP07nCD`r=i&vPH&n9NP_p=9N*2wPEb5f(Lhc-~k+9eT zGm$Zl3Ly+3+Hv0}1R#nq!^)R5lKVysj*PTe2Vi$7S?pDE70Z_?dE1wN&)`7~!Gi{+ zL(us9N7h&*8(1X&hhj!fiHlIP_mat#9UHSBb1siGOV|Nt6h! z7FKYM9a92ZX`|2*uAK=Tp+XwzyqJUts1pIPjw>aJV>?tL_o_rTRLQn4wePzHIysDW z_7sRGm^Rp|npZ$-gDh%q-drDgWs<1oBvExFF(K1VV1f+>9)LE11ulVeYdEz^Xc{ob zK{@Te7!@cT1i*cQ<%IKy?jVWUOA^(PB-_61`405SM!m2$P>0tB)uo5k2Gt-eYXenV b8_fUlQPS(AxQX+FN~V7RA(2-D(-Qyy)^=Cz literal 1213 zcmV;u1VZ~kRzVog3Vnn0Njr9A#|OE#tFWC5S#$hP-}mbuKSd_V>|OEsZz$t3fq`}o zrFsCxP+N$LR1b^WtSml1Ij2kg+nc9vj=npZwy(ZD`u^*`-khJK>!08M+P;b{qy@Au z9i(L(#gJd1Up`)4_C9>P{_y^InCt#PqasUU7nfu7JMO3s#ogm$o26y0ZHamWeL6>&{^O5(!kLVK`c^%NCJ6Cwt^)4z(?O%HSB=&reM}nzd&e1zN^2!V@ zvPpY1?C07+(H^CRj-aiRB>Te)&?U6*bslSzKsz1`M&h$QcWiL*9ail+5FFG?F9=fajNu@<~&@>JOS&64V z;|{FVcT@yt+Qc15ZRX%?x_vtIGI_E^%ac|MwGr{pAJCs>TtdO4rshUE= zJihn7T#Cuuw5z#a-Xgyb3ylR}V2+4TG0-6;Ry)jy)}R^Y7(y2?f?0^UkX%W@91X2- zlq-z8>v&zo*FufqCSCIp$hpn6?Ee_g;@%3w7qgEdHE?7t+jhD2d2L}8mm@gIpCiegTW*MdH44t-V! zeXS+nKnWE{r?5vfk(dQWMU+4oI-!ii+z_X!p_oP_kd_G%xkypN^%m%}ozQ0up}%g+ z2J}~e$E$-H#GS9ioqw^o^X75qb#WIg&>{dCV5c}YI8+c>>%&Wk!V0h<%4in?mX?B| zRw_oQHj;#lD7Pi^8vJv<79KjDPN%;OH$>!4iN|H?<%rh>p&A1PKdQkK` z1*8u0ZXLiyO=cAbS}yjtd~@l3mW!>Hivuig$Yim?WbwtAESfV})G^tG+&N++VX*~f zB4ZpCLKs4{ZDEPr$r9O+CF{1-e(z?{DPXAc zXGc7TX$7sSc?G0az@m2M&E=t228n785>*Eh6Ef`tCfH!$0caCg;1W2uhEuDArU7#t zl+*sks6go;0PYhkC!9xg3rN&Xkf??rS+`}!J boolean) { } } - if (foundReferences) { + if (fnDef.kind !== 'constructor' && foundReferences) { + // The constructor is handled in transformConstructor const { start: fnBodyStart } = getNodeBounds(fnDef.body); yield { kind: 'add-namespace-base-ref', diff --git a/src/transformations/transform-constructor.ts b/src/transformations/transform-constructor.ts index b4b9bc90..ce95dbc3 100644 --- a/src/transformations/transform-constructor.ts +++ b/src/transformations/transform-constructor.ts @@ -122,9 +122,13 @@ export function transformConstructor(isNamespaced?: (source: string) => boolean) ...modifiers.map(m => helper.read(m)), `{`, ].join(' '), - useNamespaces && varInitNodes.length > 0 && !constructorUsesStorage + + // To correctly place the namespace variable before variable initilaization + // nodes, for the constructor it must be emitted here rather than in addNamespaceStruct + useNamespaces && (varInitNodes.length > 0 || constructorUsesStorage) ? [`${namespace} storage $ = _get${namespace}();`] : [], + varInitNodes.flatMap(v => { const prefix = useNamespaces ? '$.' : ''; const newExpr = parseNewExpression(v.value!); From 898d35d45d436875ed728c578ba2e8eb965336dc Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 22:57:01 -0300 Subject: [PATCH 27/35] lint --- src/transform-namespaces.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/transform-namespaces.test.ts b/src/transform-namespaces.test.ts index 727afba0..3f4627b7 100644 --- a/src/transform-namespaces.test.ts +++ b/src/transform-namespaces.test.ts @@ -7,7 +7,10 @@ import { Transform } from './transform'; import { removeStateVarInits } from './transformations/purge-var-inits'; import { addNamespaceStruct } from './transformations/add-namespace-struct'; -import { removeLeftoverConstructorHead, transformConstructor } from './transformations/transform-constructor'; +import { + removeLeftoverConstructorHead, + transformConstructor, +} from './transformations/transform-constructor'; const test = _test as TestFn; From 531c0629d73de797377b2279750e4bca367a37d7 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 23:06:57 -0300 Subject: [PATCH 28/35] avoid moving if no variables --- src/transformations/add-namespace-struct.ts | 54 ++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index 0c1987df..30d216f7 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -50,37 +50,37 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { } } - for (const [s, v] of nonStorageVars) { - const bounds = { start: s, length: getRealEndIndex(v) + 1 - s }; - let removed = ''; + if (storageVars.length > 0) { + for (const [s, v] of nonStorageVars) { + const bounds = { start: s, length: getRealEndIndex(v) + 1 - s }; + let removed = ''; - yield { - kind: 'relocate-nonstorage-var-remove', - ...bounds, - transform: source => { - removed = source; - return ''; - }, - }; + yield { + kind: 'relocate-nonstorage-var-remove', + ...bounds, + transform: source => { + removed = source; + return ''; + }, + }; - yield { - kind: 'relocate-nonstorage-var-reinsert', - start, - length: 0, - text: removed, - }; - } + yield { + kind: 'relocate-nonstorage-var-reinsert', + start, + length: 0, + text: removed, + }; + } - if (nonStorageVars.length > 0) { - yield { - kind: 'relocate-nonstorage-var-newline', - start, - length: 0, - text: '\n', - }; - } + if (nonStorageVars.length > 0) { + yield { + kind: 'relocate-nonstorage-var-newline', + start, + length: 0, + text: '\n', + }; + } - if (storageVars.length > 0) { for (const v of storageVars) { const { start, length } = getNodeBounds(v); yield { From eeaee5c92e0f337ca00dd7dbe96552f498091300 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 23:18:47 -0300 Subject: [PATCH 29/35] add comments --- src/transformations/add-namespace-struct.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index 30d216f7..bdc0b41a 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -28,6 +28,8 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { const nonStorageVars: [number, VariableDeclaration][] = []; const storageVars: VariableDeclaration[] = []; + // We look for the start of the source code block in the contract + // where variables are written for (const n of contract.nodes) { if ( n.nodeType === 'VariableDeclaration' && @@ -44,13 +46,19 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { storageVars.push(n); } } else if (storageVars.length > 0) { + // We've seen storage variables before and the current node is not a + // variable, so we consider the block to have finished finished = true; } else { + // We haven't found storage variables yet. We assume the block of + // variables will start after the current node start = getRealEndIndex(n) + 1; } } if (storageVars.length > 0) { + // We first move non-storage variables from their location to the beginning of + // the block, so they are excluded from the namespace struct for (const [s, v] of nonStorageVars) { const bounds = { start: s, length: getRealEndIndex(v) + 1 - s }; let removed = ''; @@ -101,9 +109,11 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { start, length: end - start, transform: source => { - const [, leading, rest] = source.match(/^((?:[ \t\v\f]*[\n\r]+)*)(.*)$/s)!; + // We extract the newlines at the beginning of the block so we can leave + // them outside of the struct definition + const [, leadingNewlines, rest] = source.match(/^((?:[ \t\v\f]*[\n\r])*)(.*)$/s)!; return ( - leading + + leadingNewlines + formatLines(1, [ `/// @custom:storage-location erc7201:${id}`, `struct ${namespace} {`, From 6f806608e9342165af96f35270a5a7f140a2c597 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 24 Aug 2023 23:37:43 -0300 Subject: [PATCH 30/35] simplify getRealEndIndex --- src/transform.ts | 43 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/src/transform.ts b/src/transform.ts index 95c2ac43..3d43fc2d 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -11,6 +11,7 @@ import { applyTransformation } from './transformations/apply'; import { compareTransformations, compareContainment } from './transformations/compare'; import { Bounds, Transformation, WithSrc } from './transformations/type'; import { ASTResolver } from './ast-resolver'; +import { matchBufferAt } from './utils/match'; type Transformer = (sourceUnit: SourceUnit, tools: TransformerTools) => Generator; @@ -176,43 +177,21 @@ export class Transform { const { source, start, length } = this.decodeSrc(node.src); const buf = this.state[source].originalBuf; - let end: number | undefined; + let end = start + length - 1; - if (node.nodeType !== 'VariableDeclaration') { - end = start + length; - } else { + if (node.nodeType === 'VariableDeclaration') { // VariableDeclaration node bounds don't include the semicolon so we manually look for it - for (let i = start + length; i < buf.length; i++) { - const c = buf.toString('utf8', i, i + 1); - if (c === ';') { - end = i; - break; - } else if (/\S/.test(c)) { - throw this.error(node, 'Found unexpected content before semicolon'); - } - } - if (end === undefined) { - throw this.error(node, 'could not find end of node'); + const semicolonMatch = matchBufferAt(buf, /\s*;/, end + 1); + if (semicolonMatch === undefined) { + throw this.error(node, 'Could not find end of node'); } + end += semicolonMatch.length; } - let foundComment = false; - - for (let i = end + 1; i < buf.length; i++) { - // look ahead 2 bytes to search for '//' - const next = buf.toString('utf8', i, i + 2); - if (foundComment) { - if (/[^\n\r]/.test(next[0])) { - end = i; - } else { - break; - } - } else if (next === '//') { - end = i + 1; - foundComment = true; - } else if (/[^ \t]/.test(next[0])) { - break; - } + const commentMatch = matchBufferAt(buf, /[ \t]*\/\/.*/, end + 1); + + if (commentMatch) { + end += commentMatch.length; } return end; From 73582e898048a9b37e2bbce0f2569fc0a280feac Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 25 Aug 2023 00:11:09 -0300 Subject: [PATCH 31/35] simplify transformer abstraction --- src/transform.ts | 30 +++++---------------- src/transformations/add-namespace-struct.ts | 19 +++++++++---- src/utils/match.ts | 4 +-- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/transform.ts b/src/transform.ts index 3d43fc2d..18f91d68 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -11,7 +11,7 @@ import { applyTransformation } from './transformations/apply'; import { compareTransformations, compareContainment } from './transformations/compare'; import { Bounds, Transformation, WithSrc } from './transformations/type'; import { ASTResolver } from './ast-resolver'; -import { matchBufferAt } from './utils/match'; +import { ByteMatch, matchBufferAt } from './utils/match'; type Transformer = (sourceUnit: SourceUnit, tools: TransformerTools) => Generator; @@ -24,11 +24,11 @@ export interface TransformerTools { originalSource: string; originalSourceBuf: Buffer; readOriginal: ReadOriginal; + matchOriginalAfter: (node: Node, re: RegExp) => ByteMatch | undefined; resolver: ASTResolver; getData: (node: Node) => Partial; getLayout: LayoutGetter; error: (node: Node, msg: string) => Error; - getRealEndIndex: (node: Node) => number; } // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -94,7 +94,7 @@ export class Transform { const readOriginal = this.readOriginal.bind(this); const getData = this.getData.bind(this); const error = this.error.bind(this); - const getRealEndIndex = this.getRealEndIndex.bind(this); + const matchOriginalAfter = this.matchOriginalAfter.bind(this); const tools: TransformerTools = { originalSource, originalSourceBuf, @@ -103,7 +103,7 @@ export class Transform { getData, getLayout, error, - getRealEndIndex, + matchOriginalAfter, }; for (const t of transform(ast, tools)) { @@ -173,28 +173,10 @@ export class Transform { return error; } - getRealEndIndex(node: Node): number { + matchOriginalAfter(node: Node, re: RegExp): ByteMatch | undefined { const { source, start, length } = this.decodeSrc(node.src); const buf = this.state[source].originalBuf; - - let end = start + length - 1; - - if (node.nodeType === 'VariableDeclaration') { - // VariableDeclaration node bounds don't include the semicolon so we manually look for it - const semicolonMatch = matchBufferAt(buf, /\s*;/, end + 1); - if (semicolonMatch === undefined) { - throw this.error(node, 'Could not find end of node'); - } - end += semicolonMatch.length; - } - - const commentMatch = matchBufferAt(buf, /[ \t]*\/\/.*/, end + 1); - - if (commentMatch) { - end += commentMatch.length; - } - - return end; + return matchBufferAt(buf, re, start + length); } results(): { [file in string]: string } { diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index bdc0b41a..ab30ebf0 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -7,6 +7,7 @@ import { newFunctionPosition } from './utils/new-function-position'; import { formatLines } from './utils/format-lines'; import { isStorageVariable } from './utils/is-storage-variable'; import { erc7201Location } from '../utils/erc7201'; +import { Node } from 'solidity-ast/node'; export function getNamespaceStructName(contractName: string): string { return contractName + 'Storage'; @@ -18,7 +19,7 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { return; } - const { error, resolver, getRealEndIndex } = tools; + const { error, resolver } = tools; for (const contract of findAll('ContractDefinition', sourceUnit)) { let start = newFunctionPosition(contract, tools); @@ -40,7 +41,7 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { } if (!isStorageVariable(n, resolver)) { - const varStart = getRealEndIndex(storageVars.at(-1)!) + 1; + const varStart = getRealEndIndex(storageVars.at(-1)!, tools) + 1; nonStorageVars.push([varStart, n]); } else { storageVars.push(n); @@ -52,7 +53,7 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { } else { // We haven't found storage variables yet. We assume the block of // variables will start after the current node - start = getRealEndIndex(n) + 1; + start = getRealEndIndex(n, tools) + 1; } } @@ -60,7 +61,7 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { // We first move non-storage variables from their location to the beginning of // the block, so they are excluded from the namespace struct for (const [s, v] of nonStorageVars) { - const bounds = { start: s, length: getRealEndIndex(v) + 1 - s }; + const bounds = { start: s, length: getRealEndIndex(v, tools) + 1 - s }; let removed = ''; yield { @@ -102,7 +103,7 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { const namespace = getNamespaceStructName(contract.name); const id = 'openzeppelin.storage.' + contract.name; - const end = getRealEndIndex(storageVars.at(-1)!) + 1; + const end = getRealEndIndex(storageVars.at(-1)!, tools) + 1; yield { kind: 'add-namespace-struct', @@ -175,3 +176,11 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { } }; } + +function getRealEndIndex(node: Node, tools: TransformerTools): number { + // VariableDeclaration node bounds don't include the semicolon, so we look for it, + // and include a comment if there is one after the node. + // This regex always matches at least the empty string. + const { start, length } = tools.matchOriginalAfter(node, /(\s*;)?([ \t]*\/\/[^\n\r]*)?/)!; + return start + length - 1; +} diff --git a/src/utils/match.ts b/src/utils/match.ts index 01a132c1..8a07a65b 100644 --- a/src/utils/match.ts +++ b/src/utils/match.ts @@ -1,4 +1,4 @@ -interface ByteMatch { +export interface ByteMatch { start: number; length: number; captureLengths: number[]; @@ -26,7 +26,7 @@ function matchWithFlags( if (m) { const start = index + Buffer.from(str.slice(0, m.index), 'utf8').length; const length = Buffer.from(str.slice(m.index, m.index + m[0].length), 'utf8').length; - const captureLengths = m.slice(1).map(c => Buffer.from(c, 'utf8').length); + const captureLengths = m.slice(1).map(c => c === undefined ? c : Buffer.from(c, 'utf8').length); return { start, length, captureLengths }; } } From 0c98349750e3de8256ac3ad3508f6023fecbe782 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 25 Aug 2023 00:17:08 -0300 Subject: [PATCH 32/35] add new helper contractStartPosition (same as newFunctionPosition) --- src/transformations/add-namespace-struct.ts | 4 +-- .../utils/contract-start-position.ts | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 src/transformations/utils/contract-start-position.ts diff --git a/src/transformations/add-namespace-struct.ts b/src/transformations/add-namespace-struct.ts index ab30ebf0..99ab6b42 100644 --- a/src/transformations/add-namespace-struct.ts +++ b/src/transformations/add-namespace-struct.ts @@ -3,10 +3,10 @@ import { findAll } from 'solidity-ast/utils'; import { getNodeBounds } from '../solc/ast-utils'; import { TransformerTools } from '../transform'; import { Transformation } from './type'; -import { newFunctionPosition } from './utils/new-function-position'; import { formatLines } from './utils/format-lines'; import { isStorageVariable } from './utils/is-storage-variable'; import { erc7201Location } from '../utils/erc7201'; +import { contractStartPosition } from './utils/contract-start-position'; import { Node } from 'solidity-ast/node'; export function getNamespaceStructName(contractName: string): string { @@ -22,7 +22,7 @@ export function addNamespaceStruct(include?: (source: string) => boolean) { const { error, resolver } = tools; for (const contract of findAll('ContractDefinition', sourceUnit)) { - let start = newFunctionPosition(contract, tools); + let start = contractStartPosition(contract, tools); let finished = false; diff --git a/src/transformations/utils/contract-start-position.ts b/src/transformations/utils/contract-start-position.ts new file mode 100644 index 00000000..adb6d990 --- /dev/null +++ b/src/transformations/utils/contract-start-position.ts @@ -0,0 +1,27 @@ +import { ContractDefinition } from 'solidity-ast'; + +import { TransformerTools } from '../../transform'; +import { getNodeBounds } from '../../solc/ast-utils'; +import { matchBufferFrom } from '../../utils/match'; + +export function contractStartPosition( + contract: ContractDefinition, + { readOriginal }: TransformerTools, +): number { + const offset = getNodeBounds(contract).start; + let searchStart = 0; + + if (contract.baseContracts.length > 0) { + const [lastParent] = contract.baseContracts.slice(-1); + const pb = getNodeBounds(lastParent); + searchStart = pb.start + pb.length - offset; + } + + const brace = matchBufferFrom(readOriginal(contract, 'buffer'), /\{\n?/, searchStart); + + if (!brace) { + throw new Error(`Can't find start of contract ${contract.name}`); + } + + return offset + brace.start + brace.length; +} From c167f524bf7fe366cc45d6d68215c4d9315aa8bd Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 25 Aug 2023 00:23:28 -0300 Subject: [PATCH 33/35] redefine newFunctionPosition --- src/index.test.ts.md | 4 +-- src/index.test.ts.snap | Bin 2211 -> 2212 bytes src/transform-namespaces.test.ts.md | 16 +++++------ src/transform-namespaces.test.ts.snap | Bin 1213 -> 1214 bytes src/transform.test.ts.md | 6 ++-- src/transform.test.ts.snap | Bin 2487 -> 2484 bytes .../utils/new-function-position.ts | 27 ++++++++---------- 7 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/index.test.ts.md b/src/index.test.ts.md index 588f0cd4..818f53b1 100644 --- a/src/index.test.ts.md +++ b/src/index.test.ts.md @@ -58,6 +58,8 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ contract CIDUpgradeable is Initializable, CICUpgradeable {␊ + uint256 public val;␊ + ␊ function __CID_init() internal onlyInitializing {␊ __CID_init_unchained();␊ }␊ @@ -65,8 +67,6 @@ Generated by [AVA](https://avajs.dev). function __CID_init_unchained() internal onlyInitializing {␊ val = 123;␊ }␊ - uint256 public val;␊ - ␊ function fooBar(uint a) override external{␊ ␊ }␊ diff --git a/src/index.test.ts.snap b/src/index.test.ts.snap index 4e4631c9498b79dc45d0078b560421cb7a42c710..195eeba3faae30c78be2d18d0b786d24686356c6 100644 GIT binary patch delta 2194 zcmV;D2yOSH5u_0^K~_N^Q*L2!b7*gLAa*kf0{{VoC_15=e>^m}58aAf%15va>tq%$b?*`}WMtZXON?vMSy+KKlYwLS;<5vS1i{$_VR( z3W|suhAI<75j10@QscoxNfM~=?&@T5;p~F>Q(3JnU4_qUaDRLV$1iYPtgKw9tlS#h z!6L0xysziapI@k)Tc|89RGx$~XD*rFmM>IRheXD22xIJ?xWoz~WVECSbmacg5>$BFbR*6EfJ`_ZZx_ez;o#=iQ!Ow7_h?J-b8mekX(CZT@ zkAyXZkHAb3G(8#w05o{Z8DIFXnJm2=kXMSb6Gv88&oIC z!CE^Q!u~$^-zVVF4r3tbYsiWp0zs-G&%D~e+NsR^nSUGZgRhZ56fD(EYr6tyK}r*TtLo){n z&TA72F(6Gg|E4MuWLZ6g=;=hqXo__M+F)20Bnc__(DghObYhNzfer~Bso=#Jks&n$ zm()WA8Glp-3}MqZ9hn~<6p_^l4cAd0V>F^vGhS{sB~>&Us)m(&Sktf!r9^eyoWpy& zanzj5A@Q73$^HQl)bZE!gW|pIm)=L3PNo9IFc45IjId4;!q&qOydNFfjt!w>KxeD9 zz19vC>4b|UKr31{QzTQkd>w7Jwp`B)Doss7mVb!iL{u*gQ4C#-?fAe@_jsY!Q;7?IZ29q%jrgTa&q=}R&qk%_`ZPTg9_TBiV-5(!z6&>az3O1`T{6=t0UplJSRy3UW5xp`q&aqrRf zY)x9rqD0<(zXTu$0G-?Yv`2)osz|A;64k$1H+}<--wL?#Kf?|qDFxVOqySMbT*<&w z)ng|Ey)26g_Ts_K@Zv$-T7!?0yVet1TCZF@$UD{R zbrLhm^$^nR@v!0K0%(Mx!=e!CWX?KMFyvhBM3c~1j4{e)io$9Nz^rC{sWGwE*(|}9 z8*GW0C>v}8Rh3<+d8>zk!OoniW&~O^ag7IBjwIJ=l%NC5s6N4LjI~OP<;7Sx1%F}z z46cU-&>kY_80c2ROZ^TN%m7~ZlyH|OfX?-9cGyOXW@>}g4}e>zd+HlUo2{)iCW5;q zfb%Sijd~bs?96x(u`*)}$4>=h#;b0{yt%Nd;3hp(n{=dO+%&y#<-)I>iOYrk$*}$V zij2pQ(F*$P_DsV@sGeFoYLT8t2Y=(uusC8`2enG$fa(N3Rk!IXkx|gbcvQCb)oo=CATbJ zIn+1J&Hr7D%cLwKaytq8{eOEFGqJ>0v*rGY?)UpE=iTpjZMhWc)1_l8lv^+7j=yI% ze=5*i>_1xf*8OLBCN4p@p@#s$tLHw^c}W`HZCkhBQx;B{V2Q;>>p0l3?-{Xp0B5t< zTSPE`5=EynA0{_dQIKO6l|E+a?huYg1?cW$Ud>6O`#eK*EkiEF{eLmTLQCV6_D}eYi~b(x(-HmXw9*T&p z**K@cmvVrm@IyI{B$7I(ZUr;^= zf$);T^7RKQU$M$DsknQS40J)Cu^C-iW-)pM$9DxV`f*>~NjzR-&HZgt9`;sVjGg?; zwl@^@3aIk>itY{!D~_%cPmBycd!p~mvx4A#XFlwMO9b1wMNn|6MV=Za1d?GHJ8Yf* zksGF`^6{G!lYgD@p8M|;Vua@$i$izd_@Mv}oeR{SM4lH|dp)i(m-t+ZUwQQYlLX7N zUx4nsg%xN9yUSL-Vs+U89N!kuWz~7rN&Qu4^p|bPB{6?4=am>&$?Zy+dLE!Y#fGUE z?rYi}nf((q+gCn`3fkruD2AU>o=$R4&F=6X)?{^t(^ryo({DUVbTRs9M$kRqJe^^i zWy+mmmZ@@GgjsfMOY0lH^#A}wLdlpYB`Z2VA$1IJ1DMrgefj4>cIkX|v!!4@w2YL~ UHYwK>IMx*Y1<>oWYl%t#05xee2LJ#7 delta 2193 zcmV;C2yXYJ5u*_@K~_N^Q*L2!b7*gLAa*kf0{~3T`X;22lYwJ*JmXTujo*%4KJaY4 z0*U$bi+MfgzekZWD}OG+MF=5?*1O|)+V$?TJ9gq$1y#KB#t$e69tuJTAs!JzNQj?+ z#P5Jt&R)Hj*~@G;K}Z{AWoLKJnKLur_wAXP-8>u)WL3OleD(#Vgvyw9Wx+7^lo8em z6%-LS3{@tEB51})rN)DYk|a>!z17L$!r2A$r?OgEx(c7y;D7iCj$h!oSXsGHS$T7C z8;i73@xGove}18IZlSWcPuA z3nDd|P*S|I(YV?S`*=q?&;R9E=5Iwq7E1hCT$Jjg5Ad zj5SrKsMcsS_kR>Zi6E1^uFqP#S|tj_`cM!t>h5)Yb)tJ!1V6)xB2uC%XsD_kL9b7s zJQCIrJ_0jEklWS!)vDVXaIx!mK@1eA)A4EgXzg4@+GHRT(e&K5&f_Tt=dyZGH>ggO zgSB=rg#CT+zfZuU9mYV=*N_!I1cFpWo_V!_wNsh-Gk-VS2VWzBC|IhS)^-KZf|z=I z#rbN4Hlgcg@wRsgkBQy5T7Pf17Oc8?`LbQ^GP)t*DY`X+uES#u#!<%x)~8rPhGq^D zoYy84VnCW~{!LXR$g+9}(bI{J(G=?jw85}0ND@-;q3d}n=)@ca1051NQo)NcB138h zE~$qKGJmKF7{aD+Ix;^zC?cy98m^;0#%M&TX1v^NN~&lyR1GV4v8G`eN{Q;YIfwUl zc9c0uiu|V2jqK#)?C-4PguwBA0m;b|{>qb*lFN*w#I@y0 zM*dmJn~Zp*d`r+F7ud{@O!&Cs7-c16lx%(nT!gzHArTn4BqKVVfGN9DND)$smK^gq zwtuscsO0wWweoVu%sLA|(Yw9rIzL+G=7nL!y+_xx zHEAu25_$Li5`Y{4bZ+<49udZ>BBicMRR3n(_zgIIE8xce3_FaZ6kwZ?0z|!VB?C`Y zkDUzkvMegtiw8HuiwALQ4L(ZtcKOoxUVmgh7@NH_igGL;Y_~$I2WIPPy>js&?^LhX zNz5qMLrAm7!-kU!pb>@+i$bWAIqOWpkaM{cO+sTa#weR93acpqvzqm##>84@vjkgi zuq9@qY_JVfRd%7~tsVvjJ9DO*5opoGH6Ca=l3c4%f(|gF`UJBv)+#ZU7h~NNh<^nz zxE>Zjdx)T8pj!?0B)V`sc#%@wzk%o2=0~u z&a*5w>S3(0Gvh_X%8W4_KNXM}ueufU=EACioAgj^(vgmF)AYiX3%_9q8KMJEl8 zp9`SVMMexs%-UoyD;e&|wEA-K*i+2->Z2@)(j;Wfcc)|-XSuJX*%fk=gT5hC9Le5d zrw*bzfm!%tl4ucnLxmT>~nVn7kB1=&df=%e}6wKK6SAY zX*>G1e;VhTznNQHR$%j$0w+?(#f)NOtL4V&D|O`iJ}Wm|BlrBRc)dERg>d^WG^7iy z1%Qd*I7Yv|X6e@_aQsz(eq{(LNzQJh%UQ@Hm%2SFT;1ZMi50ukC0dHqh2lS!+_HS- zP~S8+|93Gild_1&?Ii5??|)g$#1dQ0mis5V-|w%Scfa4Y(Uerm#U16VPUZp43>=0E|IMB07FEz11%|997QL6z@LoM-`RMTMOPh;Ukjk? z)66K6sJq3WZo~-}jfc74+VB|KKjAkn`g@#DNA#nQ%g2(ARW?&K<+~I`>>l>h-lgcL zyi3vNeU~C09Pah(FMm?7%9bxu{HJhA*^Lh2jrDj9>zN1eds--SuV>#~W|if5C?c|E zNpRF-jK``zgAc<1bbn;l38qgUlU;v&LHQg6 z!b=Lv*B_{S#VW_7;?7Mn&;@3WE2Y`LGWz5p3rcLBXjOd1{ytNQPzXuyy`N zZkV3R$8Szdc7Miu?!Qln5uS4_4&8?1hXOcsE>L?Cd0t@c^|;1d;&Uy2<V8o zuW5T^_D|4kU-={|Xq#W47=B85I>|jXyTf}}lhqkcOIFfNzws#1#pt6MLHB&~bcSt~ zDR+ulrpk2@X4$bVt#A0&0{{>SC1awLtmyoN)G@#fU{;Uy<(~)HrSsLzmV)`vGEz?4 Tq+C-sPYE zfg&yv7-;8Est1sdw1qfN^(em`7Wt7)3gS3dF7_xKp>xZk$-un;N@82~>neGoX%7;np;$njSz#Y}0xZ7yhVOnI` z7N|$i#|H9$EgGk`h=(bOq0o_?~8R3Pvf*-E_!V2SbO7p zZgrf3J7|~3Rf}lZ4fh@t`nlQaKA(~o+1QW&gg&CN-x5u`i}UBNeuKQw{-K915bMqd zyq`?@aE5-gvme0Cg22XcbdD?2BHX{D_ z2lSVJnG}#Sx?GMQqNvrHpHvQ^Q5N5OU#`St0qttxmkZ?AVWF`A49pP`Dh4{F#A=5b z(Hbi!QN6i;EmjKb* z){4hB5dRGoqQV$0mtwofD=nyxqjv-#lPLGFXL(u^J-A{)>p!lmfOU1#DXi z{6`{#JYNXFYmuAPCpW7ix7HGHpo9vfQ`mEsNX!DGB1#|(olwSMZiv&=P)s8dNXvwO zh+L$o;d%$T*UGSXrlfZf4lv6so) zu{@5+n^-=t;6X)#2Q^BEp!WSoR#+r!SS0_4Vn(h}L2gr_yvoe)H$D#s1Ao_KYpjn> zUY8}ZK1*a3OZ;bxNuoq(wXlM7?3fbRN*jfiaP3U!2o=&u=gA~QK%EGPbzCV)9NWPX zxtArfCQCN4RDSQ~(aB+?vu8&Rev+uFlUM{CM(@N5 zlnw&mUSK)lJfb_2MD0xyRWnI8vFyL;sv~Oyb$D&CJ@v5KVA~0c+CWv-2D86*%Jga$ Sw{d<@$@DK0A=v`c6951hUQ$c| delta 1203 zcmV;k1WfzB3B3t_K~_N^Q*L2!b7*gLAa*kf0|3w5e&BE^q5;~4Ko`r)_2pAvqe1{T zddUtRq;b88&8r`a2mk;800003#aP{H<363Qs$c}BvwNr)dTsWG4|8vgweMd)mj7&1JxB2J4 zp@@qFhT1ul>LKJ~Z6VH6J`-4;%VvzHZUai)`W}@FV(!Cf){rH0v!5UUYqk@GZ_yu?I7<=(p*Q-(MdA;!(X5a=-lZn)+T{YJRDAn`P1_qt06S? zm(bF%^}|bdJD$OM5kttVq?nwI#*ofnJccAryXC5GpRRlM9JJ>^`lI!#v#{a5x7nYS zR+I;S&2h-d2A=+mTd-E&QW2bJ6L%rCBL^q*?en4M$>SYX9=F@5gNXnA0sU#F1>}sb zw&VLKYPT0Rl~ZV(#dkiIYnUuuyIjWQ9Ql1%XeihoID zkmpNzycYFYbLz7?>T4|l2TG_wI)y!>iNq{0Dxw6!&fiHlIP_matFcUQ zHdl$PQ;C0VF-epNtrk{rjvZ41TWO=v60V&I9ic)R>AaYP2&fYQv5qSxiDNrdBKN99 zHdM*BFSYNx1v)v5b@mj9Czv+as+w0oYJ)6lZ{A!VdS#NR<|I*dlUxKGNxv8sC>;dA zeS+nL^N8*siP}pN)sQ6HzU=u9^vOoOur^SK*9O(4ht&qvAS`PGRa+a(|M5}M>!i4e R^MgvJe*htoR|C@%005P%RiFR> diff --git a/src/transform.test.ts.md b/src/transform.test.ts.md index fc540306..e178046f 100644 --- a/src/transform.test.ts.md +++ b/src/transform.test.ts.md @@ -726,12 +726,12 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ contract FooWithArgs2 {␊ - function initialize(uint x, uint y) public virtual initializer {␊ - __FooWithArgs2_init(x, y);␊ - }␊ modifier hasModifierArguments(uint x) {␊ _;␊ }␊ + function initialize(uint x, uint y) public virtual initializer {␊ + __FooWithArgs2_init(x, y);␊ + }␊ constructor(uint x, uint y) public hasModifierArguments(x) {}␊ }␊ ` diff --git a/src/transform.test.ts.snap b/src/transform.test.ts.snap index eb4491a29d34c5b507e6c11e1032fab6135c82bd..f87ba45b9a1b37b7310d64526ab475682c71e227 100644 GIT binary patch delta 133 zcmV;00DAwo6SNaDK~_N^Q*L2!b7*gLAa*kf0|2RCIPEf!oC`znHb~gaO$&||$$G(O ziCEJpfQ#ori(9cWISEObyIs@gBvDa#)O?WgV&K~QYB~S_TF*X^ delta 136 zcmV;30C)ei6SosGK~_N^Q*L2!b7*gLAa*kf0|3Qin3>5HbZeK(!`+l16$giBok_FU z5Zu;gbFSXOIG3?9ISEXu91J_E#deL!O&_mBMVV9c`AY}9TCrRC! 0) { - const [lastParent] = contract.baseContracts.slice(-1); - const pb = getNodeBounds(lastParent); - searchStart = pb.start + pb.length - offset; + if (firstFunctionIndex <= 0) { + return contractStartPosition(contract, tools); + } else { + const prevNode = contract.nodes[firstFunctionIndex - 1]; + // VariableDeclaration node bounds don't include the semicolon, so we look for it + // in case prevNode is that type of node + const m = tools.matchOriginalAfter(prevNode, /(\s*;)?([ \t\v\f]*[\n\r])*/)!; + return m.start + m.length; } - - const brace = matchBufferFrom(readOriginal(contract, 'buffer'), /\{\n?/, searchStart); - - if (!brace) { - throw new Error(`Can't find start of contract ${contract.name}`); - } - - return offset + brace.start + brace.length; } From 949c4669267e76948a6ec1e5e7795ed98ab6d1d4 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 25 Aug 2023 00:28:22 -0300 Subject: [PATCH 34/35] lint --- src/transformations/utils/new-function-position.ts | 7 +------ src/utils/match.ts | 4 +++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/transformations/utils/new-function-position.ts b/src/transformations/utils/new-function-position.ts index 2e01518a..7c486a29 100644 --- a/src/transformations/utils/new-function-position.ts +++ b/src/transformations/utils/new-function-position.ts @@ -1,15 +1,10 @@ import { ContractDefinition } from 'solidity-ast'; import { TransformerTools } from '../../transform'; -import { getNodeBounds } from '../../solc/ast-utils'; -import { matchBufferFrom } from '../../utils/match'; import { isNodeType } from 'solidity-ast/utils'; import { contractStartPosition } from './contract-start-position'; -export function newFunctionPosition( - contract: ContractDefinition, - tools: TransformerTools, -): number { +export function newFunctionPosition(contract: ContractDefinition, tools: TransformerTools): number { const firstFunctionIndex = contract.nodes.findIndex(isNodeType('FunctionDefinition')); if (firstFunctionIndex <= 0) { diff --git a/src/utils/match.ts b/src/utils/match.ts index 8a07a65b..03bebfc7 100644 --- a/src/utils/match.ts +++ b/src/utils/match.ts @@ -26,7 +26,9 @@ function matchWithFlags( if (m) { const start = index + Buffer.from(str.slice(0, m.index), 'utf8').length; const length = Buffer.from(str.slice(m.index, m.index + m[0].length), 'utf8').length; - const captureLengths = m.slice(1).map(c => c === undefined ? c : Buffer.from(c, 'utf8').length); + const captureLengths = m + .slice(1) + .map(c => (c === undefined ? c : Buffer.from(c, 'utf8').length)); return { start, length, captureLengths }; } } From ffd38247e0ee8f63df8bfc25a2363ae4f9626bc9 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 25 Aug 2023 23:14:51 -0300 Subject: [PATCH 35/35] 0.3.26-2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d562766..9ba8f2c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.26-1", + "version": "0.3.26-2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.26-1", + "version": "0.3.26-2", "license": "MIT", "dependencies": { "ajv": "^8.0.0", diff --git a/package.json b/package.json index 925aa595..c5010ece 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/upgrade-safe-transpiler", - "version": "0.3.26-1", + "version": "0.3.26-2", "description": "Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe.", "main": "dist/index.js", "types": "dist/index.d.ts",