diff --git a/packages/contracts/deploy/10_create_repo/10_create_token_voting_repo.ts b/packages/contracts/deploy/10_create_repo/10_create_token_voting_repo.ts
deleted file mode 100644
index 50045745..00000000
--- a/packages/contracts/deploy/10_create_repo/10_create_token_voting_repo.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import tokenVotingBuildMetadata from '../../src/build-metadata.json';
-import tokenVotingReleaseMetadata from '../../src/release-metadata.json';
-import {
- createPluginRepo,
- populatePluginRepo,
- getContractAddress,
- uploadToIPFS,
-} from '../helpers';
-import {ethers} from 'ethers';
-import {DeployFunction} from 'hardhat-deploy/types';
-import {HardhatRuntimeEnvironment} from 'hardhat/types';
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
- console.log(`\nCreating token-voting repo.`);
-
- console.warn(
- 'Please make sure pluginRepo is not created more than once with the same name.'
- );
-
- const {network} = hre;
-
- const tokenVotingReleaseCIDPath = await uploadToIPFS(
- JSON.stringify(tokenVotingReleaseMetadata),
- network.name
- );
- const tokenVotingBuildCIDPath = await uploadToIPFS(
- JSON.stringify(tokenVotingBuildMetadata),
- network.name
- );
-
- const tokenVotingSetupContract = await getContractAddress(
- 'TokenVotingSetup',
- hre
- );
-
- await createPluginRepo(hre, 'TokenVotingRepoProxy', 'token-voting');
- await populatePluginRepo(hre, 'TokenVotingRepoProxy', [
- {
- versionTag: [1, 2],
- pluginSetupContract: tokenVotingSetupContract,
- releaseMetadata: ethers.utils.hexlify(
- ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingReleaseCIDPath}`)
- ),
- buildMetadata: ethers.utils.hexlify(
- ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingBuildCIDPath}`)
- ),
- },
- ]);
-};
-
-export default func;
-func.tags = ['New', 'CreateTokenVotingRepo'];
diff --git a/packages/contracts/deploy/10_create_repo/11_create_token_voting_repo_conclude.ts b/packages/contracts/deploy/10_create_repo/11_create_token_voting_repo_conclude.ts
deleted file mode 100644
index 7bd82236..00000000
--- a/packages/contracts/deploy/10_create_repo/11_create_token_voting_repo_conclude.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import {
- PluginRepoFactory__factory,
- PluginRepo__factory,
-} from '../../../../typechain';
-import {DeployFunction} from 'hardhat-deploy/types';
-import {HardhatRuntimeEnvironment} from 'hardhat/types';
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
- console.log(`Concluding TokenVotingSetup deployment.\n`);
- const [deployer] = await hre.ethers.getSigners();
-
- const {deployments} = hre;
-
- const PluginRepoFactoryDeployment = await deployments.get(
- 'PluginRepoFactory'
- );
- const pluginRepoFactory = PluginRepoFactory__factory.connect(
- PluginRepoFactoryDeployment.address,
- deployer
- );
-
- const initializeData =
- PluginRepo__factory.createInterface().encodeFunctionData('initialize', [
- deployer.address,
- ]);
-
- const pluginRepoBase = await pluginRepoFactory.pluginRepoBase();
-
- hre.aragonToVerifyContracts.push({
- address: hre.aragonPluginRepos.TokenVotingRepoProxy,
- args: [pluginRepoBase, initializeData],
- });
-};
-
-export default func;
-func.tags = ['New', 'CreateTokenVotingRepo', 'Verify'];
diff --git a/packages/contracts/deploy/20_new_version/10_token_voting_setup.ts b/packages/contracts/deploy/20_new_version/10_token_voting_setup.ts
deleted file mode 100644
index d8983dbf..00000000
--- a/packages/contracts/deploy/20_new_version/10_token_voting_setup.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import tokenVotingSetupArtifact from '../../../../artifacts/src/plugins/governance/majority-voting/token/TokenVotingSetup.sol/TokenVotingSetup.json';
-import governanceERC20Artifact from '../../../../artifacts/src/token/ERC20/governance/GovernanceERC20.sol/GovernanceERC20.json';
-import governanceWrappedERC20Artifact from '../../../../artifacts/src/token/ERC20/governance/GovernanceWrappedERC20.sol/GovernanceWrappedERC20.json';
-import {MintSettings} from '../../../../test/token/erc20/governance-erc20';
-import {DeployFunction} from 'hardhat-deploy/types';
-import {HardhatRuntimeEnvironment} from 'hardhat/types';
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
- const {deployments, ethers} = hre;
- const {deploy} = deployments;
- const [deployer] = await ethers.getSigners();
-
- const zeroDaoAddress = ethers.constants.AddressZero;
- const zeroTokenAddress = ethers.constants.AddressZero;
- const emptyName = '';
- const emptySymbol = '';
- const emptyMintSettings: MintSettings = {
- receivers: [],
- amounts: [],
- };
-
- // Deploy the bases for the TokenVotingSetup
- const governanceERC20DeployResult = await deploy('GovernanceERC20', {
- contract: governanceERC20Artifact,
- from: deployer.address,
- args: [zeroDaoAddress, emptyName, emptySymbol, emptyMintSettings],
- log: true,
- });
-
- const governanceWrappedERC20DeployResult = await deploy(
- 'GovernanceWrappedERC20',
- {
- contract: governanceWrappedERC20Artifact,
- from: deployer.address,
- args: [zeroTokenAddress, emptyName, emptySymbol],
- log: true,
- }
- );
-
- // Deploy the TokenVotingSetup and provide the bases in the constructor
- await deploy('TokenVotingSetup', {
- contract: tokenVotingSetupArtifact,
- from: deployer.address,
- args: [
- governanceERC20DeployResult.address,
- governanceWrappedERC20DeployResult.address,
- ],
- log: true,
- });
-};
-export default func;
-func.tags = ['New', 'TokenVotingSetup'];
diff --git a/packages/contracts/deploy/20_new_version/11_token_voting_setup_conclude.ts b/packages/contracts/deploy/20_new_version/11_token_voting_setup_conclude.ts
deleted file mode 100644
index 990d7c85..00000000
--- a/packages/contracts/deploy/20_new_version/11_token_voting_setup_conclude.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import {TokenVotingSetup__factory} from '../../../../typechain';
-import {DeployFunction} from 'hardhat-deploy/types';
-import {HardhatRuntimeEnvironment} from 'hardhat/types';
-import {setTimeout} from 'timers/promises';
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
- console.log(`Concluding token voting setup deployment.\n`);
- const [deployer] = await hre.ethers.getSigners();
-
- const {deployments, network} = hre;
-
- const TokenVotingSetupDeployment = await deployments.get('TokenVotingSetup');
- const tokenVotingSetup = TokenVotingSetup__factory.connect(
- TokenVotingSetupDeployment.address,
- deployer
- );
-
- // add a timeout for polygon because the call to `implementation()` can fail for newly deployed contracts in the first few seconds
- if (network.name === 'polygon') {
- console.log(`Waiting 30secs for ${network.name} to finish up...`);
- await setTimeout(30000);
- }
-
- hre.aragonToVerifyContracts.push(
- await hre.deployments.get('GovernanceERC20')
- );
-
- hre.aragonToVerifyContracts.push(
- await hre.deployments.get('GovernanceWrappedERC20')
- );
-
- hre.aragonToVerifyContracts.push({
- contract:
- 'src/plugins/governance/majority-voting/token/TokenVotingSetup.sol:TokenVotingSetup',
- ...TokenVotingSetupDeployment,
- });
- hre.aragonToVerifyContracts.push({
- contract:
- 'src/plugins/governance/majority-voting/token/TokenVoting.sol:TokenVoting',
- address: await tokenVotingSetup.implementation(),
- args: [],
- });
-};
-
-export default func;
-func.tags = ['New', 'TokenVotingSetup', 'Verify'];
diff --git a/packages/contracts/deploy/20_new_version/21_setup.ts b/packages/contracts/deploy/20_new_version/21_setup.ts
index 041e76bc..a6bcc1fd 100644
--- a/packages/contracts/deploy/20_new_version/21_setup.ts
+++ b/packages/contracts/deploy/20_new_version/21_setup.ts
@@ -1,10 +1,22 @@
-import {PLUGIN_SETUP_CONTRACT_NAME} from '../../plugin-settings';
+import governanceERC20Artifact from '../../artifacts/src/ERC20/governance/GovernanceERC20.sol/GovernanceERC20.json';
+import governanceWrappedERC20Artifact from '../../artifacts/src/ERC20/governance/GovernanceWrappedERC20.sol/GovernanceWrappedERC20.json';
+import {
+ GOVERNANCE_ERC20_DEPLOY_ARGS,
+ GOVERNANCE_WRAPPED_ERC20_DEPLOY_ARGS,
+ PLUGIN_SETUP_CONTRACT_NAME,
+} from '../../plugin-settings';
+import {
+ GOVERNANCE_ERC20_CONTRACT_NAME,
+ GOVERNANCE_WRAPPED_ERC20_CONTRACT_NAME,
+} from '../../plugin-settings';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';
/**
* Deploys the plugin setup contract with the plugin implementation inside.
+ * In the case of the token voting plugin, we also need to deploy the governance ERC20
+ * and the wrapped variants.
* @param {HardhatRuntimeEnvironment} hre
*/
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
@@ -14,11 +26,39 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const {deploy} = deployments;
const {deployer} = await getNamedAccounts();
- await deploy(PLUGIN_SETUP_CONTRACT_NAME, {
+ // Deploy the bases for the TokenVotingSetup
+ const governanceERC20DeployResult = await deploy(
+ GOVERNANCE_ERC20_CONTRACT_NAME,
+ {
+ contract: governanceERC20Artifact,
+ from: deployer,
+ args: GOVERNANCE_ERC20_DEPLOY_ARGS,
+ log: true,
+ }
+ );
+
+ const governanceWrappedERC20DeployResult = await deploy(
+ GOVERNANCE_WRAPPED_ERC20_CONTRACT_NAME,
+ {
+ contract: governanceWrappedERC20Artifact,
+ from: deployer,
+ args: GOVERNANCE_WRAPPED_ERC20_DEPLOY_ARGS,
+ log: true,
+ }
+ );
+
+ const res = await deploy(PLUGIN_SETUP_CONTRACT_NAME, {
from: deployer,
- args: [],
+ args: [
+ governanceERC20DeployResult.address,
+ governanceWrappedERC20DeployResult.address,
+ ],
log: true,
});
+
+ console.log(
+ `Deployed contract '${PLUGIN_SETUP_CONTRACT_NAME}' at ${res.address}.`
+ );
};
export default func;
diff --git a/packages/contracts/deploy/20_new_version/22_setup_conclude.ts b/packages/contracts/deploy/20_new_version/22_setup_conclude.ts
index 1b514b68..fa64a5a6 100644
--- a/packages/contracts/deploy/20_new_version/22_setup_conclude.ts
+++ b/packages/contracts/deploy/20_new_version/22_setup_conclude.ts
@@ -1,5 +1,11 @@
-import {PLUGIN_SETUP_CONTRACT_NAME} from '../../plugin-settings';
-import {MyPluginSetup__factory, MyPlugin__factory} from '../../typechain';
+import {
+ GOVERNANCE_ERC20_CONTRACT_NAME,
+ GOVERNANCE_ERC20_DEPLOY_ARGS,
+ GOVERNANCE_WRAPPED_ERC20_CONTRACT_NAME,
+ GOVERNANCE_WRAPPED_ERC20_DEPLOY_ARGS,
+ PLUGIN_SETUP_CONTRACT_NAME,
+} from '../../plugin-settings';
+import {TokenVotingSetup__factory, TokenVoting__factory} from '../../typechain';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';
@@ -17,24 +23,45 @@ 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 = TokenVotingSetup__factory.connect(
setupDeployment.address,
deployer
);
// Get the plugin implementation address
- const implementation = MyPlugin__factory.connect(
+ const implementation = TokenVoting__factory.connect(
await setup.implementation(),
deployer
);
+ const governanceERC20DeployResult = await deployments.get(
+ GOVERNANCE_ERC20_CONTRACT_NAME
+ );
+ const governanceWrappedERC20DeployResult = await deployments.get(
+ GOVERNANCE_WRAPPED_ERC20_CONTRACT_NAME
+ );
+
// Queue the plugin setup and implementation for verification on the block explorers
hre.aragonToVerifyContracts.push({
address: setup.address,
args: setupDeployment.args,
});
+
hre.aragonToVerifyContracts.push({
address: implementation.address,
- args: [],
+ args: [
+ governanceERC20DeployResult.address,
+ governanceWrappedERC20DeployResult.address,
+ ],
+ });
+
+ hre.aragonToVerifyContracts.push({
+ address: governanceERC20DeployResult.address,
+ args: GOVERNANCE_ERC20_DEPLOY_ARGS,
+ });
+
+ hre.aragonToVerifyContracts.push({
+ address: governanceWrappedERC20DeployResult.address,
+ args: GOVERNANCE_WRAPPED_ERC20_DEPLOY_ARGS,
});
};
diff --git a/packages/contracts/deploy/20_new_version/41_TokenVoting_Plugin.ts b/packages/contracts/deploy/20_new_version/41_TokenVoting_Plugin.ts
deleted file mode 100644
index 1976d1a3..00000000
--- a/packages/contracts/deploy/20_new_version/41_TokenVoting_Plugin.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-import tokenVotingSetupArtifact from '../../../artifacts/src/plugins/governance/majority-voting/token/TokenVotingSetup.sol/TokenVotingSetup.json';
-import governanceERC20Artifact from '../../../artifacts/src/token/ERC20/governance/GovernanceERC20.sol/GovernanceERC20.json';
-import governanceWrappedERC20Artifact from '../../../artifacts/src/token/ERC20/governance/GovernanceWrappedERC20.sol/GovernanceWrappedERC20.json';
-import tokenVotingBuildMetadata from '../../../src/plugins/governance/majority-voting/token/build-metadata.json';
-import tokenVotingReleaseMetadata from '../../../src/plugins/governance/majority-voting/token/release-metadata.json';
-import {MintSettings} from '../../../test/token/erc20/governance-erc20';
-import {PluginRepo__factory} from '../../../typechain';
-import {getContractAddress, uploadToIPFS} from '../../helpers';
-import {DeployFunction} from 'hardhat-deploy/types';
-import {HardhatRuntimeEnvironment} from 'hardhat/types';
-
-const TARGET_RELEASE = 1;
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
- console.log('\nUpdate TokenVoting Plugin');
- const {deployments, ethers, network} = hre;
- const {deploy} = deployments;
- const [deployer] = await ethers.getSigners();
-
- const zeroDaoAddress = ethers.constants.AddressZero;
- const zeroTokenAddress = ethers.constants.AddressZero;
- const emptyName = '';
- const emptySymbol = '';
- const emptyMintSettings: MintSettings = {
- receivers: [],
- amounts: [],
- };
-
- // Deploy the bases for the TokenVotingSetup
- const governanceERC20DeployResult = await deploy('GovernanceERC20', {
- contract: governanceERC20Artifact,
- from: deployer.address,
- args: [zeroDaoAddress, emptyName, emptySymbol, emptyMintSettings],
- log: true,
- });
-
- const governanceWrappedERC20DeployResult = await deploy(
- 'GovernanceWrappedERC20',
- {
- contract: governanceWrappedERC20Artifact,
- from: deployer.address,
- args: [zeroTokenAddress, emptyName, emptySymbol],
- log: true,
- }
- );
-
- // Deploy the TokenVotingSetup and provide the bases in the constructor
- const deployResult = await deploy('TokenVotingSetup', {
- contract: tokenVotingSetupArtifact,
- from: deployer.address,
- args: [
- governanceERC20DeployResult.address,
- governanceWrappedERC20DeployResult.address,
- ],
- log: true,
- });
-
- const tokenVotingReleaseCIDPath = await uploadToIPFS(
- JSON.stringify(tokenVotingReleaseMetadata),
- network.name
- );
- const tokenVotingBuildCIDPath = await uploadToIPFS(
- JSON.stringify(tokenVotingBuildMetadata),
- network.name
- );
-
- const tokenVotingRepoAddress = await getContractAddress(
- 'TokenVotingRepoProxy',
- hre
- );
- const tokenVotingRepo = PluginRepo__factory.connect(
- tokenVotingRepoAddress,
- ethers.provider
- );
- if (
- await tokenVotingRepo.callStatic.isGranted(
- tokenVotingRepoAddress,
- deployer.address,
- await tokenVotingRepo.MAINTAINER_PERMISSION_ID(),
- '0x00'
- )
- ) {
- console.log(`Deployer has permission to install new TokenVoting version`);
- const tx = await tokenVotingRepo
- .connect(deployer)
- .createVersion(
- TARGET_RELEASE,
- deployResult.address,
- ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingBuildCIDPath}`),
- ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingReleaseCIDPath}`)
- );
- console.log(`Creating new TokenVoting build version with ${tx.hash}`);
- await tx.wait();
- return;
- }
-
- const tx = await tokenVotingRepo
- .connect(deployer)
- .populateTransaction.createVersion(
- TARGET_RELEASE,
- deployResult.address,
- ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingBuildCIDPath}`),
- ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingReleaseCIDPath}`)
- );
-
- if (!tx.to || !tx.data) {
- throw new Error(
- `Failed to populate TokenVoting Repo createVersion transaction`
- );
- }
-
- console.log(
- `Deployer has no permission to create a new version. Adding managementDAO action`
- );
- hre.managementDAOActions.push({
- to: tx.to,
- data: tx.data,
- value: 0,
- description: `Creates a new build for release 1 in the TokenVoting PluginRepo (${tokenVotingRepoAddress}
) with TokenVotingSetup (${deployResult.address}
).`,
- });
-};
-export default func;
-func.tags = ['Update', 'TokenVotingPlugin', 'v1.3.0'];
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..7ca2b168 100644
--- a/packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts
+++ b/packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts
@@ -1,11 +1,20 @@
-import {findPluginRepo, getProductionNetworkName} from '../../utils/helpers';
+import {
+ findPluginRepo,
+ getProductionNetworkName,
+ impersonatedManagementDaoSigner,
+ isLocal,
+} from '../../utils/helpers';
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 {writeFile} from 'fs/promises';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';
@@ -15,6 +24,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 +45,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,22 +69,36 @@ 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,
]);
*/
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,
[]
)
@@ -84,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}.`
);
}
};
@@ -102,11 +158,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/deploy/30_upgrade_repo/40_TokenVoting_PluginRepo.ts b/packages/contracts/deploy/30_upgrade_repo/40_TokenVoting_PluginRepo.ts
deleted file mode 100644
index 28f8e5fd..00000000
--- a/packages/contracts/deploy/30_upgrade_repo/40_TokenVoting_PluginRepo.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import {
- PluginRepo__factory,
- PluginRepoFactory__factory,
-} from '../../../typechain';
-import {getContractAddress} from '../../helpers';
-import {DeployFunction} from 'hardhat-deploy/types';
-import {HardhatRuntimeEnvironment} from 'hardhat/types';
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
- console.log(
- '\nUpgrade the `token-voting-repo` PluginRepo to the new implementation'
- );
-
- const pluginRepoFactoryAddress = await getContractAddress(
- 'PluginRepoFactory',
- hre
- );
- const newPluginRepoImplementation = await PluginRepoFactory__factory.connect(
- pluginRepoFactoryAddress,
- hre.ethers.provider
- ).pluginRepoBase();
-
- const tokenVotingPluginRepoAddress = await getContractAddress(
- 'TokenVotingRepoProxy',
- hre
- );
- const tokenVotingPluginRepo = PluginRepo__factory.connect(
- tokenVotingPluginRepoAddress,
- hre.ethers.provider
- );
- const upgradeTX = await tokenVotingPluginRepo.populateTransaction.upgradeTo(
- newPluginRepoImplementation
- );
-
- if (!upgradeTX.to || !upgradeTX.data) {
- throw new Error(`Failed to populate upgradeTo transaction`);
- }
-
- hre.managementDAOActions.push({
- to: upgradeTX.to,
- data: upgradeTX.data,
- value: 0,
- description: `Upgrade the TokenVoting PluginRepo (${tokenVotingPluginRepoAddress}
) to the new implementation (${newPluginRepoImplementation}
).`,
- });
-};
-export default func;
-func.tags = ['TokenVotingPluginRepo', 'v1.3.0'];
diff --git a/packages/contracts/deploy/30_upgrade_repo/41_TokenVoting_Plugin.ts b/packages/contracts/deploy/30_upgrade_repo/41_TokenVoting_Plugin.ts
new file mode 100644
index 00000000..482a36f2
--- /dev/null
+++ b/packages/contracts/deploy/30_upgrade_repo/41_TokenVoting_Plugin.ts
@@ -0,0 +1,123 @@
+/**
+ * TODO:
+ * I'm not 100% sure about the manner in which we upgrade to new versions of upgradeable plugins, in particular how
+ * we handle:
+ * - Versioning the plugin
+ * - Upgrading the plugin
+ * - Updating the governance tokens
+ ** /
+
+// import tokenVotingSetupArtifact from '../../../artifacts/src/plugins/governance/majority-voting/token/TokenVotingSetup.sol/TokenVotingSetup.json';
+// import governanceERC20Artifact from '../../../artifacts/src/token/ERC20/governance/GovernanceERC20.sol/GovernanceERC20.json';
+// import governanceWrappedERC20Artifact from '../../../artifacts/src/token/ERC20/governance/GovernanceWrappedERC20.sol/GovernanceWrappedERC20.json';
+// import tokenVotingBuildMetadata from '../../../src/plugins/governance/majority-voting/token/build-metadata.json';
+// import tokenVotingReleaseMetadata from '../../../src/plugins/governance/majority-voting/token/release-metadata.json';
+// import {PluginRepo__factory} from '@aragon/osx-ethers';
+// import {getContractAddress, uploadToIPFS} from '../helpers';
+// import {DeployFunction} from 'hardhat-deploy/types';
+// import {HardhatRuntimeEnvironment} from 'hardhat/types';
+// import { GOVERNANCE_ERC20_DEPLOY_ARGS, GOVERNANCE_WRAPPED_ERC20_DEPLOY_ARGS } from '../../plugin-settings';
+
+// const TARGET_RELEASE = 1;
+
+// const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
+// console.log('\nUpdate TokenVoting Plugin');
+// const {deployments, ethers, network} = hre;
+// const {deploy} = deployments;
+// const [deployer] = await ethers.getSigners();
+
+// // Deploy the bases for the TokenVotingSetup
+// const governanceERC20DeployResult = await deploy('GovernanceERC20', {
+// contract: governanceERC20Artifact,
+// from: deployer.address,
+// args: GOVERNANCE_ERC20_DEPLOY_ARGS,
+// log: true,
+// });
+
+// const governanceWrappedERC20DeployResult = await deploy(
+// 'GovernanceWrappedERC20',
+// {
+// contract: governanceWrappedERC20Artifact,
+// from: deployer.address,
+// args: GOVERNANCE_WRAPPED_ERC20_DEPLOY_ARGS,
+// log: true,
+// }
+// );
+
+// // Deploy the TokenVotingSetup and provide the bases in the constructor
+// const deployResult = await deploy('TokenVotingSetup', {
+// contract: tokenVotingSetupArtifact,
+// from: deployer.address,
+// args: [
+// governanceERC20DeployResult.address,
+// governanceWrappedERC20DeployResult.address,
+// ],
+// log: true,
+// });
+
+// const tokenVotingReleaseCIDPath = await uploadToIPFS(
+// JSON.stringify(tokenVotingReleaseMetadata),
+// network.name
+// );
+// const tokenVotingBuildCIDPath = await uploadToIPFS(
+// JSON.stringify(tokenVotingBuildMetadata),
+// network.name
+// );
+
+// const tokenVotingRepoAddress = await getContractAddress(
+// 'TokenVotingRepoProxy',
+// hre
+// );
+// const tokenVotingRepo = PluginRepo__factory.connect(
+// tokenVotingRepoAddress,
+// ethers.provider
+// );
+// if (
+// await tokenVotingRepo.callStatic.isGranted(
+// tokenVotingRepoAddress,
+// deployer.address,
+// await tokenVotingRepo.MAINTAINER_PERMISSION_ID(),
+// '0x00'
+// )
+// ) {
+// console.log(`Deployer has permission to install new TokenVoting version`);
+// const tx = await tokenVotingRepo
+// .connect(deployer)
+// .createVersion(
+// TARGET_RELEASE,
+// deployResult.address,
+// ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingBuildCIDPath}`),
+// ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingReleaseCIDPath}`)
+// );
+// console.log(`Creating new TokenVoting build version with ${tx.hash}`);
+// await tx.wait();
+// return;
+// }
+
+// const tx = await tokenVotingRepo
+// .connect(deployer)
+// .populateTransaction.createVersion(
+// TARGET_RELEASE,
+// deployResult.address,
+// ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingBuildCIDPath}`),
+// ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingReleaseCIDPath}`)
+// );
+
+// if (!tx.to || !tx.data) {
+// throw new Error(
+// `Failed to populate TokenVoting Repo createVersion transaction`
+// );
+// }
+
+// console.log(
+// `Deployer has no permission to create a new version. Adding managementDAO action`
+// );
+// hre.managementDAOActions.push({
+// to: tx.to,
+// data: tx.data,
+// value: 0,
+// description: `Creates a new build for release 1 in the TokenVoting PluginRepo (${tokenVotingRepoAddress}
) with TokenVotingSetup (${deployResult.address}
).`,
+// });
+// };
+// export default func;
+// func.tags = ['Update', 'TokenVotingPlugin', 'v1.3.0'];*/
diff --git a/packages/contracts/deploy/40_conclude/42_TokenVoting_Plugin_conclude.ts b/packages/contracts/deploy/40_conclude/42_TokenVoting_Plugin_conclude.ts
deleted file mode 100644
index 2f1a8a70..00000000
--- a/packages/contracts/deploy/40_conclude/42_TokenVoting_Plugin_conclude.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import {TokenVotingSetup__factory} from '../../../typechain';
-import {DeployFunction} from 'hardhat-deploy/types';
-import {HardhatRuntimeEnvironment} from 'hardhat/types';
-
-const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
- console.log('\nConcluding TokenVoting Plugin Update');
- const [deployer] = await hre.ethers.getSigners();
-
- const TokenVotingSetupDeployment = await hre.deployments.get(
- 'TokenVotingSetup'
- );
- const tokenVotingSetup = TokenVotingSetup__factory.connect(
- TokenVotingSetupDeployment.address,
- deployer
- );
-
- hre.aragonToVerifyContracts.push(
- await hre.deployments.get('GovernanceERC20')
- );
-
- hre.aragonToVerifyContracts.push(
- await hre.deployments.get('GovernanceWrappedERC20')
- );
-
- hre.aragonToVerifyContracts.push(TokenVotingSetupDeployment);
- hre.aragonToVerifyContracts.push({
- address: await tokenVotingSetup.implementation(),
- args: [],
- });
-
- hre.aragonToVerifyContracts.push();
-};
-export default func;
-func.tags = ['TokenVotingPlugin', 'Verify', 'v1.3.0'];
diff --git a/packages/contracts/plugin-settings.ts b/packages/contracts/plugin-settings.ts
index f19ee5bf..dce9a196 100644
--- a/packages/contracts/plugin-settings.ts
+++ b/packages/contracts/plugin-settings.ts
@@ -1,10 +1,14 @@
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';
-export const PLUGIN_CONTRACT_NAME = 'MyPlugin'; // This must match the filename `packages/contracts/src/MyPlugin.sol` and the contract name `MyPlugin` within.
-export const PLUGIN_SETUP_CONTRACT_NAME = 'MyPluginSetup'; // This must match the filename `packages/contracts/src/MyPluginSetup.sol` and the contract name `MyPluginSetup` within.
-export const PLUGIN_REPO_ENS_SUBDOMAIN_NAME = 'my'; // This will result in the ENS domain name 'my.plugin.dao.eth'
+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.
+export const PLUGIN_REPO_ENS_SUBDOMAIN_NAME = 'token-voting'; // This will result in the ENS domain name 'my.plugin.dao.eth'
+
+export const GOVERNANCE_ERC20_CONTRACT_NAME = 'GovernanceERC20';
+export const GOVERNANCE_WRAPPED_ERC20_CONTRACT_NAME = 'GovernanceWrappedERC20';
export const VERSION: VersionTag = {
release: 1, // Increment this number ONLY if breaking/incompatible changes were made. Updates between releases are NOT possible.
@@ -16,3 +20,31 @@ export const METADATA = {
build: buildMetadata,
release: releaseMetadata,
};
+
+const zeroDaoAddress = ethers.constants.AddressZero;
+const zeroTokenAddress = ethers.constants.AddressZero;
+const emptyName = '';
+const emptySymbol = '';
+
+export type MintSettings = {
+ receivers: string[];
+ amounts: number[];
+};
+
+export const emptyMintSettings: MintSettings = {
+ receivers: [],
+ amounts: [],
+};
+
+export const GOVERNANCE_ERC20_DEPLOY_ARGS = [
+ zeroDaoAddress,
+ emptyName,
+ emptySymbol,
+ emptyMintSettings,
+];
+
+export const GOVERNANCE_WRAPPED_ERC20_DEPLOY_ARGS = [
+ zeroTokenAddress,
+ emptyName,
+ emptySymbol,
+];
diff --git a/packages/contracts/utils/helpers.ts b/packages/contracts/utils/helpers.ts
index f40c8088..79e077a8 100644
--- a/packages/contracts/utils/helpers.ts
+++ b/packages/contracts/utils/helpers.ts
@@ -10,6 +10,8 @@ import {
findEvent,
} from '@aragon/osx-commons-sdk';
import {
+ DAO,
+ DAO__factory,
ENSSubdomainRegistrar__factory,
ENS__factory,
IAddrResolver__factory,
@@ -17,7 +19,9 @@ import {
PluginRepoEvents,
PluginRepo__factory,
} from '@aragon/osx-ethers';
-import {ContractTransaction} from 'ethers';
+import {setBalance} from '@nomicfoundation/hardhat-network-helpers';
+import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers';
+import {BigNumber, ContractTransaction} from 'ethers';
import {LogDescription, defaultAbiCoder, keccak256} from 'ethers/lib/utils';
import {ethers} from 'hardhat';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
@@ -186,3 +190,38 @@ export async function createVersion(
export const AragonOSxAsciiArt =
" ____ _____ \n /\\ / __ \\ / ____| \n / \\ _ __ __ _ __ _ ___ _ __ | | | | (_____ __ \n / /\\ \\ | '__/ _` |/ _` |/ _ \\| '_ \\ | | | |\\___ \\ \\/ / \n / ____ \\| | | (_| | (_| | (_) | | | | | |__| |____) > < \n /_/ \\_\\_| \\__,_|\\__, |\\___/|_| |_| \\____/|_____/_/\\_\\ \n __/ | \n |___/ \n";
+
+export async function getManagementDao(
+ hre: HardhatRuntimeEnvironment
+): Promise {
+ const [deployer] = await hre.ethers.getSigners();
+ const productionNetworkName = 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}.`;
+ }
+
+ return DAO__factory.connect(
+ networkDeployments.ManagementDAOProxy.address,
+ deployer
+ );
+}
+
+export async function impersonatedManagementDaoSigner(
+ hre: HardhatRuntimeEnvironment
+): Promise {
+ return await (async () => {
+ const managementDaoProxy = getManagementDao(hre);
+ const signer = await hre.ethers.getImpersonatedSigner(
+ (
+ await managementDaoProxy
+ ).address
+ );
+ await setBalance(signer.address, BigNumber.from(10).pow(18));
+ return signer;
+ })();
+}