Skip to content

Commit

Permalink
refactor: split upgrade repo script into two (#60)
Browse files Browse the repository at this point in the history
* refactor: renamed file

* refactor: extract skip function

* refactor: renaming and commenting

* style: satisfy linter

* chore: maintained guide

* refactor: don't alias

* fix: wrong import

* fix: change the execution order so that reinitialization happens by default

* refactor: common steps
  • Loading branch information
heueristik committed Apr 15, 2024
1 parent 5d892e4 commit d35e7e1
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 168 deletions.
4 changes: 3 additions & 1 deletion USAGE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ The standard deploy scripts in the `packages/contracts/deploy` should already be
- Fetches the plugin setup and implementation contract and queues it for block explorer verification.
- `20_new_version/23_publish.ts`
- Publishes the plugin setup contract on the plugin repo created in `10_repo/11_create_repo.ts`
- `30_upgrade_repo/31_upgrade_repo.ts`
- `30_upgrade_repo/31a_upgrade_and_reinitialize_repo.ts`
- Upgrades the plugin repo to the latest Aragon OSx protocol version and reinitializes it.
- `30_upgrade_repo/31b_upgrade_repo.ts`
- Upgrades the plugin repo to the latest Aragon OSx protocol version.
- `40_conclude/41_conclude.ts`
- Prints information on the used account's balance after deployment.
Expand Down
167 changes: 0 additions & 167 deletions packages/contracts/deploy/30_upgrade_repo/31_upgrade_repo.ts

This file was deleted.

36 changes: 36 additions & 0 deletions packages/contracts/deploy/30_upgrade_repo/31a_upgrade_repo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {fetchData, skipUpgrade} from './_common';
import {PLUGIN_REPO_PERMISSIONS} from '@aragon/osx-commons-sdk';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';

/**
* Upgrades the plugin repo to the latest implementation.
* This script CAN be called if the contract does not require reinitialization.
* It MUST NOY be called if the contract requires reinitialization, because this
* would leave the proxy unreinitialized.
* @param {HardhatRuntimeEnvironment} hre
*/
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const {deployer, pluginRepo, latestPluginRepoImplementation} =
await fetchData(hre);

// Check if deployer has the permission to upgrade the plugin repo
if (
await pluginRepo.isGranted(
pluginRepo.address,
deployer.address,
PLUGIN_REPO_PERMISSIONS.UPGRADE_REPO_PERMISSION_ID,
[]
)
) {
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.`
);
}
};
export default func;
func.tags = ['UpgradeRepo'];
func.skip = skipUpgrade;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {fetchData, skipUpgrade} from './_common';
import {PLUGIN_REPO_PERMISSIONS} from '@aragon/osx-commons-sdk';
import {BytesLike} from 'ethers';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';

/**
* Upgrades the plugin repo to the latest implementation and reinitializes the proxy.
* This script MUST be called if the contract requires reinitialization -- otherwise
* the proxy is left unreinitialized.
* @param {HardhatRuntimeEnvironment} hre
*/
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const {deployer, pluginRepo, latestPluginRepoImplementation, current} =
await fetchData(hre);

// Define the `_initData` arguments
const initData: BytesLike[] = [];

// Encode the call to `function initializeFrom(uint8[3] calldata _previousProtocolVersion, bytes calldata _initData)` with `initData`.
const initializeFromCalldata =
latestPluginRepoImplementation.interface.encodeFunctionData(
// Re-initialization will happen through a call to `function initializeFrom(uint8[3] calldata _previousProtocolVersion, bytes calldata _initData)`
// that Aragon will add to the `PluginRepo` contract once it's required.
'initializeFrom',
[current, initData]
);

// Check if deployer has the permission to upgrade the plugin repo
if (
await pluginRepo.isGranted(
pluginRepo.address,
deployer.address,
PLUGIN_REPO_PERMISSIONS.UPGRADE_REPO_PERMISSION_ID,
[]
)
) {
// Use `upgradeToAndCall` to reinitialize the new `PluginRepo` implementation after the update.
if (initializeFromCalldata.length > 0) {
await pluginRepo.upgradeToAndCall(
latestPluginRepoImplementation.address,
initializeFromCalldata
);
} else {
throw Error(
`Initialization data is missing for 'upgradeToAndCall'. Stopping repo upgrade and reinitialization...`
);
}
} 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.`
);
}
};
export default func;
func.tags = ['UpgradeAndReinitializeRepo'];
func.skip = skipUpgrade;
106 changes: 106 additions & 0 deletions packages/contracts/deploy/30_upgrade_repo/_common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {findPluginRepo, getProductionNetworkName} from '../../utils/helpers';
import {
getLatestNetworkDeployment,
getNetworkNameByAlias,
} from '@aragon/osx-commons-configs';
import {UnsupportedNetworkError} from '@aragon/osx-commons-sdk';
import {PluginRepo, PluginRepo__factory} from '@aragon/osx-ethers';
import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import path from 'path';

export type SemVer = [number, number, number];

type FetchedData = {
deployer: SignerWithAddress;
pluginRepo: PluginRepo;
latestPluginRepoImplementation: PluginRepo;
ensDomain: string;
current: SemVer;
latest: SemVer;
};

export async function fetchData(
hre: HardhatRuntimeEnvironment
): Promise<FetchedData> {
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);
if (pluginRepo === null) {
throw `PluginRepo '${ensDomain}' does not exist yet.`;
}

console.log(
`Upgrading plugin repo '${ensDomain}' (${pluginRepo.address})...`
);

// Get the latest `PluginRepo` implementation as the upgrade target
const latestPluginRepoImplementation = PluginRepo__factory.connect(
networkDeployments.PluginRepoBase.address,
deployer
);

// Get the current OSX protocol version from the current plugin repo implementation
let current: SemVer;
try {
current = await pluginRepo.protocolVersion();
} catch {
current = [1, 0, 0];
}

// Get the OSX protocol version from the latest plugin repo implementation
const latest: SemVer = await latestPluginRepoImplementation.protocolVersion();

console.log(
`Upgrading from current protocol version v${current[0]}.${current[1]}.${current[2]} to the latest version v${latest[0]}.${latest[1]}.${latest[2]}.`
);

return {
deployer,
pluginRepo,
latestPluginRepoImplementation,
ensDomain,
current,
latest,
};
}

/**
* Skips the plugin repo upgrade if the implementation is already up-to-date.
* @param {HardhatRuntimeEnvironment} hre
*/
export const skipUpgrade = async (hre: HardhatRuntimeEnvironment) => {
console.log(`\n🏗️ ${path.basename(__filename)}:`);

const {ensDomain, pluginRepo, current, latest: target} = await fetchData(hre);

// Throw an error if attempting to upgrade to an earlier version
if (
current[0] > target[0] ||
current[1] > target[1] ||
current[2] > target[2]
) {
throw `The plugin repo, currently at 'v${current[0]}.${current[1]}.${current[2]}' cannot be upgraded to the earlier version v${target[0]}.${target[1]}.${target[2]}.`;
}

// Skip if versions are equal
if (JSON.stringify(current) == JSON.stringify(target)) {
console.log(
`PluginRepo '${ensDomain}' (${pluginRepo.address}) has already been upgraded to
the current protocol version v${target[0]}.${target[1]}.${target[2]}. Skipping upgrade...`
);
return true;
}

return false;
};

0 comments on commit d35e7e1

Please sign in to comment.