Skip to content

Commit

Permalink
refactor: moved over and adapted multisig script
Browse files Browse the repository at this point in the history
  • Loading branch information
heueristik committed Mar 7, 2024
1 parent a76ae73 commit a997fe8
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 215 deletions.
34 changes: 0 additions & 34 deletions packages/contracts/deploy/00_info/00-env-check.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/contracts/deploy/10_create_repo/11_create_repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
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
5 changes: 2 additions & 3 deletions packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ import path from 'path';
type SemVer = [number, number, number];

/**
* This function pushes an upgrade to the plugin repo. It does not upgrade the actual plugin - this requires
* DAOs installing said plugin to upgrade the plugin themselves. In Aragon's case, this requires the management
* DAO to create a proposal to upgrade the plugin.
* Upgrades the plugin repo to the latest implementation.
* @param {HardhatRuntimeEnvironment} hre
*/
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const [deployer] = await hre.ethers.getSigners();
Expand Down
111 changes: 111 additions & 0 deletions packages/contracts/deploy/40_conclude/41_transfer_ownership.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {findPluginRepo, getManagementDao} from '../../utils/helpers';
import {
DAO_PERMISSIONS,
Operation,
PERMISSION_MANAGER_FLAGS,
PLUGIN_REPO_PERMISSIONS,
} from '@aragon/osx-commons-sdk';
import {DAOStructs} from '@aragon/osx-ethers';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';

/**
* Creates a plugin repo under Aragon's ENS base domain with subdomain requested in the `./plugin-settings.ts` file.
* @param {HardhatRuntimeEnvironment} hre
*/
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
// Get PluginRepo
const {pluginRepo, ensDomain} = await findPluginRepo(hre);
if (pluginRepo === null) {
throw `PluginRepo '${ensDomain}' does not exist yet.`;
}

// Get the management DAO address
const managementDao = await getManagementDao(hre);
const [deployer] = await hre.ethers.getSigners();

console.log(
`Transferring ownership of the '${ensDomain}' plugin repo at '${pluginRepo.address}' from the deployer '${deployer.address}' to the management DAO at '${managementDao.address}'...`
);

const permissions: DAOStructs.MultiTargetPermissionStruct[] = [
// Grant to the managment DAO
{
operation: Operation.Grant,
where: pluginRepo.address,
who: managementDao.address,
condition: PERMISSION_MANAGER_FLAGS.NO_CONDITION,
permissionId: PLUGIN_REPO_PERMISSIONS.MAINTAINER_PERMISSION_ID,
},
{
operation: Operation.Grant,
where: pluginRepo.address,
who: managementDao.address,
condition: PERMISSION_MANAGER_FLAGS.NO_CONDITION,
permissionId: PLUGIN_REPO_PERMISSIONS.UPGRADE_REPO_PERMISSION_ID,
},
{
operation: Operation.Grant,
where: pluginRepo.address,
who: managementDao.address,
condition: PERMISSION_MANAGER_FLAGS.NO_CONDITION,
permissionId: DAO_PERMISSIONS.ROOT_PERMISSION_ID,
},
// Revoke from deployer
{
operation: Operation.Revoke,
where: pluginRepo.address,
who: deployer.address,
condition: PERMISSION_MANAGER_FLAGS.NO_CONDITION,
permissionId: PLUGIN_REPO_PERMISSIONS.MAINTAINER_PERMISSION_ID,
},
{
operation: Operation.Revoke,
where: pluginRepo.address,
who: deployer.address,
condition: PERMISSION_MANAGER_FLAGS.NO_CONDITION,
permissionId: PLUGIN_REPO_PERMISSIONS.UPGRADE_REPO_PERMISSION_ID,
},
{
operation: Operation.Revoke,
where: pluginRepo.address,
who: deployer.address,
condition: PERMISSION_MANAGER_FLAGS.NO_CONDITION,
permissionId: DAO_PERMISSIONS.ROOT_PERMISSION_ID,
},
];

await pluginRepo.connect(deployer).applyMultiTargetPermissions(permissions);
};

export default func;
func.tags = ['TransferOwnershipToManagmentDao'];

/**
* Skips the transfer of ownership if it has already been transferred to the management DAO
* @param {HardhatRuntimeEnvironment} hre
*/
func.skip = async (hre: HardhatRuntimeEnvironment) => {
console.log(`\n🏗️ ${path.basename(__filename)}:`);

const {pluginRepo, ensDomain} = await findPluginRepo(hre);
if (pluginRepo === null) {
throw `PluginRepo '${ensDomain}' does not exist yet.`;
}
const managementDao = await getManagementDao(hre);

const mgmtDaoHasRootPerm = await pluginRepo.isGranted(
pluginRepo.address,
managementDao.address,
DAO_PERMISSIONS.ROOT_PERMISSION_ID,
[]
);

if (mgmtDaoHasRootPerm)
console.log(
`The ownership of the plugin repo '${ensDomain}' has already been transferred to the management DAO. Skipping...`
);

return mgmtDaoHasRootPerm;
};
2 changes: 1 addition & 1 deletion packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const config: HardhatUserConfig = {
throwOnTransactionFailures: true,
throwOnCallFailures: true,
blockGasLimit: BigNumber.from(10).pow(6).mul(30).toNumber(), // 30 million, really high to test some things that are only possible with a higher block gas limit
gasPrice: BigNumber.from(10).pow(9).mul(150).toNumber(), // 150 gwei
gasPrice: BigNumber.from(10).pow(9).mul(1000).toNumber(), // 1000 gwei
accounts: getHardhatNetworkAccountsConfig(
Object.keys(namedAccounts).length
),
Expand Down
8 changes: 2 additions & 6 deletions packages/contracts/plugin-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import buildMetadata from './src/build-metadata.json';
import releaseMetadata from './src/release-metadata.json';
import {VersionTag} from '@aragon/osx-commons-sdk';
import {ethers} from 'hardhat';
import { GovernanceERC20 } from './test/test-utils/typechain-versions';

export const PLUGIN_CONTRACT_NAME = 'TokenVoting'; // This must match the filename `packages/contracts/src/MyPlugin.sol` and the contract name `MyPlugin` within.
export const PLUGIN_SETUP_CONTRACT_NAME = 'TokenVotingSetup'; // This must match the filename `packages/contracts/src/MyPluginSetup.sol` and the contract name `MyPluginSetup` within.
Expand All @@ -26,12 +27,7 @@ const zeroTokenAddress = ethers.constants.AddressZero;
const emptyName = '';
const emptySymbol = '';

export type MintSettings = {
receivers: string[];
amounts: number[];
};

export const emptyMintSettings: MintSettings = {
export const emptyMintSettings: GovernanceERC20.MintSettingsStruct = {
receivers: [],
amounts: [],
};
Expand Down
Loading

0 comments on commit a997fe8

Please sign in to comment.