Skip to content

Commit e7c3e71

Browse files
authored
feat(sharing): Deploy contracts using Hardhat Ignition (#440)
1 parent 6582e96 commit e7c3e71

File tree

12 files changed

+199
-157
lines changed

12 files changed

+199
-157
lines changed

packages/sharing-smart-contract/.env.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# wallet used for transactions
2-
WALLET_PRIVATE_KEY=...
2+
PRIVATE_KEY=...
33

44
# environment to use for configuration (prod/staging). The default is prod.
55
ENV=...

packages/sharing-smart-contract/README.md

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,26 @@ To verify the contracts:
3939
npm run verify
4040
```
4141

42-
### Deploy (Production)
42+
### Deployment
4343

44-
To deploy the project on the production network - bellecour.
45-
⚠️ Be sure before deploying on bellecour
44+
To deploy the contracts on a local hardhat network, run:
4645

4746
```bash
48-
npm run script:prod
47+
npm run deploy # [-- --network <localhost>] if using an external local node.
4948
```
5049

51-
### Deploy (Test)
52-
53-
To deploy the project on the test network - localhost.
54-
You need first to start a local hardhat node which will be a fork of bellecour network :
55-
50+
To deploy the project on a live network, two options are available:
51+
1. Triggering the dedicated Github Action workflow (recommended).
52+
2. Or adding a private key locally and running:
5653
```bash
57-
npx hardhat node
54+
npm run deploy -- --network <name>
5855
```
5956

60-
Open a new terminal and run :
57+
#### Note:
58+
* Deployment on chains that support CreateX factory will deploy contracts
59+
using `create2` strategy.
60+
* Github Actions workflow should be used for production deployments.
6161

62-
```bash
63-
npm run script:test
64-
```
6562

6663
### Run Tests
6764

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Hardhat Ignition does not support ESM modules, so we use CommonJS syntax.
2+
// TODO refactor this to use ESM syntax when Hardhat Ignition supports it.
3+
4+
module.exports = {
5+
POCO_ADDRESS: '0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f',
6+
DATASET_REGISTRY_ADDRESS: '0x799DAa22654128d0C64d5b79eac9283008158730',
7+
APP_REGISTRY_ADDRESS: '0xB1C52075b276f87b1834919167312221d50c9D16',
8+
};
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export const SMART_CONTRACT_ADDRESS_FILE = '.smart-contract-address';
2-
export const POCO_ADDRESS = '0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f';
3-
export const DATASET_REGISTRY_ADDRESS = '0x799DAa22654128d0C64d5b79eac9283008158730';
4-
export const APP_REGISTRY_ADDRESS = '0xB1C52075b276f87b1834919167312221d50c9D16';
1+
import config from './config.cjs';
2+
3+
export const POCO_ADDRESS = config.POCO_ADDRESS;
4+
export const DATASET_REGISTRY_ADDRESS = config.DATASET_REGISTRY_ADDRESS;
5+
export const APP_REGISTRY_ADDRESS = config.APP_REGISTRY_ADDRESS;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Hardhat Ignition does not support ESM modules, so we use CommonJS syntax.
2+
// TODO refactor this to use ESM syntax when Hardhat Ignition supports it.
3+
4+
require('dotenv/config.js');
5+
const { z } = require('zod');
6+
7+
const addressRegex = /(^|\b)(0x)?[0-9a-fA-F]{40}(\b|$)/;
8+
const privateKeyRegex = /(^|\b)(0x)?[0-9a-fA-F]{64}(\b|$)/;
9+
10+
const envSchema = z.object({
11+
// Private key of the wallet used for transactions
12+
PRIVATE_KEY: z
13+
.string()
14+
.regex(privateKeyRegex, 'Invalid private key format')
15+
.optional()
16+
.or(z.literal('')),
17+
18+
// environment to use for configuration (prod/staging)
19+
ENV: z.enum(['prod', 'staging'], 'ENV must be either "prod" or "staging"').default('prod'),
20+
21+
// Address of the PoCo contract
22+
POCO_ADDRESS: z
23+
.string()
24+
.regex(addressRegex, 'Invalid Ethereum address format')
25+
.optional()
26+
.or(z.literal('')),
27+
28+
// Address of the DatasetRegistry
29+
DATASET_REGISTRY_ADDRESS: z
30+
.string()
31+
.regex(addressRegex, 'Invalid Ethereum address format')
32+
.optional()
33+
.or(z.literal('')),
34+
35+
// URL of the RPC used for network connection
36+
RPC_URL: z.string().url('RPC_URL must be a valid URL').optional().or(z.literal('')),
37+
38+
// Mnemonic for deployment or network interaction
39+
MNEMONIC: z.string().min(1, 'MNEMONIC cannot be empty').optional().or(z.literal('')),
40+
41+
FUJI_RPC_URL: z.string().url('FUJI_RPC_URL must be a valid URL').optional(),
42+
43+
ARBITRUM_SEPOLIA_RPC_URL: z
44+
.string()
45+
.url('ARBITRUM_SEPOLIA_RPC_URL must be a valid URL')
46+
.optional(),
47+
});
48+
49+
module.exports = {
50+
env: envSchema.parse(process.env),
51+
};
Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,3 @@
1-
import 'dotenv/config.js';
2-
import { z } from 'zod';
1+
import _env from './env.cjs';
32

4-
const addressRegex = /(^|\b)(0x)?[0-9a-fA-F]{64}(\b|$)/;
5-
const privateKeyRegex = /(^|\b)(0x)?[0-9a-fA-F]{64}(\b|$)/;
6-
7-
const envSchema = z.object({
8-
// Private key of the wallet used for transactions
9-
WALLET_PRIVATE_KEY: z
10-
.string()
11-
.regex(privateKeyRegex, 'Invalid private key format')
12-
.optional()
13-
.or(z.literal('')),
14-
15-
// environment to use for configuration (prod/staging)
16-
ENV: z.enum(['prod', 'staging'], 'ENV must be either "prod" or "staging"').default('prod'),
17-
18-
// Address of the PoCo contract
19-
POCO_ADDRESS: z
20-
.string()
21-
.regex(addressRegex, 'Invalid Ethereum address format')
22-
.optional()
23-
.or(z.literal('')),
24-
25-
// Address of the DatasetRegistry
26-
DATASET_REGISTRY_ADDRESS: z
27-
.string()
28-
.regex(addressRegex, 'Invalid Ethereum address format')
29-
.optional()
30-
.or(z.literal('')),
31-
32-
// URL of the RPC used for network connection
33-
RPC_URL: z.string().url('RPC_URL must be a valid URL').optional().or(z.literal('')),
34-
35-
// Mnemonic for deployment or network interaction
36-
MNEMONIC: z.string().min(1, 'MNEMONIC cannot be empty').optional().or(z.literal('')),
37-
});
38-
39-
export const env = envSchema.parse(process.env);
3+
export const env = _env.env;

packages/sharing-smart-contract/hardhat.config.cjs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ require('@nomicfoundation/hardhat-toolbox');
33
require('@openzeppelin/hardhat-upgrades');
44
require('hardhat-contract-sizer');
55
require('@openzeppelin/hardhat-upgrades');
6-
require('dotenv').config();
6+
require('hardhat-dependency-compiler');
7+
const env = require('./config/env.cjs');
78

8-
const { WALLET_PRIVATE_KEY } = process.env;
9+
// TODO format
910

1011
const bellecourBase = {
1112
gasPrice: 0,
@@ -34,14 +35,32 @@ module.exports = {
3435
bellecour: {
3536
...bellecourBase,
3637
url: 'https://bellecour.iex.ec',
37-
accounts: WALLET_PRIVATE_KEY ? [WALLET_PRIVATE_KEY] : [],
38+
accounts: env.PRIVATE_KEY ? [env.PRIVATE_KEY] : [],
39+
},
40+
avalancheFujiTestnet: {
41+
chainId: 43113,
42+
url: env.FUJI_RPC_URL || 'https://api.avax-test.network/ext/bc/C/rpc',
43+
accounts: [
44+
env.PRIVATE_KEY ||
45+
'0x0000000000000000000000000000000000000000000000000000000000000000',
46+
],
47+
blockGasLimit: 8_000_000,
48+
},
49+
arbitrumSepolia: {
50+
chainId: 421614,
51+
url: env.ARBITRUM_SEPOLIA_RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc',
52+
accounts: [
53+
process.env.PRIVATE_KEY ||
54+
'0x0000000000000000000000000000000000000000000000000000000000000000',
55+
],
56+
blockGasLimit: 30_000_000,
3857
},
3958
// poco-chain native config
4059
'dev-native': {
4160
chainId: 65535,
42-
url: process.env.RPC_URL ?? 'http://localhost:8545',
61+
url: env.RPC_URL ?? 'http://localhost:8545',
4362
accounts: {
44-
mnemonic: process.env.MNEMONIC ?? '',
63+
mnemonic: env.MNEMONIC ?? '',
4564
},
4665
gasPrice: 0,
4766
},
@@ -87,4 +106,16 @@ module.exports = {
87106
},
88107
},
89108
},
109+
ignition: {
110+
strategyConfig: {
111+
create2: {
112+
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
113+
},
114+
},
115+
},
116+
dependencyCompiler: {
117+
paths: [
118+
'@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol',
119+
],
120+
},
90121
};
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const { buildModule } = require('@nomicfoundation/hardhat-ignition/modules');
2+
3+
const {
4+
DATASET_REGISTRY_ADDRESS: defaultDatasetRegistryAddress,
5+
POCO_ADDRESS: defaultPocoAddress,
6+
} = require('../../config/config.cjs');
7+
const { env } = require('../../config/env.cjs');
8+
9+
// Hardhat Ignition does not support ESM yet.
10+
11+
// @ts-ignore
12+
module.exports = buildModule('DataProtectorSharingModule', (m) => {
13+
const proxyAdminOwner = m.getAccount(0);
14+
const pocoAddress = env.POCO_ADDRESS || defaultPocoAddress;
15+
const datasetRegistryAddress = env.DATASET_REGISTRY_ADDRESS || defaultDatasetRegistryAddress;
16+
17+
// Whitelist
18+
const addOnlyAppWhitelistRegistryImpl = m.contract('AddOnlyAppWhitelistRegistry', [], {
19+
id: 'AddOnlyAppWhitelistRegistryImpl',
20+
});
21+
const addOnlyAppWhitelistRegistryProxy = m.contract(
22+
'TransparentUpgradeableProxy',
23+
[
24+
addOnlyAppWhitelistRegistryImpl,
25+
proxyAdminOwner,
26+
'0x', // No initialization data.
27+
],
28+
{
29+
id: 'AddOnlyAppWhitelistRegistryProxy',
30+
},
31+
);
32+
const addOnlyAppWhitelistRegistry = m.contractAt(
33+
'AddOnlyAppWhitelistRegistry',
34+
addOnlyAppWhitelistRegistryProxy,
35+
);
36+
37+
// DPS
38+
const dataProtectorSharingImpl = m.contract(
39+
'DataProtectorSharing',
40+
[pocoAddress, datasetRegistryAddress, addOnlyAppWhitelistRegistryProxy],
41+
{
42+
id: 'DataProtectorSharingImpl',
43+
},
44+
);
45+
const dataProtectorSharingProxy = m.contract(
46+
'TransparentUpgradeableProxy',
47+
[
48+
dataProtectorSharingImpl,
49+
proxyAdminOwner,
50+
'0x', // No initialization data.
51+
],
52+
{
53+
id: 'DataProtectorSharingProxy',
54+
},
55+
);
56+
const dataProtectorSharing = m.contractAt('DataProtectorSharing', dataProtectorSharingProxy);
57+
58+
return { addOnlyAppWhitelistRegistry, dataProtectorSharing };
59+
});

packages/sharing-smart-contract/package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/sharing-smart-contract/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"clean": "hardhat clean",
1010
"compile": "hardhat clean && hardhat compile && npm run artifact-to-abis",
1111
"verify": "hardhat verify",
12-
"deploy": "npm run compile && hardhat run ./scripts/deploy.js",
12+
"deploy": "hardhat ignition deploy ignition/modules/DataProtectorSharingModule.cts --strategy create2",
1313
"update-env": "hardhat run ./scripts/updateEnv.js",
1414
"upgrade": "hardhat run ./scripts/upgrade.js",
1515
"upgrade-local-fork": "mkdir -p .openzeppelin/local-fork && cp -r .openzeppelin/prod/. .openzeppelin/local-fork && MANIFEST_DEFAULT_DIR=.openzeppelin/local-fork ENV=prod hardhat run ./scripts/upgrade-local-fork.js",
@@ -41,6 +41,7 @@
4141
"eslint-plugin-import": "^2.31.0",
4242
"hardhat": "^2.23.0",
4343
"hardhat-contract-sizer": "^2.10.0",
44+
"hardhat-dependency-compiler": "^1.2.1",
4445
"prettier": "^3.3.3",
4546
"prettier-plugin-organize-imports": "^4.0.0",
4647
"prettier-plugin-solidity": "^1.4.1",

0 commit comments

Comments
 (0)