diff --git a/.github/workflows/contracts-tests.yml b/.github/workflows/contracts-tests.yml index b16b49ab..e4b3728b 100644 --- a/.github/workflows/contracts-tests.yml +++ b/.github/workflows/contracts-tests.yml @@ -36,4 +36,5 @@ jobs: - name: 'Test the contracts and generate the coverage report' run: 'yarn coverage' env: + NETWORK_NAME: ${{ vars.NETWORK_NAME }} INFURA_API_KEY: ${{ secrets.INFURA_API_KEY }} diff --git a/package.json b/package.json index 193e18bb..26e1cb04 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@aragon/osx-plugin-template", "description": "A template to fork from when developing an Aragon OSx plugin", - "version": "0.0.1-alpha.0", + "version": "0.0.1-alpha.1", "license": "AGPL-3.0-or-later", "author": { "name": "Aragon", diff --git a/packages/contracts/deploy/00_info/01_info.ts b/packages/contracts/deploy/00_info/01_info.ts index 9ebd2dc6..ade3e9bb 100644 --- a/packages/contracts/deploy/00_info/01_info.ts +++ b/packages/contracts/deploy/00_info/01_info.ts @@ -4,6 +4,7 @@ import { isLocal, } from '../../utils/helpers'; import {getNetworkByNameOrAlias} from '@aragon/osx-commons-configs'; +import {UnsupportedNetworkError} from '@aragon/osx-commons-sdk'; import {DeployFunction} from 'hardhat-deploy/types'; import {HardhatRuntimeEnvironment} from 'hardhat/types'; import path from 'path'; @@ -26,7 +27,10 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { ); // Fork the network provided in the `.env` file - const networkConfig = getNetworkByNameOrAlias(productionNetworkName)!; + const networkConfig = getNetworkByNameOrAlias(productionNetworkName); + if (networkConfig === null) { + throw new UnsupportedNetworkError(productionNetworkName); + } await hre.network.provider.request({ method: 'hardhat_reset', params: [ diff --git a/packages/contracts/deploy/10_create_repo/11_create_repo.ts b/packages/contracts/deploy/10_create_repo/11_create_repo.ts index 76fcef7d..b4ed1445 100644 --- a/packages/contracts/deploy/10_create_repo/11_create_repo.ts +++ b/packages/contracts/deploy/10_create_repo/11_create_repo.ts @@ -70,7 +70,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { ); console.log( - `'${pluginEnsDomain(hre)}' PluginRepo deployed at: ${pluginRepo.address}.` + `PluginRepo '${pluginEnsDomain(hre)}' deployed at '${pluginRepo.address}'.` ); hre.aragonToVerifyContracts.push({ diff --git a/packages/contracts/deploy/20_new_version/21_setup.ts b/packages/contracts/deploy/20_new_version/21_setup.ts index 041e76bc..7ef97b63 100644 --- a/packages/contracts/deploy/20_new_version/21_setup.ts +++ b/packages/contracts/deploy/20_new_version/21_setup.ts @@ -14,11 +14,15 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const {deploy} = deployments; const {deployer} = await getNamedAccounts(); - await deploy(PLUGIN_SETUP_CONTRACT_NAME, { + const res = await deploy(PLUGIN_SETUP_CONTRACT_NAME, { from: deployer, args: [], log: true, }); + + console.log( + `Deployed '${PLUGIN_SETUP_CONTRACT_NAME}' contract at '${res.address}'` + ); }; export default func; diff --git a/packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts b/packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts index a6d47f77..f862559c 100644 --- a/packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts +++ b/packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts @@ -3,7 +3,10 @@ import { getLatestNetworkDeployment, getNetworkNameByAlias, } from '@aragon/osx-commons-configs'; -import {PLUGIN_REPO_PERMISSIONS} from '@aragon/osx-commons-sdk'; +import { + PLUGIN_REPO_PERMISSIONS, + UnsupportedNetworkError, +} from '@aragon/osx-commons-sdk'; import {PluginRepo__factory} from '@aragon/osx-ethers'; import {BytesLike} from 'ethers'; import {DeployFunction} from 'hardhat-deploy/types'; @@ -15,6 +18,14 @@ type SemVer = [number, number, number]; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const [deployer] = await hre.ethers.getSigners(); const productionNetworkName: string = getProductionNetworkName(hre); + const network = getNetworkNameByAlias(productionNetworkName); + if (network === null) { + throw new UnsupportedNetworkError(productionNetworkName); + } + const networkDeployments = getLatestNetworkDeployment(network); + if (networkDeployments === null) { + throw `Deployments are not available on network ${network}.`; + } // Get PluginRepo const {pluginRepo, ensDomain} = await findPluginRepo(hre); @@ -28,8 +39,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // Get the latest `PluginRepo` implementation as the upgrade target const latestPluginRepoImplementation = PluginRepo__factory.connect( - getLatestNetworkDeployment(getNetworkNameByAlias(productionNetworkName)!)! - .PluginRepoBase.address, + networkDeployments.PluginRepoBase.address, deployer ); @@ -53,11 +63,11 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // Re-initialization will happen through a call to `function initializeFrom(uint8[3] calldata _previousProtocolVersion, bytes calldata _initData)` // that Aragon might add to the `PluginRepo` contract once it's required. /* - // Define the `initData` arguments that + // Define the `_initData` arguments const initData: BytesLike[] = []; // Encode the call to `function initializeFrom(uint8[3] calldata _previousProtocolVersion, bytes calldata _initData)` with `initData` const initializeFromCalldata = - newPluginRepoImplementation.interface.encodeFunctionData('initializeFrom', [ + latestPluginRepoImplementation.interface.encodeFunctionData('initializeFrom', [ current, initData, ]); @@ -102,11 +112,18 @@ func.skip = async (hre: HardhatRuntimeEnvironment) => { const [deployer] = await hre.ethers.getSigners(); const productionNetworkName: string = getProductionNetworkName(hre); + const network = getNetworkNameByAlias(productionNetworkName); + if (network === null) { + throw new UnsupportedNetworkError(productionNetworkName); + } + const networkDeployments = getLatestNetworkDeployment(network); + if (networkDeployments === null) { + throw `Deployments are not available on network ${network}.`; + } // Get the latest `PluginRepo` implementation as the upgrade target const latestPluginRepoImplementation = PluginRepo__factory.connect( - getLatestNetworkDeployment(getNetworkNameByAlias(productionNetworkName)!)! - .PluginRepoBase.address, + networkDeployments.PluginRepoBase.address, deployer ); diff --git a/packages/contracts/test/10_unit-testing/12_plugin-setup.ts b/packages/contracts/test/10_unit-testing/12_plugin-setup.ts index 75ceb99f..381580b2 100644 --- a/packages/contracts/test/10_unit-testing/12_plugin-setup.ts +++ b/packages/contracts/test/10_unit-testing/12_plugin-setup.ts @@ -24,6 +24,8 @@ type FixtureResult = { alice: SignerWithAddress; bob: SignerWithAddress; pluginSetup: MyPluginSetup; + prepareInstallationInputs: string; + prepareUninstallationInputs: string; daoMock: DAOMock; }; @@ -32,24 +34,36 @@ async function fixture(): Promise { const daoMock = await new DAOMock__factory(deployer).deploy(); const pluginSetup = await new MyPluginSetup__factory(deployer).deploy(); - return {deployer, alice, bob, pluginSetup, daoMock}; + const prepareInstallationInputs = ethers.utils.defaultAbiCoder.encode( + getNamedTypesFromMetadata( + buildMetadata.pluginSetup.prepareInstallation.inputs + ), + [defaultInitData.number] + ); + + const prepareUninstallationInputs = ethers.utils.defaultAbiCoder.encode( + getNamedTypesFromMetadata( + buildMetadata.pluginSetup.prepareUninstallation.inputs + ), + [] + ); + + return { + deployer, + alice, + bob, + pluginSetup, + prepareInstallationInputs, + prepareUninstallationInputs, + daoMock, + }; } describe(PLUGIN_SETUP_CONTRACT_NAME, function () { describe('prepareInstallation', async () => { - let initData: string; - - before(async () => { - initData = ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - buildMetadata.pluginSetup.prepareInstallation.inputs - ), - [defaultInitData.number] - ); - }); - it('returns the plugin, helpers, and permissions', async () => { - const {deployer, pluginSetup, daoMock} = await loadFixture(fixture); + const {deployer, pluginSetup, prepareInstallationInputs, daoMock} = + await loadFixture(fixture); const nonce = await ethers.provider.getTransactionCount( pluginSetup.address @@ -64,7 +78,7 @@ describe(PLUGIN_SETUP_CONTRACT_NAME, function () { preparedSetupData: {helpers, permissions}, } = await pluginSetup.callStatic.prepareInstallation( daoMock.address, - initData + prepareInstallationInputs ); expect(plugin).to.be.equal(anticipatedPluginAddress); @@ -80,7 +94,10 @@ describe(PLUGIN_SETUP_CONTRACT_NAME, function () { ], ]); - await pluginSetup.prepareInstallation(daoMock.address, initData); + await pluginSetup.prepareInstallation( + daoMock.address, + prepareInstallationInputs + ); const myPlugin = new MyPlugin__factory(deployer).attach(plugin); // initialization is correct @@ -91,17 +108,17 @@ describe(PLUGIN_SETUP_CONTRACT_NAME, function () { describe('prepareUninstallation', async () => { it('returns the permissions', async () => { - const {pluginSetup, daoMock} = await loadFixture(fixture); + const {pluginSetup, daoMock, prepareUninstallationInputs} = + await loadFixture(fixture); const dummyAddr = ADDRESS.ZERO; - const emptyData = '0x'; const permissions = await pluginSetup.callStatic.prepareUninstallation( daoMock.address, { plugin: dummyAddr, currentHelpers: [], - data: emptyData, + data: prepareUninstallationInputs, } ); diff --git a/packages/contracts/test/20_integration-testing/21_deployment.ts b/packages/contracts/test/20_integration-testing/21_deployment.ts index dd5633c0..1bdcfb7f 100644 --- a/packages/contracts/test/20_integration-testing/21_deployment.ts +++ b/packages/contracts/test/20_integration-testing/21_deployment.ts @@ -1,4 +1,4 @@ -import {METADATA} from '../../plugin-settings'; +import {METADATA, VERSION} from '../../plugin-settings'; import {getProductionNetworkName, findPluginRepo} from '../../utils/helpers'; import { getLatestNetworkDeployment, @@ -8,6 +8,7 @@ import { DAO_PERMISSIONS, PERMISSION_MANAGER_FLAGS, PLUGIN_REPO_PERMISSIONS, + UnsupportedNetworkError, toHex, uploadToIPFS, } from '@aragon/osx-commons-sdk'; @@ -66,13 +67,13 @@ describe(`Deployment on network '${productionNetworkName}'`, function () { const {pluginRepo} = await loadFixture(fixture); await pluginRepo['getVersion((uint8,uint16))']({ - release: 1, - build: 1, + release: VERSION.release, + build: VERSION.build, }); const results = await pluginRepo['getVersion((uint8,uint16))']({ - release: 1, - build: 1, + release: VERSION.release, + build: VERSION.build, }); const buildMetadataURI = `ipfs://${await uploadToIPFS( @@ -97,17 +98,26 @@ async function fixture(): Promise { const [deployer] = await ethers.getSigners(); - // Plugin repo registry - const pluginRepoRegistry = PluginRepoRegistry__factory.connect( - getLatestNetworkDeployment(getNetworkNameByAlias(productionNetworkName)!)! - .PluginRepoRegistryProxy.address, - deployer - ); - + // Plugin Repo const {pluginRepo, ensDomain} = await findPluginRepo(env); if (pluginRepo === null) { throw `PluginRepo '${ensDomain}' does not exist yet.`; } + const network = getNetworkNameByAlias(productionNetworkName); + if (network === null) { + throw new UnsupportedNetworkError(productionNetworkName); + } + const networkDeployments = getLatestNetworkDeployment(network); + if (networkDeployments === null) { + throw `Deployments are not available on network ${network}.`; + } + + // Plugin repo registry + const pluginRepoRegistry = PluginRepoRegistry__factory.connect( + networkDeployments.PluginRepoRegistryProxy.address, + deployer + ); + return {deployer, pluginRepo, pluginRepoRegistry}; } diff --git a/packages/contracts/test/20_integration-testing/22_setup-processing.ts b/packages/contracts/test/20_integration-testing/22_setup-processing.ts index 783a4d38..bb9da6af 100644 --- a/packages/contracts/test/20_integration-testing/22_setup-processing.ts +++ b/packages/contracts/test/20_integration-testing/22_setup-processing.ts @@ -12,7 +12,10 @@ import { getLatestNetworkDeployment, getNetworkNameByAlias, } from '@aragon/osx-commons-configs'; -import {getNamedTypesFromMetadata} from '@aragon/osx-commons-sdk'; +import { + UnsupportedNetworkError, + getNamedTypesFromMetadata, +} from '@aragon/osx-commons-sdk'; import { PluginSetupProcessor, PluginRepo, @@ -28,55 +31,55 @@ import env, {deployments, ethers} from 'hardhat'; const productionNetworkName = getProductionNetworkName(env); describe(`PluginSetup processing on network '${productionNetworkName}'`, function () { - context('Build 1', async () => { - it('installs & uninstalls', async () => { - const {deployer, psp, daoMock, pluginSetup, pluginSetupRef} = - await loadFixture(fixture); - - // Allow all authorized calls to happen - await daoMock.setHasPermissionReturnValueMock(true); - - // Install build 1. - const results = await installPLugin( - psp, - daoMock, - pluginSetupRef, - ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - METADATA.build.pluginSetup.prepareInstallation.inputs - ), - [123] - ) - ); - - const plugin = MyPlugin__factory.connect( - results.preparedEvent.args.plugin, - deployer - ); - - // Check implementation. - expect(await plugin.implementation()).to.be.eq( - await pluginSetup.implementation() - ); - - // Check state. - expect(await plugin.number()).to.eq(123); - - // Uninstall build 1. - await uninstallPLugin( - psp, - daoMock, - plugin, - pluginSetupRef, - ethers.utils.defaultAbiCoder.encode( - getNamedTypesFromMetadata( - METADATA.build.pluginSetup.prepareUninstallation.inputs - ), - [] + it('installs & uninstalls the current build', async () => { + const {deployer, psp, daoMock, pluginSetup, pluginSetupRef} = + await loadFixture(fixture); + + // Allow all authorized calls to happen + await daoMock.setHasPermissionReturnValueMock(true); + + // Install the current build. + const results = await installPLugin( + deployer, + psp, + daoMock, + pluginSetupRef, + ethers.utils.defaultAbiCoder.encode( + getNamedTypesFromMetadata( + METADATA.build.pluginSetup.prepareInstallation.inputs + ), + [123] + ) + ); + + const plugin = MyPlugin__factory.connect( + results.preparedEvent.args.plugin, + deployer + ); + + // Check implementation. + expect(await plugin.implementation()).to.be.eq( + await pluginSetup.implementation() + ); + + // Check state. + expect(await plugin.number()).to.eq(123); + + // Uninstall the current build. + await uninstallPLugin( + deployer, + psp, + daoMock, + plugin, + pluginSetupRef, + ethers.utils.defaultAbiCoder.encode( + getNamedTypesFromMetadata( + METADATA.build.pluginSetup.prepareUninstallation.inputs ), [] - ); - }); + ), + [] + ); }); }); @@ -99,10 +102,18 @@ async function fixture(): Promise { const [deployer, alice, bob] = await ethers.getSigners(); const daoMock = await new DAOMock__factory(deployer).deploy(); + const network = getNetworkNameByAlias(productionNetworkName); + if (network === null) { + throw new UnsupportedNetworkError(productionNetworkName); + } + const networkDeployments = getLatestNetworkDeployment(network); + if (networkDeployments === null) { + throw `Deployments are not available on network ${network}.`; + } + // Get the `PluginSetupProcessor` from the network const psp = PluginSetupProcessor__factory.connect( - getLatestNetworkDeployment(getNetworkNameByAlias(productionNetworkName)!)! - .PluginSetupProcessor.address, + networkDeployments.PluginSetupProcessor.address, deployer ); diff --git a/packages/contracts/test/20_integration-testing/test-helpers.ts b/packages/contracts/test/20_integration-testing/test-helpers.ts index 4e583736..a8712834 100644 --- a/packages/contracts/test/20_integration-testing/test-helpers.ts +++ b/packages/contracts/test/20_integration-testing/test-helpers.ts @@ -1,15 +1,22 @@ import {DAOMock, IPlugin} from '../../typechain'; import {hashHelpers} from '../../utils/helpers'; -import {findEvent} from '@aragon/osx-commons-sdk'; +import { + DAO_PERMISSIONS, + PLUGIN_SETUP_PROCESSOR_PERMISSIONS, + findEvent, +} from '@aragon/osx-commons-sdk'; import { PluginSetupProcessorEvents, PluginSetupProcessorStructs, PluginSetupProcessor, + DAOStructs, } from '@aragon/osx-ethers'; +import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {expect} from 'chai'; import {ContractTransaction} from 'ethers'; export async function installPLugin( + signer: SignerWithAddress, psp: PluginSetupProcessor, dao: DAOMock, pluginSetupRef: PluginSetupProcessorStructs.PluginSetupRefStruct, @@ -20,7 +27,7 @@ export async function installPLugin( preparedEvent: PluginSetupProcessorEvents.InstallationPreparedEvent; appliedEvent: PluginSetupProcessorEvents.InstallationAppliedEvent; }> { - const prepareTx = await psp.prepareInstallation(dao.address, { + const prepareTx = await psp.connect(signer).prepareInstallation(dao.address, { pluginSetupRef: pluginSetupRef, data: data, }); @@ -32,11 +39,20 @@ export async function installPLugin( ); const plugin = preparedEvent.args.plugin; + const preparedPermissions = preparedEvent.args.preparedSetupData.permissions; + + await checkPermissions( + preparedPermissions, + dao, + psp, + signer, + PLUGIN_SETUP_PROCESSOR_PERMISSIONS.APPLY_INSTALLATION_PERMISSION_ID + ); - const applyTx = await psp.applyInstallation(dao.address, { + const applyTx = await psp.connect(signer).applyInstallation(dao.address, { pluginSetupRef: pluginSetupRef, plugin: plugin, - permissions: preparedEvent.args.preparedSetupData.permissions, + permissions: preparedPermissions, helpersHash: hashHelpers(preparedEvent.args.preparedSetupData.helpers), }); @@ -50,6 +66,7 @@ export async function installPLugin( } export async function uninstallPLugin( + signer: SignerWithAddress, psp: PluginSetupProcessor, dao: DAOMock, plugin: IPlugin, @@ -62,14 +79,16 @@ export async function uninstallPLugin( preparedEvent: PluginSetupProcessorEvents.UninstallationPreparedEvent; appliedEvent: PluginSetupProcessorEvents.UninstallationAppliedEvent; }> { - const prepareTx = await psp.prepareUninstallation(dao.address, { - pluginSetupRef: pluginSetupRef, - setupPayload: { - plugin: plugin.address, - currentHelpers: currentHelpers, - data: data, - }, - }); + const prepareTx = await psp + .connect(signer) + .prepareUninstallation(dao.address, { + pluginSetupRef: pluginSetupRef, + setupPayload: { + plugin: plugin.address, + currentHelpers: currentHelpers, + data: data, + }, + }); const preparedEvent = await findEvent( @@ -79,7 +98,15 @@ export async function uninstallPLugin( const preparedPermissions = preparedEvent.args.permissions; - const applyTx = await psp.applyUninstallation(dao.address, { + await checkPermissions( + preparedPermissions, + dao, + psp, + signer, + PLUGIN_SETUP_PROCESSOR_PERMISSIONS.APPLY_UNINSTALLATION_PERMISSION_ID + ); + + const applyTx = await psp.connect(signer).applyUninstallation(dao.address, { plugin: plugin.address, pluginSetupRef: pluginSetupRef, permissions: preparedPermissions, @@ -93,8 +120,8 @@ export async function uninstallPLugin( return {prepareTx, applyTx, preparedEvent, appliedEvent}; } - export async function updatePlugin( + signer: SignerWithAddress, psp: PluginSetupProcessor, dao: DAOMock, plugin: IPlugin, @@ -112,7 +139,7 @@ export async function updatePlugin( pluginSetupRefUpdate.pluginSetupRepo ); - const prepareTx = await psp.prepareUpdate(dao.address, { + const prepareTx = await psp.connect(signer).prepareUpdate(dao.address, { currentVersionTag: pluginSetupRefCurrent.versionTag, newVersionTag: pluginSetupRefUpdate.versionTag, pluginSetupRepo: pluginSetupRefUpdate.pluginSetupRepo, @@ -128,11 +155,21 @@ export async function updatePlugin( psp.interface.getEvent('UpdatePrepared').name ); - const applyTx = await psp.applyUpdate(dao.address, { + const preparedPermissions = preparedEvent.args.preparedSetupData.permissions; + + await checkPermissions( + preparedPermissions, + dao, + psp, + signer, + PLUGIN_SETUP_PROCESSOR_PERMISSIONS.APPLY_UPDATE_PERMISSION_ID + ); + + const applyTx = await psp.connect(signer).applyUpdate(dao.address, { plugin: plugin.address, pluginSetupRef: pluginSetupRefUpdate, initData: preparedEvent.args.initData, - permissions: preparedEvent.args.preparedSetupData.permissions, + permissions: preparedPermissions, helpersHash: hashHelpers(preparedEvent.args.preparedSetupData.helpers), }); const appliedEvent = @@ -143,3 +180,35 @@ export async function updatePlugin( return {prepareTx, applyTx, preparedEvent, appliedEvent}; } + +async function checkPermissions( + preparedPermissions: DAOStructs.MultiTargetPermissionStruct[], + dao: DAOMock, + psp: PluginSetupProcessor, + signer: SignerWithAddress, + applyPermissionId: string +) { + if (preparedPermissions.length !== 0) { + if ( + !(await dao.hasPermission( + dao.address, + psp.address, + DAO_PERMISSIONS.ROOT_PERMISSION_ID, + [] + )) + ) { + throw `The 'PluginSetupProcessor' does not have 'ROOT_PERMISSION_ID' on the DAO and thus cannot process the list of permissions requested by the plugin setup.`; + } + } + if ( + signer.address !== dao.address && + !(await dao.hasPermission( + psp.address, + signer.address, + applyPermissionId, + [] + )) + ) { + throw `The used signer does not have the permission with ID '${applyPermissionId}' granted and thus cannot apply the setup`; + } +} diff --git a/packages/contracts/utils/helpers.ts b/packages/contracts/utils/helpers.ts index f40c8088..c76f6992 100644 --- a/packages/contracts/utils/helpers.ts +++ b/packages/contracts/utils/helpers.ts @@ -68,10 +68,17 @@ export async function findPluginRepo( ): Promise<{pluginRepo: PluginRepo | null; ensDomain: string}> { const [deployer] = await hre.ethers.getSigners(); const productionNetworkName: string = getProductionNetworkName(hre); + const network = getNetworkNameByAlias(productionNetworkName); + if (network === null) { + throw new UnsupportedNetworkError(productionNetworkName); + } + const networkDeployments = getLatestNetworkDeployment(network); + if (networkDeployments === null) { + throw `Deployments are not available on network ${network}.`; + } const registrar = ENSSubdomainRegistrar__factory.connect( - getLatestNetworkDeployment(getNetworkNameByAlias(productionNetworkName)!)! - .PluginENSSubdomainRegistrarProxy.address, + networkDeployments.PluginENSSubdomainRegistrarProxy.address, deployer ); diff --git a/packages/subgraph/package.json b/packages/subgraph/package.json index c00bb5cb..6fd0d40e 100644 --- a/packages/subgraph/package.json +++ b/packages/subgraph/package.json @@ -16,15 +16,14 @@ "clean": "rimraf deploy-output.txt subgraph.yaml ./build ./imported ./generated ./tests/.bin tests/.latest.json && yarn postinstall" }, "devDependencies": { - "@aragon/osx-ethers": "1.3.0", + "@aragon/osx-ethers": "1.4.0-alpha.0", + "@aragon/osx-commons-configs": "0.2.0", "@graphprotocol/graph-cli": "^0.51.0", "@graphprotocol/graph-ts": "^0.31.0", "cross-env": "^7.0.3", "dotenv": "^16.3.1", "matchstick-as": "^0.5.2", "mustache": "^4.2.0", - "@aragon/osx-ethers": "1.4.0-alpha.0", - "@aragon/osx-commons-configs": "0.2.0", "ts-morph": "^17.0.1", "ts-node": "^10.9.1", "typescript": "^5.2.2"