From 82bb7443def0b2c46022720bb6cfc4b699277416 Mon Sep 17 00:00:00 2001 From: 0xOneTony <112496816+0xOneTony@users.noreply.github.com> Date: Mon, 27 Nov 2023 17:22:07 +0200 Subject: [PATCH] chore: improve e2e base (#14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 🤖 Linear Closes SAF-XXX --- .env.example | 15 +++- .github/workflows/test.yml | 12 +++- README.md | 2 +- e2e-tests-with-nodes.js | 75 ++++++++++++++++++++ foundry.toml | 3 + package.json | 4 ++ solidity/test/e2e/Common.sol | 128 ++++++++++++++++++++++++++--------- yarn.lock | 72 ++------------------ 8 files changed, 209 insertions(+), 102 deletions(-) create mode 100644 e2e-tests-with-nodes.js diff --git a/.env.example b/.env.example index e44c7bd..bfabc93 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,22 @@ -## For e2e tests and deployment scripts +# For anvil to fork from MAINNET_RPC= GOERLI_RPC= OPTIMISM_RPC= OPTIMISM_GOERLI_RPC= +# Deployer address for the E2E Tests +MAINNET_DEPLOYER_ADDR= +# Safe owner address for the E2E Tests +MAINNET_SAFE_OWNER_ADDR= +# Deployer private key for the E2E Tests +MAINNET_DEPLOYER_PK= +# Safe owner private key for the E2E Tests +MAINNET_SAFE_OWNER_PK= +# Mainnet rpc for the E2E Tests, should be the anvil url +MAINNET_E2E_RPC= +# Optimism rpc for the E2E Tests, should be the anvil url +OPTIMISM_E2E_RPC= + ## For deployment scripts DEPLOYER_MAINNNET_PRIVATE_KEY= DEPLOYER_GOERLI_PRIVATE_KEY= diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 010bb44..d83799a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - name: Install dependencies run: yarn --frozen-lockfile --network-concurrency 1 - - name: Precompile using 0.8.14 and via-ir=false + - name: Precompile using 0.8.19 and via-ir=false run: yarn build - name: "Create env file" @@ -35,11 +35,17 @@ jobs: touch .env echo MAINNET_RPC="${{ secrets.MAINNET_RPC }}" >> .env echo GOERLI_RPC="${{ secrets.GOERLI_RPC }}" >> .env + echo OPTIMISM_RPC="${{ secrets.OPTIMISM_RPC }}" >> .env + echo MAINNET_E2E_RPC="${{ secrets.MAINNET_E2E_RPC }}" >> .env + echo OPTIMISM_E2E_RPC="${{ secrets.OPTIMISM_E2E_RPC }}" >> .env + echo MAINNET_SAFE_OWNER_ADDR="${{ secrets.MAINNET_SAFE_OWNER_ADDR }}" >> .env + echo MAINNET_SAFE_OWNER_PK="${{ secrets.MAINNET_SAFE_OWNER_PK }}" >> .env + echo MAINNET_DEPLOYER_ADDR="${{ secrets.MAINNET_DEPLOYER_ADDR }}" >> .env + echo MAINNET_DEPLOYER_PK="${{ secrets.MAINNET_DEPLOYER_PK }}" >> .env cat .env - name: Run tests - shell: bash - run: yarn test + run: yarn test:e2e-workflow forge-optimized: name: Run Optimized Unit Tests diff --git a/README.md b/README.md index c0214a7..f68c6ae 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ yarn build ### Available Commands -Make sure to set `MAINNET_RPC` environment variable before running end-to-end tests. +Make sure to set `MAINNET_RPC` and `OPTIMISM_RPC` environment variable before running end-to-end tests. | Yarn Command | Description | | ----------------------- | ---------------------------------------------------------- | diff --git a/e2e-tests-with-nodes.js b/e2e-tests-with-nodes.js new file mode 100644 index 0000000..08e0e3d --- /dev/null +++ b/e2e-tests-with-nodes.js @@ -0,0 +1,75 @@ +const { spawn } = require('child_process'); +require('dotenv').config(); // Initialize dotenv to load environment variables + +(async() => { + // Starting Anvil nodes for 'mainnet' and 'optimism' + console.debug(`Starting Anvil nodes`); + const anvilMainnetPromise = runAnvilNode('mainnet'); + const anvilOptimismPromise = runAnvilNode('optimism'); + + // Waiting for both nodes to be fully operational + console.debug(`Waiting for nodes to be up and running...`); + const [anvilMainnet, anvilOptimism] = await Promise.all([anvilMainnetPromise, anvilOptimismPromise]); + + // Running end-to-end tests + console.debug(`Running tests`); + const testProcess = spawn('yarn', [`test:e2e`]); + + // Handle test errors + testProcess.stderr.on('data', (data) => console.error(`Test error: ${data}`)); + + // Track the test result + let testPassed = true; + testProcess.stdout.on('data', (data) => { + console.info(String(data)); + if (String(data).includes('Failing tests:')) testPassed = false; + }); + + // When tests are complete, kill the Anvil nodes + testProcess.on('close', (code) => { + console.debug(`Tests finished running, killing anvil nodes...`); + try { + anvilMainnet.kill(); + anvilOptimism.kill(); + console.debug('Anvil nodes terminated successfully.'); + } catch (error) { + console.error(`Error terminating Anvil nodes: ${error}`); + } + + // Exit with an error code if tests failed + if (!testPassed) { + console.error('Tests failed. Setting exit code to 1.'); + process.exit(1); + } + + // Exit with a success code if tests passed + process.exit(0); + }); +})(); + + +/** + * Start an Anvil node for a given network + * + * @param network: name of the network to run (string) + * @returns promise which resolves when the node is running + */ +function runAnvilNode(network) { + return new Promise((resolve, reject) => { + const node = spawn('yarn', [`anvil:${network}`]); + + // Handle errors without exposing sensitive information + node.stderr.on('data', () => { + console.error(`Anvil ${network} node errored! Not showing the error log since it could reveal the RPC url.`); + reject(); + }); + + // Resolve the promise when the node is up + node.stdout.on('data', (data) => { + if (String(data).includes('Listening on')) { + console.debug(`Anvil ${network} node up and running`); + resolve(node); + } + }); + }); +} diff --git a/foundry.toml b/foundry.toml index a2f7a89..6d7ab48 100644 --- a/foundry.toml +++ b/foundry.toml @@ -34,3 +34,6 @@ src = './solidity/interfaces/' [rpc_endpoints] mainnet = "${MAINNET_RPC}" goerli = "${GOERLI_RPC}" +optimism = "${OPTIMISM_RPC}" +mainnet_e2e = "${MAINNET_E2E_RPC}" +optimism_e2e = "${OPTIMISM_E2E_RPC}" diff --git a/package.json b/package.json index 0dbbaed..9ec5fcc 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ }, "author": "Wonderland", "scripts": { + "anvil:mainnet": "anvil --port 8545 -f $MAINNET_RPC --fork-block-number 18621047 --chain-id 1", + "anvil:optimism": "anvil --port 9545 -f $OPTIMISM_RPC --fork-block-number 112491451 --chain-id 10", "build": "forge build", "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "coverage": "forge coverage --match-contract Unit", @@ -27,6 +29,7 @@ "proof": "python3 proofs/generate_proof.py", "test": "forge test -vvv", "test:e2e": "forge test --match-contract E2E -vvv", + "test:e2e-workflow": "node e2e-tests-with-nodes.js", "test:unit": "forge test --match-contract Unit -vvv", "test:unit:deep": "FOUNDRY_FUZZ_RUNS=5000 yarn test:unit" }, @@ -38,6 +41,7 @@ "dependencies": { "@defi-wonderland/solidity-utils": "0.0.0-3e9c8e8b", "Solidity-RLP": "github:hamdiallam/Solidity-RLP", + "dotenv": "16.3.1", "ds-test": "github:dapphub/ds-test#e282159", "forge-std": "github:foundry-rs/forge-std#v1.5.6", "isolmate": "github:defi-wonderland/isolmate#59e1804", diff --git a/solidity/test/e2e/Common.sol b/solidity/test/e2e/Common.sol index 508f5b3..6e28156 100644 --- a/solidity/test/e2e/Common.sol +++ b/solidity/test/e2e/Common.sol @@ -11,19 +11,30 @@ import {UpdateStorageMirrorGuard} from 'contracts/UpdateStorageMirrorGuard.sol'; import {GuardCallbackModule} from 'contracts/GuardCallbackModule.sol'; import {BlockHeaderOracle} from 'contracts/BlockHeaderOracle.sol'; import {NeedsUpdateGuard} from 'contracts/NeedsUpdateGuard.sol'; +import {VerifierModule} from 'contracts/VerifierModule.sol'; +import {StorageMirrorRootRegistry} from 'contracts/StorageMirrorRootRegistry.sol'; import {IGuardCallbackModule} from 'interfaces/IGuardCallbackModule.sol'; import {ISafe} from 'interfaces/ISafe.sol'; import {IVerifierModule} from 'interfaces/IVerifierModule.sol'; +import {IStorageMirrorRootRegistry} from 'interfaces/IStorageMirrorRootRegistry.sol'; +import {IBlockHeaderOracle} from 'interfaces/IBlockHeaderOracle.sol'; import {IGnosisSafeProxyFactory} from 'test/e2e/IGnosisSafeProxyFactory.sol'; import {TestConstants} from 'test/utils/TestConstants.sol'; import {ContractDeploymentAddress} from 'test/utils/ContractDeploymentAddress.sol'; +// solhint-disable-next-line max-states-count contract CommonE2EBase is DSTestPlus, TestConstants { - uint256 internal constant _FORK_BLOCK = 15_452_788; + uint256 internal constant _MAINNET_FORK_BLOCK = 18_621_047; + uint256 internal constant _OPTIMISM_FORK_BLOCK = 112_491_451; - address public deployer = makeAddr('deployer'); + uint256 internal _mainnetForkId; + uint256 internal _optimismForkId; + + address public deployer; + uint256 public deployerKey; + address public deployerOptimism = makeAddr('deployerOptimism'); address public proposer = makeAddr('proposer'); address public safeOwner; uint256 public safeOwnerKey; @@ -36,35 +47,45 @@ contract CommonE2EBase is DSTestPlus, TestConstants { GuardCallbackModule public guardCallbackModule; BlockHeaderOracle public oracle; NeedsUpdateGuard public needsUpdateGuard; + VerifierModule public verifierModule; + StorageMirrorRootRegistry public storageMirrorRootRegistry; ISafe public safe; ISafe public nonHomeChainSafe; - IVerifierModule public verifierModule = IVerifierModule(makeAddr('verifierModule')); IGnosisSafeProxyFactory public gnosisSafeProxyFactory = IGnosisSafeProxyFactory(GNOSIS_SAFE_PROXY_FACTORY); function setUp() public virtual { - vm.createSelectFork(vm.rpcUrl('mainnet'), _FORK_BLOCK); + // Set up both forks + _mainnetForkId = vm.createFork(vm.rpcUrl('mainnet_e2e'), _MAINNET_FORK_BLOCK); + _optimismForkId = vm.createFork(vm.rpcUrl('optimism_e2e'), _OPTIMISM_FORK_BLOCK); + // Select mainnet fork + vm.selectFork(_mainnetForkId); // Make address and key of safe owner - (safeOwner, safeOwnerKey) = makeAddrAndKey('safeOwner'); - // Make address and key of non home chain safe owner - (nonHomeChainSafeOwner, nonHomeChainSafeOwnerKey) = makeAddrAndKey('nonHomeChainSafeOwner'); + safeOwner = vm.envAddress('MAINNET_SAFE_OWNER_ADDR'); + safeOwnerKey = vm.envUint('MAINNET_SAFE_OWNER_PK'); + + // Make address and key of deployer + deployer = vm.envAddress('MAINNET_DEPLOYER_ADDR'); + deployerKey = vm.envUint('MAINNET_DEPLOYER_PK'); /// =============== HOME CHAIN =============== - vm.prank(safeOwner); + vm.broadcast(safeOwnerKey); safe = ISafe(address(gnosisSafeProxyFactory.createProxy(GNOSIS_SAFE_SINGLETON, ''))); // safeOwner nonce 0 label(address(safe), 'SafeProxy'); - address _updateStorageMirrorGuardTheoriticalAddress = ContractDeploymentAddress.addressFrom(deployer, 2); + uint256 _nonce = vm.getNonce(deployer); + + address _updateStorageMirrorGuardTheoriticalAddress = ContractDeploymentAddress.addressFrom(deployer, _nonce + 2); - vm.prank(deployer); + vm.broadcast(deployer); storageMirror = new StorageMirror(); // deployer nonce 0 label(address(storageMirror), 'StorageMirror'); - vm.prank(deployer); + vm.broadcast(deployer); guardCallbackModule = new GuardCallbackModule(address(storageMirror), _updateStorageMirrorGuardTheoriticalAddress); // deployer nonce 1 label(address(guardCallbackModule), 'GuardCallbackModule'); - vm.prank(deployer); + vm.broadcast(deployer); updateStorageMirrorGuard = new UpdateStorageMirrorGuard(guardCallbackModule); // deployer nonce 2 label(address(updateStorageMirrorGuard), 'UpdateStorageMirrorGuard'); @@ -74,11 +95,11 @@ contract CommonE2EBase is DSTestPlus, TestConstants { // Set up owner home chain safe address[] memory _owners = new address[](1); _owners[0] = safeOwner; - vm.prank(safeOwner); // safeOwner nonce 1 + vm.broadcast(safeOwnerKey); // safeOwner nonce 1 safe.setup(_owners, 1, address(safe), bytes(''), address(0), address(0), 0, payable(0)); // Enable guard callback module - enableModule(safe, safeOwner, safeOwnerKey, address(guardCallbackModule)); + enableModule(safe, safeOwnerKey, address(guardCallbackModule)); // data to sign and send to set the guard bytes memory _setGuardData = abi.encodeWithSelector(IGuardCallbackModule.setGuard.selector); @@ -91,7 +112,7 @@ contract CommonE2EBase is DSTestPlus, TestConstants { bytes memory _setGuardSignature = abi.encodePacked(_r, _s, _v); // execute setup of guard - vm.prank(safeOwner); + vm.broadcast(safeOwnerKey); safe.execTransaction( address(guardCallbackModule), 0, @@ -106,45 +127,90 @@ contract CommonE2EBase is DSTestPlus, TestConstants { ); /// =============== NON HOME CHAIN =============== + vm.selectFork(_optimismForkId); + // Make address and key of non home chain safe owner + (nonHomeChainSafeOwner, nonHomeChainSafeOwnerKey) = makeAddrAndKey('nonHomeChainSafeOwner'); + + address _storageMirrorRootRegistryTheoriticalAddress = ContractDeploymentAddress.addressFrom(deployerOptimism, 2); + // Set up non home chain safe - vm.prank(nonHomeChainSafeOwner); - nonHomeChainSafe = ISafe(address(gnosisSafeProxyFactory.createProxy(GNOSIS_SAFE_SINGLETON, ''))); // nonHomeChainSafeOwner nonce 0 + vm.broadcast(nonHomeChainSafeOwnerKey); + nonHomeChainSafe = ISafe(address(gnosisSafeProxyFactory.createProxy(GNOSIS_SAFE_SINGLETON_L2, ''))); // nonHomeChainSafeOwner nonce 0 label(address(nonHomeChainSafe), 'NonHomeChainSafeProxy'); // Deploy non home chain contracts - vm.prank(deployer); - oracle = new BlockHeaderOracle(); // deployer nonce 3 - label(address(oracle), 'MockOracle'); - - // vm.prank(deployer); - // verifierModule = new VerifierModule(..); // deployer nonce 4 - // label(address(verifierModule), 'VerifierModule'); - - vm.prank(deployer); - needsUpdateGuard = new NeedsUpdateGuard(verifierModule); // deployer nonce 5 + oracle = new BlockHeaderOracle(); // deployerOptimism nonce 0 + label(address(oracle), 'BlockHeaderOracle'); + + vm.broadcast(deployerOptimism); + verifierModule = new VerifierModule( + IStorageMirrorRootRegistry(_storageMirrorRootRegistryTheoriticalAddress), address(storageMirror) + ); // deployerOptimism nonce 1 + label(address(verifierModule), 'VerifierModule'); + + vm.broadcast(deployerOptimism); + storageMirrorRootRegistry = + new StorageMirrorRootRegistry(address(storageMirror), IVerifierModule(verifierModule), IBlockHeaderOracle(oracle)); // deployerOptimism nonce 2 + label(address(storageMirrorRootRegistry), 'StorageMirrorRootRegistry'); + + vm.broadcast(deployerOptimism); + needsUpdateGuard = new NeedsUpdateGuard(verifierModule); // deployer nonce 3 label(address(needsUpdateGuard), 'NeedsUpdateGuard'); // set up non home chain safe address[] memory _nonHomeChainSafeOwners = new address[](1); _nonHomeChainSafeOwners[0] = nonHomeChainSafeOwner; - vm.prank(nonHomeChainSafeOwner); // nonHomeChainSafeOwner nonce 1 + + vm.broadcast(nonHomeChainSafeOwnerKey); // nonHomeChainSafeOwner nonce 1 nonHomeChainSafe.setup( _nonHomeChainSafeOwners, 1, address(nonHomeChainSafe), bytes(''), address(0), address(0), 0, payable(0) ); // enable verifier module + enableModule(nonHomeChainSafe, nonHomeChainSafeOwnerKey, address(verifierModule)); + + // data to sign and send to set the guard + _setGuardData = abi.encodeWithSelector(ISafe.setGuard.selector, address(needsUpdateGuard)); + _setGuardEncodedTxData = nonHomeChainSafe.encodeTransactionData( + address(nonHomeChainSafe), + 0, + _setGuardData, + Enum.Operation.Call, + 0, + 0, + 0, + address(0), + payable(0), + nonHomeChainSafe.nonce() + ); + + // signature + (_v, _r, _s) = vm.sign(nonHomeChainSafeOwnerKey, keccak256(_setGuardEncodedTxData)); + _setGuardSignature = abi.encodePacked(_r, _s, _v); // set needs update guard + vm.broadcast(nonHomeChainSafeOwnerKey); + nonHomeChainSafe.execTransaction( + address(nonHomeChainSafe), + 0, + _setGuardData, + Enum.Operation.Call, + 0, + 0, + 0, + address(0), + payable(0), + _setGuardSignature + ); } /** * @notice Enables a module for the given safe * @param _safe The safe that will enable the module - * @param _safeOwner The address of the owner of the safe * @param _safeOwnerKey The private key to sign the tx * @param _module The module address to enable */ - function enableModule(ISafe _safe, address _safeOwner, uint256 _safeOwnerKey, address _module) public { + function enableModule(ISafe _safe, uint256 _safeOwnerKey, address _module) public { uint256 _safeNonce = _safe.nonce(); // data to sign to enable module bytes memory _enableModuleData = abi.encodeWithSelector(ISafe.enableModule.selector, address(_module)); @@ -157,7 +223,7 @@ contract CommonE2EBase is DSTestPlus, TestConstants { bytes memory _enableModuleSignature = abi.encodePacked(_r, _s, _v); // execute enable module - vm.prank(_safeOwner); + vm.broadcast(safeOwnerKey); _safe.execTransaction( address(_safe), 0, _enableModuleData, Enum.Operation.Call, 0, 0, 0, address(0), payable(0), _enableModuleSignature ); diff --git a/yarn.lock b/yarn.lock index 228b8f5..dc0d41e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -200,15 +200,6 @@ ds-test "https://github.com/dapphub/ds-test" forge-std "https://github.com/foundry-rs/forge-std" -"@defi-wonderland/solidity-utils@0.0.0-4298c6c6": - version "0.0.0-4298c6c6" - resolved "https://registry.yarnpkg.com/@defi-wonderland/solidity-utils/-/solidity-utils-0.0.0-4298c6c6.tgz#4ac9e4bcc586f7434715357310a7a3c30e81f17f" - integrity sha512-jpecgVx9hpnXXGnYnN8ayd1ONj4ljk0hI36ltNfkNwlDkLLzPt4/FY5YSyY/628Exfuy5X9Rl9gGv5UtYgAmtw== - dependencies: - "@openzeppelin/contracts" "4.8.1" - ds-test "https://github.com/dapphub/ds-test" - forge-std "https://github.com/foundry-rs/forge-std" - "@jridgewell/resolve-uri@^3.0.3": version "3.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" @@ -248,11 +239,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@openzeppelin/contracts@4.8.1": - version "4.8.1" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.8.1.tgz#709cfc4bbb3ca9f4460d60101f15dac6b7a2d5e4" - integrity sha512-xQ6eUZl+RDyb/FiZe1h+U7qr/f4p/SrTSQcTPH2bjur3C5DbuW/zFgCU/b1P/xcIaEqJep+9ju4xDRi3rmChdQ== - "@openzeppelin/contracts@4.9.2": version "4.9.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.2.tgz#1cb2d5e4d3360141a17dbc45094a8cad6aac16c1" @@ -819,10 +805,10 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" -"ds-test@git+https://github.com/dapphub/ds-test.git": - version "1.0.0" - uid e282159d5170298eb2455a6c05280ab5a73a4ef0 - resolved "git+https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0" +dotenv@16.3.1: + version "16.3.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" + integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== "ds-test@github:dapphub/ds-test#e282159": version "1.0.0" @@ -1102,11 +1088,6 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -"forge-std@git+https://github.com/foundry-rs/forge-std.git": - version "1.7.2" - uid bdea49f9bb3c58c8c35850c3bdc17eaeea756e9a - resolved "git+https://github.com/foundry-rs/forge-std.git#bdea49f9bb3c58c8c35850c3bdc17eaeea756e9a" - "forge-std@github:foundry-rs/forge-std#v1.5.6": version "1.5.6" resolved "https://codeload.github.com/foundry-rs/forge-std/tar.gz/e8a047e3f40f13fa37af6fe14e6e06283d9a060e" @@ -1115,15 +1096,6 @@ flatted@^2.0.0: version "1.7.2" resolved "https://github.com/foundry-rs/forge-std#bdea49f9bb3c58c8c35850c3bdc17eaeea756e9a" -foundry-mock-generator@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/foundry-mock-generator/-/foundry-mock-generator-1.0.1.tgz#7473cc24920a65cdd70ed14cc5f6896fc3be76de" - integrity sha512-tl9gkhsB8V+FqLjz/WNusuAKDpUXTqbs/KC9roVKaqc7d9oC+2EDLtHRt9bHWEKTE9ocsCs2nH9+r8letnZsLQ== - dependencies: - "@defi-wonderland/solidity-utils" "0.0.0-4298c6c6" - handlebars "4.7.7" - yargs "17.7.2" - fs-extra@^11.0.0: version "11.1.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" @@ -1224,18 +1196,6 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -handlebars@4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - hard-rejection@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" @@ -1737,7 +1697,7 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -1764,11 +1724,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -neo-async@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -2333,11 +2288,6 @@ sort-package-json@1.53.1: is-plain-obj "2.1.0" sort-object-keys "^1.1.3" -source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - spdx-correct@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" @@ -2604,11 +2554,6 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826" integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== -uglify-js@^3.1.4: - version "3.17.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" - integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== - universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -2658,11 +2603,6 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -2718,7 +2658,7 @@ yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@17.7.2, yargs@^17.0.0: +yargs@^17.0.0: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==