@diamondslab/diamonds 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/README.md +618 -0
  2. package/diamonds/README.md +3 -0
  3. package/dist/core/CallbackManager.d.ts +13 -0
  4. package/dist/core/CallbackManager.d.ts.map +1 -0
  5. package/dist/core/CallbackManager.js +95 -0
  6. package/dist/core/CallbackManager.js.map +1 -0
  7. package/dist/core/DeploymentManager.d.ts +10 -0
  8. package/dist/core/DeploymentManager.d.ts.map +1 -0
  9. package/dist/core/DeploymentManager.js +50 -0
  10. package/dist/core/DeploymentManager.js.map +1 -0
  11. package/dist/core/Diamond.d.ts +58 -0
  12. package/dist/core/Diamond.d.ts.map +1 -0
  13. package/dist/core/Diamond.js +146 -0
  14. package/dist/core/Diamond.js.map +1 -0
  15. package/dist/core/DiamondDeployer.d.ts +10 -0
  16. package/dist/core/DiamondDeployer.d.ts.map +1 -0
  17. package/dist/core/DiamondDeployer.js +33 -0
  18. package/dist/core/DiamondDeployer.js.map +1 -0
  19. package/dist/core/index.d.ts +5 -0
  20. package/dist/core/index.d.ts.map +1 -0
  21. package/dist/core/index.js +12 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +22 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/repositories/DBDeploymentRepository.d.ts +1 -0
  28. package/dist/repositories/DBDeploymentRepository.d.ts.map +1 -0
  29. package/dist/repositories/DBDeploymentRepository.js +20 -0
  30. package/dist/repositories/DBDeploymentRepository.js.map +1 -0
  31. package/dist/repositories/DeploymentRepository.d.ts +8 -0
  32. package/dist/repositories/DeploymentRepository.d.ts.map +1 -0
  33. package/dist/repositories/DeploymentRepository.js +7 -0
  34. package/dist/repositories/DeploymentRepository.js.map +1 -0
  35. package/dist/repositories/FileDeploymentRepository.d.ts +18 -0
  36. package/dist/repositories/FileDeploymentRepository.d.ts.map +1 -0
  37. package/dist/repositories/FileDeploymentRepository.js +58 -0
  38. package/dist/repositories/FileDeploymentRepository.js.map +1 -0
  39. package/dist/repositories/databaseHandler.d.ts +1 -0
  40. package/dist/repositories/databaseHandler.d.ts.map +1 -0
  41. package/dist/repositories/databaseHandler.js +13 -0
  42. package/dist/repositories/databaseHandler.js.map +1 -0
  43. package/dist/repositories/index.d.ts +4 -0
  44. package/dist/repositories/index.d.ts.map +1 -0
  45. package/dist/repositories/index.js +20 -0
  46. package/dist/repositories/index.js.map +1 -0
  47. package/dist/repositories/jsonFileHandler.d.ts +81 -0
  48. package/dist/repositories/jsonFileHandler.d.ts.map +1 -0
  49. package/dist/repositories/jsonFileHandler.js +223 -0
  50. package/dist/repositories/jsonFileHandler.js.map +1 -0
  51. package/dist/repositories/prismaDBHandler.d.ts +1 -0
  52. package/dist/repositories/prismaDBHandler.d.ts.map +1 -0
  53. package/dist/repositories/prismaDBHandler.js +11 -0
  54. package/dist/repositories/prismaDBHandler.js.map +1 -0
  55. package/dist/schemas/DeploymentSchema.d.ts +309 -0
  56. package/dist/schemas/DeploymentSchema.d.ts.map +1 -0
  57. package/dist/schemas/DeploymentSchema.js +56 -0
  58. package/dist/schemas/DeploymentSchema.js.map +1 -0
  59. package/dist/schemas/index.d.ts +2 -0
  60. package/dist/schemas/index.d.ts.map +1 -0
  61. package/dist/schemas/index.js +18 -0
  62. package/dist/schemas/index.js.map +1 -0
  63. package/dist/strategies/BaseDeploymentStrategy.d.ts +41 -0
  64. package/dist/strategies/BaseDeploymentStrategy.d.ts.map +1 -0
  65. package/dist/strategies/BaseDeploymentStrategy.js +545 -0
  66. package/dist/strategies/BaseDeploymentStrategy.js.map +1 -0
  67. package/dist/strategies/DeploymentStrategy.d.ts +19 -0
  68. package/dist/strategies/DeploymentStrategy.d.ts.map +1 -0
  69. package/dist/strategies/DeploymentStrategy.js +3 -0
  70. package/dist/strategies/DeploymentStrategy.js.map +1 -0
  71. package/dist/strategies/LocalDeploymentStrategy.d.ts +4 -0
  72. package/dist/strategies/LocalDeploymentStrategy.d.ts.map +1 -0
  73. package/dist/strategies/LocalDeploymentStrategy.js +8 -0
  74. package/dist/strategies/LocalDeploymentStrategy.js.map +1 -0
  75. package/dist/strategies/OZDefenderDeploymentStrategy.d.ts +62 -0
  76. package/dist/strategies/OZDefenderDeploymentStrategy.d.ts.map +1 -0
  77. package/dist/strategies/OZDefenderDeploymentStrategy.js +757 -0
  78. package/dist/strategies/OZDefenderDeploymentStrategy.js.map +1 -0
  79. package/dist/strategies/RPCDeploymentStrategy.d.ts +139 -0
  80. package/dist/strategies/RPCDeploymentStrategy.d.ts.map +1 -0
  81. package/dist/strategies/RPCDeploymentStrategy.js +710 -0
  82. package/dist/strategies/RPCDeploymentStrategy.js.map +1 -0
  83. package/dist/strategies/index.d.ts +6 -0
  84. package/dist/strategies/index.d.ts.map +1 -0
  85. package/dist/strategies/index.js +12 -0
  86. package/dist/strategies/index.js.map +1 -0
  87. package/dist/types/config.d.ts +26 -0
  88. package/dist/types/config.d.ts.map +1 -0
  89. package/dist/types/config.js +3 -0
  90. package/dist/types/config.js.map +1 -0
  91. package/dist/types/defender.d.ts +22 -0
  92. package/dist/types/defender.d.ts.map +1 -0
  93. package/dist/types/defender.js +3 -0
  94. package/dist/types/defender.js.map +1 -0
  95. package/dist/types/deployments.d.ts +71 -0
  96. package/dist/types/deployments.d.ts.map +1 -0
  97. package/dist/types/deployments.js +20 -0
  98. package/dist/types/deployments.js.map +1 -0
  99. package/dist/types/index.d.ts +5 -0
  100. package/dist/types/index.d.ts.map +1 -0
  101. package/dist/types/index.js +21 -0
  102. package/dist/types/index.js.map +1 -0
  103. package/dist/types/rpc.d.ts +35 -0
  104. package/dist/types/rpc.d.ts.map +1 -0
  105. package/dist/types/rpc.js +3 -0
  106. package/dist/types/rpc.js.map +1 -0
  107. package/dist/utils/common.d.ts +20 -0
  108. package/dist/utils/common.d.ts.map +1 -0
  109. package/dist/utils/common.js +45 -0
  110. package/dist/utils/common.js.map +1 -0
  111. package/dist/utils/configurationResolver.d.ts +30 -0
  112. package/dist/utils/configurationResolver.d.ts.map +1 -0
  113. package/dist/utils/configurationResolver.js +151 -0
  114. package/dist/utils/configurationResolver.js.map +1 -0
  115. package/dist/utils/contractMapping.d.ts +29 -0
  116. package/dist/utils/contractMapping.d.ts.map +1 -0
  117. package/dist/utils/contractMapping.js +224 -0
  118. package/dist/utils/contractMapping.js.map +1 -0
  119. package/dist/utils/defenderClients.d.ts +5 -0
  120. package/dist/utils/defenderClients.d.ts.map +1 -0
  121. package/dist/utils/defenderClients.js +21 -0
  122. package/dist/utils/defenderClients.js.map +1 -0
  123. package/dist/utils/defenderStore.d.ts +14 -0
  124. package/dist/utils/defenderStore.d.ts.map +1 -0
  125. package/dist/utils/defenderStore.js +92 -0
  126. package/dist/utils/defenderStore.js.map +1 -0
  127. package/dist/utils/diamondAbiGenerator.d.ts +113 -0
  128. package/dist/utils/diamondAbiGenerator.d.ts.map +1 -0
  129. package/dist/utils/diamondAbiGenerator.js +415 -0
  130. package/dist/utils/diamondAbiGenerator.js.map +1 -0
  131. package/dist/utils/diffDeployedFacets.d.ts +26 -0
  132. package/dist/utils/diffDeployedFacets.d.ts.map +1 -0
  133. package/dist/utils/diffDeployedFacets.js +106 -0
  134. package/dist/utils/diffDeployedFacets.js.map +1 -0
  135. package/dist/utils/index.d.ts +16 -0
  136. package/dist/utils/index.d.ts.map +1 -0
  137. package/dist/utils/index.js +35 -0
  138. package/dist/utils/index.js.map +1 -0
  139. package/dist/utils/loupe.d.ts +44 -0
  140. package/dist/utils/loupe.d.ts.map +1 -0
  141. package/dist/utils/loupe.js +128 -0
  142. package/dist/utils/loupe.js.map +1 -0
  143. package/dist/utils/rpcStore.d.ts +36 -0
  144. package/dist/utils/rpcStore.d.ts.map +1 -0
  145. package/dist/utils/rpcStore.js +166 -0
  146. package/dist/utils/rpcStore.js.map +1 -0
  147. package/dist/utils/signer.d.ts +36 -0
  148. package/dist/utils/signer.d.ts.map +1 -0
  149. package/dist/utils/signer.js +91 -0
  150. package/dist/utils/signer.js.map +1 -0
  151. package/dist/utils/txlogging.d.ts +13 -0
  152. package/dist/utils/txlogging.d.ts.map +1 -0
  153. package/dist/utils/txlogging.js +87 -0
  154. package/dist/utils/txlogging.js.map +1 -0
  155. package/dist/utils/workspaceSetup.d.ts +32 -0
  156. package/dist/utils/workspaceSetup.d.ts.map +1 -0
  157. package/dist/utils/workspaceSetup.js +311 -0
  158. package/dist/utils/workspaceSetup.js.map +1 -0
  159. package/docs/DIAMOND_ABI_CONFIGURATION_SUMMARY.md +40 -0
  160. package/docs/DIAMOND_ABI_GENERATION.md +220 -0
  161. package/docs/DIAMOND_ABI_GENERATOR_EXAMPLES.md +1204 -0
  162. package/docs/DIAMOND_ABI_GENERATOR_IMPLEMENTATION.md +947 -0
  163. package/docs/DIAMOND_ABI_GENERATOR_QUICK_REFERENCE.md +336 -0
  164. package/docs/README-DEFENDER.md +394 -0
  165. package/docs/README_DIAMOND_ABI_GENERATOR.md +303 -0
  166. package/docs/ROADMAP.md +250 -0
  167. package/docs/assets/image.png +0 -0
  168. package/docs/defender-integration.md +451 -0
  169. package/docs/diamond_module-BaseStrategy_design-v2.uxf +247 -0
  170. package/docs/diamond_module-BaseStrategy_design.uxf +272 -0
  171. package/docs/monitoring-troubleshooting.md +556 -0
  172. package/docs/testing-guide.md +713 -0
  173. package/examples/Diamond_Config_and_Deployment_examples/diamonds/ProxyDiamond/callbacks/ERC20ProxyFacet.ts +31 -0
  174. package/examples/Diamond_Config_and_Deployment_examples/diamonds/ProxyDiamond/proxydiamond.config.json +27 -0
  175. package/examples/Local_Hardhat_Deployer_Script_example/LocalDiamondDeployer.ts +180 -0
  176. package/examples/OZ_Defender_Deployer_Script_example/OZDiamondDeployer.ts +107 -0
  177. package/examples/OZ_Defender_Deployer_Script_example/run-oz-deploy.ts +17 -0
  178. package/examples/Test_examples/ProxyDiamondDeployment.test.ts +202 -0
  179. package/examples/defender-deployment/.env.example +35 -0
  180. package/examples/defender-deployment/README.md +415 -0
  181. package/examples/defender-deployment/contracts/ExampleDiamond.sol +41 -0
  182. package/examples/defender-deployment/contracts/ExampleFacet1.sol +84 -0
  183. package/examples/defender-deployment/contracts/ExampleFacet2.sol +104 -0
  184. package/examples/defender-deployment/contracts/UpgradeFacet.sol +92 -0
  185. package/examples/defender-deployment/deploy-script.ts +170 -0
  186. package/examples/defender-deployment/diamond-config.json +36 -0
  187. package/examples/defender-deployment/upgrade-script.ts +237 -0
  188. package/examples/hardhat-diamonds-config.example.ts +41 -0
  189. package/package.json +228 -0
  190. package/src/core/CallbackManager.ts +70 -0
  191. package/src/core/DeploymentManager.ts +64 -0
  192. package/src/core/Diamond.ts +197 -0
  193. package/src/core/DiamondDeployer.ts +36 -0
  194. package/src/core/index.ts +4 -0
  195. package/src/index.ts +5 -0
  196. package/src/repositories/DBDeploymentRepository.ts +22 -0
  197. package/src/repositories/DeploymentRepository.ts +12 -0
  198. package/src/repositories/FileDeploymentRepository.ts +67 -0
  199. package/src/repositories/databaseHandler.ts +14 -0
  200. package/src/repositories/index.ts +4 -0
  201. package/src/repositories/jsonFileHandler.ts +252 -0
  202. package/src/repositories/prismaDBHandler.ts +10 -0
  203. package/src/schemas/DeploymentSchema.ts +71 -0
  204. package/src/schemas/index.ts +1 -0
  205. package/src/strategies/BaseDeploymentStrategy.ts +649 -0
  206. package/src/strategies/DeploymentStrategy.ts +25 -0
  207. package/src/strategies/LocalDeploymentStrategy.ts +5 -0
  208. package/src/strategies/OZDefenderDeploymentStrategy.ts +849 -0
  209. package/src/strategies/RPCDeploymentStrategy.ts +881 -0
  210. package/src/strategies/index.ts +5 -0
  211. package/src/types/config.ts +34 -0
  212. package/src/types/defender.ts +24 -0
  213. package/src/types/deployments.ts +102 -0
  214. package/src/types/index.ts +4 -0
  215. package/src/types/rpc.ts +37 -0
  216. package/src/utils/common.ts +54 -0
  217. package/src/utils/configurationResolver.ts +141 -0
  218. package/src/utils/contractMapping.ts +220 -0
  219. package/src/utils/defenderClients.ts +22 -0
  220. package/src/utils/defenderStore.ts +62 -0
  221. package/src/utils/diamondAbiGenerator.ts +523 -0
  222. package/src/utils/diffDeployedFacets.ts +131 -0
  223. package/src/utils/index.ts +15 -0
  224. package/src/utils/loupe.ts +159 -0
  225. package/src/utils/rpcStore.ts +152 -0
  226. package/src/utils/signer.ts +93 -0
  227. package/src/utils/txlogging.ts +97 -0
  228. package/src/utils/workspaceSetup.ts +315 -0
  229. package/test/README.md +136 -0
