Skip to content

Commit

Permalink
Enhance upgrade of voucherHub
Browse files Browse the repository at this point in the history
  • Loading branch information
Le-Caignec committed Jan 10, 2025
1 parent fcbde2b commit 51a4471
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 40 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,30 @@ Deployment configuration can also be provided/overridden using env variables:
* `IEXEC_VOUCHER_MINTER_ACCOUNT_INDEX`

Run:

```
npx hardhat deploy --network <name>
```

#### Local Bellecour fork

Complete the `.env` file with the following variables:

```
LOCAL_FORK=true MNEMONIC=<mnemonic> npx hardhat deploy --network hardhat
IS_LOCAL_FORK=true
MNEMONIC=<mnemonic>
```

If a `MNEMONIC` is not provided, the default Hardhat one will be used.

```
npx hardhat node
```

#### Bellecour

With appropriate deployer key:

```
npx hardhat deploy --network bellecour
```
Expand Down
6 changes: 4 additions & 2 deletions config/deployment.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"31337": {
"factory": true,
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
"pocoAddress": "0x123456789a123456789b123456789b123456789d"
"pocoAddress": "0x123456789a123456789b123456789b123456789d",
"voucherHubAddress": "0x63264C515d0121B0C167098aF1661d8ADE7BCD3d"
},
"65535": {
"factory": true,
Expand All @@ -12,6 +13,7 @@
"134": {
"factory": true,
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
"pocoAddress": "0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f"
"pocoAddress": "0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f",
"voucherHubAddress": "0x3137B6DF4f36D338b82260eDBB2E7bab034AFEda"
}
}
6 changes: 4 additions & 2 deletions config/deployment.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// SPDX-FileCopyrightText: 2024 IEXEC BLOCKCHAIN TECH <[email protected]>
// SPDX-License-Identifier: Apache-2.0

const deploymentConfig = require('./deployment.json') as DeploymentConfig;
export default deploymentConfig;
import deploymentConfigRaw from './deployment.json';

export type DeploymentConfig = {
[chainId: string]: {
factory: boolean;
salt: string;
pocoAddress: string;
voucherHubAddress?: string; //some chains used doesn't have the voucher deployed
};
};

