Skip to content

Commit a8ffae3

Browse files
authored
Add CreateX factory for new chain deployment (#215)
2 parents 993b920 + e737a6b commit a8ffae3

File tree

14 files changed

+405
-123
lines changed

14 files changed

+405
-123
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
- [x] `IexecPoco2Delegate.sol`
1010

1111
### Features
12-
12+
- Add CreateX factory for new chain deployment (#215)
13+
- Support Arbitrum & Avalanche Fuji testnets (#215)
1314
- Housekeeping (#207, )
1415
- Add Halborn "Poco v5.5 & Voucher v1.0" audit report (#205)
1516
- Refactor Factory deployer (#206)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ It contains:
5353
- **"asset":** can be "Token" or "Native", select which escrow to use.
5454
- **"token":** the address of the token to use. If asset is set to token, and no token address is provided, a mock will be deployed on the fly.
5555
- **"v3":** a list of resources from a previous (v3) deployment. This allows previous resources to be automatically available. It also enables score transfer from v3 to v5. [optional]
56-
- **"v5":** deployment parameters for the new version. If usefactory is set to true, and no salt is provided, `bytes32(0)` will be used by default.
56+
- **"v5":** deployment parameters for the new version. If factory address is set, and no salt is provided, `bytes32(0)` will be used by default.
5757

5858
If you want to deploy the iExec PoCo V5 smart contracts on a new blockchain, the recommended process is to:
5959

config/config.json

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"WorkerpoolRegistry": "0xc398052563469e6Ea7C442aBf124aADE7ec2CC92"
4545
},
4646
"v5": {
47-
"usefactory": true,
4847
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
4948
"AppRegistry": "0xB1C52075b276f87b1834919167312221d50c9D16",
5049
"DatasetRegistry": "0x799DAa22654128d0C64d5b79eac9283008158730",
@@ -63,7 +62,6 @@
6362
"WorkerpoolRegistry": null
6463
},
6564
"v5": {
66-
"usefactory": true,
6765
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
6866
}
6967
},
@@ -79,7 +77,6 @@
7977
"WorkerpoolRegistry": null
8078
},
8179
"v5": {
82-
"usefactory": true,
8380
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
8481
}
8582
},
@@ -96,7 +93,6 @@
9693
"WorkerpoolRegistry": "0xdAD30AAb14F569830bFd26EdF72df876dc30D20c"
9794
},
9895
"v5": {
99-
"usefactory": true,
10096
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
10197
}
10298
},
@@ -112,7 +108,6 @@
112108
"WorkerpoolRegistry": "0x3f4C18C322064576C048b1284b700288ffEf126B"
113109
},
114110
"v5": {
115-
"usefactory": true,
116111
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
117112
}
118113
},
@@ -126,7 +121,6 @@
126121
"WorkerpoolRegistry": "0x1Cae59C7745A61dD37CD17f174745959D0f3f400"
127122
},
128123
"v5": {
129-
"usefactory": true,
130124
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
131125
}
132126
},
@@ -142,7 +136,43 @@
142136
"v5": {
143137
"ERC1538Proxy": "0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f",
144138
"IexecLibOrders_v5": "0xE8b04c85C47fcEc0e9eE30D4034e2997f6519123",
145-
"usefactory": true,
139+
"factory": "0xfAC000a12dA42B871c0AaD5F25391aAe62958Db1",
140+
"factoryType": "generic",
141+
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
142+
}
143+
},
144+
"43113": {
145+
"_comment": "Avalanche Fuji Testnet",
146+
"asset": "Token",
147+
"token": "0xb96484C8B0e27B08a86661a3c19A028f4d3e89ad",
148+
"richman": "0xd88CF17D89533816E99C0427581aa8C72129037D",
149+
"uniswap": false,
150+
"v3": {
151+
"Hub": null,
152+
"AppRegistry": null,
153+
"DatasetRegistry": null,
154+
"WorkerpoolRegistry": null
155+
},
156+
"v5": {
157+
"factory": "0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed",
158+
"factoryType": "createx",
159+
"ERC1538Proxy": "0x14B465079537655E1662F012e99EBa3863c8B9E0",
160+
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
161+
}
162+
},
163+
"421614": {
164+
"_comment": "Arbitrum Sepolia Testnet",
165+
"asset": "Token",
166+
"uniswap": false,
167+
"v3": {
168+
"Hub": null,
169+
"AppRegistry": null,
170+
"DatasetRegistry": null,
171+
"WorkerpoolRegistry": null
172+
},
173+
"v5": {
174+
"factory": "0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed",
175+
"factoryType": "createx",
146176
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
147177
}
148178
},
@@ -158,7 +188,6 @@
158188
"WorkerpoolRegistry": null
159189
},
160190
"v5": {
161-
"usefactory": true,
162191
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
163192
}
164193
}

