Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: moved subgraph from OSx #45

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 24 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,13 @@
# Aragon OSX Plugin Template [![Hardhat][hardhat-badge]][hardhat] [![License: AGPL v3][license-badge]][license]
# Multisig Plugin [![Hardhat][hardhat-badge]][hardhat] [![License: AGPL v3][license-badge]][license]

[hardhat]: https://hardhat.org/
[hardhat-badge]: https://img.shields.io/badge/Built%20with-Hardhat-FFDB1C.svg
[license]: https://opensource.org/licenses/AGPL-v3
[license-badge]: https://img.shields.io/badge/License-AGPL_v3-blue.svg

## Quickstart

After [creating a new repository from this template](https://github.com/new?template_name=osx-plugin-template-hardhat&template_owner=aragon), cloning, and opening it in your IDE, run

```sh
yarn install && cd packages/contracts && yarn install && yarn build && yarn typechain
```

Meanwhile, create an `.env` file from the `.env.example` file and put in the API keys for the services that you want to use.
You can now develop a plugin by changing the `src/MyPlugin.sol` and `src/MyPluginSetup.sol` files. You can directly import contracts from [Aragon OSx](https://github.com/aragon/osx) as well as OpenZeppelin's [openzeppelin-contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) and [openzeppelin-contracts-upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable) that are already set up for you.

```sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.17;

import {IDAO, PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol";
import {SafeCastUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol';

contract MyPlugin is PluginUUPSUpgradeable {
//...
};
```

The initial `MyPlugin` and `MyPluginSetup` example comes with unit test, integration test, and test helpers in the `package/contracts/test` folder that you can reuse.

To build and test your contracts, run

```sh
yarn clean && yarn build && yarn test
```

## Project

The root folder of the repo includes three subfolders:
The root folder of the repo includes two subfolders:

```markdown
.
Expand Down Expand Up @@ -202,22 +171,38 @@ Deploy the contracts to the local Hardhat Network (being forked from the network
yarn deploy --tags CreateRepo,NewVersion
```

This will create a plugin repo and publish the the first version (`v1.1`) of your plugin.
This will create a plugin repo and publish the first version (`v1.1`) of your plugin.
By adding the tag `TransferOwnershipToManagmentDao`, the `ROOT_PERMISSION_ID`, `MAINTAINER_PERMISSION_ID`, and
`UPGRADE_REPO_PERMISSION_ID` are granted to the management DAO and revoked from the deployer.
You can do this directly

```sh
yarn deploy --tags CreateRepo,NewVersion,TransferOwnershipToManagmentDao
```

or at a later point by executing

```sh
yarn deploy --tags TransferOwnershipToManagmentDao
```

Deploy the contracts to sepolia with
To deploy the contracts to a production network use the `--network` option, for example

```sh
yarn deploy --network sepolia --tags CreateRepo,NewVersion,Verification
yarn deploy --network sepolia --tags CreateRepo,NewVersion,TransferOwnershipToManagmentDao,Verification
```

This will create a plugin repo, publish the the first version (`v1.1`) of your plugin, and verfiy the contracts on sepolia.
This will create a plugin repo, publish the first version (`v1.1`) of your plugin, transfer permissions to the
management DAO, and lastly verfiy the contracts on sepolia.

If you want to deploy a new version of your plugin afterwards (e.g., `1.2`), simply change the `VERSION` entry in the `packages/contracts/plugin-settings.ts` file and use

```sh
yarn deploy --network sepolia --tags NewVersion,Verification
```

Note, that if the deploying account doesn't own the repo anymore, this will create a `createVersionProposalData-sepolia.json` containing the data for a management DAO signer to create a proposal publishing a new version.

Note, that if you include the `CreateRepo` tag after you've created your plugin repo already, this part of the script will be skipped.

#### Upgrading Your Plugin Repository
Expand All @@ -237,6 +222,8 @@ yarn deploy --network sepolia --tags UpgradeRepo
This will upgrade your plugin repo to the latest Aragon OSx protocol version implementation, which might include new features and security updates.
**For this to work, make sure that you are using the latest version of [this repository](https://github.com/aragon/osx-plugin-template-hardhat) in your fork.**

Note, that if the deploying account doesn't own the repo anymore, this will create a `upgradeRepoProposalData-sepolia.json` containing the data for a management DAO signer to create a proposal upgrading the repo.

## Subgraph

### Installing
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@aragon/osx-plugin-template",
"name": "@aragon/multisig-plugin",
"description": "A template to fork from when developing an Aragon OSx plugin",
"version": "0.0.1-alpha.1",
"license": "AGPL-3.0-or-later",
Expand Down
17 changes: 17 additions & 0 deletions packages/contracts/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Multisig Plugin

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to the [Aragon OSx Plugin Versioning Convention](https://devs.aragon.org/docs/osx/how-to-guides/plugin-development/publication/versioning).

## v1.3

### Added

- Copied files from [aragon/osx commit 1130df](https://github.com/aragon/osx/commit/1130dfce94fd294c4341e91a8f3faccc54cf43b7)

### Changed

- Used `ProxyLib` from `osx-commons-contracts` for the minimal proxy deployment in `MultisigSetup`.
- Hard-coded the `bytes32 internal constant EXECUTE_PERMISSION_ID` constant in `MultisigSetup` until it is available in `PermissionLib`.
2 changes: 1 addition & 1 deletion packages/contracts/deploy/20_new_version/21_setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
});

console.log(
`Deployed '${PLUGIN_SETUP_CONTRACT_NAME}' contract at '${res.address}'`
`Deployed contract '${PLUGIN_SETUP_CONTRACT_NAME}' at ${res.address}.`
);
};

Expand Down
6 changes: 3 additions & 3 deletions packages/contracts/deploy/20_new_version/22_setup_conclude.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {PLUGIN_SETUP_CONTRACT_NAME} from '../../plugin-settings';
import {MyPluginSetup__factory, MyPlugin__factory} from '../../typechain';
import {MultisigSetup__factory, Multisig__factory} from '../../typechain';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';
Expand All @@ -17,12 +17,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

// Get the plugin setup address
const setupDeployment = await deployments.get(PLUGIN_SETUP_CONTRACT_NAME);
const setup = MyPluginSetup__factory.connect(
const setup = MultisigSetup__factory.connect(
setupDeployment.address,
deployer
);
// Get the plugin implementation address
const implementation = MyPlugin__factory.connect(
const implementation = Multisig__factory.connect(
await setup.implementation(),
deployer
);
Expand Down
74 changes: 59 additions & 15 deletions packages/contracts/deploy/20_new_version/23_publish.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import {
METADATA,
PLUGIN_CONTRACT_NAME,
PLUGIN_REPO_ENS_SUBDOMAIN_NAME,
PLUGIN_SETUP_CONTRACT_NAME,
VERSION,
} from '../../plugin-settings';
import {
findPluginRepo,
getPastVersionCreatedEvents,
impersonatedManagementDaoSigner,
isLocal,
pluginEnsDomain,
} from '../../utils/helpers';
import {
PLUGIN_REPO_PERMISSIONS,
toHex,
uploadToIPFS,
} from '@aragon/osx-commons-sdk';
import {writeFile} from 'fs/promises';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';
Expand Down Expand Up @@ -77,25 +81,42 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
);
}

// Create Version
if (setup == undefined || setup?.receipt == undefined) {
throw Error('setup deployment unavailable');
}

const isDeployerMaintainer = await pluginRepo.isGranted(
pluginRepo.address,
deployer.address,
PLUGIN_REPO_PERMISSIONS.MAINTAINER_PERMISSION_ID,
[]
);

// If this is a local deployment and the deployer doesn't have `MAINTAINER_PERMISSION_ID` permission
// we impersonate the management DAO for integration testing purposes.
const signer =
isDeployerMaintainer || !isLocal(hre)
? deployer
: await impersonatedManagementDaoSigner(hre);

// Check if the signer has the permission to maintain the plugin repo
if (
await pluginRepo.callStatic.isGranted(
await pluginRepo.isGranted(
pluginRepo.address,
deployer.address,
signer.address,
PLUGIN_REPO_PERMISSIONS.MAINTAINER_PERMISSION_ID,
[]
)
) {
const tx = await pluginRepo.createVersion(
VERSION.release,
setup.address,
toHex(buildMetadataURI),
toHex(releaseMetadataURI)
);

if (setup == undefined || setup?.receipt == undefined) {
throw Error('setup deployment unavailable');
}
// Create the new version
const tx = await pluginRepo
.connect(signer)
.createVersion(
VERSION.release,
setup.address,
toHex(buildMetadataURI),
toHex(releaseMetadataURI)
);

await tx.wait();

Expand All @@ -110,8 +131,31 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
`Published ${PLUGIN_SETUP_CONTRACT_NAME} at ${setup.address} in PluginRepo ${PLUGIN_REPO_ENS_SUBDOMAIN_NAME} at ${pluginRepo.address}.`
);
} else {
throw Error(
`The new version cannot be published because the deployer ('${deployer.address}') is lacking the ${PLUGIN_REPO_PERMISSIONS.MAINTAINER_PERMISSION_ID} permission on repo (${pluginRepo.address}).`
// The deployer does not have `MAINTAINER_PERMISSION_ID` permission and we are not deploying to a production network,
// so we write the data into a file for a management DAO member to create a proposal from it.
const data = {
proposalTitle: `Publish '${PLUGIN_CONTRACT_NAME}' plugin v${VERSION.release}.${VERSION.build}`,
proposalSummary: `Publishes v${VERSION.release}.${VERSION.build} of the '${PLUGIN_CONTRACT_NAME}' plugin in the '${ensDomain}' plugin repo.`,
proposalDescription: `Publishes the '${PLUGIN_SETUP_CONTRACT_NAME}' deployed at '${setup.address}'
as v${VERSION.release}.${VERSION.build} in the '${ensDomain}' plugin repo at '${pluginRepo.address}',
with release metadata '${releaseMetadataURI}' and (immutable) build metadata '${buildMetadataURI}'.`,
actions: [
{
to: pluginRepo.address,
createVersion: {
_release: VERSION.release,
_pluginSetup: setup.address,
_buildMetadata: toHex(buildMetadataURI),
_releaseMetadata: toHex(releaseMetadataURI),
},
},
],
};

const path = `./createVersionProposalData-${hre.network.name}.json`;
await writeFile(path, JSON.stringify(data, null, 2));
console.log(
`Saved data to '${path}'. Use this to create a proposal on the managing DAO calling the 'createVersion' function on the ${ensDomain} plugin repo deployed at ${pluginRepo.address}.`
);
}
};
Expand Down
58 changes: 52 additions & 6 deletions packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import {findPluginRepo, getProductionNetworkName} from '../../utils/helpers';
import {
findPluginRepo,
getProductionNetworkName,
impersonatedManagementDaoSigner,
isLocal,
} from '../../utils/helpers';
import {
getLatestNetworkDeployment,
getNetworkNameByAlias,
Expand All @@ -9,6 +14,7 @@ import {
} from '@aragon/osx-commons-sdk';
import {PluginRepo__factory} from '@aragon/osx-ethers';
import {BytesLike} from 'ethers';
import {writeFile} from 'fs/promises';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';
Expand Down Expand Up @@ -74,11 +80,25 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
*/
const initializeFromCalldata: BytesLike = [];

// Check if deployer has the permission to upgrade the plugin repo
const isDeployerUpgrader = await pluginRepo.isGranted(
pluginRepo.address,
deployer.address,
PLUGIN_REPO_PERMISSIONS.UPGRADE_REPO_PERMISSION_ID,
[]
);

// If this is a local deployment and the deployer doesn't have `UPGRADE_REPO_PERMISSION_ID` permission
// we impersonate the management DAO for integration testing purposes.
const signer =
isDeployerUpgrader || !isLocal(hre)
? deployer
: await impersonatedManagementDaoSigner(hre);

// Check if the signer has the permission to upgrade the plugin repo
if (
await pluginRepo.isGranted(
pluginRepo.address,
deployer.address,
signer.address,
PLUGIN_REPO_PERMISSIONS.UPGRADE_REPO_PERMISSION_ID,
[]
)
Expand All @@ -94,9 +114,35 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
await pluginRepo.upgradeTo(latestPluginRepoImplementation.address);
}
} else {
throw Error(
`The new version cannot be published because the deployer ('${deployer.address}')
is lacking the ${PLUGIN_REPO_PERMISSIONS.UPGRADE_REPO_PERMISSION_ID} permission.`
// The deployer does not have `UPGRADE_REPO_PERMISSION_ID` permission and we are not deploying to a production network,
// so we write the data into a file for a management DAO member to create a proposal from it.
const upgradeAction =
initializeFromCalldata.length === 0
? {
to: pluginRepo.address,
upgradeTo: {
NewImplementation: latestPluginRepoImplementation.address,
},
}
: {
to: pluginRepo.address,
upgradeToAndCall: {
NewImplementation: latestPluginRepoImplementation.address,
Data: initializeFromCalldata,
PayableAmount: 0,
},
};
const data = {
proposalTitle: `Upgrade the '${ensDomain}' plugin repo`,
proposalSummary: `Upgrades '${ensDomain}' plugin repo at '${pluginRepo.address}',' plugin in the '${ensDomain}' plugin repo.`,
proposalDescription: `TODO: Describe the changes to the 'PluginRepo' implementation.`,
actions: [upgradeAction],
};

const path = `./upgradeRepoProposalData-${hre.network.name}.json`;
await writeFile(path, JSON.stringify(data, null, 2));
console.log(
`Saved data to '${path}'. Use this to create a proposal on the managing DAO calling the 'upgradeTo' or 'upgradeToAndCall' function on the ${ensDomain} plugin repo deployed at ${pluginRepo.address}.`
);
}
};
Expand Down
Loading
Loading