Skip to content

Commit f53c7e3

Browse files
authored
refactor: Fix and refactor bulk processing upgrade script (#298)
1 parent 950ec4e commit f53c7e3

File tree

9 files changed

+314
-226
lines changed

9 files changed

+314
-226
lines changed

deploy/0_deploy.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ import { Ownable__factory } from '../typechain/factories/@openzeppelin/contracts
4040
import { FactoryDeployer } from '../utils/FactoryDeployer';
4141
import config from '../utils/config';
4242
import { getDeployerAndOwnerSigners } from '../utils/deploy-tools';
43-
import { getFunctionSelectors, linkContractToProxy } from '../utils/proxy-tools';
43+
import {
44+
getFunctionSelectors,
45+
linkContractToProxy,
46+
printOnchainProxyFunctions,
47+
} from '../utils/proxy-tools';
4448
import { getLibDiamondConfigOrEmpty } from '../utils/tools';
4549

4650
let factoryDeployer: FactoryDeployer;
@@ -123,12 +127,7 @@ export default async function deploy() {
123127
const functionCount = diamondFacets
124128
.map((facet) => facet.functionSelectors.length)
125129
.reduce((acc, curr) => acc + curr, 0);
126-
console.log(`The deployed Diamond Proxy now supports ${functionCount} functions:`);
127-
// TODO
128-
// for (let i = 0; i < Number(functionCount); i++) {
129-
// const [method, , contract] = await diamondLoupeFacetInstance.functionByIndex(i);
130-
// console.log(`[${i}] ${contract} ${method}`);
131-
// }
130+
await printOnchainProxyFunctions(diamondProxyAddress);
132131
/**
133132
* Deploy registries and link them to the proxy.
134133
*/

hardhat.config.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import { cleanupDeployments, copyDeployments } from './scripts/tools/copy-deploy
1515
import chainConfig from './utils/config';
1616

1717
const isNativeChainType = chainConfig.isNativeChain();
18-
const isLocalFork = process.env.LOCAL_FORK == 'true';
19-
const isArbitrumSepoliaFork = process.env.ARBITRUM_SEPOLIA_FORK == 'true';
20-
const isArbitrumFork = process.env.ARBITRUM_FORK == 'true';
18+
const isLocalFork = chainConfig.isLocalFork();
19+
const isArbitrumSepoliaFork = chainConfig.isArbitrumSepoliaFork();
20+
const isArbitrumFork = chainConfig.isArbitrumFork();
2121
const bellecourBlockscoutUrl = 'https://blockscout.bellecour.iex.ec';
2222

2323
/**
@@ -35,15 +35,15 @@ const bellecourBaseConfig = {
3535

3636
// Arbitrum Sepolia specific configuration
3737
const arbitrumSepoliaBaseConfig = {
38-
gasPrice: 100_000_000, // 0.1 Gwei default (Arbitrum has lower gas prices)
39-
blockGasLimit: 30_000_000, // Arbitrum has higher block gas limits
4038
chainId: 421614,
39+
blockGasLimit: 32_000_000,
4140
};
4241

4342
// Arbitrum specific configuration
4443
const arbitrumBaseConfig = {
45-
blockGasLimit: 30_000_000,
4644
chainId: 42161,
45+
// https://docs.arbitrum.io/build-decentralized-apps/arbitrum-vs-ethereum/block-numbers-and-time#block-gas-limit
46+
blockGasLimit: 32_000_000,
4747
};
4848

4949
const settings = {
@@ -117,13 +117,15 @@ const config: HardhatUserConfig = {
117117
: undefined,
118118
},
119119
...arbitrumSepoliaBaseConfig,
120+
gasPrice: 100_000_000, // 0.1 Gwei
120121
}),
121122

122123
...(isArbitrumFork && {
123124
forking: {
124125
url: process.env.ARBITRUM_RPC_URL || 'https://arbitrum.gateway.tenderly.co',
125126
},
126127
...arbitrumBaseConfig,
128+
gasPrice: 100_000_000, // 0.1 Gwei
127129
}),
128130
},
129131
'external-hardhat': {
@@ -278,7 +280,7 @@ task('test').setAction(async (taskArgs: any, hre, runSuper) => {
278280
let deploymentsCopied = false;
279281
let networkName = '';
280282
try {
281-
if (process.env.ARBITRUM_SEPOLIA_FORK === 'true') {
283+
if (isArbitrumSepoliaFork) {
282284
networkName = 'arbitrumSepolia';
283285
deploymentsCopied = await copyDeployments(networkName);
284286
}

scripts/upgrades/upgrade-helper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { FacetCutAction } from 'hardhat-deploy/dist/types';
77
import { DiamondCutFacet__factory } from '../../typechain';
88
import { getFunctionSelectors } from '../../utils/proxy-tools';
99

10+
// TODO remove this module.
11+
1012
function encodeModuleProxyUpdate(contractFactory: ContractFactory, moduleAddress: string) {
1113
// Get function selectors from the contract factory
1214
const functionSelectors = getFunctionSelectors(contractFactory);

scripts/upgrades/v6.1.0-bulk-processing.ts

Lines changed: 82 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -1,217 +1,101 @@
11
// SPDX-FileCopyrightText: 2025 IEXEC BLOCKCHAIN TECH <[email protected]>
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers';
5-
import { ZeroAddress } from 'ethers';
6-
import { ethers } from 'hardhat';
7-
import { FacetCutAction } from 'hardhat-deploy/dist/types';
8-
import type { DiamondCutFacet, IDiamond } from '../../typechain';
4+
import { FunctionFragment } from 'ethers';
5+
import { IexecPoco1Facet__factory, IexecPocoAccessorsFacet__factory } from '../../typechain';
96
import {
10-
DiamondCutFacet__factory,
11-
DiamondLoupeFacet__factory,
12-
IexecPoco1Facet__factory,
13-
IexecPocoAccessorsFacet__factory,
14-
} from '../../typechain';
15-
import { Ownable__factory } from '../../typechain/factories/rlc-faucet-contract/contracts';
16-
import { FactoryDeployer } from '../../utils/FactoryDeployer';
17-
import config from '../../utils/config';
18-
import { getDeployerAndOwnerSigners } from '../../utils/deploy-tools';
19-
import { linkContractToProxy, printOnchainProxyFunctions } from '../../utils/proxy-tools';
7+
deployFacets,
8+
FacetDetails,
9+
getUpgradeContext,
10+
linkFacetsToDiamond,
11+
printOnchainProxyFunctions,
12+
removeFacetsFromDiamond,
13+
removeFunctionsFromDiamond,
14+
} from '../../utils/proxy-tools';
2015
import { tryVerify } from '../verify';
16+
import { isArbitrumFork } from '../../utils/config';
2117

2218
async function main() {
23-
console.log('Deploying and updating IexecPocoAccessorsFacet & IexecPoco1Facet...');
24-
25-
const { deployer, owner } = await getDeployerAndOwnerSigners();
26-
const chainId = (await ethers.provider.getNetwork()).chainId;
27-
const deploymentOptions = config.getChainConfig(chainId).v5;
28-
29-
if (!deploymentOptions.IexecLibOrders_v5) {
30-
throw new Error('IexecLibOrders_v5 is required');
31-
}
32-
if (!deploymentOptions.DiamondProxy) {
33-
throw new Error('DiamondProxy is required');
34-
}
35-
36-
const diamondProxyAddress = deploymentOptions.DiamondProxy;
37-
console.log(`Network: ${chainId}`);
38-
console.log(`Diamond proxy address: ${diamondProxyAddress}`);
39-
40-
const proxyOwnerAddress = await Ownable__factory.connect(diamondProxyAddress, owner).owner();
41-
console.log(`Diamond proxy owner: ${proxyOwnerAddress}`);
42-
43-
// Use impersonated signer only for fork testing, otherwise use owner signer
44-
const proxyOwnerSigner =
45-
process.env.ARBITRUM_FORK === 'true' || process.env.ARBITRUM_SEPOLIA_FORK === 'true'
46-
? await ethers.getImpersonatedSigner(proxyOwnerAddress)
47-
: owner;
48-
const diamondProxyAsOwner = DiamondCutFacet__factory.connect(
49-
diamondProxyAddress,
50-
proxyOwnerSigner,
51-
);
52-
53-
const { iexecPocoAccessorsFacet, newIexecPoco1Facet } = await deployNewFacets(
54-
deployer,
55-
chainId,
56-
deploymentOptions.IexecLibOrders_v5,
57-
);
58-
const iexecLibOrders = {
59-
['contracts/libs/IexecLibOrders_v5.sol:IexecLibOrders_v5']:
60-
deploymentOptions.IexecLibOrders_v5,
19+
console.log('Performing bulk processing upgrade...');
20+
const { chainId, deployer, proxyOwner, proxyAddress, iexecLibOrders } =
21+
await getUpgradeContext();
22+
23+
// TODO read addresses from deployments.
24+
const facetAddressesPerChain: { [key: string]: { [key: string]: string } } = {
25+
// Arbitrum sepolia
26+
'421614': {
27+
IexecAccessorsFacet: '0xEa232be31ab0112916505Aeb7A2a94b5571DCc6b',
28+
IexecPocoAccessorsFacet: '0x6C56FFFd001939d03779929702B2722C904a34da',
29+
IexecPoco1Facet: '0xB670bf6165f1Df353CeA45AFB622dd91EA973AB9',
30+
},
31+
// Arbitrum mainnet
32+
'42161': {
33+
IexecAccessorsFacet: '0xEa232be31ab0112916505Aeb7A2a94b5571DCc6b',
34+
IexecPocoAccessorsFacet: '0xeb40697b275413241d9b31dE568C98B3EA12FFF0',
35+
IexecPoco1Facet: '0x46b555fE117DFd8D4eAC2470FA2d739c6c3a0152',
36+
},
6137
};
62-
const iexecPocoAccessorsFacetFactory = new IexecPocoAccessorsFacet__factory(iexecLibOrders);
63-
const newIexecPoco1FacetFactory = new IexecPoco1Facet__factory(iexecLibOrders);
64-
await removeOldFacetsFromDiamond(diamondProxyAsOwner, chainId);
65-
await linkNewFacetsToDiamond(
66-
diamondProxyAsOwner,
67-
iexecPocoAccessorsFacet,
68-
newIexecPoco1Facet,
69-
iexecPocoAccessorsFacetFactory,
70-
newIexecPoco1FacetFactory,
71-
);
72-
await tryVerify([
38+
const facetsToRemove: FacetDetails[] = [
7339
{
74-
name: 'IexecPocoAccessorsFacet',
75-
address: iexecPocoAccessorsFacet,
76-
constructorArguments: [],
40+
name: 'IexecAccessorsFacet',
41+
address: facetAddressesPerChain[chainId.toString()]['IexecAccessorsFacet'],
42+
factory: null,
7743
},
7844
{
7945
name: 'IexecPoco1Facet',
80-
address: newIexecPoco1Facet,
81-
constructorArguments: [],
46+
address: facetAddressesPerChain[chainId.toString()]['IexecPoco1Facet'],
47+
factory: null,
48+
},
49+
{
50+
name: 'IexecPocoAccessorsFacet',
51+
address: facetAddressesPerChain[chainId.toString()]['IexecPocoAccessorsFacet'],
52+
factory: null,
8253
},
83-
]);
84-
}
85-
86-
async function deployNewFacets(
87-
deployer: SignerWithAddress,
88-
chainId: bigint,
89-
iexecLibOrdersAddress: string,
90-
) {
91-
console.log('\n=== Step 1: Deploying all new facets ===');
92-
const factoryDeployer = new FactoryDeployer(deployer, chainId);
93-
const iexecLibOrders = {
94-
['contracts/libs/IexecLibOrders_v5.sol:IexecLibOrders_v5']: iexecLibOrdersAddress,
95-
};
96-
97-
console.log('Deploying new IexecPocoAccessorsFacet...');
98-
const iexecPocoAccessorsFacetFactory = new IexecPocoAccessorsFacet__factory(iexecLibOrders);
99-
const iexecPocoAccessorsFacet = await factoryDeployer.deployContract(
100-
new IexecPocoAccessorsFacet__factory(iexecLibOrders),
101-
);
102-
103-
console.log('Deploying new IexecPoco1Facet...');
104-
const newIexecPoco1FacetFactory = new IexecPoco1Facet__factory(iexecLibOrders);
105-
const newIexecPoco1Facet = await factoryDeployer.deployContract(newIexecPoco1FacetFactory);
106-
return { iexecPocoAccessorsFacet, newIexecPoco1Facet };
107-
}
108-
109-
async function removeOldFacetsFromDiamond(diamondProxyAsOwner: DiamondCutFacet, chainId: bigint) {
110-
const diamondProxyAddress = await diamondProxyAsOwner.getAddress();
111-
console.log(
112-
'\n=== Step 2: Remove old facets (IexecAccessorsFacet & IexecPocoAccessorsFacet & IexecPoco1Facet) ===',
113-
);
114-
115-
const diamondLoupe = DiamondLoupeFacet__factory.connect(diamondProxyAddress, ethers.provider);
116-
const currentFacets = await diamondLoupe.facets();
117-
118-
console.log('\nCurrent facets in diamond:');
119-
currentFacets.forEach((facet) => {
120-
console.log(` ${facet.facetAddress}: ${facet.functionSelectors.length} functions`);
121-
});
122-
123-
console.log('Diamond functions before upgrade:');
124-
await printOnchainProxyFunctions(diamondProxyAddress);
125-
126-
const removalCuts: IDiamond.FacetCutStruct[] = [];
127-
128-
// constant functions are deployed within IexecAccessorsFacet on arbitrum sepolia
129-
if (process.env.ARBITRUM_FORK === 'true' || chainId == 42161n) {
130-
const constantFunctionSignatures = [
131-
'CONTRIBUTION_DEADLINE_RATIO()',
132-
'FINAL_DEADLINE_RATIO()',
133-
'GROUPMEMBER_PURPOSE()',
134-
'KITTY_ADDRESS()',
135-
'KITTY_MIN()',
136-
'KITTY_RATIO()',
137-
'REVEAL_DEADLINE_RATIO()',
138-
'WORKERPOOL_STAKE_RATIO()',
139-
];
140-
const constantFunctionsToRemove = constantFunctionSignatures.map((sig) =>
141-
ethers.id(sig).slice(0, 10),
142-
);
143-
console.log(
144-
`Removing specific constant functions from diamond Proxy - will remove ${constantFunctionsToRemove.length} specific constant functions`,
145-
);
146-
removalCuts.push({
147-
facetAddress: ZeroAddress,
148-
action: FacetCutAction.Remove,
149-
functionSelectors: constantFunctionsToRemove,
150-
});
151-
}
152-
153-
const oldFacets = [
154-
'0xEa232be31ab0112916505Aeb7A2a94b5571DCc6b', //IexecAccessorsFacet
155-
'0xeb40697b275413241d9b31dE568C98B3EA12FFF0', //IexecPocoAccessorsFacet
156-
'0x46b555fE117DFd8D4eAC2470FA2d739c6c3a0152', //IexecPoco1Facet
15754
];
158-
// Remove ALL functions from the old facets using diamondLoupe.facetFunctionSelectors() except of constant founctions
159-
for (const facetAddress of oldFacets) {
160-
const selectors = await diamondLoupe.facetFunctionSelectors(facetAddress);
161-
if (selectors.length > 0) {
162-
console.log(
163-
`Removing old facet ${facetAddress} with ${selectors.length} functions - will remove ALL`,
164-
);
165-
removalCuts.push({
166-
facetAddress: ZeroAddress,
167-
action: FacetCutAction.Remove,
168-
functionSelectors: [...selectors],
169-
});
170-
}
171-
}
172-
173-
if (removalCuts.length > 0) {
174-
console.log('Executing diamond cut to remove old functions...');
175-
console.log(`Removal cuts: ${removalCuts.length}`);
176-
removalCuts.forEach((cut, index) => {
177-
console.log(` Cut ${index + 1}: Remove ${cut.functionSelectors.length} functions`);
178-
});
17955

180-
const removeTx = await diamondProxyAsOwner.diamondCut(removalCuts, ZeroAddress, '0x');
181-
await removeTx.wait();
182-
console.log(`Transaction hash: ${removeTx.hash}`);
183-
console.log('Diamond functions after removing old facets:');
184-
await printOnchainProxyFunctions(diamondProxyAddress);
56+
const facetsToAdd: FacetDetails[] = [
57+
{
58+
name: 'IexecPoco1Facet',
59+
address: null,
60+
factory: new IexecPoco1Facet__factory(iexecLibOrders),
61+
},
62+
{
63+
name: 'IexecPocoAccessorsFacet',
64+
address: null,
65+
factory: new IexecPocoAccessorsFacet__factory(iexecLibOrders),
66+
},
67+
];
68+
await printOnchainProxyFunctions(proxyAddress);
69+
// This function adds the address of each deployed facet to `facetsToAdd` array.
70+
await deployFacets(deployer, chainId, facetsToAdd);
71+
await removeFacetsFromDiamond(proxyAddress, proxyOwner, facetsToRemove);
72+
await printOnchainProxyFunctions(proxyAddress);
73+
if (isArbitrumFork() || chainId == 42161n) {
74+
// Remove these functions from Arbitrum Mainnet without removing
75+
// their facet completely.
76+
// On Arbitrum Mainnet, they were deployed in `IexecAccessorsABILegacyFacet`.
77+
// On Arbitrum Sepolia, they were deployed in `IexecAccessorsFacet` so no need
78+
// to remove them manually since they are automatically removed when executing
79+
// `removeFacetsFromDiamond`.
80+
const functionSignatures = [
81+
FunctionFragment.from('function CONTRIBUTION_DEADLINE_RATIO() view returns (uint256)'),
82+
FunctionFragment.from('function FINAL_DEADLINE_RATIO() view returns (uint256)'),
83+
FunctionFragment.from('function GROUPMEMBER_PURPOSE() view returns (uint256)'),
84+
FunctionFragment.from('function KITTY_ADDRESS() view returns (address)'),
85+
FunctionFragment.from('function KITTY_MIN() view returns (uint256)'),
86+
FunctionFragment.from('function KITTY_RATIO() view returns (uint256)'),
87+
FunctionFragment.from('function REVEAL_DEADLINE_RATIO() view returns (uint256)'),
88+
FunctionFragment.from('function WORKERPOOL_STAKE_RATIO() view returns (uint256)'),
89+
];
90+
await removeFunctionsFromDiamond(proxyAddress, proxyOwner, functionSignatures);
91+
await printOnchainProxyFunctions(proxyAddress);
18592
}
186-
}
187-
188-
async function linkNewFacetsToDiamond(
189-
diamondProxyAsOwner: DiamondCutFacet,
190-
iexecPocoAccessorsFacet: string,
191-
newIexecPoco1Facet: string,
192-
iexecPocoAccessorsFacetFactory: IexecPocoAccessorsFacet__factory,
193-
newIexecPoco1FacetFactory: IexecPoco1Facet__factory,
194-
) {
195-
const diamondProxyAddress = await diamondProxyAsOwner.getAddress();
196-
console.log('\n=== Step 3: Updating diamond proxy with all new facets ===');
197-
console.log('Adding new IexecPocoAccessorsFacet...');
198-
await linkContractToProxy(
199-
diamondProxyAsOwner,
200-
iexecPocoAccessorsFacet,
201-
iexecPocoAccessorsFacetFactory,
202-
);
203-
console.log('New IexecPocoAccessorsFacet added successfully');
204-
205-
console.log('Adding new IexecPoco1Facet ...');
206-
await linkContractToProxy(diamondProxyAsOwner, newIexecPoco1Facet, newIexecPoco1FacetFactory);
207-
console.log('New IexecPoco1Facet with assertDatasetDealCompatibility added successfully');
208-
209-
console.log('Diamond functions after adding new facets:');
210-
await printOnchainProxyFunctions(diamondProxyAddress);
211-
212-
console.log('\nUpgrade completed successfully!');
213-
console.log(`New IexecPocoAccessorsFacet deployed at: ${iexecPocoAccessorsFacet}`);
214-
console.log(`New IexecPoco1Facet deployed at: ${newIexecPoco1Facet}`);
93+
// TODO remove boost from Arbitrum Sepolia
94+
await linkFacetsToDiamond(proxyAddress, proxyOwner, facetsToAdd);
95+
await printOnchainProxyFunctions(proxyAddress);
96+
console.log('Upgrade performed successfully!');
97+
// TODO pass only name as argument and get address from deployments.
98+
await tryVerify(facetsToAdd as { name: string; address: string }[]);
21599
}
216100

217101
if (require.main === module) {

0 commit comments

Comments
 (0)