config/config_native.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
"WorkerpoolRegistry": null
4444
},
4545
"v5": {
46-
"usefactory": true,
4746
"salt": "0xbe1a000000000000000000000000000000000000000000000000000000000000"
4847
}
4948
}

config/config_token.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
"WorkerpoolRegistry": null
4444
},
4545
"v5": {
46-
"usefactory": true,
4746
"salt": "0xbe1a000000000000000000000000000000000000000000000000000000000000"
4847
}
4948
}

deploy/0_deploy.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers';
55
import { ZeroAddress, ZeroHash } from 'ethers';
6-
import { ethers } from 'hardhat';
6+
import { deployments, ethers } from 'hardhat';
77
import {
88
AppRegistry__factory,
99
DatasetRegistry__factory,
@@ -37,8 +37,8 @@ import {
3737
WorkerpoolRegistry__factory,
3838
} from '../typechain';
3939
import { Ownable__factory } from '../typechain/factories/@openzeppelin/contracts/access';
40-
import config from '../utils/config';
4140
import { FactoryDeployer } from '../utils/FactoryDeployer';
41+
import config from '../utils/config';
4242
import { linkContractToProxy } from '../utils/proxy-tools';
4343

4444
/**
@@ -56,16 +56,15 @@ export default async function deploy() {
5656
const chainId = (await ethers.provider.getNetwork()).chainId;
5757
const [owner] = await ethers.getSigners();
5858
const deploymentOptions = config.getChainConfigOrDefault(chainId);
59-
const salt = process.env.SALT || deploymentOptions.v5.salt || ethers.ZeroHash;
60-
const factoryDeployer = new FactoryDeployer(owner, salt);
59+
const factoryDeployer = new FactoryDeployer(owner, chainId);
6160
// Deploy RLC
6261
const isTokenMode = !config.isNativeChain(deploymentOptions);
6362
let rlcInstanceAddress = isTokenMode
6463
? await getOrDeployRlc(deploymentOptions.token!, owner) // token
6564
: ZeroAddress; // native
6665
console.log(`RLC: ${rlcInstanceAddress}`);
6766
// Deploy ERC1538 proxy contracts
68-
const erc1538UpdateAddress = await factoryDeployer.deployWithFactory(
67+
const erc1538UpdateAddress = await factoryDeployer.deployContract(
6968
new ERC1538UpdateDelegate__factory(),
7069
);
7170
const transferOwnershipCall = await Ownable__factory.connect(
@@ -77,15 +76,15 @@ export default async function deploy() {
7776
.catch(() => {
7877
throw new Error('Failed to prepare transferOwnership data');
7978
});
80-
const erc1538ProxyAddress = await factoryDeployer.deployWithFactory(
79+
const erc1538ProxyAddress = await factoryDeployer.deployContract(
8180
new ERC1538Proxy__factory(),
8281
[erc1538UpdateAddress],
8382
transferOwnershipCall,
8483
);
8584
const erc1538: ERC1538Update = ERC1538Update__factory.connect(erc1538ProxyAddress, owner);
8685
console.log(`IexecInstance found at address: ${await erc1538.getAddress()}`);
8786
// Deploy library & modules
88-
const iexecLibOrdersAddress = await factoryDeployer.deployWithFactory(
87+
const iexecLibOrdersAddress = await factoryDeployer.deployContract(
8988
new IexecLibOrders_v5__factory(),
9089
);
9190
const iexecLibOrders = {
@@ -112,7 +111,7 @@ export default async function deploy() {
112111
new IexecPocoBoostAccessorsDelegate__factory(),
113112
];
114113
for (const module of modules) {
115-
const address = await factoryDeployer.deployWithFactory(module);
114+
const address = await factoryDeployer.deployContract(module);
116115
await linkContractToProxy(erc1538, address, module);
117116
}
118117
// Verify linking on ERC1538Proxy
@@ -126,17 +125,17 @@ export default async function deploy() {
126125
const [method, , contract] = await erc1538QueryInstance.functionByIndex(i);
127126
console.log(`[${i}] ${contract} ${method}`);
128127
}
129-
const appRegistryAddress = await factoryDeployer.deployWithFactory(
128+
const appRegistryAddress = await factoryDeployer.deployContract(
130129
new AppRegistry__factory(),
131130
[],
132131
transferOwnershipCall,
133132
);
134-
const datasetRegistryAddress = await factoryDeployer.deployWithFactory(
133+
const datasetRegistryAddress = await factoryDeployer.deployContract(
135134
new DatasetRegistry__factory(),
136135
[],
137136
transferOwnershipCall,
138137
);
139-
const workerpoolRegistryAddress = await factoryDeployer.deployWithFactory(
138+
const workerpoolRegistryAddress = await factoryDeployer.deployContract(
140139
new WorkerpoolRegistry__factory(),
141140
[],
142141
transferOwnershipCall,
@@ -213,11 +212,26 @@ export default async function deploy() {
213212
}
214213

215214
async function getOrDeployRlc(token: string, owner: SignerWithAddress) {
216-
return token // token
217-
? token
218-
: await new RLC__factory()
219-
.connect(owner)
220-
.deploy()
221-
.then((contract) => contract.waitForDeployment())
222-
.then((contract) => contract.getAddress());
215+
const rlcFactory = new RLC__factory().connect(owner);
216+
let rlcAddress: string;
217+
218+
if (token) {
219+
console.log(`Using existing RLC token at: ${token}`);
220+
rlcAddress = token;
221+
} else {
222+
console.log('Deploying new RLC token...');
223+
rlcAddress = await rlcFactory
224+
.deploy()
225+
.then((contract) => contract.waitForDeployment())
226+
.then((contract) => contract.getAddress());
227+
console.log(`New RLC token deployed at: ${rlcAddress}`);
228+
}
229+
230+
await deployments.save('RLC', {
231+
abi: (rlcFactory as any).constructor.abi,
232+
address: rlcAddress,
233+
bytecode: (await rlcFactory.getDeployTransaction()).data,
234+
deployedBytecode: await ethers.provider.getCode(rlcAddress),
235+
});
236+
return rlcAddress;
223237
}

hardhat.config.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import chainConfig from './utils/config';
1313

1414
const isNativeChainType = chainConfig.isNativeChain();
1515
const isLocalFork = process.env.LOCAL_FORK == 'true';
16+
const isFujiFork = process.env.FUJI_FORK == 'true';
17+
const isArbitrumSepoliaFork = process.env.ARBITRUM_SEPOLIA_FORK == 'true';
1618
const bellecourBlockscoutUrl = 'https://blockscout.bellecour.iex.ec';
1719

1820
/**
@@ -28,6 +30,20 @@ const bellecourBaseConfig = {
2830
blockGasLimit: 6_700_000,
2931
};
3032

33+
// Avalanche Fuji specific configuration
34+
const fujiBaseConfig = {
35+
gasPrice: 25_000_000_000, // 25 Gwei default
36+
blockGasLimit: 8_000_000,
37+
chainId: 43113,
38+
};
39+
40+
// Arbitrum Sepolia specific configuration
41+
const arbitrumSepoliaBaseConfig = {
42+
gasPrice: 100_000_000, // 0.1 Gwei default (Arbitrum has lower gas prices)
43+
blockGasLimit: 30_000_000, // Arbitrum has higher block gas limits
44+
chainId: 421614,
45+
};
46+
3147
const settings = {
3248
optimizer: {
3349
enabled: true,
@@ -81,6 +97,26 @@ const config: HardhatUserConfig = {
8197
},
8298
chainId: 134,
8399
}),
100+
...(isFujiFork && {
101+
forking: {
102+
url: process.env.FUJI_RPC_URL || 'https://api.avax-test.network/ext/bc/C/rpc',
103+
blockNumber: process.env.FUJI_BLOCK_NUMBER
104+
? parseInt(process.env.FUJI_BLOCK_NUMBER)
105+
: undefined,
106+
},
107+
...fujiBaseConfig,
108+
}),
109+
...(isArbitrumSepoliaFork && {
110+
forking: {
111+
url:
112+
process.env.ARBITRUM_SEPOLIA_RPC_URL ||
113+
'https://sepolia-rollup.arbitrum.io/rpc',
114+
blockNumber: process.env.ARBITRUM_SEPOLIA_BLOCK_NUMBER
115+
? parseInt(process.env.ARBITRUM_SEPOLIA_BLOCK_NUMBER)
116+
: undefined,
117+
},
118+
...arbitrumSepoliaBaseConfig,
119+
}),
84120
},
85121
'external-hardhat': {
86122
...defaultHardhatNetworkParams,
@@ -93,6 +129,14 @@ const config: HardhatUserConfig = {
93129
accounts: 'remote', // Override defaults accounts for impersonation
94130
chainId: 134,
95131
}),
132+
...(isFujiFork && {
133+
accounts: 'remote', // Override defaults accounts for impersonation
134+
...fujiBaseConfig,
135+
}),
136+
...(isArbitrumSepoliaFork && {
137+
accounts: 'remote', // Override defaults accounts for impersonation
138+
...arbitrumSepoliaBaseConfig,
139+
}),
96140
},
97141
'dev-native': {
98142
chainId: 65535,
@@ -128,6 +172,22 @@ const config: HardhatUserConfig = {
128172
mnemonic: process.env.MNEMONIC || '',
129173
},
130174
},
175+
// Add Fuji as a network
176+
avalancheFujiTestnet: {
177+
url: process.env.FUJI_RPC_URL || 'https://api.avax-test.network/ext/bc/C/rpc',
178+
accounts: {
179+
mnemonic: process.env.MNEMONIC || HARDHAT_NETWORK_MNEMONIC,
180+
},
181+
...fujiBaseConfig,
182+
},
183+
// Add Arbitrum Sepolia as a network
184+
'arbitrum-sepolia': {
185+
url: process.env.ARBITRUM_SEPOLIA_RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc',
186+
accounts: {
187+
mnemonic: process.env.MNEMONIC || HARDHAT_NETWORK_MNEMONIC,
188+
},
189+
...arbitrumSepoliaBaseConfig,
190+
},
131191
viviani: {
132192
chainId: 133,
133193
url: 'https://viviani.iex.ec',
@@ -155,6 +215,8 @@ const config: HardhatUserConfig = {
155215
etherscan: {
156216
apiKey: {
157217
mainnet: process.env.ETHERSCAN_API_KEY || '',
218+
avalancheFujiTestnet: 'nothing', // a non-empty string is needed by the plugin.
219+
arbitrumSepolia: process.env.ARBISCAN_API_KEY || '',
158220
viviani: 'nothing', // a non-empty string is needed by the plugin.
159221
bellecour: 'nothing', // a non-empty string is needed by the plugin.
160222
},
@@ -195,6 +257,7 @@ const config: HardhatUserConfig = {
195257
'@openzeppelin/contracts-v5/interfaces/IERC1271.sol',
196258
// Used in deployment
197259
'@amxx/factory/contracts/v6/GenericFactory.sol',
260+
'createx/src/ICreateX.sol',
198261
],
199262
keep: true, // Slither requires compiled dependencies
200263
},
@@ -218,7 +281,7 @@ const config: HardhatUserConfig = {
218281
'Store.v8.sol',
219282
],
220283
},
221-
mocha: { timeout: 50000 },
284+
mocha: { timeout: 300000 },
222285
};
223286

224287
/**

0 commit comments

Comments
 (0)