export default deploymentConfigRaw as DeploymentConfig;
4 changes: 4 additions & 0 deletions config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const envSchema = z.object({
.string()
.regex(addressRegex, 'Invalid Ethereum address if provided')
.optional(),
IEXEC_VOUCHER_HUB_ADDRESS: z
.string()
.regex(addressRegex, 'Invalid Ethereum address if provided')
.optional(),
USE_FACTORY: z.preprocess(
(val) => typeof val === 'string' && val.toLowerCase() === 'true',
z.boolean().default(false),
Expand Down
11 changes: 2 additions & 9 deletions deploy/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// SPDX-FileCopyrightText: 2024 IEXEC BLOCKCHAIN TECH <[email protected]>
// SPDX-License-Identifier: Apache-2.0

import * as helpers from '@nomicfoundation/hardhat-network-helpers';
import { ContractFactory } from 'ethers';
import { deployments, ethers, upgrades } from 'hardhat';
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import deploymentConfig from '../config/deployment';
import { env } from '../config/env';
import { mineBlockIfOnLocalFork } from '../scripts/utils/mineBlockIfOnLocalFork';
import * as voucherHubUtils from '../scripts/voucherHubUtils';
import * as voucherUtils from '../scripts/voucherUtils';
import {
Expand All @@ -19,14 +19,7 @@ import {
} from '../typechain-types';

export default async function (hre: HardhatRuntimeEnvironment) {
if (env.IS_LOCAL_FORK) {
/**
* This fixes following issue when deploying to a local Bellecour fork:
* `ProviderError: No known hardfork for execution on historical block [...] in chain with id 134.`
* See: https://github.com/NomicFoundation/hardhat/issues/5511#issuecomment-2288072104
*/
await helpers.mine();
}
mineBlockIfOnLocalFork();
const { deployer, manager, minter } = await hre.getNamedAccounts();
await deployAll(deployer, manager, minter);
}
Expand Down
18 changes: 11 additions & 7 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ const managerAccount = env.IEXEC_VOUCHER_MANAGER_ACCOUNT_INDEX || null;
const minterAccount = env.IEXEC_VOUCHER_MINTER_ACCOUNT_INDEX || null;
const bellecourBlockscoutUrl = 'https://blockscout.bellecour.iex.ec';

const bellecourBase = {
gasPrice: 0,
blockGasLimit: 6_700_000,
hardfork: 'berlin', // No EIP-1559 before London fork
};

const config: HardhatUserConfig = {
solidity: {
compilers: [
Expand Down Expand Up @@ -48,7 +54,6 @@ const config: HardhatUserConfig = {
},
networks: {
hardhat: {
hardfork: 'berlin', // No EIP-1559 before London fork
accounts: {
mnemonic: env.MNEMONIC || HARDHAT_NETWORK_MNEMONIC,
},
Expand All @@ -58,25 +63,25 @@ const config: HardhatUserConfig = {
},
chainId: 134,
}),
gasPrice: 0,
blockGasLimit: 6_700_000,
...bellecourBase,
},
//TODO: rename into 'external-node'
'external-hardhat': {
...defaultHardhatNetworkParams,
...defaultLocalhostNetworkParams,
accounts: 'remote', // will use accounts set in hardhat network config
...(env.IS_LOCAL_FORK && {
chainId: 134,
}),
gasPrice: 0,
...bellecourBase,
},
'dev-native': {
chainId: 65535,
url: 'http://localhost:8545',
accounts: {
mnemonic: env.MNEMONIC || '',
},
gasPrice: 0, // Get closer to Bellecour network
...bellecourBase,
},
bellecour: {
chainId: 134,
Expand All @@ -85,8 +90,7 @@ const config: HardhatUserConfig = {
env.PROD_PRIVATE_KEY ||
'0x0000000000000000000000000000000000000000000000000000000000000000',
],
gasPrice: 0,
gas: 6700000,
...bellecourBase,
},
},
etherscan: {
Expand Down
38 changes: 38 additions & 0 deletions scripts/upgradeHub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ethers, upgrades } from 'hardhat';
import { env } from '../config/env';
import { getDeploymentConfig } from '../deploy/deploy';
import { mineBlockIfOnLocalFork } from './utils/mineBlockIfOnLocalFork';
import { upgradeProxy } from './voucherHubUtils';

async function upgradeVoucherHub() {
console.log(`Upgrading VoucherHub contract ...`);
mineBlockIfOnLocalFork();

const chainId = (await ethers.provider.getNetwork()).chainId.toString();
console.log('ChainId:', chainId);

const config = await getDeploymentConfig(Number(chainId));
const voucherHubProxyAddress = config.voucherHubAddress || env.IEXEC_VOUCHER_HUB_ADDRESS;
if (!voucherHubProxyAddress) {
throw new Error(`No VoucherHub deployed on the target chain ${chainId}`);
}
console.log(
'Current implementation address:',
await upgrades.erc1967.getImplementationAddress(voucherHubProxyAddress),
);

const voucherHubFactoryUpgrade = await ethers.getContractFactory('VoucherHub');
await upgradeProxy(voucherHubProxyAddress, voucherHubFactoryUpgrade);

// Fetch new implementation address
const implementationAddress =
await upgrades.erc1967.getImplementationAddress(voucherHubProxyAddress);
console.log(
`VoucherHub upgraded successfully ✅! New implementation address (VoucherHub.sol): ${implementationAddress}`,
);
}

upgradeVoucherHub().catch((error) => {
console.error(error);
process.exitCode = 1;
});
16 changes: 16 additions & 0 deletions scripts/utils/mineBlockIfOnLocalFork.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as helpers from '@nomicfoundation/hardhat-network-helpers';
import { env } from '../../config/env';

/**
* This function is used to force mining if we are one a local fork
*/
export async function mineBlockIfOnLocalFork() {
if (env.IS_LOCAL_FORK) {
/**
* This fixes following issue when deploying to a local Bellecour fork:
* `ProviderError: No known hardfork for execution on historical block [...] in chain with id 134.`
* See: https://github.com/NomicFoundation/hardhat/issues/5511#issuecomment-2288072104
*/
await helpers.mine();
}
}
29 changes: 13 additions & 16 deletions scripts/voucherHubUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { ContractFactory } from 'ethers';
import hre, { ethers, upgrades } from 'hardhat';
import { env } from '../config/env';
import { getDeploymentConfig } from '../deploy/deploy';
import { VoucherHub, VoucherProxy__factory } from '../typechain-types';

Expand Down Expand Up @@ -33,22 +34,18 @@ export async function upgradeProxy(
voucherHubAddress: string,
newVoucherHubImplementationFactory: ContractFactory,
): Promise<VoucherHub> {
const contractUpgrade: unknown = await upgrades.upgradeProxy(
voucherHubAddress,
newVoucherHubImplementationFactory,
);
const voucherHubUpgrade = contractUpgrade as VoucherHub;
await voucherHubUpgrade.waitForDeployment();
const voucherBeaconAddress = await voucherHubUpgrade.getVoucherBeacon();
const expectedHash = await getExpectedVoucherProxyCodeHash(voucherBeaconAddress);
const actualHash = await voucherHubUpgrade.getVoucherProxyCodeHash();
if (actualHash !== expectedHash) {
throw new Error(
'Voucher proxy code hash in the new VoucherHub implementation does not match the real hash ' +
`[actual: ${actualHash}, expected:${expectedHash}]`,
);
}
return voucherHubUpgrade;
// Fetch proxy admin details
const voucherHub: unknown = newVoucherHubImplementationFactory.attach(voucherHubAddress);
const voucherHubContract = voucherHub as VoucherHub;
const upgraderAddress = await voucherHubContract.defaultAdmin();
const upgrader = env.IS_LOCAL_FORK
? await ethers.getImpersonatedSigner(upgraderAddress)
: await ethers.getSigner(upgraderAddress);

const contractUpgrade: unknown = await upgrades
.upgradeProxy(voucherHubAddress, newVoucherHubImplementationFactory.connect(upgrader))
.then((contract) => contract.waitForDeployment());
return contractUpgrade as VoucherHub;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions test/VoucherHub.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe('VoucherHub', function () {

describe('Upgrade', function () {
it('Should upgrade', async function () {
const { voucherHub, admin } = await loadFixture(deployFixture);
const { admin } = await loadFixture(deployFixture);
const VoucherHubV2Factory = await ethers.getContractFactory('VoucherHubV2Mock', admin);
// Next line should throw if new storage schema is not compatible with previous one
await voucherHubUtils.upgradeProxy(voucherHubAddress, VoucherHubV2Factory);
Expand All @@ -135,7 +135,7 @@ describe('VoucherHub', function () {
});

it('Should not upgrade when account is unauthorized', async function () {
const { voucherHub, anyone } = await loadFixture(deployFixture);
const { voucherHub } = await loadFixture(deployFixture);

await expect(
voucherHubAsAnyone.upgradeToAndCall(ethers.Wallet.createRandom().address, '0x'),
Expand All @@ -159,7 +159,7 @@ describe('VoucherHub', function () {
});

it('Should not create a voucher type when the caller is not authorized', async function () {
const { voucherHub, anyone } = await loadFixture(deployFixture);
const { voucherHub } = await loadFixture(deployFixture);
await expect(
voucherHubAsAnyone.createVoucherType(description, duration),
).to.be.revertedWithCustomError(voucherHub, 'AccessControlUnauthorizedAccount');
Expand Down

0 comments on commit 51a4471

Please sign in to comment.