From 087cebfd76cad754235ca2657334ba09ed82131f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Thu, 24 Aug 2023 10:49:05 +0100 Subject: [PATCH] Initial scaffolding --- .github/workflows/js-client-tests.yml | 116 +++++++++--------- README.md | 45 ++++++- packages/contracts/src/MemberAccessPlugin.sol | 37 ++++++ .../contracts/src/MemberAccessPluginSetup.sol | 65 ++++++++++ packages/contracts/src/Migrations.sol | 3 +- .../src/PersonalSpaceVotingPlugin.sol | 37 ++++++ .../src/PersonalSpaceVotingPluginSetup.sol | 65 ++++++++++ .../src/{MyPlugin.sol => SpacePlugin.sol} | 4 +- ...MyPluginSetup.sol => SpacePluginSetup.sol} | 21 ++-- packages/contracts/src/SpaceVotingPlugin.sol | 37 ++++++ .../contracts/src/SpaceVotingPluginSetup.sol | 65 ++++++++++ .../test/integration-testing/deployment.ts | 68 +++++----- .../{simple-storage-common.ts => common.ts} | 0 .../test/unit-testing/simple-storage-setup.ts | 44 +++---- .../test/unit-testing/simple-storage.ts | 48 ++++---- 15 files changed, 501 insertions(+), 154 deletions(-) create mode 100644 packages/contracts/src/MemberAccessPlugin.sol create mode 100644 packages/contracts/src/MemberAccessPluginSetup.sol create mode 100644 packages/contracts/src/PersonalSpaceVotingPlugin.sol create mode 100644 packages/contracts/src/PersonalSpaceVotingPluginSetup.sol rename packages/contracts/src/{MyPlugin.sol => SpacePlugin.sol} (93%) rename packages/contracts/src/{MyPluginSetup.sol => SpacePluginSetup.sol} (74%) create mode 100644 packages/contracts/src/SpaceVotingPlugin.sol create mode 100644 packages/contracts/src/SpaceVotingPluginSetup.sol rename packages/contracts/test/unit-testing/{simple-storage-common.ts => common.ts} (100%) diff --git a/.github/workflows/js-client-tests.yml b/.github/workflows/js-client-tests.yml index 361b9ce..621522d 100644 --- a/.github/workflows/js-client-tests.yml +++ b/.github/workflows/js-client-tests.yml @@ -1,69 +1,69 @@ -name: 00-JS-Test +# name: 00-JS-Test -on: - workflow_call: - inputs: - run: - description: 'Forces a run if true' - required: false - type: boolean - secrets: - IPFS_API_KEY: - description: 'IPFS API Key' - required: true - push: - branches-ignore: - - develop - - main - paths: - - 'packages/js-client/**' - - '.github/workflows/js-client-*.yml' +# on: +# workflow_call: +# inputs: +# run: +# description: 'Forces a run if true' +# required: false +# type: boolean +# secrets: +# IPFS_API_KEY: +# description: 'IPFS API Key' +# required: true +# push: +# branches-ignore: +# - develop +# - main +# paths: +# - 'packages/js-client/**' +# - '.github/workflows/js-client-*.yml' -jobs: - build-js: - if: ${{ github.actor != 'arabot-1' || inputs.run }} - name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} +# jobs: +# build-js: +# if: ${{ github.actor != 'arabot-1' || inputs.run }} +# name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - node: ['16.x'] - os: [ubuntu-latest] +# runs-on: ${{ matrix.os }} +# strategy: +# matrix: +# node: ['16.x'] +# os: [ubuntu-latest] - steps: - - name: Checkout repo - uses: actions/checkout@v3 +# steps: +# - name: Checkout repo +# uses: actions/checkout@v3 - - name: Use Node ${{ matrix.node }} - uses: actions/setup-node@v3 - with: - cache: 'yarn' - node-version: ${{ matrix.node }} +# - name: Use Node ${{ matrix.node }} +# uses: actions/setup-node@v3 +# with: +# cache: 'yarn' +# node-version: ${{ matrix.node }} - - name: Install deps - run: yarn install --frozen-lockfile - working-directory: packages/js-client +# - name: Install deps +# run: yarn install --frozen-lockfile +# working-directory: packages/js-client - - name: Build Contracts Ethers typings - run: yarn run build - working-directory: packages/contracts-ethers +# - name: Build Contracts Ethers typings +# run: yarn run build +# working-directory: packages/contracts-ethers - - name: Build Contracts Ethers package - run: yarn run build:npm - working-directory: packages/contracts-ethers +# - name: Build Contracts Ethers package +# run: yarn run build:npm +# working-directory: packages/contracts-ethers - - name: Build JS Client - run: yarn run build - working-directory: packages/js-client +# - name: Build JS Client +# run: yarn run build +# working-directory: packages/js-client - - name: Integration test - run: yarn test integration --ci --coverage --passWithNoTests - working-directory: packages/js-client - env: - IPFS_API_KEY: ${{ secrets.IPFS_API_KEY }} +# - name: Integration test +# run: yarn test integration --ci --coverage --passWithNoTests +# working-directory: packages/js-client +# env: +# IPFS_API_KEY: ${{ secrets.IPFS_API_KEY }} - - name: Run unit tests - run: yarn test --testPathIgnorePatterns=/integration --ci --coverage --passWithNoTests - working-directory: packages/js-client - env: - IPFS_API_KEY: ${{ secrets.IPFS_API_KEY }} +# - name: Run unit tests +# run: yarn test --testPathIgnorePatterns=/integration --ci --coverage --passWithNoTests +# working-directory: packages/js-client +# env: +# IPFS_API_KEY: ${{ secrets.IPFS_API_KEY }} diff --git a/README.md b/README.md index 5dffb70..5bdcd7d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,44 @@ -# 🚧 UNDER CONSTRUCTION 🚧 +# Geo Browser - Aragon OSx -## License +The following project contains the plugin smart contracts providing the foundation of the Geo Browser project. See `packages/contracts` and `packages/contracts-ethers`. -This project is licensed under AGPL-3.0-or-later. +A template for a future JS client and a Subgraph indexer is also provided. + +## Contracts + +### SpacePlugin + +Acts as the source of truth regarding the Space associated to the DAO. It is in charge of emitting the events that notify new content being approved and it also emits events accepting a certain DAO as a Subpspace. + +- SpacePlugin +- SpacePluginSetup + +### MemberAccess + +Provides a simple way for any address to request membership on a space. Editors can approve it. + +- MemberAccessPlugin +- MemberAccessPluginSetup + +### SpaceVotingPlugin + +Default governance plugin for spaces, where all proposals are voted by editors. + +- SpaceVotingPlugin +- SpaceVotingPlugin + +### PersonalSpaceVotingPlugin + +Governance plugin providing the default implementation for personal spaces, where addresses with editor permissioin can apply proposals right away. + +- PersonalSpaceVotingPlugin +- PersonalSpaceVotingPlugin + +## Getting started + +``` +yarn +cd packages/contracts +yarn build +yarn test +``` diff --git a/packages/contracts/src/MemberAccessPlugin.sol b/packages/contracts/src/MemberAccessPlugin.sol new file mode 100644 index 0000000..70f3082 --- /dev/null +++ b/packages/contracts/src/MemberAccessPlugin.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.8; + +import {IDAO, PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol"; + +/// @title MemberAccessPlugin +/// @dev Release 1, Build 1 +contract MemberAccessPlugin is PluginUUPSUpgradeable { + bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); + + uint256 public number; // added in build 1 + + /// @notice Emitted when a number is stored. + /// @param number The number. + event NumberStored(uint256 number); + + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the plugin when build 1 is installed. + /// @param _number The number to be stored. + function initialize(IDAO _dao, uint256 _number) external initializer { + __PluginUUPSUpgradeable_init(_dao); + number = _number; + + emit NumberStored({number: _number}); + } + + /// @notice Stores a new number to storage. Caller needs STORE_PERMISSION. + /// @param _number The number to be stored. + function storeNumber(uint256 _number) external auth(STORE_PERMISSION_ID) { + number = _number; + + emit NumberStored({number: _number}); + } +} diff --git a/packages/contracts/src/MemberAccessPluginSetup.sol b/packages/contracts/src/MemberAccessPluginSetup.sol new file mode 100644 index 0000000..e3695bc --- /dev/null +++ b/packages/contracts/src/MemberAccessPluginSetup.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.8; + +import {PermissionLib} from "@aragon/osx/core/permission/PermissionLib.sol"; +import {PluginSetup, IPluginSetup} from "@aragon/osx/framework/plugin/setup/PluginSetup.sol"; +import {MemberAccessPlugin} from "./MemberAccessPlugin.sol"; + +/// @title MemberAccessPluginSetup +/// @dev Release 1, Build 1 +contract MemberAccessPluginSetup is PluginSetup { + address private immutable pluginImplementation; + bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); + + constructor() { + pluginImplementation = address(new MemberAccessPlugin()); + } + + /// @inheritdoc IPluginSetup + function prepareInstallation( + address _dao, + bytes memory _data + ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { + uint256 number = abi.decode(_data, (uint256)); + + plugin = createERC1967Proxy( + pluginImplementation, + abi.encodeWithSelector(MemberAccessPlugin.initialize.selector, _dao, number) + ); + + PermissionLib.MultiTargetPermission[] + memory permissions = new PermissionLib.MultiTargetPermission[](1); + + permissions[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: STORE_PERMISSION_ID + }); + + preparedSetupData.permissions = permissions; + } + + /// @inheritdoc IPluginSetup + function prepareUninstallation( + address _dao, + SetupPayload calldata _payload + ) external pure returns (PermissionLib.MultiTargetPermission[] memory permissions) { + permissions = new PermissionLib.MultiTargetPermission[](1); + + permissions[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: STORE_PERMISSION_ID + }); + } + + /// @inheritdoc IPluginSetup + function implementation() external view returns (address) { + return pluginImplementation; + } +} diff --git a/packages/contracts/src/Migrations.sol b/packages/contracts/src/Migrations.sol index fd5c435..be391ec 100644 --- a/packages/contracts/src/Migrations.sol +++ b/packages/contracts/src/Migrations.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -pragma solidity 0.8.17; +pragma solidity ^0.8.8; // Import all contracts from other repositories to make the openzeppelin-upgrades package work to deploy things. // See related issue here https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/86 +import {DAOFactory} from "@aragon/osx/framework/dao/DAOFactory.sol"; import {PluginSetupProcessor} from "@aragon/osx/framework/plugin/setup/PluginSetupProcessor.sol"; import {PluginRepoFactory} from "@aragon/osx/framework/plugin/repo/PluginRepoFactory.sol"; diff --git a/packages/contracts/src/PersonalSpaceVotingPlugin.sol b/packages/contracts/src/PersonalSpaceVotingPlugin.sol new file mode 100644 index 0000000..dbe84e9 --- /dev/null +++ b/packages/contracts/src/PersonalSpaceVotingPlugin.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.8; + +import {IDAO, PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol"; + +/// @title PersonalSpaceVotingPlugin +/// @dev Release 1, Build 1 +contract PersonalSpaceVotingPlugin is PluginUUPSUpgradeable { + bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); + + uint256 public number; // added in build 1 + + /// @notice Emitted when a number is stored. + /// @param number The number. + event NumberStored(uint256 number); + + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the plugin when build 1 is installed. + /// @param _number The number to be stored. + function initialize(IDAO _dao, uint256 _number) external initializer { + __PluginUUPSUpgradeable_init(_dao); + number = _number; + + emit NumberStored({number: _number}); + } + + /// @notice Stores a new number to storage. Caller needs STORE_PERMISSION. + /// @param _number The number to be stored. + function storeNumber(uint256 _number) external auth(STORE_PERMISSION_ID) { + number = _number; + + emit NumberStored({number: _number}); + } +} diff --git a/packages/contracts/src/PersonalSpaceVotingPluginSetup.sol b/packages/contracts/src/PersonalSpaceVotingPluginSetup.sol new file mode 100644 index 0000000..31b2a5e --- /dev/null +++ b/packages/contracts/src/PersonalSpaceVotingPluginSetup.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.8; + +import {PermissionLib} from "@aragon/osx/core/permission/PermissionLib.sol"; +import {PluginSetup, IPluginSetup} from "@aragon/osx/framework/plugin/setup/PluginSetup.sol"; +import {PersonalSpaceVotingPlugin} from "./PersonalSpaceVotingPlugin.sol"; + +/// @title PersonalSpaceVotingPluginSetup +/// @dev Release 1, Build 1 +contract PersonalSpaceVotingPluginSetup is PluginSetup { + address private immutable pluginImplementation; + bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); + + constructor() { + pluginImplementation = address(new PersonalSpaceVotingPlugin()); + } + + /// @inheritdoc IPluginSetup + function prepareInstallation( + address _dao, + bytes memory _data + ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { + uint256 number = abi.decode(_data, (uint256)); + + plugin = createERC1967Proxy( + pluginImplementation, + abi.encodeWithSelector(PersonalSpaceVotingPlugin.initialize.selector, _dao, number) + ); + + PermissionLib.MultiTargetPermission[] + memory permissions = new PermissionLib.MultiTargetPermission[](1); + + permissions[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: STORE_PERMISSION_ID + }); + + preparedSetupData.permissions = permissions; + } + + /// @inheritdoc IPluginSetup + function prepareUninstallation( + address _dao, + SetupPayload calldata _payload + ) external pure returns (PermissionLib.MultiTargetPermission[] memory permissions) { + permissions = new PermissionLib.MultiTargetPermission[](1); + + permissions[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: STORE_PERMISSION_ID + }); + } + + /// @inheritdoc IPluginSetup + function implementation() external view returns (address) { + return pluginImplementation; + } +} diff --git a/packages/contracts/src/MyPlugin.sol b/packages/contracts/src/SpacePlugin.sol similarity index 93% rename from packages/contracts/src/MyPlugin.sol rename to packages/contracts/src/SpacePlugin.sol index ddc8954..e100939 100644 --- a/packages/contracts/src/MyPlugin.sol +++ b/packages/contracts/src/SpacePlugin.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.8; import {IDAO, PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol"; -/// @title MyPlugin +/// @title SpacePlugin /// @dev Release 1, Build 1 -contract MyPlugin is PluginUUPSUpgradeable { +contract SpacePlugin is PluginUUPSUpgradeable { bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); uint256 public number; // added in build 1 diff --git a/packages/contracts/src/MyPluginSetup.sol b/packages/contracts/src/SpacePluginSetup.sol similarity index 74% rename from packages/contracts/src/MyPluginSetup.sol rename to packages/contracts/src/SpacePluginSetup.sol index 68d159b..a272d90 100644 --- a/packages/contracts/src/MyPluginSetup.sol +++ b/packages/contracts/src/SpacePluginSetup.sol @@ -4,15 +4,16 @@ pragma solidity ^0.8.8; import {PermissionLib} from "@aragon/osx/core/permission/PermissionLib.sol"; import {PluginSetup, IPluginSetup} from "@aragon/osx/framework/plugin/setup/PluginSetup.sol"; -import {MyPlugin} from "./MyPlugin.sol"; +import {SpacePlugin} from "./SpacePlugin.sol"; -/// @title MyPluginSetup +/// @title SpacePluginSetup /// @dev Release 1, Build 1 -contract MyPluginSetup is PluginSetup { - address private immutable myPluginImplementation; +contract SpacePluginSetup is PluginSetup { + address private immutable pluginImplementation; + bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); constructor() { - myPluginImplementation = address(new MyPlugin()); + pluginImplementation = address(new SpacePlugin()); } /// @inheritdoc IPluginSetup @@ -23,8 +24,8 @@ contract MyPluginSetup is PluginSetup { uint256 number = abi.decode(_data, (uint256)); plugin = createERC1967Proxy( - myPluginImplementation, - abi.encodeWithSelector(MyPlugin.initialize.selector, _dao, number) + pluginImplementation, + abi.encodeWithSelector(SpacePlugin.initialize.selector, _dao, number) ); PermissionLib.MultiTargetPermission[] @@ -35,7 +36,7 @@ contract MyPluginSetup is PluginSetup { where: plugin, who: _dao, condition: PermissionLib.NO_CONDITION, - permissionId: keccak256("STORE_PERMISSION") + permissionId: STORE_PERMISSION_ID }); preparedSetupData.permissions = permissions; @@ -53,12 +54,12 @@ contract MyPluginSetup is PluginSetup { where: _payload.plugin, who: _dao, condition: PermissionLib.NO_CONDITION, - permissionId: keccak256("STORE_PERMISSION") + permissionId: STORE_PERMISSION_ID }); } /// @inheritdoc IPluginSetup function implementation() external view returns (address) { - return myPluginImplementation; + return pluginImplementation; } } diff --git a/packages/contracts/src/SpaceVotingPlugin.sol b/packages/contracts/src/SpaceVotingPlugin.sol new file mode 100644 index 0000000..9345ba9 --- /dev/null +++ b/packages/contracts/src/SpaceVotingPlugin.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.8; + +import {IDAO, PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol"; + +/// @title SpaceVotingPlugin +/// @dev Release 1, Build 1 +contract SpaceVotingPlugin is PluginUUPSUpgradeable { + bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); + + uint256 public number; // added in build 1 + + /// @notice Emitted when a number is stored. + /// @param number The number. + event NumberStored(uint256 number); + + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the plugin when build 1 is installed. + /// @param _number The number to be stored. + function initialize(IDAO _dao, uint256 _number) external initializer { + __PluginUUPSUpgradeable_init(_dao); + number = _number; + + emit NumberStored({number: _number}); + } + + /// @notice Stores a new number to storage. Caller needs STORE_PERMISSION. + /// @param _number The number to be stored. + function storeNumber(uint256 _number) external auth(STORE_PERMISSION_ID) { + number = _number; + + emit NumberStored({number: _number}); + } +} diff --git a/packages/contracts/src/SpaceVotingPluginSetup.sol b/packages/contracts/src/SpaceVotingPluginSetup.sol new file mode 100644 index 0000000..7f3dc16 --- /dev/null +++ b/packages/contracts/src/SpaceVotingPluginSetup.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.8; + +import {PermissionLib} from "@aragon/osx/core/permission/PermissionLib.sol"; +import {PluginSetup, IPluginSetup} from "@aragon/osx/framework/plugin/setup/PluginSetup.sol"; +import {SpaceVotingPlugin} from "./SpaceVotingPlugin.sol"; + +/// @title SpaceVotingPluginSetup +/// @dev Release 1, Build 1 +contract SpaceVotingPluginSetup is PluginSetup { + address private immutable pluginImplementation; + bytes32 public constant STORE_PERMISSION_ID = keccak256("STORE_PERMISSION"); + + constructor() { + pluginImplementation = address(new SpaceVotingPlugin()); + } + + /// @inheritdoc IPluginSetup + function prepareInstallation( + address _dao, + bytes memory _data + ) external returns (address plugin, PreparedSetupData memory preparedSetupData) { + uint256 number = abi.decode(_data, (uint256)); + + plugin = createERC1967Proxy( + pluginImplementation, + abi.encodeWithSelector(SpaceVotingPlugin.initialize.selector, _dao, number) + ); + + PermissionLib.MultiTargetPermission[] + memory permissions = new PermissionLib.MultiTargetPermission[](1); + + permissions[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Grant, + where: plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: STORE_PERMISSION_ID + }); + + preparedSetupData.permissions = permissions; + } + + /// @inheritdoc IPluginSetup + function prepareUninstallation( + address _dao, + SetupPayload calldata _payload + ) external pure returns (PermissionLib.MultiTargetPermission[] memory permissions) { + permissions = new PermissionLib.MultiTargetPermission[](1); + + permissions[0] = PermissionLib.MultiTargetPermission({ + operation: PermissionLib.Operation.Revoke, + where: _payload.plugin, + who: _dao, + condition: PermissionLib.NO_CONDITION, + permissionId: STORE_PERMISSION_ID + }); + } + + /// @inheritdoc IPluginSetup + function implementation() external view returns (address) { + return pluginImplementation; + } +} diff --git a/packages/contracts/test/integration-testing/deployment.ts b/packages/contracts/test/integration-testing/deployment.ts index 4cf6b72..50138ea 100644 --- a/packages/contracts/test/integration-testing/deployment.ts +++ b/packages/contracts/test/integration-testing/deployment.ts @@ -1,22 +1,22 @@ import { - PluginRepo, MyPluginSetup, MyPluginSetup__factory, -} from '../../typechain'; -import {getPluginInfo, osxContracts} from '../../utils/helpers'; -import {toHex} from '../../utils/ipfs'; -import {PluginRepoRegistry__factory} from '@aragon/osx-ethers'; -import {PluginRepoRegistry} from '@aragon/osx-ethers'; -import {PluginRepo__factory} from '@aragon/osx-ethers'; -import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; -import {expect} from 'chai'; -import {deployments, ethers} from 'hardhat'; + PluginRepo, +} from "../../typechain"; +import { getPluginInfo, osxContracts } from "../../utils/helpers"; +import { toHex } from "../../utils/ipfs"; +import { PluginRepoRegistry__factory } from "@aragon/osx-ethers"; +import { PluginRepoRegistry } from "@aragon/osx-ethers"; +import { PluginRepo__factory } from "@aragon/osx-ethers"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { expect } from "chai"; +import { deployments, ethers } from "hardhat"; async function deployAll() { await deployments.fixture(); } -describe('PluginRepo Deployment', function () { +describe("PluginRepo Deployment", function () { let alice: SignerWithAddress; let repoRegistry: PluginRepoRegistry; let pluginRepo: PluginRepo; @@ -24,7 +24,7 @@ describe('PluginRepo Deployment', function () { before(async () => { const hardhatForkNetwork = process.env.NETWORK_NAME ? process.env.NETWORK_NAME - : 'mainnet'; + : "mainnet"; [alice] = await ethers.getSigners(); @@ -35,71 +35,71 @@ describe('PluginRepo Deployment', function () { await deployAll(); // Print info - console.log(JSON.stringify(getPluginInfo('hardhat')['hardhat'], null, 2)); + console.log(JSON.stringify(getPluginInfo("hardhat")["hardhat"], null, 2)); // plugin repo registry repoRegistry = PluginRepoRegistry__factory.connect( - osxContracts[hardhatForkNetwork]['PluginRepoRegistry'], - alice + osxContracts[hardhatForkNetwork]["PluginRepoRegistry"], + alice, ); pluginRepo = PluginRepo__factory.connect( - getPluginInfo('hardhat')['hardhat'].address, - alice + getPluginInfo("hardhat")["hardhat"].address, + alice, ); }); - it('creates the repo', async () => { + it("creates the repo", async () => { expect(await repoRegistry.entries(pluginRepo.address)).to.be.true; }); - it('makes the deployer the repo maintainer', async () => { + it("makes the deployer the repo maintainer", async () => { expect( await pluginRepo.isGranted( pluginRepo.address, alice.address, - ethers.utils.id('ROOT_PERMISSION'), - ethers.constants.AddressZero - ) + ethers.utils.id("ROOT_PERMISSION"), + ethers.constants.AddressZero, + ), ).to.be.true; expect( await pluginRepo.isGranted( pluginRepo.address, alice.address, - ethers.utils.id('UPGRADE_REPO_PERMISSION'), - ethers.constants.AddressZero - ) + ethers.utils.id("UPGRADE_REPO_PERMISSION"), + ethers.constants.AddressZero, + ), ).to.be.true; expect( await pluginRepo.isGranted( pluginRepo.address, alice.address, - ethers.utils.id('MAINTAINER_PERMISSION'), - ethers.constants.AddressZero - ) + ethers.utils.id("MAINTAINER_PERMISSION"), + ethers.constants.AddressZero, + ), ).to.be.true; }); - context('PluginSetup Publication', async () => { + context("PluginSetup Publication", async () => { let setup: MyPluginSetup; before(async () => { setup = MyPluginSetup__factory.connect( - (await deployments.get('MyPluginSetup')).address, - alice + (await deployments.get("MyPluginSetup")).address, + alice, ); }); - it('registerd the setup', async () => { - const results = await pluginRepo['getVersion((uint8,uint16))']({ + it("registerd the setup", async () => { + const results = await pluginRepo["getVersion((uint8,uint16))"]({ release: 1, build: 1, }); expect(results.pluginSetup).to.equal(setup.address); expect(results.buildMetadata).to.equal( - toHex('ipfs://QmY919VZ9gkeF6L169qQo89ucsUB9ScTaJVbGn8vMGGHxr') + toHex("ipfs://QmY919VZ9gkeF6L169qQo89ucsUB9ScTaJVbGn8vMGGHxr"), ); }); }); diff --git a/packages/contracts/test/unit-testing/simple-storage-common.ts b/packages/contracts/test/unit-testing/common.ts similarity index 100% rename from packages/contracts/test/unit-testing/simple-storage-common.ts rename to packages/contracts/test/unit-testing/common.ts diff --git a/packages/contracts/test/unit-testing/simple-storage-setup.ts b/packages/contracts/test/unit-testing/simple-storage-setup.ts index ff37f3b..422b8d3 100644 --- a/packages/contracts/test/unit-testing/simple-storage-setup.ts +++ b/packages/contracts/test/unit-testing/simple-storage-setup.ts @@ -1,24 +1,24 @@ -import {PLUGIN_SETUP_CONTRACT_NAME} from '../../plugin-settings'; -import buildMetadata from '../../src/build-metadata.json'; +import { PLUGIN_SETUP_CONTRACT_NAME } from "../../plugin-settings"; +import buildMetadata from "../../src/build-metadata.json"; import { DAO, + MyPlugin__factory, MyPluginSetup, MyPluginSetup__factory, - MyPlugin__factory, -} from '../../typechain'; -import {deployTestDao} from '../helpers/test-dao'; -import {Operation, getNamedTypesFromMetadata} from '../helpers/types'; -import {defaultInitData} from './simple-storage'; +} from "../../typechain"; +import { deployTestDao } from "../helpers/test-dao"; +import { getNamedTypesFromMetadata, Operation } from "../helpers/types"; +import { defaultInitData } from "./simple-storage"; import { + abiCoder, ADDRESS_ZERO, EMPTY_DATA, NO_CONDITION, STORE_PERMISSION_ID, - abiCoder, -} from './simple-storage-common'; -import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; -import {expect} from 'chai'; -import {ethers} from 'hardhat'; +} from "./common"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { expect } from "chai"; +import { ethers } from "hardhat"; describe(PLUGIN_SETUP_CONTRACT_NAME, function () { let alice: SignerWithAddress; @@ -34,21 +34,21 @@ describe(PLUGIN_SETUP_CONTRACT_NAME, function () { myPluginSetup = await MyPluginSetup.deploy(); }); - describe('prepareInstallation', async () => { + describe("prepareInstallation", async () => { let initData: string; before(async () => { initData = abiCoder.encode( getNamedTypesFromMetadata( - buildMetadata.pluginSetup.prepareInstallation.inputs + buildMetadata.pluginSetup.prepareInstallation.inputs, ), - [defaultInitData.number] + [defaultInitData.number], ); }); - it('returns the plugin, helpers, and permissions', async () => { + it("returns the plugin, helpers, and permissions", async () => { const nonce = await ethers.provider.getTransactionCount( - myPluginSetup.address + myPluginSetup.address, ); const anticipatedPluginAddress = ethers.utils.getContractAddress({ from: myPluginSetup.address, @@ -57,10 +57,10 @@ describe(PLUGIN_SETUP_CONTRACT_NAME, function () { const { plugin, - preparedSetupData: {helpers, permissions}, + preparedSetupData: { helpers, permissions }, } = await myPluginSetup.callStatic.prepareInstallation( dao.address, - initData + initData, ); expect(plugin).to.be.equal(anticipatedPluginAddress); @@ -85,8 +85,8 @@ describe(PLUGIN_SETUP_CONTRACT_NAME, function () { }); }); - describe('prepareUninstallation', async () => { - it('returns the permissions', async () => { + describe("prepareUninstallation", async () => { + it("returns the permissions", async () => { const dummyAddr = ADDRESS_ZERO; const permissions = await myPluginSetup.callStatic.prepareUninstallation( @@ -95,7 +95,7 @@ describe(PLUGIN_SETUP_CONTRACT_NAME, function () { plugin: dummyAddr, currentHelpers: [], data: EMPTY_DATA, - } + }, ); expect(permissions.length).to.be.equal(1); diff --git a/packages/contracts/test/unit-testing/simple-storage.ts b/packages/contracts/test/unit-testing/simple-storage.ts index cd30c6b..a5f97b8 100644 --- a/packages/contracts/test/unit-testing/simple-storage.ts +++ b/packages/contracts/test/unit-testing/simple-storage.ts @@ -1,15 +1,15 @@ -import {PLUGIN_CONTRACT_NAME} from '../../plugin-settings'; -import {DAO, MyPlugin, MyPlugin__factory} from '../../typechain'; -import '../../typechain/src/MyPlugin'; -import {deployWithProxy} from '../../utils/helpers'; -import {deployTestDao} from '../helpers/test-dao'; -import {STORE_PERMISSION_ID} from './simple-storage-common'; -import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; -import {expect} from 'chai'; -import {BigNumber} from 'ethers'; -import {ethers} from 'hardhat'; +import { PLUGIN_CONTRACT_NAME } from "../../plugin-settings"; +import { DAO, MyPlugin, MyPlugin__factory } from "../../typechain"; +import "../../typechain/src/MyPlugin"; +import { deployWithProxy } from "../../utils/helpers"; +import { deployTestDao } from "../helpers/test-dao"; +import { STORE_PERMISSION_ID } from "./common"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { expect } from "chai"; +import { BigNumber } from "ethers"; +import { ethers } from "hardhat"; -export type InitData = {number: BigNumber}; +export type InitData = { number: BigNumber }; export const defaultInitData: InitData = { number: BigNumber.from(123), }; @@ -25,7 +25,7 @@ describe(PLUGIN_CONTRACT_NAME, function () { [alice, bob] = await ethers.getSigners(); dao = await deployTestDao(alice); - defaultInput = {number: BigNumber.from(123)}; + defaultInput = { number: BigNumber.from(123) }; }); beforeEach(async () => { @@ -34,44 +34,44 @@ describe(PLUGIN_CONTRACT_NAME, function () { await myPlugin.initialize(dao.address, defaultInput.number); }); - describe('initialize', async () => { - it('reverts if trying to re-initialize', async () => { + describe("initialize", async () => { + it("reverts if trying to re-initialize", async () => { await expect( - myPlugin.initialize(dao.address, defaultInput.number) - ).to.be.revertedWith('Initializable: contract is already initialized'); + myPlugin.initialize(dao.address, defaultInput.number), + ).to.be.revertedWith("Initializable: contract is already initialized"); }); - it('stores the number', async () => { + it("stores the number", async () => { expect(await myPlugin.number()).to.equal(defaultInput.number); }); }); - describe('storeNumber', async () => { + describe("storeNumber", async () => { const newNumber = BigNumber.from(456); beforeEach(async () => { await dao.grant(myPlugin.address, alice.address, STORE_PERMISSION_ID); }); - it('reverts if sender lacks permission', async () => { + it("reverts if sender lacks permission", async () => { await expect(myPlugin.connect(bob).storeNumber(newNumber)) - .to.be.revertedWithCustomError(myPlugin, 'DaoUnauthorized') + .to.be.revertedWithCustomError(myPlugin, "DaoUnauthorized") .withArgs( dao.address, myPlugin.address, bob.address, - STORE_PERMISSION_ID + STORE_PERMISSION_ID, ); }); - it('stores the number', async () => { + it("stores the number", async () => { await expect(myPlugin.storeNumber(newNumber)).to.not.be.reverted; expect(await myPlugin.number()).to.equal(newNumber); }); - it('emits the NumberStored event', async () => { + it("emits the NumberStored event", async () => { await expect(myPlugin.storeNumber(newNumber)) - .to.emit(myPlugin, 'NumberStored') + .to.emit(myPlugin, "NumberStored") .withArgs(newNumber); }); });