diff --git a/contracts/Imports.sol b/contracts/Imports.sol new file mode 100644 index 00000000..7a17d9ea --- /dev/null +++ b/contracts/Imports.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.6.0; + +// We import the contract so truffle compiles it, and we have the ABI +// available when working from truffle console. +import "@gnosis.pm/mock-contract/contracts/MockContract.sol"; diff --git a/package.json b/package.json index 20ee94de..4159895a 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "format": "yarn format:sol && yarn format:ts", "format:sol": "prettier --write --plugin=prettier-plugin-solidity ./contracts/**/*.sol", "format:ts": "prettier --write ./sdk/**/*.ts ./test/**/*.ts ./*.ts", - "generate:types": "rm -rf src/types && typechain --target ethers-v5 --out-dir sdk/types './sdk/abi/*.json'", + "generate:types": "rm -rf src/types && typechain --target ethers-v6 --out-dir sdk/types './sdk/abi/*.json'", "prepare": "yarn generate:types && yarn build", "prerelease": "yarn clean && yarn build && yarn build:sdk", "release": "yarn publish --access public", @@ -49,13 +49,15 @@ "url": "https://github.com/gnosis/zodiac.git" }, "devDependencies": { - "@nomicfoundation/hardhat-chai-matchers": "^1.0.5", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.3", + "@nomicfoundation/hardhat-ethers": "^3.0.0", "@nomicfoundation/hardhat-network-helpers": "^1.0.7", - "@nomicfoundation/hardhat-toolbox": "^2.0.0", - "@nomiclabs/hardhat-ethers": "2.2.3", + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.0", + "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "3.1.7", - "@typechain/ethers-v5": "^11.1.0", - "@typechain/hardhat": "^6.1.5", + "@typechain/ethers-v6": "^0.5.1", + "@typechain/hardhat": "^9.1.0", "@types/chai": "^4.3.3", "@types/mocha": "^10.0.0", "@types/node": "^18.8.5", @@ -90,6 +92,6 @@ "@gnosis.pm/safe-contracts": "1.3.0", "@openzeppelin/contracts": "^5.0.0", "@openzeppelin/contracts-upgradeable": "^5.0.0", - "ethers": "^5.7.1" + "ethers": "^6.9.2" } -} \ No newline at end of file +} diff --git a/sdk/factory/__tests__/index.spec.ts b/sdk/factory/__tests__/index.spec.ts index f04ba243..0a558582 100644 --- a/sdk/factory/__tests__/index.spec.ts +++ b/sdk/factory/__tests__/index.spec.ts @@ -61,14 +61,15 @@ describe("Factory JS functions ", () => { KnownContracts.REALITY_ETH, args, hre.ethers.provider, - chainId, + Number(chainId), saltNonce ); const transaction = await signer.sendTransaction(deployTx); const receipt = await transaction.wait(); - expect(receipt.transactionHash).to.be.a("string"); + + expect(receipt.hash).to.be.a("string"); expect(receipt.status).to.be.eq(1); expect(expectedModuleAddress).to.a("string"); }); @@ -99,7 +100,8 @@ describe("Factory JS functions ", () => { ], }; - const chainContracts = ContractAddresses[chainId as SupportedNetworks]; + const chainContracts = + ContractAddresses[Number(chainId) as SupportedNetworks]; const masterCopyAddress = chainContracts[KnownContracts.REALITY_ETH]; const abi = ContractAbis[KnownContracts.REALITY_ETH]; @@ -109,14 +111,14 @@ describe("Factory JS functions ", () => { abi, args, hre.ethers.provider, - chainId, + Number(chainId), saltNonce ); const transaction = await signer.sendTransaction(deployTx); const receipt = await transaction.wait(); - expect(receipt.transactionHash).to.be.a("string"); + expect(receipt.hash).to.be.a("string"); expect(receipt.status).to.be.eq(1); expect(expectedModuleAddress).to.a("string"); }); @@ -126,11 +128,11 @@ describe("Factory JS functions ", () => { const module = await getModuleInstance( KnownContracts.REALITY_ETH, - mock.address, + await mock.getAddress(), hre.ethers.provider ); await mock.givenMethodReturnBool( - module.interface.getSighash("owner"), + module.interface.getFunction("owner").selector, true ); @@ -146,7 +148,7 @@ describe("Factory JS functions ", () => { await getModuleFactoryAndMasterCopy( KnownContracts.REALITY_ETH, hre.ethers.provider, - chainId + Number(chainId) ); expect(moduleFactory).to.be.instanceOf(Contract); expect(moduleMastercopy).to.be.instanceOf(Contract); diff --git a/sdk/factory/deployModuleFactory.ts b/sdk/factory/deployModuleFactory.ts index df495a80..0fd0630a 100644 --- a/sdk/factory/deployModuleFactory.ts +++ b/sdk/factory/deployModuleFactory.ts @@ -1,13 +1,13 @@ import assert from "assert"; -import { constants as ethersConstants, ethers } from "ethers"; +import { ZeroAddress, JsonRpcSigner } from "ethers"; import { MasterCopyInitData } from "../contracts"; import { getSingletonFactory } from "./singletonFactory"; import { KnownContracts } from "./types"; -const { AddressZero } = ethersConstants; +const AddressZero = ZeroAddress; const FactoryInitData = MasterCopyInitData[KnownContracts.FACTORY]; @@ -21,7 +21,7 @@ assert(FactoryInitData); * @returns The address of the deployed Module Proxy Factory, or the zero address if it was already deployed */ export const deployModuleFactory = async ( - signer: ethers.providers.JsonRpcSigner + signer: JsonRpcSigner ): Promise => { console.log("Deploying the Module Proxy Factory..."); const singletonFactory = await getSingletonFactory(signer); @@ -30,13 +30,15 @@ export const deployModuleFactory = async ( singletonFactory.address ); - const targetAddress = await singletonFactory.callStatic.deploy( + const targetAddress = await singletonFactory.deploy.staticCall( FactoryInitData.initCode, FactoryInitData.salt ); if (targetAddress === AddressZero) { console.log( - ` ✔ Module Proxy Factory already deployed to target address on ${signer.provider.network.name}.` + ` ✔ Module Proxy Factory already deployed to target address on ${ + (await signer.provider.getNetwork()).name + }.` ); return AddressZero; } diff --git a/sdk/factory/mastercopyDeployer.ts b/sdk/factory/mastercopyDeployer.ts index 2516f8fc..3ebef99a 100644 --- a/sdk/factory/mastercopyDeployer.ts +++ b/sdk/factory/mastercopyDeployer.ts @@ -1,14 +1,16 @@ import { BytesLike, ContractFactory, - constants as ethersConstants, - ethers, + ZeroAddress, + JsonRpcSigner, + keccak256, + getAddress, + getCreate2Address, } from "ethers"; -import { keccak256, getCreate2Address, getAddress } from "ethers/lib/utils"; import { getSingletonFactory } from "./singletonFactory"; -const { AddressZero } = ethersConstants; +const AddressZero = ZeroAddress; /** * Deploy a module's mastercopy via the singleton factory. @@ -20,12 +22,14 @@ const { AddressZero } = ethersConstants; * @returns The address of the deployed module mastercopy or the zero address if it was already deployed */ export const deployMastercopy = async ( - signer: ethers.providers.JsonRpcSigner, + signer: JsonRpcSigner, mastercopyContractFactory: ContractFactory, args: Array, salt: string ): Promise => { - const deploymentTx = mastercopyContractFactory.getDeployTransaction(...args); + const deploymentTx = await mastercopyContractFactory.getDeployTransaction( + ...args + ); if (!deploymentTx.data) { throw new Error("Unable to create the deployment data (no init code)."); @@ -45,12 +49,14 @@ export const deployMastercopy = async ( * } */ export const computeTargetAddress = async ( - signer: ethers.providers.JsonRpcSigner, + signer: JsonRpcSigner, mastercopyContractFactory: ContractFactory, args: Array, salt: string ): Promise<{ address: string; isDeployed: boolean }> => { - const deploymentTx = mastercopyContractFactory.getDeployTransaction(...args); + const deploymentTx = await mastercopyContractFactory.getDeployTransaction( + ...args + ); const singletonFactory = await getSingletonFactory(signer); if (!deploymentTx.data) { @@ -60,13 +66,13 @@ export const computeTargetAddress = async ( const initCodeHash = keccak256(deploymentTx.data); const computedAddress = getCreate2Address( - singletonFactory.address, + await singletonFactory.getAddress(), salt, initCodeHash ); const targetAddress = getAddress( - (await singletonFactory.callStatic.deploy( + (await singletonFactory.deploy.staticCall( deploymentTx.data, salt )) as string @@ -86,7 +92,7 @@ export const computeTargetAddress = async ( }; export const deployMastercopyWithInitData = async ( - signer: ethers.providers.JsonRpcSigner, + signer: JsonRpcSigner, initCode: BytesLike, salt: string ): Promise => { @@ -94,13 +100,13 @@ export const deployMastercopyWithInitData = async ( // throws if this for some reason is not a valid address const targetAddress = getAddress( - (await singletonFactory.callStatic.deploy(initCode, salt)) as string + (await singletonFactory.deploy.staticCall(initCode, salt)) as string ); const initCodeHash = keccak256(initCode); const computedTargetAddress = getCreate2Address( - singletonFactory.address, + await singletonFactory.address(), salt, initCodeHash ); @@ -118,7 +124,7 @@ export const deployMastercopyWithInitData = async ( } let gasLimit; - switch (signer.provider.network.name) { + switch ((await signer.provider.getNetwork()).name) { case "optimism": gasLimit = 6000000; break; diff --git a/sdk/factory/moduleDeployer.ts b/sdk/factory/moduleDeployer.ts index 95fe4bf2..5101a4c0 100644 --- a/sdk/factory/moduleDeployer.ts +++ b/sdk/factory/moduleDeployer.ts @@ -1,5 +1,12 @@ -import { Provider } from "@ethersproject/providers"; -import { ethers, Contract, Signer, BigNumber } from "ethers"; +import { + Contract, + Signer, + Provider, + getCreate2Address, + AbiCoder, + solidityPackedKeccak256, + keccak256, +} from "ethers"; import { ContractAddresses, @@ -17,7 +24,7 @@ type TxAndExpectedAddress = { transaction: { data: string; to: string; - value: ethers.BigNumber; + value: bigint; }; expectedModuleAddress: string; }; @@ -33,7 +40,7 @@ type TxAndExpectedAddress = { * @param saltNonce * @returns the transaction and the expected address of the module proxy */ -export const deployAndSetUpModule = ( +export const deployAndSetUpModule = async ( moduleName: KnownContracts, setupArgs: { types: Array; @@ -42,15 +49,19 @@ export const deployAndSetUpModule = ( provider: Provider, chainId: number, saltNonce: string -): TxAndExpectedAddress => { +): Promise<{ + transaction: { data: string; to: string; value: bigint }; + expectedModuleAddress: string; +}> => { const { moduleFactory, moduleMastercopy } = getModuleFactoryAndMasterCopy( moduleName, provider, chainId ); + return getDeployAndSetupTx( - moduleFactory, - moduleMastercopy, + moduleFactory as unknown as Contract, + moduleMastercopy as unknown as Contract, setupArgs, saltNonce ); @@ -69,7 +80,7 @@ export const deployAndSetUpModule = ( * @param saltNonce * @returns the transaction and the expected address of the module proxy */ -export const deployAndSetUpCustomModule = ( +export const deployAndSetUpCustomModule = async ( mastercopyAddress: string, abi: ABI, setupArgs: { @@ -79,7 +90,7 @@ export const deployAndSetUpCustomModule = ( provider: Provider, chainId: number, saltNonce: string -): TxAndExpectedAddress => { +): Promise => { const chainContracts = ContractAddresses[chainId as SupportedNetworks]; const moduleFactoryAddress = chainContracts.factory; const moduleFactory = new Contract( @@ -88,48 +99,50 @@ export const deployAndSetUpCustomModule = ( provider ); const moduleMastercopy = new Contract(mastercopyAddress, abi, provider); - - return getDeployAndSetupTx( + const deployAndSetupTx = await getDeployAndSetupTx( moduleFactory, moduleMastercopy, setupArgs, saltNonce ); + + return deployAndSetupTx; }; -const getDeployAndSetupTx = ( - moduleFactory: ethers.Contract, - moduleMastercopy: ethers.Contract, +const getDeployAndSetupTx = async ( + moduleFactory: Contract, + moduleMastercopy: Contract, setupArgs: { types: Array; values: Array; }, saltNonce: string ) => { - const encodedInitParams = ethers.utils.defaultAbiCoder.encode( + const encodedInitParams = AbiCoder.defaultAbiCoder().encode( setupArgs.types, setupArgs.values ); + const moduleSetupData = moduleMastercopy.interface.encodeFunctionData( "setUp", [encodedInitParams] ); - const expectedModuleAddress = calculateProxyAddress( + const expectedModuleAddress = await calculateProxyAddress( moduleFactory, - moduleMastercopy.address, + await moduleMastercopy.getAddress(), moduleSetupData, saltNonce ); const deployData = moduleFactory.interface.encodeFunctionData( "deployModule", - [moduleMastercopy.address, moduleSetupData, saltNonce] + [await moduleMastercopy.getAddress(), moduleSetupData, saltNonce] ); const transaction = { data: deployData, - to: moduleFactory.address, - value: BigNumber.from(0), + to: await moduleFactory.getAddress(), + value: 0n, }; return { transaction, @@ -137,12 +150,12 @@ const getDeployAndSetupTx = ( }; }; -export const calculateProxyAddress = ( +export const calculateProxyAddress = async ( moduleFactory: Contract, mastercopyAddress: string, initData: string, saltNonce: string -): string => { +): Promise => { const mastercopyAddressFormatted = mastercopyAddress .toLowerCase() .replace(/^0x/, ""); @@ -151,15 +164,15 @@ export const calculateProxyAddress = ( mastercopyAddressFormatted + "5af43d82803e903d91602b57fd5bf3"; - const salt = ethers.utils.solidityKeccak256( + const salt = solidityPackedKeccak256( ["bytes32", "uint256"], - [ethers.utils.solidityKeccak256(["bytes"], [initData]), saltNonce] + [solidityPackedKeccak256(["bytes"], [initData]), saltNonce] ); - return ethers.utils.getCreate2Address( - moduleFactory.address, + return getCreate2Address( + await moduleFactory.getAddress(), salt, - ethers.utils.keccak256(byteCode) + keccak256(byteCode) ); }; diff --git a/sdk/factory/singletonFactory.ts b/sdk/factory/singletonFactory.ts index 0958275b..4531356d 100644 --- a/sdk/factory/singletonFactory.ts +++ b/sdk/factory/singletonFactory.ts @@ -1,4 +1,4 @@ -import { Contract, ethers } from "ethers"; +import { Contract, JsonRpcSigner, parseEther } from "ethers"; const singletonFactoryAbi = [ "function deploy(bytes memory _initCode, bytes32 _salt) public returns (address payable createdContract)", @@ -15,34 +15,40 @@ export const SingletonFactoryAddress = * @returns Singleton Factory contract */ export const getSingletonFactory = async ( - signer: ethers.providers.JsonRpcSigner + signer: JsonRpcSigner ): Promise => { const singletonDeployer = "0xBb6e024b9cFFACB947A71991E386681B1Cd1477D"; - const singletonFactory = new ethers.Contract( + const singletonFactory = new Contract( SingletonFactoryAddress, singletonFactoryAbi, signer ); // check if singleton factory is deployed. - if ((await signer.provider.getCode(singletonFactory.address)) === "0x") { + if ( + (await signer.provider.getCode(await singletonFactory.getAddress())) === + "0x" + ) { console.log( "Singleton factory is not deployed on this chain. Deploying singleton factory..." ); // fund the singleton factory deployer account await signer.sendTransaction({ to: singletonDeployer, - value: ethers.utils.parseEther("0.0247"), + value: parseEther("0.0247"), }); // deploy the singleton factory await ( - await signer.provider.sendTransaction( + await signer.provider.broadcastTransaction( "0xf9016c8085174876e8008303c4d88080b90154608060405234801561001057600080fd5b50610134806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634af63f0214602d575b600080fd5b60cf60048036036040811015604157600080fd5b810190602081018135640100000000811115605b57600080fd5b820183602082011115606c57600080fd5b80359060200191846001830284011164010000000083111715608d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550509135925060eb915050565b604080516001600160a01b039092168252519081900360200190f35b6000818351602085016000f5939250505056fea26469706673582212206b44f8a82cb6b156bfcc3dc6aadd6df4eefd204bc928a4397fd15dacf6d5320564736f6c634300060200331b83247000822470" ) ).wait(); - if ((await signer.provider.getCode(singletonFactory.address)) == "0x") { + if ( + (await signer.provider.getCode(await singletonFactory.getAddress())) == + "0x" + ) { throw Error( "Singleton factory could not be deployed to correct address, deployment haulted." ); diff --git a/test/01_IAvatar.spec.ts b/test/01_IAvatar.spec.ts index ab9134d8..170fb283 100644 --- a/test/01_IAvatar.spec.ts +++ b/test/01_IAvatar.spec.ts @@ -10,9 +10,12 @@ describe("IAvatar", async () => { const [signer] = await hre.ethers.getSigners(); const Avatar = await hre.ethers.getContractFactory("TestAvatar"); const avatar = await Avatar.connect(signer).deploy(); - const iAvatar = TestAvatar__factory.connect(avatar.address, signer); + const iAvatar = TestAvatar__factory.connect( + await avatar.getAddress(), + signer + ); const tx = { - to: avatar.address, + to: await avatar.getAddress(), value: 0, data: "0x", operation: 0, diff --git a/test/02_Module.spec.ts b/test/02_Module.spec.ts index f2d03b33..fc6d60bd 100644 --- a/test/02_Module.spec.ts +++ b/test/02_Module.spec.ts @@ -7,14 +7,20 @@ describe("Module", async () => { async function setupTests() { const Avatar = await hre.ethers.getContractFactory("TestAvatar"); const avatar = await Avatar.deploy(); - const iAvatar = await hre.ethers.getContractAt("IAvatar", avatar.address); + const iAvatar = await hre.ethers.getContractAt( + "IAvatar", + await avatar.getAddress() + ); const Module = await hre.ethers.getContractFactory("TestModule"); - const module = await Module.deploy(iAvatar.address, iAvatar.address); - await avatar.enableModule(module.address); + const module = await Module.deploy( + await iAvatar.getAddress(), + await iAvatar.getAddress() + ); + await avatar.enableModule(await module.getAddress()); const Guard = await hre.ethers.getContractFactory("TestGuard"); - const guard = await Guard.deploy(module.address); + const guard = await Guard.deploy(await module.getAddress()); const tx = { - to: avatar.address, + to: await avatar.getAddress(), value: 0, data: "0x", operation: 0, @@ -40,14 +46,14 @@ describe("Module", async () => { const [owner, wallet1] = await hre.ethers.getSigners(); await module.transferOwnership(wallet1.address); - await expect(module.setAvatar(iAvatar.address)) + await expect(module.setAvatar(await iAvatar.getAddress())) .to.be.revertedWithCustomError(module, "OwnableUnauthorizedAccount") .withArgs(owner.address); }); it("allows owner to set avatar", async () => { const { iAvatar, module } = await loadFixture(setupTests); - await expect(module.setAvatar(iAvatar.address)); + await expect(module.setAvatar(await iAvatar.getAddress())); }); it("emits previous owner and new owner", async () => { @@ -57,7 +63,7 @@ describe("Module", async () => { await expect(module.setAvatar(wallet1.address)) .to.emit(module, "AvatarSet") - .withArgs(iAvatar.address, wallet1.address); + .withArgs(await iAvatar.getAddress(), wallet1.address); }); }); @@ -66,14 +72,14 @@ describe("Module", async () => { const { iAvatar, module } = await loadFixture(setupTests); const [owner, wallet1] = await hre.ethers.getSigners(); await module.transferOwnership(wallet1.address); - await expect(module.setTarget(iAvatar.address)) + await expect(module.setTarget(await iAvatar.getAddress())) .to.be.revertedWithCustomError(module, "OwnableUnauthorizedAccount") .withArgs(owner.address); }); it("allows owner to set avatar", async () => { const { iAvatar, module } = await loadFixture(setupTests); - await expect(module.setTarget(iAvatar.address)); + await expect(module.setTarget(await iAvatar.getAddress())); }); it("emits previous owner and new owner", async () => { @@ -81,7 +87,7 @@ describe("Module", async () => { const [, wallet1] = await hre.ethers.getSigners(); await expect(module.setTarget(wallet1.address)) .to.emit(module, "TargetSet") - .withArgs(iAvatar.address, wallet1.address); + .withArgs(await iAvatar.getAddress(), wallet1.address); }); }); @@ -95,7 +101,7 @@ describe("Module", async () => { it("pre-checks transaction if guard is set", async () => { const { guard, module, tx } = await loadFixture(setupTests); - await module.setGuard(guard.address); + await module.setGuard(await guard.getAddress()); await expect( module.executeTransaction(tx.to, tx.value, tx.data, tx.operation) ).to.emit(guard, "PreChecked"); @@ -117,7 +123,7 @@ describe("Module", async () => { it("post-checks transaction if guard is set", async () => { const { guard, module, tx } = await loadFixture(setupTests); - await module.setGuard(guard.address); + await module.setGuard(await guard.getAddress()); await expect( module.executeTransaction(tx.to, tx.value, tx.data, tx.operation) ) @@ -141,7 +147,7 @@ describe("Module", async () => { it("pre-checks transaction if guard is set", async () => { const { guard, module, tx } = await loadFixture(setupTests); - await module.setGuard(guard.address); + await module.setGuard(await guard.getAddress()); await expect( module.executeTransactionReturnData( tx.to, @@ -178,7 +184,7 @@ describe("Module", async () => { it("post-checks transaction if guard is set", async () => { const { guard, module, tx } = await loadFixture(setupTests); - await module.setGuard(guard.address); + await module.setGuard(await guard.getAddress()); await expect( module.executeTransactionReturnData( tx.to, diff --git a/test/03_Modifier.spec.ts b/test/03_Modifier.spec.ts index 16c95505..4af1621f 100644 --- a/test/03_Modifier.spec.ts +++ b/test/03_Modifier.spec.ts @@ -1,12 +1,17 @@ -import { AddressZero } from "@ethersproject/constants"; import { AddressOne } from "@gnosis.pm/safe-contracts"; import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect } from "chai"; -import { PopulatedTransaction } from "ethers"; -import { defaultAbiCoder, keccak256, toUtf8Bytes } from "ethers/lib/utils"; +import { + TransactionLike, + keccak256, + toUtf8Bytes, + AbiCoder, + ZeroAddress, + Signer, +} from "ethers"; import hre from "hardhat"; +const AddressZero = ZeroAddress; import { TestAvatar__factory, TestModifier__factory } from "../typechain-types"; import typedDataForTransaction from "./typedDataForTransaction"; @@ -18,16 +23,19 @@ describe("Modifier", async () => { const [signer, alice, bob, charlie] = await hre.ethers.getSigners(); const Avatar = await hre.ethers.getContractFactory("TestAvatar"); const avatar = await Avatar.connect(signer).deploy(); - const iAvatar = TestAvatar__factory.connect(avatar.address, signer); + const iAvatar = TestAvatar__factory.connect( + await avatar.getAddress(), + signer + ); const Modifier = await hre.ethers.getContractFactory("TestModifier"); const modifier = await Modifier.connect(signer).deploy( - iAvatar.address, - iAvatar.address + await iAvatar.getAddress(), + await iAvatar.getAddress() ); - await iAvatar.enableModule(modifier.address); + await iAvatar.enableModule(await modifier.getAddress()); const tx = { - to: avatar.address, + to: await avatar.getAddress(), value: 0, data: "0x", operation: 0, @@ -40,7 +48,10 @@ describe("Modifier", async () => { }; return { iAvatar, - modifier: TestModifier__factory.connect(modifier.address, signer), + modifier: TestModifier__factory.connect( + await modifier.getAddress(), + signer + ), tx, alice, bob, @@ -332,7 +343,7 @@ describe("Modifier", async () => { .withArgs(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModule( + await modifier.execTransactionFromModule.populateTransaction( tx.to, tx.value, tx.data, @@ -340,7 +351,7 @@ describe("Modifier", async () => { ); const signature = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user1 @@ -368,7 +379,7 @@ describe("Modifier", async () => { .withArgs(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModule( + await modifier.execTransactionFromModule.populateTransaction( tx.to, tx.value, tx.data, @@ -376,13 +387,13 @@ describe("Modifier", async () => { ); const signatureOk = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user1 ); const signatureBad = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user2 @@ -415,7 +426,7 @@ describe("Modifier", async () => { .withArgs(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModule( + await modifier.execTransactionFromModule.populateTransaction( tx.to, tx.value, tx.data, @@ -423,13 +434,13 @@ describe("Modifier", async () => { ); const signatureOk = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user1 ); const signatureBad = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user2 @@ -465,7 +476,7 @@ describe("Modifier", async () => { await modifier.enableModule(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModule( + await modifier.execTransactionFromModule.populateTransaction( tx.to, tx.value, tx.data, @@ -475,7 +486,7 @@ describe("Modifier", async () => { const salt = keccak256(toUtf8Bytes("salt")); const signatureOk = await sign( - modifier.address, + await modifier.getAddress(), transaction, salt, user1 @@ -537,7 +548,7 @@ describe("Modifier", async () => { .withArgs(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModuleReturnData( + await modifier.execTransactionFromModuleReturnData.populateTransaction( tx.to, tx.value, tx.data, @@ -545,7 +556,7 @@ describe("Modifier", async () => { ); const signature = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user1 @@ -573,7 +584,7 @@ describe("Modifier", async () => { .withArgs(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModuleReturnData( + await modifier.execTransactionFromModuleReturnData.populateTransaction( tx.to, tx.value, tx.data, @@ -581,13 +592,13 @@ describe("Modifier", async () => { ); const signatureBad = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user2 ); const signatureOk = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user1 @@ -620,7 +631,7 @@ describe("Modifier", async () => { .withArgs(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModuleReturnData( + await modifier.execTransactionFromModuleReturnData.populateTransaction( tx.to, tx.value, tx.data, @@ -628,13 +639,13 @@ describe("Modifier", async () => { ); const signatureOk = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user1 ); const signatureBad = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), user2 @@ -670,7 +681,7 @@ describe("Modifier", async () => { await modifier.enableModule(user1.address); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModuleReturnData( + await modifier.execTransactionFromModuleReturnData.populateTransaction( tx.to, tx.value, tx.data, @@ -680,7 +691,7 @@ describe("Modifier", async () => { const salt = keccak256(toUtf8Bytes("salt")); const signatureOk = await sign( - modifier.address, + await modifier.getAddress(), transaction, salt, user1 @@ -725,20 +736,20 @@ describe("Modifier", async () => { await modifier.enableModule(bob.address); const transaction = await signTransaction( - modifier.address, - await modifier.populateTransaction.exposeSentOrSignedByModule(), + await modifier.getAddress(), + await modifier.exposeSentOrSignedByModule.populateTransaction(), keccak256(toUtf8Bytes("something salty")), bob ); // if alice sends it, msg.sender is taken into account, because alice module expect(await alice.call(transaction)).to.equal( - defaultAbiCoder.encode(["address"], [alice.address]) + AbiCoder.defaultAbiCoder().encode(["address"], [alice.address]) ); // if charlie sends it, signature is taken into account because bob module expect(await charlie.call(transaction)).to.equal( - defaultAbiCoder.encode(["address"], [bob.address]) + AbiCoder.defaultAbiCoder().encode(["address"], [bob.address]) ); }); @@ -748,15 +759,15 @@ describe("Modifier", async () => { await modifier.enableModule(alice.address); const transaction = await signTransaction( - modifier.address, - await modifier.populateTransaction.exposeSentOrSignedByModule(), + await modifier.getAddress(), + await modifier.exposeSentOrSignedByModule.populateTransaction(), keccak256(toUtf8Bytes("something salty")), alice ); // if alice sends it, msg.sender is taken into account, because alice module expect(await charlie.call(transaction)).to.equal( - defaultAbiCoder.encode(["address"], [alice.address]) + AbiCoder.defaultAbiCoder().encode(["address"], [alice.address]) ); }); @@ -766,15 +777,15 @@ describe("Modifier", async () => { // no modules enabled const transaction = await signTransaction( - modifier.address, - await modifier.populateTransaction.exposeSentOrSignedByModule(), + await modifier.getAddress(), + await modifier.exposeSentOrSignedByModule.populateTransaction(), keccak256(toUtf8Bytes("something salty")), alice ); // if alice sends it, msg.sender is taken into account, because alice module expect(await charlie.call(transaction)).to.equal( - defaultAbiCoder.encode(["address"], [AddressZero]) + AbiCoder.defaultAbiCoder().encode(["address"], [AddressZero]) ); }); }); @@ -782,32 +793,32 @@ describe("Modifier", async () => { async function sign( contract: string, - transaction: PopulatedTransaction, + transaction: TransactionLike, salt: string, - signer: SignerWithAddress + signer: Signer ) { const { domain, types, message } = typedDataForTransaction( { contract, chainId: 31337, salt }, transaction.data || "0x" ); - const signature = await signer._signTypedData(domain, types, message); + const signature = await signer.signTypedData(domain, types, message); return `${salt}${signature.slice(2)}`; } async function signTransaction( contract: string, - { from, ...transaction }: PopulatedTransaction, + { from, ...transaction }: TransactionLike, salt: string, - signer: SignerWithAddress + signer: Signer ) { const { domain, types, message } = typedDataForTransaction( { contract, chainId: 31337, salt }, transaction.data || "0x" ); - const signature = await signer._signTypedData(domain, types, message); + const signature = await signer.signTypedData(domain, types, message); return { ...transaction, diff --git a/test/04_Guard.spec.ts b/test/04_Guard.spec.ts index 4cee01ec..86cd7c79 100644 --- a/test/04_Guard.spec.ts +++ b/test/04_Guard.spec.ts @@ -11,15 +11,19 @@ async function setupTests() { const avatar = await Avatar.deploy(); const Module = await hre.ethers.getContractFactory("TestModule"); const module = TestModule__factory.connect( - (await Module.connect(owner).deploy(avatar.address, avatar.address)) - .address, + await ( + await Module.connect(owner).deploy( + await avatar.getAddress(), + await avatar.getAddress() + ) + ).getAddress(), owner ); - await avatar.enableModule(module.address); + await avatar.enableModule(await module.getAddress()); const Guard = await hre.ethers.getContractFactory("TestGuard"); const guard = TestGuard__factory.connect( - (await Guard.deploy(module.address)).address, + await (await Guard.deploy(await module.getAddress())).getAddress(), relayer ); @@ -27,12 +31,12 @@ async function setupTests() { "TestNonCompliantGuard" ); const guardNonCompliant = TestGuard__factory.connect( - (await GuardNonCompliant.deploy()).address, + await (await GuardNonCompliant.deploy()).getAddress(), hre.ethers.provider ); const tx = { - to: avatar.address, + to: await avatar.getAddress(), value: 0, data: "0x", operation: 0, @@ -58,35 +62,35 @@ describe("Guardable", async () => { describe("setGuard", async () => { it("reverts if reverts if caller is not the owner", async () => { const { other, guard, module } = await loadFixture(setupTests); - await expect(module.connect(other).setGuard(guard.address)) + await expect(module.connect(other).setGuard(await guard.getAddress())) .to.be.revertedWithCustomError(module, "OwnableUnauthorizedAccount") .withArgs(other.address); }); it("reverts if guard does not implement ERC165", async () => { const { module } = await loadFixture(setupTests); - await expect(module.setGuard(module.address)).to.be.reverted; + await expect(module.setGuard(await module.getAddress())).to.be.reverted; }); it("reverts if guard implements ERC165 and returns false", async () => { const { module, guardNonCompliant } = await loadFixture(setupTests); - await expect(module.setGuard(guardNonCompliant.address)) + await expect(module.setGuard(await guardNonCompliant.getAddress())) .to.be.revertedWithCustomError(module, "NotIERC165Compliant") - .withArgs(guardNonCompliant.address); + .withArgs(await guardNonCompliant.getAddress()); }); it("sets module and emits event", async () => { const { module, guard } = await loadFixture(setupTests); - await expect(module.setGuard(guard.address)) + await expect(module.setGuard(await guard.getAddress())) .to.emit(module, "ChangedGuard") - .withArgs(guard.address); + .withArgs(await guard.getAddress()); }); it("sets guard back to zero", async () => { const { module, guard } = await loadFixture(setupTests); - await expect(module.setGuard(guard.address)) + await expect(module.setGuard(await guard.getAddress())) .to.emit(module, "ChangedGuard") - .withArgs(guard.address); + .withArgs(await guard.getAddress()); await expect(module.setGuard(AddressZero)) .to.emit(module, "ChangedGuard") @@ -160,9 +164,9 @@ describe("BaseGuard", async () => { }); it("checks state after execution", async () => { const { module, guard } = await loadFixture(setupTests); - await expect(module.setGuard(guard.address)) + await expect(module.setGuard(await guard.getAddress())) .to.emit(module, "ChangedGuard") - .withArgs(guard.address); + .withArgs(await guard.getAddress()); await expect(guard.checkAfterExecution(txHash, true)) .to.emit(guard, "PostChecked") .withArgs(true); diff --git a/test/05_ModuleProxyFactory.spec.ts b/test/05_ModuleProxyFactory.spec.ts index c6386cbb..e1c63beb 100644 --- a/test/05_ModuleProxyFactory.spec.ts +++ b/test/05_ModuleProxyFactory.spec.ts @@ -1,11 +1,12 @@ -import { AddressZero } from "@ethersproject/constants"; import { AddressOne } from "@gnosis.pm/safe-contracts"; import { expect } from "chai"; -import { Contract } from "ethers"; +import { AbiCoder, Contract, ZeroAddress } from "ethers"; import { ethers } from "hardhat"; import { calculateProxyAddress } from "../sdk/factory"; +const AddressZero = ZeroAddress; + describe("ModuleProxyFactory", async () => { let moduleFactory: Contract; let moduleMasterCopy: Contract; @@ -23,36 +24,36 @@ describe("ModuleProxyFactory", async () => { const MasterCopyModule = await ethers.getContractFactory("TestModule"); moduleMasterCopy = await MasterCopyModule.deploy( - avatar.address, - avatar.address + await avatar.getAddress(), + await avatar.getAddress() ); - const encodedInitParams = new ethers.utils.AbiCoder().encode( + const encodedInitParams = AbiCoder.defaultAbiCoder().encode( ["address", "address"], - [avatar.address, avatar.address] + [await avatar.getAddress(), await avatar.getAddress()] ); initData = moduleMasterCopy.interface.encodeFunctionData("setUp", [ encodedInitParams, ]); - avatarAddress = avatar.address; + avatarAddress = await avatar.getAddress(); }); describe("createProxy", () => { it("should deploy the expected address ", async () => { const expectedAddress = await calculateProxyAddress( moduleFactory, - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), initData, saltNonce ); const deploymentTx = await moduleFactory.deployModule( - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), initData, saltNonce ); const transaction = await deploymentTx.wait(); - const [moduleAddress] = transaction.events[2].args; + const [moduleAddress] = transaction.logs[2].args; expect(moduleAddress).to.be.equal(expectedAddress); }); @@ -69,14 +70,14 @@ describe("ModuleProxyFactory", async () => { it("should fail to deploy because address its already taken ", async () => { await moduleFactory.deployModule( - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), initData, saltNonce ); await expect( moduleFactory.deployModule( - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), initData, saltNonce ) @@ -89,12 +90,12 @@ describe("ModuleProxyFactory", async () => { describe("deployModule ", () => { it("should deploy module", async () => { const deploymentTx = await moduleFactory.deployModule( - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), initData, saltNonce ); const transaction = await deploymentTx.wait(); - const [moduleAddress] = transaction.events[2].args; + const [moduleAddress] = transaction.logs[2].args; const newModule = await ethers.getContractAt("TestModule", moduleAddress); @@ -105,25 +106,25 @@ describe("ModuleProxyFactory", async () => { it("should emit event on module deployment", async () => { const moduleAddress = await calculateProxyAddress( moduleFactory, - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), initData, saltNonce ); await expect( moduleFactory.deployModule( - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), initData, saltNonce ) ) .to.emit(moduleFactory, "ModuleProxyCreation") - .withArgs(moduleAddress, moduleMasterCopy.address); + .withArgs(moduleAddress, await moduleMasterCopy.getAddress()); }); it("should fail to deploy because parameters are not valid ", async () => { await expect( moduleFactory.deployModule( - moduleMasterCopy.address, + await moduleMasterCopy.getAddress(), "0xaabc", saltNonce ) diff --git a/test/06_SignatureChecker.spec.ts b/test/06_SignatureChecker.spec.ts index c93b8ee8..f9e30b9e 100644 --- a/test/06_SignatureChecker.spec.ts +++ b/test/06_SignatureChecker.spec.ts @@ -1,13 +1,13 @@ import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect } from "chai"; -import { PopulatedTransaction } from "ethers"; import { - defaultAbiCoder, + TransactionLike, + AbiCoder, keccak256, - solidityPack, + solidityPacked, toUtf8Bytes, -} from "ethers/lib/utils"; + Signer, +} from "ethers"; import hre from "hardhat"; import { TestSignature__factory } from "../typechain-types"; @@ -22,7 +22,7 @@ describe("SignatureChecker", async () => { return { testSignature: TestSignature__factory.connect( - testSignature.address, + await testSignature.getAddress(), relayer ), signer, @@ -35,9 +35,9 @@ describe("SignatureChecker", async () => { it("correctly detects an appended signature, for an entrypoint no arguments", async () => { const { testSignature, signer, relayer } = await loadFixture(setup); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); const signature = await sign( - testSignature.address, + await testSignature.getAddress(), transaction, keccak256(toUtf8Bytes("Hello this is a salt")), signer @@ -59,12 +59,12 @@ describe("SignatureChecker", async () => { it("correctly detects an appended signature, entrypoint with arguments", async () => { const { testSignature, signer, relayer } = await loadFixture(setup); - const transaction = await testSignature.populateTransaction.goodbye( + const transaction = await testSignature.goodbye.populateTransaction( 0, "0xbadfed" ); const signature = await sign( - testSignature.address, + await testSignature.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), signer @@ -89,9 +89,9 @@ describe("SignatureChecker", async () => { const ContractSigner = await hre.ethers.getContractFactory("ContractSignerYes"); - const signer = (await ContractSigner.deploy()).address; + const signer = await (await ContractSigner.deploy()).getAddress(); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); // 4 bytes of selector plus 3 bytes of custom signature // an s of 4, 5 or 6 should be okay. 7 and higher should fail @@ -100,7 +100,7 @@ describe("SignatureChecker", async () => { "0xdddddd", keccak256(toUtf8Bytes("salt")), signer, - defaultAbiCoder.encode(["uint256"], [1000]) + AbiCoder.defaultAbiCoder().encode(["uint256"], [1000]) ); await expect( @@ -117,7 +117,7 @@ describe("SignatureChecker", async () => { "0xdddddd", keccak256(toUtf8Bytes("salt")), signer, - defaultAbiCoder.encode(["uint256"], [6]) + AbiCoder.defaultAbiCoder().encode(["uint256"], [6]) ); await expect( @@ -134,16 +134,16 @@ describe("SignatureChecker", async () => { const ContractSigner = await hre.ethers.getContractFactory("ContractSignerYes"); - const signer = (await ContractSigner.deploy()).address; + const signer = await (await ContractSigner.deploy()).getAddress(); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); let signature = makeContractSignature( transaction, "0xdddddd", keccak256(toUtf8Bytes("salt")), signer, - defaultAbiCoder.encode(["uint256"], [3]) + AbiCoder.defaultAbiCoder().encode(["uint256"], [3]) ); await expect( @@ -160,7 +160,7 @@ describe("SignatureChecker", async () => { "0xdddddd", keccak256(toUtf8Bytes("salt")), signer, - defaultAbiCoder.encode(["uint256"], [4]) + AbiCoder.defaultAbiCoder().encode(["uint256"], [4]) ); await expect( @@ -177,16 +177,16 @@ describe("SignatureChecker", async () => { const ContractSigner = await hre.ethers.getContractFactory("ContractSignerYes"); - const signer = (await ContractSigner.deploy()).address; + const signer = await (await ContractSigner.deploy()).getAddress(); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); let signature = makeContractSignature( transaction, "0xdddddd", keccak256(toUtf8Bytes("salt")), signer, - defaultAbiCoder.encode(["uint256"], [60]) + AbiCoder.defaultAbiCoder().encode(["uint256"], [60]) ); await expect( @@ -203,7 +203,7 @@ describe("SignatureChecker", async () => { "0xdddddd", keccak256(toUtf8Bytes("salt")), signer, - defaultAbiCoder.encode(["uint256"], [6]) + AbiCoder.defaultAbiCoder().encode(["uint256"], [6]) ); await expect( @@ -223,7 +223,7 @@ describe("SignatureChecker", async () => { ); const contractSigner = await ContractSigner.deploy(); - const transaction = await testSignature.populateTransaction.goodbye( + const transaction = await testSignature.goodbye.populateTransaction( 0, "0xbadfed" ); @@ -232,14 +232,14 @@ describe("SignatureChecker", async () => { transaction, "0x001122334455", keccak256(toUtf8Bytes("some irrelevant salt")), - contractSigner.address + await contractSigner.getAddress() ); const signatureBad = makeContractSignature( transaction, "0x00112233445566", keccak256(toUtf8Bytes("some irrelevant salt")), - contractSigner.address + await contractSigner.getAddress() ); const transactionWithGoodSig = { @@ -257,7 +257,7 @@ describe("SignatureChecker", async () => { await expect(await relayer.sendTransaction(transactionWithGoodSig)) .to.emit(testSignature, "Goodbye") - .withArgs(contractSigner.address); + .withArgs(await contractSigner.getAddress()); await expect(await relayer.sendTransaction(transactionWithBadSig)) .to.emit(testSignature, "Goodbye") @@ -270,7 +270,7 @@ describe("SignatureChecker", async () => { await hre.ethers.getContractFactory("ContractSignerYes"); const contractSigner = await ContractSigner.deploy(); - const transaction = await testSignature.populateTransaction.goodbye( + const transaction = await testSignature.goodbye.populateTransaction( 0, "0xbadfed" ); @@ -279,7 +279,7 @@ describe("SignatureChecker", async () => { transaction, "0xaabbccddeeff", keccak256(toUtf8Bytes("salt")), - contractSigner.address + await contractSigner.getAddress() ); const transactionWithSig = { @@ -293,7 +293,7 @@ describe("SignatureChecker", async () => { await expect(await relayer.sendTransaction(transactionWithSig)) .to.emit(testSignature, "Goodbye") - .withArgs(contractSigner.address); + .withArgs(await contractSigner.getAddress()); }); it("signer returns isValid no", async () => { const { testSignature, relayer } = await loadFixture(setup); @@ -301,13 +301,13 @@ describe("SignatureChecker", async () => { const Signer = await hre.ethers.getContractFactory("ContractSignerNo"); const signer = await Signer.deploy(); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); const signature = makeContractSignature( transaction, "0xaabbccddeeff", keccak256(toUtf8Bytes("salt")), - signer.address + await signer.getAddress() ); const transactionWithSig = { @@ -328,7 +328,7 @@ describe("SignatureChecker", async () => { ); const contractSigner = await ContractSigner.deploy(); - const transaction = await testSignature.populateTransaction.goodbye( + const transaction = await testSignature.goodbye.populateTransaction( 0, "0xbadfed" ); @@ -337,14 +337,14 @@ describe("SignatureChecker", async () => { transaction, "0x", keccak256(toUtf8Bytes("some irrelevant salt")), - contractSigner.address + await contractSigner.getAddress() ); const signatureBad = makeContractSignature( transaction, "0xffff", keccak256(toUtf8Bytes("some irrelevant salt")), - contractSigner.address + await contractSigner.getAddress() ); const transactionWithGoodSig = { @@ -362,7 +362,7 @@ describe("SignatureChecker", async () => { await expect(await relayer.sendTransaction(transactionWithGoodSig)) .to.emit(testSignature, "Goodbye") - .withArgs(contractSigner.address); + .withArgs(await contractSigner.getAddress()); await expect(await relayer.sendTransaction(transactionWithBadSig)) .to.emit(testSignature, "Goodbye") @@ -376,13 +376,13 @@ describe("SignatureChecker", async () => { ); const signer = await Signer.deploy(); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); const signature = makeContractSignature( transaction, "0xaabbccddeeff", keccak256(toUtf8Bytes("salt")), - signer.address + await signer.getAddress() ); const transactionWithSig = { @@ -402,13 +402,13 @@ describe("SignatureChecker", async () => { ); const signer = await Signer.deploy(); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); const signature = makeContractSignature( transaction, "0xaabbccddeeff", keccak256(toUtf8Bytes("salt")), - signer.address + await signer.getAddress() ); const transactionWithSig = { @@ -429,7 +429,7 @@ describe("SignatureChecker", async () => { "0x" ); - const transaction = await testSignature.populateTransaction.hello(); + const transaction = await testSignature.hello.populateTransaction(); const signature = makeContractSignature( transaction, @@ -452,22 +452,22 @@ describe("SignatureChecker", async () => { async function sign( contract: string, - transaction: PopulatedTransaction, + transaction: TransactionLike, salt: string, - signer: SignerWithAddress + signer: Signer ) { const { domain, types, message } = typedDataForTransaction( { contract, chainId: 31337, salt }, transaction.data || "0x" ); - const signature = await signer._signTypedData(domain, types, message); + const signature = await signer.signTypedData(domain, types, message); return `${salt}${signature.slice(2)}`; } function makeContractSignature( - transaction: PopulatedTransaction, + transaction: TransactionLike, signerSpecificSignature: string, salt: string, r: string, @@ -475,9 +475,9 @@ function makeContractSignature( ) { const dataBytesLength = ((transaction.data?.length as number) - 2) / 2; - r = defaultAbiCoder.encode(["address"], [r]); - s = s || defaultAbiCoder.encode(["uint256"], [dataBytesLength]); - const v = solidityPack(["uint8"], [0]); + r = AbiCoder.defaultAbiCoder().encode(["address"], [r]); + s = s || AbiCoder.defaultAbiCoder().encode(["uint256"], [dataBytesLength]); + const v = solidityPacked(["uint8"], [0]); return `${signerSpecificSignature}${salt.slice(2)}${r.slice(2)}${s.slice( 2 diff --git a/test/07_GuardableModifier.spec.ts b/test/07_GuardableModifier.spec.ts index a9a853a4..90c29c6c 100644 --- a/test/07_GuardableModifier.spec.ts +++ b/test/07_GuardableModifier.spec.ts @@ -1,8 +1,6 @@ import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { expect } from "chai"; -import { PopulatedTransaction } from "ethers"; -import { keccak256, toUtf8Bytes } from "ethers/lib/utils"; +import { Signer, TransactionLike, keccak256, toUtf8Bytes } from "ethers"; import hre from "hardhat"; import { @@ -20,7 +18,7 @@ describe("GuardableModifier", async () => { const Avatar = await hre.ethers.getContractFactory("TestAvatar"); const avatar = TestAvatar__factory.connect( - (await Avatar.deploy()).address, + await (await Avatar.deploy()).getAddress(), deployer ); @@ -28,18 +26,22 @@ describe("GuardableModifier", async () => { "TestGuardableModifier" ); const modifier = TestGuardableModifier__factory.connect( - (await Modifier.connect(deployer).deploy(avatar.address, avatar.address)) - .address, + await ( + await Modifier.connect(deployer).deploy( + await avatar.getAddress(), + await avatar.getAddress() + ) + ).getAddress(), deployer ); const Guard = await hre.ethers.getContractFactory("TestGuard"); const guard = TestGuard__factory.connect( - (await Guard.deploy(modifier.address)).address, + await (await Guard.deploy(await modifier.getAddress())).getAddress(), hre.ethers.provider ); - await avatar.enableModule(modifier.address); - await modifier.enableModule(executor.address); + await avatar.enableModule(await modifier.getAddress()); + await modifier.enableModule(await executor.getAddress()); return { executor, @@ -59,70 +61,70 @@ describe("GuardableModifier", async () => { await expect( modifier .connect(executor) - .execTransactionFromModule(avatar.address, 0, "0x", 0) + .execTransactionFromModule(await avatar.getAddress(), 0, "0x", 0) ).to.not.be.reverted; }); it("pre-checks transaction if guard is set", async () => { const { avatar, executor, modifier, guard } = await loadFixture(setupTests); - await modifier.setGuard(guard.address); + await modifier.setGuard(await guard.getAddress()); await expect( modifier .connect(executor) - .execTransactionFromModule(avatar.address, 0, "0x", 0) + .execTransactionFromModule(await avatar.getAddress(), 0, "0x", 0) ) .to.emit(guard, "PreChecked") - .withArgs(executor.address); + .withArgs(await executor.getAddress()); }); it("pre-check gets called with signer when transaction is relayed", async () => { const { signer, modifier, relayer, avatar, guard } = await loadFixture(setupTests); - await modifier.enableModule(signer.address); - await modifier.setGuard(guard.address); + await modifier.enableModule(await signer.getAddress()); + await modifier.setGuard(await guard.getAddress()); - const inner = await avatar.populateTransaction.enableModule( + const inner = await avatar.enableModule.populateTransaction( "0xff00000000000000000000000000000000ff3456" ); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModule( - avatar.address, + await modifier.execTransactionFromModule.populateTransaction( + await avatar.getAddress(), 0, inner.data as string, 0 ); const signature = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), signer ); const transactionWithSig = { ...transaction, - to: modifier.address, + to: await modifier.getAddress(), data: `${transaction.data}${signature.slice(2)}`, value: 0, }; await expect(await relayer.sendTransaction(transactionWithSig)) .to.emit(guard, "PreChecked") - .withArgs(signer.address); + .withArgs(await signer.getAddress()); }); it("pre-checks and reverts transaction if guard is set", async () => { const { avatar, executor, modifier, guard } = await loadFixture(setupTests); - await modifier.setGuard(guard.address); + await modifier.setGuard(await guard.getAddress()); await expect( modifier .connect(executor) - .execTransactionFromModule(avatar.address, 1337, "0x", 0) + .execTransactionFromModule(await avatar.getAddress(), 1337, "0x", 0) ).to.be.revertedWith("Cannot send 1337"); }); @@ -133,19 +135,19 @@ describe("GuardableModifier", async () => { await expect( modifier .connect(executor) - .execTransactionFromModule(avatar.address, 0, "0x", 0) + .execTransactionFromModule(await avatar.getAddress(), 0, "0x", 0) ).not.to.emit(guard, "PostChecked"); }); it("post-checks transaction if guard is set", async () => { const { avatar, executor, modifier, guard } = await loadFixture(setupTests); - await modifier.setGuard(guard.address); + await modifier.setGuard(await guard.getAddress()); await expect( modifier .connect(executor) - .execTransactionFromModule(avatar.address, 0, "0x", 0) + .execTransactionFromModule(await avatar.getAddress(), 0, "0x", 0) ) .to.emit(guard, "PostChecked") .withArgs(true); @@ -159,22 +161,32 @@ describe("GuardableModifier", async () => { await expect( modifier .connect(executor) - .execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0) + .execTransactionFromModuleReturnData( + await avatar.getAddress(), + 0, + "0x", + 0 + ) ).to.not.be.reverted; }); it("pre-checks transaction if guard is set", async () => { const { avatar, executor, modifier, guard } = await loadFixture(setupTests); - await modifier.setGuard(guard.address); + await modifier.setGuard(await guard.getAddress()); await expect( modifier .connect(executor) - .execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0) + .execTransactionFromModuleReturnData( + await avatar.getAddress(), + 0, + "0x", + 0 + ) ) .to.emit(guard, "PreChecked") - .withArgs(executor.address); + .withArgs(await executor.getAddress()); }); it("pre-check gets called with signer when transaction is relayed", async () => { @@ -182,29 +194,29 @@ describe("GuardableModifier", async () => { await loadFixture(setupTests); await modifier.enableModule(signer.address); - await modifier.setGuard(guard.address); + await modifier.setGuard(await guard.getAddress()); - const inner = await avatar.populateTransaction.enableModule( + const inner = await avatar.enableModule.populateTransaction( "0xff00000000000000000000000000000000ff3456" ); const { from, ...transaction } = - await modifier.populateTransaction.execTransactionFromModuleReturnData( - avatar.address, + await modifier.execTransactionFromModuleReturnData.populateTransaction( + await avatar.getAddress(), 0, inner.data as string, 0 ); const signature = await sign( - modifier.address, + await modifier.getAddress(), transaction, keccak256(toUtf8Bytes("salt")), signer ); const transactionWithSig = { ...transaction, - to: modifier.address, + to: await modifier.getAddress(), data: `${transaction.data}${signature.slice(2)}`, value: 0, }; @@ -217,12 +229,17 @@ describe("GuardableModifier", async () => { it("pre-checks and reverts transaction if guard is set", async () => { const { avatar, executor, modifier, guard } = await loadFixture(setupTests); - await modifier.setGuard(guard.address); + await modifier.setGuard(await guard.getAddress()); await expect( modifier .connect(executor) - .execTransactionFromModuleReturnData(avatar.address, 1337, "0x", 0) + .execTransactionFromModuleReturnData( + await avatar.getAddress(), + 1337, + "0x", + 0 + ) ).to.be.revertedWith("Cannot send 1337"); }); @@ -233,19 +250,29 @@ describe("GuardableModifier", async () => { await expect( modifier .connect(executor) - .execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0) + .execTransactionFromModuleReturnData( + await avatar.getAddress(), + 0, + "0x", + 0 + ) ).not.to.emit(guard, "PostChecked"); }); it("post-checks transaction if guard is set", async () => { const { avatar, executor, modifier, guard } = await loadFixture(setupTests); - await modifier.setGuard(guard.address); + await modifier.setGuard(await guard.getAddress()); await expect( modifier .connect(executor) - .execTransactionFromModuleReturnData(avatar.address, 0, "0x", 0) + .execTransactionFromModuleReturnData( + await avatar.getAddress(), + 0, + "0x", + 0 + ) ) .to.emit(guard, "PostChecked") .withArgs(true); @@ -255,16 +282,16 @@ describe("GuardableModifier", async () => { async function sign( contract: string, - transaction: PopulatedTransaction, + transaction: TransactionLike, salt: string, - signer: SignerWithAddress + signer: Signer ) { const { domain, types, message } = typedDataForTransaction( { contract, chainId: 31337, salt }, transaction.data || "0x" ); - const signature = await signer._signTypedData(domain, types, message); + const signature = await signer.signTypedData(domain, types, message); return `${salt}${signature.slice(2)}`; } diff --git a/yarn.lock b/yarn.lock index ca9709c8..49ebf1c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@adraffy/ens-normalize@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" + integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== + "@babel/code-frame@^7.0.0": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" @@ -542,6 +547,13 @@ dependencies: "@noble/hashes" "1.3.1" +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" @@ -552,7 +564,7 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== -"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": +"@noble/hashes@1.3.2", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": version "1.3.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== @@ -717,17 +729,24 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/hardhat-chai-matchers@^1.0.5": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz#72a2e312e1504ee5dd73fe302932736432ba96bc" - integrity sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ== +"@nomicfoundation/hardhat-chai-matchers@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.3.tgz#f4c074d39b74bd283c99e2c2bf143e3cef51ae18" + integrity sha512-A40s7EAK4Acr8UP1Yudgi9GGD9Cca/K3LHt3DzmRIje14lBfHtg9atGQ7qK56vdPcTwKmeaGn30FzxMUfPGEMw== dependencies: - "@ethersproject/abi" "^5.1.2" "@types/chai-as-promised" "^7.1.3" chai-as-promised "^7.1.1" deep-eql "^4.0.1" ordinal "^1.0.3" +"@nomicfoundation/hardhat-ethers@^3.0.0": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz#0422c2123dec7c42e7fb2be8e1691f1d9708db56" + integrity sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw== + dependencies: + debug "^4.1.1" + lodash.isequal "^4.5.0" + "@nomicfoundation/hardhat-network-helpers@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.9.tgz#767449e8a2acda79306ac84626117583d95d25aa" @@ -735,10 +754,25 @@ dependencies: ethereumjs-util "^7.1.4" -"@nomicfoundation/hardhat-toolbox@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-2.0.2.tgz#ec95f23b53cb4e71a1a7091380fa223aad18f156" - integrity sha512-vnN1AzxbvpSx9pfdRHbUzTRIXpMLPXnUlkW855VaDk6N1pwRaQ2gNzEmFAABk4lWf11E00PKwFd/q27HuwYrYg== +"@nomicfoundation/hardhat-toolbox@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-4.0.0.tgz#eb1f619218dd1414fa161dfec92d3e5e53a2f407" + integrity sha512-jhcWHp0aHaL0aDYj8IJl80v4SZXWMS1A2XxXa1CA6pBiFfJKuZinCkO6wb+POAt0LIfXB3gA3AgdcOccrcwBwA== + +"@nomicfoundation/hardhat-verify@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.3.tgz#173557f8cfa53c8c9da23a326f54d24fe459ae68" + integrity sha512-ESbRu9by53wu6VvgwtMtm108RSmuNsVqXtzg061D+/4R7jaWh/Wl/8ve+p6SdDX7vA1Z3L02hDO1Q3BY4luLXQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^8.1.0" + chalk "^2.4.2" + debug "^4.1.1" + lodash.clonedeep "^4.5.0" + semver "^6.3.0" + table "^6.8.0" + undici "^5.14.0" "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1": version "0.1.1" @@ -806,7 +840,7 @@ "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.1" "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.1" -"@nomiclabs/hardhat-ethers@2.2.3": +"@nomiclabs/hardhat-ethers@^2.2.3": version "2.2.3" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz#b41053e360c31a32c2640c9a45ee981a7e603fe0" integrity sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg== @@ -1033,18 +1067,18 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@typechain/ethers-v5@^11.1.0": - version "11.1.2" - resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-11.1.2.tgz#82510c1744f37a2f906b9e0532ac18c0b74ffe69" - integrity sha512-ID6pqWkao54EuUQa0P5RgjvfA3MYqxUQKpbGKERbsjBW5Ra7EIXvbMlPp2pcP5IAdUkyMCFYsP2SN5q7mPdLDQ== +"@typechain/ethers-v6@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz#42fe214a19a8b687086c93189b301e2b878797ea" + integrity sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA== dependencies: lodash "^4.17.15" ts-essentials "^7.0.1" -"@typechain/hardhat@^6.1.5": - version "6.1.6" - resolved "https://registry.yarnpkg.com/@typechain/hardhat/-/hardhat-6.1.6.tgz#1a749eb35e5054c80df531cf440819cb347c62ea" - integrity sha512-BiVnegSs+ZHVymyidtK472syodx1sXYlYJJixZfRstHVGYTi8V1O7QG4nsjyb0PC/LORcq7sfBUcHto1y6UgJA== +"@typechain/hardhat@^9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@typechain/hardhat/-/hardhat-9.1.0.tgz#6985015f01dfb37ef2ca8a29c742d05890351ddc" + integrity sha512-mtaUlzLlkqTlfPwB3FORdejqBskSnh+Jl8AIJGjXNAQfRQ4ofHADPl1+oU7Z3pAJzmZbUXII8MhOLQltcHgKnA== dependencies: fs-extra "^9.1.0" @@ -1133,6 +1167,11 @@ dependencies: undici-types "~5.26.4" +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^10.0.3": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -1342,6 +1381,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -2714,6 +2758,19 @@ ethers@^5.7.0, ethers@^5.7.1, ethers@^5.7.2: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +ethers@^6.9.2: + version "6.9.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.9.2.tgz#6f4632f62e2350fa8354ff28624027a175ef85a4" + integrity sha512-YpkrtILnMQz5jSEsJQRTpduaGT/CXuLnUIuOYzHA0v/7c8IX91m2J48wSKjzGL5L9J/Us3tLoUdb+OwE3U+FFQ== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -3985,6 +4042,16 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -5538,6 +5605,11 @@ tsconfig-paths@^3.14.2: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -5847,6 +5919,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"