@@ -0,0 +1,31 @@
1
+ import { ExampleDiamond } from "../../../typechain-types";
2
+ import "@nomicfoundation/hardhat-ethers";
3
+ import {
4
+ CallbackArgs,
5
+ } from "diamonds";
6
+ import hre from "hardhat";
7
+
8
+ export async function createXMPLToken(CallbackArgs: CallbackArgs) {
9
+ const { diamond } = CallbackArgs;
10
+
11
+ const networkName = diamond.networkName;
12
+ const chainID = diamond.chainId;
13
+ const deployInfo = diamond.getDeployedDiamondData();
14
+
15
+ console.log(`In ERC20ProxyFacet after Deploy function, chainID: ${chainID}`);
16
+ console.log(`Network name: ${networkName}`);
17
+ // Get the GeniusDiamond instance
18
+ const diamondName = diamond.diamondName;
19
+ const diamondAddress = deployInfo.DiamondAddress!;
20
+ const deployer = diamond.signer!;
21
+ const diamondArtifactName = `hardhat-diamond-abi/HardhatDiamondABI.sol:${diamondName}`;
22
+ const diamondArtifact = hre.artifacts.readArtifactSync(diamondArtifactName);
23
+ const diamondContract = new hre.ethers.Contract(diamondAddress, diamondArtifact.abi, diamond.provider) as ProxyDiamond;
24
+ const deployerDiamondContract = diamondContract.connect(deployer);
25
+ await deployerDiamondContract.initializeERC20Proxy(
26
+ diamondAddress,
27
+ chainID,
28
+ "ExampleToken",
29
+ "XMPL"
30
+ );
31
+ };
@@ -0,0 +1,27 @@
1
+ {
2
+ "protocolVersion": 0.0,
3
+ "facets": {
4
+ "DiamondCutFacet": {
5
+ "priority": 10,
6
+ "versions": {
7
+ "0.0": {}
8
+ }
9
+ },
10
+ "DiamondLoupeFacet": {
11
+ "priority": 20,
12
+ "versions": {
13
+ "0.0": {}
14
+ }
15
+ },
16
+ "ERC20ProxyFacet": {
17
+ "priority": 40,
18
+ "versions": {
19
+ "0.0": {
20
+ "callbacks": [
21
+ "createXMPLToken"
22
+ ]
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,180 @@
1
+ import {
2
+ Diamond,
3
+ DiamondDeployer,
4
+ DeploymentManager,
5
+ LocalDeploymentStrategy,
6
+ FileDeploymentRepository,
7
+ DeploymentRepository,
8
+ impersonateSigner,
9
+ setEtherBalance,
10
+ DiamondConfig,
11
+ DiamondPathsConfig,
12
+ cutKey,
13
+ impersonateAndFundSigner
14
+ } from 'diamonds';
15
+ import { JsonRpcProvider } from '@ethersproject/providers';
16
+ import { Signer, ethers } from 'ethers';
17
+ import hre from 'hardhat';
18
+ import "@nomicfoundation/hardhat-ethers";
19
+ import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers';
20
+ import { join } from 'path';
21
+ import 'hardhat-diamonds';
22
+ import { HardhatEthersProvider } from '@nomicfoundation/hardhat-ethers/internal/hardhat-ethers-provider';
23
+
24
+ export interface LocalDiamondDeployerConfig extends DiamondConfig {
25
+ provider?: JsonRpcProvider | HardhatEthersProvider;
26
+ signer?: SignerWithAddress;
27
+ localDiamondDeployerKey?: string;
28
+ }
29
+
30
+ export class LocalDiamondDeployer {
31
+ private static instances: Map<string, LocalDiamondDeployer> = new Map();
32
+ private deployInProgress: boolean = false;
33
+ private deployComplete: boolean = false;
34
+ private diamond: Diamond | undefined;
35
+ private verbose: boolean = true;
36
+ private config: LocalDiamondDeployerConfig;
37
+ private provider: JsonRpcProvider | HardhatEthersProvider;
38
+ private signer: SignerWithAddress;
39
+ private diamondName: string;
40
+ private networkName: string = 'hardhat';
41
+ private chainId: bigint | number = 31337;
42
+ private repository: DeploymentRepository;
43
+
44
+ constructor(config: LocalDiamondDeployerConfig, repository: DeploymentRepository) {
45
+ this.config = config as DiamondConfig;
46
+ this.diamondName = config.diamondName;
47
+ this.provider = config.provider || hre.ethers.provider;
48
+ if (!config.networkName) {
49
+ // TODO account for "unknown" as hardhat
50
+ config.networkName = (this.provider as JsonRpcProvider)._network.name;
51
+ } else {
52
+ this.networkName = config.networkName;
53
+ }
54
+ if (!config.chainId) {
55
+ config.chainId = (this.provider as JsonRpcProvider)._network.chainId;
56
+ } else {
57
+ this.chainId = config.chainId;
58
+ }
59
+ this.signer = config.signer!;
60
+ // this.config.signer = this.signer;
61
+ this.repository = repository!;
62
+
63
+ // TODO make provider signer and repository optional (this may be handled in diamond constructor already)
64
+ this.diamond = new Diamond(this.config, repository);
65
+ this.diamond.setProvider(this.provider);
66
+ this.diamond.setSigner(this.signer);
67
+ }
68
+
69
+ public static async getInstance(config: LocalDiamondDeployerConfig): Promise<LocalDiamondDeployer> {
70
+ if (!config.provider) {
71
+ config.provider = hre.ethers.provider;
72
+ } else {
73
+ hre.ethers.provider = config.provider as any;
74
+ }
75
+ if (!config.networkName) {
76
+ const networkName = (await config.provider?.getNetwork()).name || 'hardhat';
77
+ config.networkName = networkName === 'unknown' ? 'hardhat' : networkName;
78
+ }
79
+ if (!config.chainId) {
80
+ config.chainId = (await config.provider.getNetwork()).chainId || 31337;
81
+ }
82
+
83
+ const key = config.localDiamondDeployerKey || await (cutKey(
84
+ config.diamondName,
85
+ config.networkName,
86
+ (config.chainId ?? 31337).toString()
87
+ ));
88
+
89
+ if (!this.instances.has(key)) {
90
+ const hardhatDiamonds: DiamondPathsConfig = hre.diamonds?.getDiamondConfig(config.diamondName);
91
+ const deployedDiamondDataFileName = `${config.diamondName.toLowerCase()}-${config.networkName.toLowerCase()}-${config.chainId.toString()}.json`;
92
+ const defaultDeployedDiamondDataFilePath = join(
93
+ 'diamonds',
94
+ config.diamondName,
95
+ 'deployments',
96
+ deployedDiamondDataFileName
97
+ );
98
+ const defaultConfigFilePath = join(
99
+ 'diamonds',
100
+ config.diamondName,
101
+ `${config.diamondName.toLowerCase()}.config.json`
102
+ );
103
+
104
+ config.deploymentsPath = config.deploymentsPath || hardhatDiamonds?.deploymentsPath
105
+ || 'diamonds';
106
+ config.contractsPath = hardhatDiamonds?.contractsPath || 'contracts';
107
+ config.callbacksPath = hardhatDiamonds?.callbacksPath
108
+ || join('diamonds', config.diamondName, 'callbacks');
109
+ config.deployedDiamondDataFilePath = config.deployedDiamondDataFilePath
110
+ || hardhatDiamonds?.deployedDiamondDataFilePath
111
+ || defaultDeployedDiamondDataFilePath;
112
+ config.configFilePath = config.configFilePath
113
+ || hardhatDiamonds?.configFilePath
114
+ || defaultConfigFilePath;
115
+
116
+ const repository = new FileDeploymentRepository(config);
117
+ repository.setWriteDeployedDiamondData(config.writeDeployedDiamondData || hardhatDiamonds?.writeDeployedDiamondData || false);
118
+ const deployedDiamondData = repository.loadDeployedDiamondData();
119
+
120
+ const [signer0] = await hre.ethers.getSigners();
121
+ // ethers.provider = config.provider;
122
+ if (!deployedDiamondData.DeployerAddress) {
123
+ config.signer = signer0;
124
+ } else {
125
+ config.signer = await hre.ethers.getSigner(deployedDiamondData.DeployerAddress);
126
+ await impersonateAndFundSigner(deployedDiamondData.DeployerAddress, config.provider as any);
127
+ }
128
+
129
+ const instance = new LocalDiamondDeployer(config, repository);
130
+ this.instances.set(key, instance);
131
+ }
132
+ return this.instances.get(key)!;
133
+ }
134
+
135
+ public async deployDiamond(): Promise<Diamond> {
136
+ const chainId = (await this.provider.getNetwork()).chainId || 31337;
137
+ const key = cutKey(this.diamondName, this.networkName, chainId.toString());
138
+ if (this.deployComplete) {
139
+ console.log(`Deployment already completed for ${this.diamondName} on ${this.networkName}-${chainId.toString()}`);
140
+ return Promise.resolve(this.diamond!);
141
+ }
142
+ else if (this.deployInProgress) {
143
+ console.log(`Deployment already in progress for ${this.networkName}`);
144
+ // Wait for the deployment to complete
145
+ while (this.deployInProgress) {
146
+ await new Promise((resolve) => setTimeout(resolve, 1000));
147
+ }
148
+ return Promise.resolve(this.diamond!);
149
+ }
150
+
151
+ this.deployInProgress = true;
152
+
153
+ // Make Deployment Strategy configurable.
154
+ const strategy = new LocalDeploymentStrategy(this.verbose);
155
+ const deployer = new DiamondDeployer(this.diamond!, strategy);
156
+
157
+ await deployer.deployDiamond();
158
+
159
+ this.deployComplete = true;
160
+ this.deployInProgress = false;
161
+
162
+ return deployer.getDiamond();
163
+ }
164
+
165
+ public async getDiamondDeployed(): Promise<Diamond> {
166
+ if (this.deployComplete && this.diamond) {
167
+ return this.diamond;
168
+ }
169
+ const diamond = await this.deployDiamond();
170
+ return diamond;
171
+ }
172
+
173
+ public async getDiamond(): Promise<Diamond> {
174
+ return this.diamond!;
175
+ }
176
+
177
+ public async setVerbose(useVerboseLogging: boolean): Promise<void> {
178
+ this.verbose = useVerboseLogging;
179
+ }
180
+ }
@@ -0,0 +1,107 @@
1
+ import {
2
+ Diamond,
3
+ DiamondDeployer,
4
+ FileDeploymentRepository,
5
+ DeploymentRepository,
6
+ DiamondConfig,
7
+ cutKey
8
+ } from 'diamonds';
9
+
10
+ import { JsonRpcProvider } from '@ethersproject/providers';
11
+ import { ethers } from 'hardhat';
12
+ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
13
+ import { OZDefenderDeploymentStrategy } from 'diamonds'; // Adjust based on your export path
14
+ import { join } from 'path';
15
+
16
+ export interface OZDiamondDeployerConfig extends DiamondConfig {
17
+ provider?: JsonRpcProvider;
18
+ signer?: SignerWithAddress;
19
+ ozDiamondDeployerKey?: string;
20
+ }
21
+
22
+ export class OZDiamondDeployer {
23
+ private static instances: Map<string, OZDiamondDeployer> = new Map();
24
+ private deployInProgress = false;
25
+ private deployComplete = false;
26
+ private config: OZDiamondDeployerConfig;
27
+ private diamond: Diamond;
28
+ private provider: JsonRpcProvider;
29
+ private signer: SignerWithAddress;
30
+ private repository: DeploymentRepository;
31
+
32
+ constructor(config: OZDiamondDeployerConfig, repository: DeploymentRepository) {
33
+ this.config = config;
34
+ this.provider = config.provider || ethers.provider;
35
+ this.signer = config.signer!;
36
+ this.repository = repository;
37
+
38
+ this.diamond = new Diamond(config, repository);
39
+ this.diamond.setProvider(this.provider);
40
+ this.diamond.setSigner(this.signer);
41
+ }
42
+
43
+ public static async getInstance(config: OZDiamondDeployerConfig): Promise<OZDiamondDeployer> {
44
+ config.provider = config.provider || ethers.provider;
45
+
46
+ const net = await config.provider.getNetwork();
47
+ config.networkName = config.networkName || (net.name === 'unknown' ? 'hardhat' : net.name);
48
+ config.chainId = config.chainId || net.chainId;
49
+
50
+ const key = config.ozDiamondDeployerKey || await cutKey(config.diamondName, config.networkName, config.chainId.toString());
51
+
52
+ if (!this.instances.has(key)) {
53
+ const defaultPaths = {
54
+ deploymentsPath: 'diamonds',
55
+ contractsPath: 'contracts',
56
+ callbacksPath: join('diamonds', config.diamondName, 'callbacks'),
57
+ deployedDiamondDataFilePath: join('diamonds', config.diamondName, 'deployments', `${config.diamondName.toLowerCase()}-${config.networkName.toLowerCase()}-${config.chainId}.json`),
58
+ configFilePath: join('diamonds', config.diamondName, `${config.diamondName.toLowerCase()}.config.json`)
59
+ };
60
+
61
+ config.deploymentsPath ||= defaultPaths.deploymentsPath;
62
+ config.contractsPath ||= defaultPaths.contractsPath;
63
+ config.callbacksPath ||= defaultPaths.callbacksPath;
64
+ config.deployedDiamondDataFilePath ||= defaultPaths.deployedDiamondDataFilePath;
65
+ config.configFilePath ||= defaultPaths.configFilePath;
66
+
67
+ const repository = new FileDeploymentRepository(config);
68
+ const [signer0] = await ethers.getSigners();
69
+ config.signer = signer0;
70
+
71
+ const instance = new OZDiamondDeployer(config, repository);
72
+ this.instances.set(key, instance);
73
+ }
74
+
75
+ return this.instances.get(key)!;
76
+ }
77
+
78
+ public async deployDiamond(): Promise<Diamond> {
79
+ if (this.deployComplete) return this.diamond;
80
+ if (this.deployInProgress) {
81
+ console.log(`Deployment already in progress. Waiting...`);
82
+ while (this.deployInProgress) await new Promise(res => setTimeout(res, 1000));
83
+ return this.diamond;
84
+ }
85
+
86
+ this.deployInProgress = true;
87
+ const strategy = new OZDefenderDeploymentStrategy(
88
+ process.env.DEFENDER_API_KEY!,
89
+ process.env.DEFENDER_API_SECRET!,
90
+ process.env.DEFENDER_RELAYER_ADDRESS!, // required
91
+ true, // auto-approve
92
+ process.env.DEFENDER_SAFE_ADDRESS!,
93
+ 'Safe' // TODO this should be configurable.
94
+ );
95
+
96
+ const deployer = new DiamondDeployer(this.diamond, strategy);
97
+ await deployer.deployDiamond();
98
+
99
+ this.deployComplete = true;
100
+ this.deployInProgress = false;
101
+ return deployer.getDiamond();
102
+ }
103
+
104
+ public async getDiamond(): Promise<Diamond> {
105
+ return this.diamond;
106
+ }
107
+ }
@@ -0,0 +1,17 @@
1
+ import { OZDiamondDeployer } from './OZDiamondDeployer';
2
+ import { config } from 'dotenv';
3
+ config();
4
+
5
+ async function main() {
6
+ const deployer = await OZDiamondDeployer.getInstance({
7
+ diamondName: 'GeniusDiamond'
8
+ });
9
+
10
+ const diamond = await deployer.deployDiamond();
11
+ console.log(`🚀 Deployed Diamond at: ${diamond.getDeployedDiamondData().DiamondAddress}`);
12
+ }
13
+
14
+ main().catch(err => {
15
+ console.error(err);
16
+ process.exit(1);
17
+ });
@@ -0,0 +1,202 @@
1
+ import { debug } from 'debug';
2
+ import { pathExistsSync } from "fs-extra";
3
+ import { expect, assert } from 'chai';
4
+ import { ethers } from 'hardhat';
5
+ import hre from 'hardhat';
6
+ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
7
+ import { JsonRpcProvider } from '@ethersproject/providers';
8
+ import { multichain } from 'hardhat-multichain';
9
+ import { getInterfaceID } from '../../scripts/utils/helpers';
10
+ import { LocalDiamondDeployer, LocalDiamondDeployerConfig } from '../../scripts/setup/LocalDiamondDeployer';
11
+ import { Diamond, deleteDeployInfo } from 'diamonds';
12
+ import {
13
+ ProxyDiamond,
14
+ IERC20Upgradeable__factory,
15
+ IDiamondCut__factory,
16
+ IDiamondLoupe__factory
17
+ } from '../../typechain-types/';
18
+
19
+ describe('🧪 Multichain Fork and Diamond Deployment Tests', async function () {
20
+ const diamondName = 'ProxyDiamond';
21
+ const log: debug.Debugger = debug('GNUSDeploy:log:${diamondName}');
22
+ this.timeout(0); // Extended indefinitely for diamond deployment time
23
+
24
+ let networkProviders = multichain.getProviders() || new Map<string, JsonRpcProvider>();
25
+
26
+ if (process.argv.includes('test-multichain')) {
27
+ const networkNames = process.argv[process.argv.indexOf('--chains') + 1].split(',');
28
+ if (networkNames.includes('hardhat')) {
29
+ networkProviders.set('hardhat', ethers.provider);
30
+ }
31
+ } else if (process.argv.includes('test') || process.argv.includes('coverage')) {
32
+ networkProviders.set('hardhat', ethers.provider);
33
+ }
34
+
35
+ for (const [networkName, provider] of networkProviders.entries()) {
36
+ describe(`🔗 Chain: ${networkName} 🔷 Diamond: ${diamondName}`, function () {
37
+ let diamond: Diamond;
38
+ let signers: SignerWithAddress[];
39
+ let signer0: string;
40
+ let signer1: string;
41
+ let signer2: string;
42
+ let owner: string;
43
+ let ownerSigner: SignerWithAddress;
44
+ let proxyDiamond: ProxyDiamond;
45
+ let signer0Diamond: ProxyDiamond;
46
+ let signer1Diamond: ProxyDiamond;
47
+ let signer2Diamond: ProxyDiamond;
48
+ let ownerDiamond: ProxyDiamond;
49
+
50
+ let ethersMultichain: typeof ethers;
51
+ let snapshotId: string;
52
+
53
+ before(async function () {
54
+ const config = {
55
+ diamondName: diamondName,
56
+ networkName: networkName,
57
+ provider: provider,
58
+ // chainId: (await provider.getNetwork()).chainId,
59
+ // writeDeployedDiamondData: false,
60
+ // configFilePath: `diamonds/GeniusDiamond/proxydiamond.config.json`,
61
+ } as LocalDiamondDeployerConfig;
62
+ const diamondDeployer = await LocalDiamondDeployer.getInstance(config);
63
+ diamond = await diamondDeployer.getDiamondDeployed();
64
+ const deployInfo = diamond.getDeployedDiamondData();
65
+
66
+ const hardhatDiamondAbiPath = 'hardhat-diamond-abi/HardhatDiamondABI.sol:';
67
+ const diamondArtifactName = `${hardhatDiamondAbiPath}${diamond.diamondName}`;
68
+ proxyDiamond = await ethers.getContractAt(diamondArtifactName, deployInfo.DiamondAddress!) as ProxyDiamond;
69
+
70
+ ethersMultichain = ethers;
71
+ ethersMultichain.provider = provider;
72
+
73
+ // Retrieve the signers for the chain
74
+ signers = await ethersMultichain.getSigners();
75
+ signer0 = signers[0].address;
76
+ signer1 = signers[1].address;
77
+ signer2 = signers[2].address;
78
+ signer0Diamond = proxyDiamond.connect(signers[0]);
79
+ signer1Diamond = proxyDiamond.connect(signers[1]);
80
+ signer2Diamond = proxyDiamond.connect(signers[2]);
81
+
82
+ // get the signer for the owner
83
+ owner = deployInfo.DeployerAddress; // this will be = signer0 for hardhat;
84
+ ownerSigner = await ethersMultichain.getSigner(owner);
85
+ ownerDiamond = proxyDiamond.connect(ownerSigner);
86
+ });
87
+
88
+ beforeEach(async function () {
89
+ snapshotId = await provider.send('evm_snapshot', []);
90
+ });
91
+
92
+ afterEach(async () => {
93
+ await provider.send('evm_revert', [snapshotId]);
94
+ });
95
+
96
+ it(`should ensure that ${networkName} chain object can be retrieved and reused`, async function () {
97
+
98
+ expect(provider).to.not.be.undefined;
99
+ // expect(diamond).to.not.be.null;
100
+
101
+ const { chainId } = await provider.getNetwork();
102
+ expect(chainId).to.be.a('number');
103
+ });
104
+
105
+ it(`should verify that ${networkName} diamond is deployed and we can get hardhat signers on ${networkName}`, async function () {
106
+
107
+ expect(signers).to.be.an('array');
108
+ expect(signers).to.have.lengthOf(20);
109
+ expect(signers[0]).to.be.instanceOf(SignerWithAddress);
110
+
111
+ expect(owner).to.not.be.undefined;
112
+ expect(owner).to.be.a('string');
113
+ // expect(owner).to.be.properAddress;
114
+ expect(ownerSigner).to.be.instanceOf(SignerWithAddress);
115
+ });
116
+
117
+ it(`should verify that ${networkName} providers are defined and have valid block numbers`, async function () {
118
+ log(`Checking chain provider for: ${networkName}`);
119
+ expect(provider).to.not.be.undefined;
120
+
121
+ const blockNumber = await ethersMultichain.provider.getBlockNumber();
122
+ log(`Block number for ${networkName}: ${blockNumber}`);
123
+
124
+ expect(blockNumber).to.be.a('number');
125
+ // Fails for hardhat because it defaults to 0.
126
+ if (networkName !== 'hardhat') {
127
+ expect(blockNumber).to.be.greaterThan(0);
128
+ }
129
+
130
+ // This isn't a perfect check, because it is trying to place the current block in
131
+ // a range relative to the configured block number used for caching.
132
+ // The default of zero is to account for hardhat chain. It also possible that no
133
+ // block number is configured in the hardhat.config.js file which will always fetch
134
+ // the latest block number. This will also cause it to fail.
135
+ const configBlockNumber = hre.config.chainManager?.chains?.[networkName]?.blockNumber ?? 0;
136
+ expect(blockNumber).to.be.gte(configBlockNumber);
137
+
138
+ expect(blockNumber).to.be.lte(configBlockNumber + 500);
139
+ });
140
+
141
+ // it(`should verify ERC173 contract ownership on ${networkName}`, async function () {
142
+ // // check if the owner is the deployer and transfer ownership to the deployer
143
+ // const currentContractOwner = await ownerDiamond.owner();
144
+ // expect(currentContractOwner.toLowerCase()).to.be.eq(await owner.toLowerCase());
145
+ // });
146
+
147
+ it(`should validate ERC165 interface compatibility on ${networkName}`, async function () {
148
+ // Test ERC165 interface compatibility
149
+ const supportsERC165 = await proxyDiamond.supportsInterface('0x01ffc9a7');
150
+ expect(supportsERC165).to.be.true;
151
+
152
+ log(`Diamond deployed and validated on ${networkName}`);
153
+ });
154
+
155
+ it(`should validate IDiamondCut interface compatibility on ${networkName}`, async function () {
156
+ // Test ERC165 interface compatibility
157
+ const iDiamonCutInterface = IDiamondCut__factory.createInterface();
158
+ // Generate the IDiamondCut interface ID by XORing with the base interface ID.
159
+ const iDiamondCutInterfaceID = getInterfaceID(iDiamonCutInterface);
160
+ // const supportsIDiamondCut = await proxyDiamond.supportsInterface('0x1f931c1c');
161
+ const supportsERC165 = await proxyDiamond.supportsInterface(iDiamondCutInterfaceID._hex);
162
+ expect(supportsERC165).to.be.true;
163
+
164
+ log(`DiamondCut Facet interface support validated on ${networkName}`);
165
+ });
166
+
167
+ it(`should validate IDiamondLoupe interface compatibility on ${networkName}`, async function () {
168
+ // Test ERC165 interface compatibility
169
+ const iDiamondLoupeInterface = IDiamondLoupe__factory.createInterface();
170
+ // Generate the IDiamondLoupe interface ID by XORing with the base interface ID.
171
+ const iDiamondLoupeInterfaceID = getInterfaceID(iDiamondLoupeInterface);
172
+ // const supportsIDiamondLoupe = await proxyDiamond.supportsInterface('0x48e3885f');
173
+ const supportsERC165 = await proxyDiamond.supportsInterface(iDiamondLoupeInterfaceID._hex);
174
+ expect(supportsERC165).to.be.true;
175
+ log(`DiamondLoupe Facet interface support validated on ${networkName}`);
176
+ });
177
+
178
+ it(`should verify ERC165 supported interface for ERC20 on ${networkName}`, async function () {
179
+ log(`Validating ERC20 interface on chain: ${networkName}`);
180
+ const IERC20UpgradeableInterface = IERC20Upgradeable__factory.createInterface();
181
+ // Generate the ERC20 interface ID by XORing with the base interface ID.
182
+ const IERC20InterfaceID = getInterfaceID(IERC20UpgradeableInterface);
183
+ // Assert that the `diamond` contract supports the ERC20 interface.
184
+ // assert(
185
+ // await proxyDiamond?.supportsInterface(IERC20InterfaceID._hex),
186
+ // "Doesn't support IERC20Upgradeable",
187
+ // );
188
+
189
+ // Test ERC165 interface compatibility for ERC20 '0x37c8e2a0'
190
+ // const supportsERC20 = await proxyDiamond?.supportsInterface(IERC20InterfaceID._hex);
191
+
192
+ // Test ERC165 interface compatibility for ERC20Upgradeable '0x36372b07'
193
+ const supportsERC20 = await proxyDiamond?.supportsInterface('0x36372b07');
194
+
195
+ expect(supportsERC20).to.be.true;
196
+
197
+ log(`ERC20 interface validated on ${networkName}`);
198
+ });
199
+ });
200
+ }
201
+ });
202
+
@@ -0,0 +1,35 @@
1
+ # OpenZeppelin Defender Configuration
2
+ # Get these from your Defender dashboard: https://defender.openzeppelin.com/
3
+ DEFENDER_API_KEY=your_defender_api_key_here
4
+ DEFENDER_API_SECRET=your_defender_api_secret_here
5
+
6
+ # Defender Relayer Configuration
7
+ # The address of your Defender Relayer (optional for deployment, required for automation)
8
+ DEFENDER_RELAYER_ADDRESS=0x1234567890123456789012345678901234567890
9
+
10
+ # Multi-signature Safe Configuration
11
+ # Address of your Gnosis Safe or similar multi-sig wallet
12
+ DEFENDER_SAFE_ADDRESS=0x0987654321098765432109876543210987654321
13
+
14
+ # Deployment Configuration
15
+ # Enable automatic approval of Defender proposals (use with caution)
16
+ AUTO_APPROVE=false
17
+
18
+ # Network Configuration for Testing
19
+ # Sepolia Testnet (recommended for testing)
20
+ SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_KEY
21
+
22
+ # Mumbai Testnet (Polygon)
23
+ MUMBAI_RPC_URL=https://polygon-mumbai.infura.io/v3/YOUR_INFURA_KEY
24
+
25
+ # Private Key for Deployment (NEVER commit this to version control)
26
+ # Use a dedicated deployment account with limited funds
27
+ DEPLOYER_PRIVATE_KEY=your_private_key_here_for_testing_only
28
+
29
+ # Contract Verification (optional)
30
+ ETHERSCAN_API_KEY=your_etherscan_api_key
31
+ POLYGONSCAN_API_KEY=your_polygonscan_api_key
32
+
33
+ # Debug and Logging
34
+ DEBUG=false
35
+ VERBOSE_DEPLOYMENT=true