@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.
- package/README.md +618 -0
- package/diamonds/README.md +3 -0
- package/dist/core/CallbackManager.d.ts +13 -0
- package/dist/core/CallbackManager.d.ts.map +1 -0
- package/dist/core/CallbackManager.js +95 -0
- package/dist/core/CallbackManager.js.map +1 -0
- package/dist/core/DeploymentManager.d.ts +10 -0
- package/dist/core/DeploymentManager.d.ts.map +1 -0
- package/dist/core/DeploymentManager.js +50 -0
- package/dist/core/DeploymentManager.js.map +1 -0
- package/dist/core/Diamond.d.ts +58 -0
- package/dist/core/Diamond.d.ts.map +1 -0
- package/dist/core/Diamond.js +146 -0
- package/dist/core/Diamond.js.map +1 -0
- package/dist/core/DiamondDeployer.d.ts +10 -0
- package/dist/core/DiamondDeployer.d.ts.map +1 -0
- package/dist/core/DiamondDeployer.js +33 -0
- package/dist/core/DiamondDeployer.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +12 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/repositories/DBDeploymentRepository.d.ts +1 -0
- package/dist/repositories/DBDeploymentRepository.d.ts.map +1 -0
- package/dist/repositories/DBDeploymentRepository.js +20 -0
- package/dist/repositories/DBDeploymentRepository.js.map +1 -0
- package/dist/repositories/DeploymentRepository.d.ts +8 -0
- package/dist/repositories/DeploymentRepository.d.ts.map +1 -0
- package/dist/repositories/DeploymentRepository.js +7 -0
- package/dist/repositories/DeploymentRepository.js.map +1 -0
- package/dist/repositories/FileDeploymentRepository.d.ts +18 -0
- package/dist/repositories/FileDeploymentRepository.d.ts.map +1 -0
- package/dist/repositories/FileDeploymentRepository.js +58 -0
- package/dist/repositories/FileDeploymentRepository.js.map +1 -0
- package/dist/repositories/databaseHandler.d.ts +1 -0
- package/dist/repositories/databaseHandler.d.ts.map +1 -0
- package/dist/repositories/databaseHandler.js +13 -0
- package/dist/repositories/databaseHandler.js.map +1 -0
- package/dist/repositories/index.d.ts +4 -0
- package/dist/repositories/index.d.ts.map +1 -0
- package/dist/repositories/index.js +20 -0
- package/dist/repositories/index.js.map +1 -0
- package/dist/repositories/jsonFileHandler.d.ts +81 -0
- package/dist/repositories/jsonFileHandler.d.ts.map +1 -0
- package/dist/repositories/jsonFileHandler.js +223 -0
- package/dist/repositories/jsonFileHandler.js.map +1 -0
- package/dist/repositories/prismaDBHandler.d.ts +1 -0
- package/dist/repositories/prismaDBHandler.d.ts.map +1 -0
- package/dist/repositories/prismaDBHandler.js +11 -0
- package/dist/repositories/prismaDBHandler.js.map +1 -0
- package/dist/schemas/DeploymentSchema.d.ts +309 -0
- package/dist/schemas/DeploymentSchema.d.ts.map +1 -0
- package/dist/schemas/DeploymentSchema.js +56 -0
- package/dist/schemas/DeploymentSchema.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +18 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/strategies/BaseDeploymentStrategy.d.ts +41 -0
- package/dist/strategies/BaseDeploymentStrategy.d.ts.map +1 -0
- package/dist/strategies/BaseDeploymentStrategy.js +545 -0
- package/dist/strategies/BaseDeploymentStrategy.js.map +1 -0
- package/dist/strategies/DeploymentStrategy.d.ts +19 -0
- package/dist/strategies/DeploymentStrategy.d.ts.map +1 -0
- package/dist/strategies/DeploymentStrategy.js +3 -0
- package/dist/strategies/DeploymentStrategy.js.map +1 -0
- package/dist/strategies/LocalDeploymentStrategy.d.ts +4 -0
- package/dist/strategies/LocalDeploymentStrategy.d.ts.map +1 -0
- package/dist/strategies/LocalDeploymentStrategy.js +8 -0
- package/dist/strategies/LocalDeploymentStrategy.js.map +1 -0
- package/dist/strategies/OZDefenderDeploymentStrategy.d.ts +62 -0
- package/dist/strategies/OZDefenderDeploymentStrategy.d.ts.map +1 -0
- package/dist/strategies/OZDefenderDeploymentStrategy.js +757 -0
- package/dist/strategies/OZDefenderDeploymentStrategy.js.map +1 -0
- package/dist/strategies/RPCDeploymentStrategy.d.ts +139 -0
- package/dist/strategies/RPCDeploymentStrategy.d.ts.map +1 -0
- package/dist/strategies/RPCDeploymentStrategy.js +710 -0
- package/dist/strategies/RPCDeploymentStrategy.js.map +1 -0
- package/dist/strategies/index.d.ts +6 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +12 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/types/config.d.ts +26 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +3 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/defender.d.ts +22 -0
- package/dist/types/defender.d.ts.map +1 -0
- package/dist/types/defender.js +3 -0
- package/dist/types/defender.js.map +1 -0
- package/dist/types/deployments.d.ts +71 -0
- package/dist/types/deployments.d.ts.map +1 -0
- package/dist/types/deployments.js +20 -0
- package/dist/types/deployments.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/rpc.d.ts +35 -0
- package/dist/types/rpc.d.ts.map +1 -0
- package/dist/types/rpc.js +3 -0
- package/dist/types/rpc.js.map +1 -0
- package/dist/utils/common.d.ts +20 -0
- package/dist/utils/common.d.ts.map +1 -0
- package/dist/utils/common.js +45 -0
- package/dist/utils/common.js.map +1 -0
- package/dist/utils/configurationResolver.d.ts +30 -0
- package/dist/utils/configurationResolver.d.ts.map +1 -0
- package/dist/utils/configurationResolver.js +151 -0
- package/dist/utils/configurationResolver.js.map +1 -0
- package/dist/utils/contractMapping.d.ts +29 -0
- package/dist/utils/contractMapping.d.ts.map +1 -0
- package/dist/utils/contractMapping.js +224 -0
- package/dist/utils/contractMapping.js.map +1 -0
- package/dist/utils/defenderClients.d.ts +5 -0
- package/dist/utils/defenderClients.d.ts.map +1 -0
- package/dist/utils/defenderClients.js +21 -0
- package/dist/utils/defenderClients.js.map +1 -0
- package/dist/utils/defenderStore.d.ts +14 -0
- package/dist/utils/defenderStore.d.ts.map +1 -0
- package/dist/utils/defenderStore.js +92 -0
- package/dist/utils/defenderStore.js.map +1 -0
- package/dist/utils/diamondAbiGenerator.d.ts +113 -0
- package/dist/utils/diamondAbiGenerator.d.ts.map +1 -0
- package/dist/utils/diamondAbiGenerator.js +415 -0
- package/dist/utils/diamondAbiGenerator.js.map +1 -0
- package/dist/utils/diffDeployedFacets.d.ts +26 -0
- package/dist/utils/diffDeployedFacets.d.ts.map +1 -0
- package/dist/utils/diffDeployedFacets.js +106 -0
- package/dist/utils/diffDeployedFacets.js.map +1 -0
- package/dist/utils/index.d.ts +16 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +35 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/loupe.d.ts +44 -0
- package/dist/utils/loupe.d.ts.map +1 -0
- package/dist/utils/loupe.js +128 -0
- package/dist/utils/loupe.js.map +1 -0
- package/dist/utils/rpcStore.d.ts +36 -0
- package/dist/utils/rpcStore.d.ts.map +1 -0
- package/dist/utils/rpcStore.js +166 -0
- package/dist/utils/rpcStore.js.map +1 -0
- package/dist/utils/signer.d.ts +36 -0
- package/dist/utils/signer.d.ts.map +1 -0
- package/dist/utils/signer.js +91 -0
- package/dist/utils/signer.js.map +1 -0
- package/dist/utils/txlogging.d.ts +13 -0
- package/dist/utils/txlogging.d.ts.map +1 -0
- package/dist/utils/txlogging.js +87 -0
- package/dist/utils/txlogging.js.map +1 -0
- package/dist/utils/workspaceSetup.d.ts +32 -0
- package/dist/utils/workspaceSetup.d.ts.map +1 -0
- package/dist/utils/workspaceSetup.js +311 -0
- package/dist/utils/workspaceSetup.js.map +1 -0
- package/docs/DIAMOND_ABI_CONFIGURATION_SUMMARY.md +40 -0
- package/docs/DIAMOND_ABI_GENERATION.md +220 -0
- package/docs/DIAMOND_ABI_GENERATOR_EXAMPLES.md +1204 -0
- package/docs/DIAMOND_ABI_GENERATOR_IMPLEMENTATION.md +947 -0
- package/docs/DIAMOND_ABI_GENERATOR_QUICK_REFERENCE.md +336 -0
- package/docs/README-DEFENDER.md +394 -0
- package/docs/README_DIAMOND_ABI_GENERATOR.md +303 -0
- package/docs/ROADMAP.md +250 -0
- package/docs/assets/image.png +0 -0
- package/docs/defender-integration.md +451 -0
- package/docs/diamond_module-BaseStrategy_design-v2.uxf +247 -0
- package/docs/diamond_module-BaseStrategy_design.uxf +272 -0
- package/docs/monitoring-troubleshooting.md +556 -0
- package/docs/testing-guide.md +713 -0
- package/examples/Diamond_Config_and_Deployment_examples/diamonds/ProxyDiamond/callbacks/ERC20ProxyFacet.ts +31 -0
- package/examples/Diamond_Config_and_Deployment_examples/diamonds/ProxyDiamond/proxydiamond.config.json +27 -0
- package/examples/Local_Hardhat_Deployer_Script_example/LocalDiamondDeployer.ts +180 -0
- package/examples/OZ_Defender_Deployer_Script_example/OZDiamondDeployer.ts +107 -0
- package/examples/OZ_Defender_Deployer_Script_example/run-oz-deploy.ts +17 -0
- package/examples/Test_examples/ProxyDiamondDeployment.test.ts +202 -0
- package/examples/defender-deployment/.env.example +35 -0
- package/examples/defender-deployment/README.md +415 -0
- package/examples/defender-deployment/contracts/ExampleDiamond.sol +41 -0
- package/examples/defender-deployment/contracts/ExampleFacet1.sol +84 -0
- package/examples/defender-deployment/contracts/ExampleFacet2.sol +104 -0
- package/examples/defender-deployment/contracts/UpgradeFacet.sol +92 -0
- package/examples/defender-deployment/deploy-script.ts +170 -0
- package/examples/defender-deployment/diamond-config.json +36 -0
- package/examples/defender-deployment/upgrade-script.ts +237 -0
- package/examples/hardhat-diamonds-config.example.ts +41 -0
- package/package.json +228 -0
- package/src/core/CallbackManager.ts +70 -0
- package/src/core/DeploymentManager.ts +64 -0
- package/src/core/Diamond.ts +197 -0
- package/src/core/DiamondDeployer.ts +36 -0
- package/src/core/index.ts +4 -0
- package/src/index.ts +5 -0
- package/src/repositories/DBDeploymentRepository.ts +22 -0
- package/src/repositories/DeploymentRepository.ts +12 -0
- package/src/repositories/FileDeploymentRepository.ts +67 -0
- package/src/repositories/databaseHandler.ts +14 -0
- package/src/repositories/index.ts +4 -0
- package/src/repositories/jsonFileHandler.ts +252 -0
- package/src/repositories/prismaDBHandler.ts +10 -0
- package/src/schemas/DeploymentSchema.ts +71 -0
- package/src/schemas/index.ts +1 -0
- package/src/strategies/BaseDeploymentStrategy.ts +649 -0
- package/src/strategies/DeploymentStrategy.ts +25 -0
- package/src/strategies/LocalDeploymentStrategy.ts +5 -0
- package/src/strategies/OZDefenderDeploymentStrategy.ts +849 -0
- package/src/strategies/RPCDeploymentStrategy.ts +881 -0
- package/src/strategies/index.ts +5 -0
- package/src/types/config.ts +34 -0
- package/src/types/defender.ts +24 -0
- package/src/types/deployments.ts +102 -0
- package/src/types/index.ts +4 -0
- package/src/types/rpc.ts +37 -0
- package/src/utils/common.ts +54 -0
- package/src/utils/configurationResolver.ts +141 -0
- package/src/utils/contractMapping.ts +220 -0
- package/src/utils/defenderClients.ts +22 -0
- package/src/utils/defenderStore.ts +62 -0
- package/src/utils/diamondAbiGenerator.ts +523 -0
- package/src/utils/diffDeployedFacets.ts +131 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/loupe.ts +159 -0
- package/src/utils/rpcStore.ts +152 -0
- package/src/utils/signer.ts +93 -0
- package/src/utils/txlogging.ts +97 -0
- package/src/utils/workspaceSetup.ts +315 -0
- package/test/README.md +136 -0
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RPCDeploymentStrategy = exports.ContractDeploymentError = exports.GasEstimationError = exports.TransactionFailedError = exports.RPCConnectionError = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ethers_1 = require("ethers");
|
|
9
|
+
const types_1 = require("../types");
|
|
10
|
+
const utils_1 = require("../utils");
|
|
11
|
+
const BaseDeploymentStrategy_1 = require("./BaseDeploymentStrategy");
|
|
12
|
+
/**
|
|
13
|
+
* Error classes for RPC-specific failures
|
|
14
|
+
*/
|
|
15
|
+
class RPCConnectionError extends Error {
|
|
16
|
+
originalError;
|
|
17
|
+
constructor(message, originalError) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.originalError = originalError;
|
|
20
|
+
this.name = "RPCConnectionError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.RPCConnectionError = RPCConnectionError;
|
|
24
|
+
class TransactionFailedError extends Error {
|
|
25
|
+
txHash;
|
|
26
|
+
originalError;
|
|
27
|
+
constructor(message, txHash, originalError) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.txHash = txHash;
|
|
30
|
+
this.originalError = originalError;
|
|
31
|
+
this.name = "TransactionFailedError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.TransactionFailedError = TransactionFailedError;
|
|
35
|
+
class GasEstimationError extends Error {
|
|
36
|
+
originalError;
|
|
37
|
+
constructor(message, originalError) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.originalError = originalError;
|
|
40
|
+
this.name = "GasEstimationError";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.GasEstimationError = GasEstimationError;
|
|
44
|
+
class ContractDeploymentError extends Error {
|
|
45
|
+
contractName;
|
|
46
|
+
originalError;
|
|
47
|
+
constructor(message, contractName, originalError) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.contractName = contractName;
|
|
50
|
+
this.originalError = originalError;
|
|
51
|
+
this.name = "ContractDeploymentError";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.ContractDeploymentError = ContractDeploymentError;
|
|
55
|
+
/**
|
|
56
|
+
* RPC Deployment Strategy for direct blockchain interaction
|
|
57
|
+
*
|
|
58
|
+
* This strategy enables direct RPC communication with blockchain networks
|
|
59
|
+
* for contract deployment, diamond cuts, and callback execution without
|
|
60
|
+
* relying on Hardhat's deployment abstractions.
|
|
61
|
+
*/
|
|
62
|
+
class RPCDeploymentStrategy extends BaseDeploymentStrategy_1.BaseDeploymentStrategy {
|
|
63
|
+
rpcUrl;
|
|
64
|
+
privateKey;
|
|
65
|
+
provider;
|
|
66
|
+
signer;
|
|
67
|
+
gasLimitMultiplier;
|
|
68
|
+
maxRetries;
|
|
69
|
+
retryDelayMs;
|
|
70
|
+
store;
|
|
71
|
+
/**
|
|
72
|
+
* Creates a new RPC Deployment Strategy
|
|
73
|
+
*
|
|
74
|
+
* @param rpcUrl - The RPC endpoint URL
|
|
75
|
+
* @param privateKey - The deployer's private key (0x prefixed)
|
|
76
|
+
* @param gasLimitMultiplier - Multiplier for gas limit estimates (default: 1.2)
|
|
77
|
+
* @param maxRetries - Maximum number of retries for failed operations (default: 3)
|
|
78
|
+
* @param retryDelayMs - Delay between retries in milliseconds (default: 2000)
|
|
79
|
+
* @param verbose - Enable verbose logging (default: false)
|
|
80
|
+
*/
|
|
81
|
+
constructor(rpcUrl, privateKey, gasLimitMultiplier = 1.2, maxRetries = 3, retryDelayMs = 2000, verbose = false) {
|
|
82
|
+
super(verbose);
|
|
83
|
+
this.rpcUrl = rpcUrl;
|
|
84
|
+
this.privateKey = privateKey;
|
|
85
|
+
// Validate inputs
|
|
86
|
+
this.validateConstructorInputs(rpcUrl, privateKey, gasLimitMultiplier, maxRetries, retryDelayMs);
|
|
87
|
+
// Initialize provider and signer
|
|
88
|
+
this.provider = new ethers_1.JsonRpcProvider(rpcUrl);
|
|
89
|
+
this.signer = new ethers_1.ethers.Wallet(privateKey, this.provider);
|
|
90
|
+
this.gasLimitMultiplier = gasLimitMultiplier;
|
|
91
|
+
this.maxRetries = maxRetries;
|
|
92
|
+
this.retryDelayMs = retryDelayMs;
|
|
93
|
+
if (this.verbose) {
|
|
94
|
+
console.log(chalk_1.default.blue(`🔗 RPC Strategy initialized with endpoint: ${rpcUrl}`));
|
|
95
|
+
console.log(chalk_1.default.blue(`👤 Deployer address: ${this.signer.getAddress()}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Initialize step tracking store for deployment
|
|
100
|
+
*/
|
|
101
|
+
async initializeStore(diamond) {
|
|
102
|
+
const diamondConfig = diamond.getDiamondConfig();
|
|
103
|
+
const network = await this.provider.getNetwork();
|
|
104
|
+
const deploymentId = `${diamond.diamondName}-${diamondConfig.networkName}-${Number(network.chainId)}`;
|
|
105
|
+
console.log("🔍 DEBUG: Creating RPCDeploymentStore with:", {
|
|
106
|
+
diamondName: diamond.diamondName,
|
|
107
|
+
deploymentId,
|
|
108
|
+
deploymentsPath: diamondConfig.deploymentsPath
|
|
109
|
+
});
|
|
110
|
+
this.store = new utils_1.RPCDeploymentStore(diamond.diamondName, deploymentId, diamondConfig.deploymentsPath);
|
|
111
|
+
// Initialize deployment metadata
|
|
112
|
+
this.store.initializeDeployment(diamondConfig.networkName || 'unknown', Number(network.chainId), this.rpcUrl, await this.signer.getAddress());
|
|
113
|
+
console.log("🔍 DEBUG: Store created and initialized");
|
|
114
|
+
if (this.verbose) {
|
|
115
|
+
console.log(chalk_1.default.blue(`📊 Step tracking initialized: ${deploymentId}`));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Save a deployment step with tracking
|
|
120
|
+
*/
|
|
121
|
+
saveStep(stepName, description, status = 'pending') {
|
|
122
|
+
if (!this.store)
|
|
123
|
+
return;
|
|
124
|
+
const step = {
|
|
125
|
+
stepName,
|
|
126
|
+
description,
|
|
127
|
+
status,
|
|
128
|
+
timestamp: Date.now()
|
|
129
|
+
};
|
|
130
|
+
this.store.saveStep(step);
|
|
131
|
+
if (this.verbose) {
|
|
132
|
+
const statusColor = status === 'completed' ? 'green' : status === 'failed' ? 'red' : 'blue';
|
|
133
|
+
console.log(chalk_1.default[statusColor](`📝 Step ${status}: ${stepName} - ${description}`));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Update step status with transaction details
|
|
138
|
+
*/
|
|
139
|
+
updateStepStatus(stepName, status, txHash, contractAddress, gasUsed, error) {
|
|
140
|
+
if (!this.store)
|
|
141
|
+
return;
|
|
142
|
+
this.store.updateStatus(stepName, status, txHash, contractAddress, error);
|
|
143
|
+
const step = this.store.getStep(stepName);
|
|
144
|
+
if (step && txHash) {
|
|
145
|
+
step.txHash = txHash;
|
|
146
|
+
step.gasUsed = gasUsed;
|
|
147
|
+
this.store.saveStep(step);
|
|
148
|
+
}
|
|
149
|
+
if (this.verbose) {
|
|
150
|
+
const statusColor = status === 'completed' ? 'green' : status === 'failed' ? 'red' : 'yellow';
|
|
151
|
+
console.log(chalk_1.default[statusColor](`🔄 Updated ${stepName}: ${status}${txHash ? ` (${txHash})` : ''}${error ? ` - ${error}` : ''}`));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Check if a step is already completed
|
|
156
|
+
*/
|
|
157
|
+
isStepCompleted(stepName) {
|
|
158
|
+
return this.store?.isStepCompleted(stepName) || false;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Skip a step that's already completed
|
|
162
|
+
*/
|
|
163
|
+
skipCompletedStep(stepName, description) {
|
|
164
|
+
if (this.isStepCompleted(stepName)) {
|
|
165
|
+
if (this.verbose) {
|
|
166
|
+
console.log(chalk_1.default.gray(`⏭️ Skipping completed step: ${stepName} - ${description}`));
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Resolve diamond contract name handling multiple artifacts issue
|
|
174
|
+
*/
|
|
175
|
+
async resolveDiamondContractName(diamondName, diamond) {
|
|
176
|
+
// For GeniusDiamond, specifically use the gnus-ai version to avoid artifact conflicts
|
|
177
|
+
if (diamondName === 'GeniusDiamond') {
|
|
178
|
+
const gnusAiFqn = `contracts/gnus-ai/${diamondName}.sol:${diamondName}`;
|
|
179
|
+
try {
|
|
180
|
+
// Test if this fully qualified name exists by trying to get the artifact
|
|
181
|
+
const { artifacts } = require('hardhat');
|
|
182
|
+
await artifacts.readArtifact(gnusAiFqn);
|
|
183
|
+
return gnusAiFqn;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
if (this.verbose) {
|
|
187
|
+
console.log(chalk_1.default.yellow(`⚠️ Could not resolve ${gnusAiFqn}, falling back to simple name`));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// For other diamonds or if the specific resolution fails, try the original approach
|
|
192
|
+
try {
|
|
193
|
+
// Try the diamond name first
|
|
194
|
+
const { artifacts } = require('hardhat');
|
|
195
|
+
await artifacts.readArtifact(diamondName);
|
|
196
|
+
return diamondName;
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
// If there are multiple artifacts and it's not GeniusDiamond, fall back to original logic
|
|
200
|
+
return await (0, utils_1.getDiamondContractName)(diamondName, diamond);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Validates constructor inputs
|
|
205
|
+
*/
|
|
206
|
+
validateConstructorInputs(rpcUrl, privateKey, gasLimitMultiplier, maxRetries, retryDelayMs) {
|
|
207
|
+
if (!rpcUrl || typeof rpcUrl !== 'string') {
|
|
208
|
+
throw new Error('Invalid RPC URL provided');
|
|
209
|
+
}
|
|
210
|
+
if (!privateKey || !privateKey.match(/^0x[a-fA-F0-9]{64}$/)) {
|
|
211
|
+
throw new Error('Invalid private key format. Must be 64 hex characters with 0x prefix');
|
|
212
|
+
}
|
|
213
|
+
if (gasLimitMultiplier < 1.0 || gasLimitMultiplier > 2.0) {
|
|
214
|
+
throw new Error('Gas limit multiplier must be between 1.0 and 2.0');
|
|
215
|
+
}
|
|
216
|
+
if (maxRetries < 1 || maxRetries > 10) {
|
|
217
|
+
throw new Error('Max retries must be between 1 and 10');
|
|
218
|
+
}
|
|
219
|
+
if (retryDelayMs < 100 || retryDelayMs > 30000) {
|
|
220
|
+
throw new Error('Retry delay must be between 100ms and 30000ms');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Retry wrapper for operations that may fail due to network issues
|
|
225
|
+
*/
|
|
226
|
+
async withRetry(operation, operationName, maxRetries = this.maxRetries) {
|
|
227
|
+
let lastError;
|
|
228
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
229
|
+
try {
|
|
230
|
+
if (this.verbose && attempt > 1) {
|
|
231
|
+
console.log(chalk_1.default.yellow(`🔄 Retrying ${operationName} (attempt ${attempt}/${maxRetries})`));
|
|
232
|
+
}
|
|
233
|
+
const result = await operation();
|
|
234
|
+
if (attempt > 1 && this.verbose) {
|
|
235
|
+
console.log(chalk_1.default.green(`✅ ${operationName} succeeded on attempt ${attempt}`));
|
|
236
|
+
}
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
lastError = error;
|
|
241
|
+
if (this.verbose) {
|
|
242
|
+
console.log(chalk_1.default.red(`❌ ${operationName} failed on attempt ${attempt}: ${lastError.message}`));
|
|
243
|
+
}
|
|
244
|
+
if (attempt < maxRetries) {
|
|
245
|
+
const delay = this.retryDelayMs * Math.pow(1.5, attempt - 1); // Exponential backoff
|
|
246
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
throw new Error(`${operationName} failed after ${maxRetries} attempts. Last error: ${lastError.message}`);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Estimates gas for a transaction with safety multiplier
|
|
254
|
+
*/
|
|
255
|
+
async estimateGasWithMultiplier(contract, methodName, args = []) {
|
|
256
|
+
try {
|
|
257
|
+
const estimatedGas = await contract[methodName].estimateGas(...args);
|
|
258
|
+
const gasWithMultiplier = BigInt(Math.floor(Number(estimatedGas) * this.gasLimitMultiplier));
|
|
259
|
+
if (this.verbose) {
|
|
260
|
+
console.log(chalk_1.default.gray(`⛽ Gas estimate for ${methodName}: ${estimatedGas.toString()} (with multiplier: ${gasWithMultiplier.toString()})`));
|
|
261
|
+
}
|
|
262
|
+
return gasWithMultiplier;
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
throw new GasEstimationError(`Failed to estimate gas for ${methodName}: ${error.message}`, error);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Gets current gas price with optional premium
|
|
270
|
+
*/
|
|
271
|
+
async getGasPrice() {
|
|
272
|
+
try {
|
|
273
|
+
const feeData = await this.provider.getFeeData();
|
|
274
|
+
if (feeData.gasPrice) {
|
|
275
|
+
if (this.verbose) {
|
|
276
|
+
console.log(chalk_1.default.gray(`⛽ Gas price: ${ethers_1.ethers.formatUnits(feeData.gasPrice, "gwei")} gwei`));
|
|
277
|
+
}
|
|
278
|
+
return feeData.gasPrice;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
// Fallback for networks that don't support getFeeData
|
|
282
|
+
const gasPrice = await this.provider.send('eth_gasPrice', []);
|
|
283
|
+
const gasPriceBigInt = BigInt(gasPrice);
|
|
284
|
+
if (this.verbose) {
|
|
285
|
+
console.log(chalk_1.default.gray(`⛽ Gas price (fallback): ${ethers_1.ethers.formatUnits(gasPriceBigInt, "gwei")} gwei`));
|
|
286
|
+
}
|
|
287
|
+
return gasPriceBigInt;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
throw new GasEstimationError(`Failed to get gas price: ${error.message}`, error);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Deploys a contract using RPC
|
|
296
|
+
*/
|
|
297
|
+
async deployContract(contractName, constructorArgs = [], diamond) {
|
|
298
|
+
return await this.withRetry(async () => {
|
|
299
|
+
try {
|
|
300
|
+
// Get contract artifact using Hardhat's artifact resolution
|
|
301
|
+
// This will find artifacts in all configured paths (contracts-starter, gnus-ai, etc.)
|
|
302
|
+
const artifact = await (0, utils_1.getContractArtifact)(contractName, diamond);
|
|
303
|
+
// Create contract factory
|
|
304
|
+
const factory = new ethers_1.ContractFactory(artifact.abi, artifact.bytecode, this.signer);
|
|
305
|
+
// Estimate gas for deployment
|
|
306
|
+
const deployTransaction = await factory.getDeployTransaction(...constructorArgs);
|
|
307
|
+
const estimatedGas = await this.provider.estimateGas({
|
|
308
|
+
data: deployTransaction.data,
|
|
309
|
+
from: await this.signer.getAddress()
|
|
310
|
+
});
|
|
311
|
+
const gasLimit = BigInt(Math.floor(Number(estimatedGas) * this.gasLimitMultiplier));
|
|
312
|
+
// Get gas price
|
|
313
|
+
const gasPrice = await this.getGasPrice();
|
|
314
|
+
if (this.verbose) {
|
|
315
|
+
console.log(chalk_1.default.blue(`🚀 Deploying ${contractName} with gas limit: ${gasLimit.toString()}`));
|
|
316
|
+
}
|
|
317
|
+
// Deploy contract
|
|
318
|
+
const contract = await factory.deploy(...constructorArgs, {
|
|
319
|
+
gasLimit,
|
|
320
|
+
gasPrice
|
|
321
|
+
});
|
|
322
|
+
// Wait for deployment
|
|
323
|
+
const deploymentReceipt = await contract.deploymentTransaction()?.wait();
|
|
324
|
+
if (!deploymentReceipt) {
|
|
325
|
+
throw new ContractDeploymentError(`Deployment transaction failed for ${contractName}`, contractName);
|
|
326
|
+
}
|
|
327
|
+
if (this.verbose) {
|
|
328
|
+
console.log(chalk_1.default.green(`✅ ${contractName} deployed at: ${await contract.getAddress()}`));
|
|
329
|
+
console.log(chalk_1.default.gray(` Transaction hash: ${deploymentReceipt.hash}`));
|
|
330
|
+
console.log(chalk_1.default.gray(` Gas used: ${deploymentReceipt.gasUsed.toString()}`));
|
|
331
|
+
}
|
|
332
|
+
return contract;
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
if (error instanceof ContractDeploymentError) {
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
throw new ContractDeploymentError(`Failed to deploy ${contractName}: ${error.message}`, contractName, error);
|
|
339
|
+
}
|
|
340
|
+
}, `Deploy ${contractName}`);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Override deployDiamondTasks to use RPC instead of Hardhat
|
|
344
|
+
*/
|
|
345
|
+
async deployDiamondTasks(diamond) {
|
|
346
|
+
// Initialize step tracking store
|
|
347
|
+
await this.initializeStore(diamond);
|
|
348
|
+
if (this.verbose) {
|
|
349
|
+
console.log(chalk_1.default.blueBright(`🚀 Explicitly deploying DiamondCutFacet and Diamond for ${diamond.diamondName} via RPC`));
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
// Step 1: Deploy DiamondCutFacet
|
|
353
|
+
const diamondCutStepName = 'deploy-diamondcutfacet';
|
|
354
|
+
if (!this.skipCompletedStep(diamondCutStepName, 'Deploy DiamondCutFacet')) {
|
|
355
|
+
this.saveStep(diamondCutStepName, 'Deploy DiamondCutFacet', 'in_progress');
|
|
356
|
+
const diamondCutContractName = await (0, utils_1.getContractName)("DiamondCutFacet", diamond);
|
|
357
|
+
const diamondCutFacet = await this.deployContract(diamondCutContractName, [], diamond);
|
|
358
|
+
const diamondCutFacetAddress = await diamondCutFacet.getAddress();
|
|
359
|
+
const diamondCutTxHash = diamondCutFacet.deploymentTransaction()?.hash;
|
|
360
|
+
this.updateStepStatus(diamondCutStepName, 'completed', diamondCutTxHash, diamondCutFacetAddress);
|
|
361
|
+
}
|
|
362
|
+
// Step 2: Deploy Diamond contract
|
|
363
|
+
const diamondStepName = 'deploy-diamond';
|
|
364
|
+
if (!this.skipCompletedStep(diamondStepName, 'Deploy Diamond contract')) {
|
|
365
|
+
this.saveStep(diamondStepName, 'Deploy Diamond contract', 'in_progress');
|
|
366
|
+
// Get DiamondCutFacet address from completed step or deploy
|
|
367
|
+
const diamondCutStep = this.store?.getStep(diamondCutStepName);
|
|
368
|
+
const diamondCutFacetAddress = diamondCutStep?.contractAddress;
|
|
369
|
+
if (!diamondCutFacetAddress) {
|
|
370
|
+
throw new Error('DiamondCutFacet address not found from previous step');
|
|
371
|
+
}
|
|
372
|
+
const diamondContractName = await this.resolveDiamondContractName(diamond.diamondName, diamond);
|
|
373
|
+
const diamondContract = await this.deployContract(diamondContractName, [await this.signer.getAddress(), diamondCutFacetAddress], diamond);
|
|
374
|
+
const diamondContractAddress = await diamondContract.getAddress();
|
|
375
|
+
const diamondTxHash = diamondContract.deploymentTransaction()?.hash;
|
|
376
|
+
this.updateStepStatus(diamondStepName, 'completed', diamondTxHash, diamondContractAddress);
|
|
377
|
+
}
|
|
378
|
+
// Step 3: Register DiamondCutFacet selectors
|
|
379
|
+
this.saveStep('register-diamondcut-selectors', 'Register DiamondCutFacet function selectors', 'in_progress');
|
|
380
|
+
// Re-create DiamondCutFacet instance to get selectors
|
|
381
|
+
const diamondCutContractName = await (0, utils_1.getContractName)("DiamondCutFacet", diamond);
|
|
382
|
+
const diamondCutArtifact = await (0, utils_1.getContractArtifact)(diamondCutContractName, diamond);
|
|
383
|
+
const diamondCutFacetAddress = this.store?.getStep(diamondCutStepName)?.contractAddress;
|
|
384
|
+
const diamondCutFacet = new ethers_1.Contract(diamondCutFacetAddress, diamondCutArtifact.abi, this.signer);
|
|
385
|
+
// Get function selectors for DiamondCutFacet
|
|
386
|
+
const diamondCutFacetFunctionSelectors = [];
|
|
387
|
+
diamondCutFacet.interface.forEachFunction((func) => {
|
|
388
|
+
diamondCutFacetFunctionSelectors.push(func.selector);
|
|
389
|
+
});
|
|
390
|
+
// Register the DiamondCutFacet function selectors
|
|
391
|
+
const diamondCutFacetSelectorsRegistry = diamondCutFacetFunctionSelectors.reduce((acc, selector) => {
|
|
392
|
+
acc[selector] = {
|
|
393
|
+
facetName: "DiamondCutFacet",
|
|
394
|
+
priority: diamond.getFacetsConfig()?.DiamondCutFacet?.priority || 1000,
|
|
395
|
+
address: diamondCutFacetAddress,
|
|
396
|
+
action: types_1.RegistryFacetCutAction.Deployed,
|
|
397
|
+
};
|
|
398
|
+
return acc;
|
|
399
|
+
}, {});
|
|
400
|
+
diamond.registerFunctionSelectors(diamondCutFacetSelectorsRegistry);
|
|
401
|
+
this.updateStepStatus('register-diamondcut-selectors', 'completed');
|
|
402
|
+
// Step 4: Update deployed diamond data
|
|
403
|
+
this.saveStep('update-diamond-data', 'Update deployed diamond data', 'in_progress');
|
|
404
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
405
|
+
const diamondContractAddress = this.store?.getStep('deploy-diamond')?.contractAddress;
|
|
406
|
+
deployedDiamondData.DeployerAddress = await this.signer.getAddress();
|
|
407
|
+
deployedDiamondData.DiamondAddress = diamondContractAddress;
|
|
408
|
+
deployedDiamondData.DeployedFacets = deployedDiamondData.DeployedFacets || {};
|
|
409
|
+
deployedDiamondData.DeployedFacets["DiamondCutFacet"] = {
|
|
410
|
+
address: diamondCutFacetAddress,
|
|
411
|
+
tx_hash: this.store?.getStep(diamondCutStepName)?.txHash || "",
|
|
412
|
+
version: 0,
|
|
413
|
+
funcSelectors: diamondCutFacetFunctionSelectors,
|
|
414
|
+
};
|
|
415
|
+
diamond.updateDeployedDiamondData(deployedDiamondData);
|
|
416
|
+
this.updateStepStatus('update-diamond-data', 'completed');
|
|
417
|
+
if (this.verbose) {
|
|
418
|
+
console.log(chalk_1.default.green(`✅ Diamond deployed at ${diamondContractAddress}, DiamondCutFacet at ${diamondCutFacetAddress}`));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
const errorMessage = error.message;
|
|
423
|
+
if (this.store) {
|
|
424
|
+
this.store.markDeploymentFailed(errorMessage);
|
|
425
|
+
}
|
|
426
|
+
console.error(chalk_1.default.red(`❌ Failed to deploy diamond via RPC: ${errorMessage}`));
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Override deployFacetsTasks to use RPC instead of Hardhat
|
|
432
|
+
*/
|
|
433
|
+
async deployFacetsTasks(diamond) {
|
|
434
|
+
console.log("🔍 DEBUG: RPCDeploymentStrategy.deployFacetsTasks called");
|
|
435
|
+
const deployConfig = diamond.getDeployConfig();
|
|
436
|
+
const facetsConfig = diamond.getDeployConfig().facets;
|
|
437
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
438
|
+
const sortedFacetNames = Object.keys(deployConfig.facets)
|
|
439
|
+
.sort((a, b) => {
|
|
440
|
+
return (deployConfig.facets[a].priority || 1000) - (deployConfig.facets[b].priority || 1000);
|
|
441
|
+
});
|
|
442
|
+
// Deploy facets sequentially to maintain order
|
|
443
|
+
for (const facetName of sortedFacetNames) {
|
|
444
|
+
const facetConfig = facetsConfig[facetName];
|
|
445
|
+
const deployedVersion = deployedDiamondData.DeployedFacets?.[facetName]?.version ?? -1;
|
|
446
|
+
const availableVersions = Object.keys(facetConfig.versions || {}).map(Number);
|
|
447
|
+
const upgradeVersion = Math.max(...availableVersions);
|
|
448
|
+
if (upgradeVersion > deployedVersion || deployedVersion === -1) {
|
|
449
|
+
const facetStepName = `deploy-facet-${facetName.toLowerCase()}`;
|
|
450
|
+
if (this.skipCompletedStep(facetStepName, `Deploy ${facetName} facet`)) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
this.saveStep(facetStepName, `Deploy ${facetName} facet v${upgradeVersion}`, 'in_progress');
|
|
454
|
+
if (this.verbose) {
|
|
455
|
+
console.log(chalk_1.default.blueBright(`🚀 Deploying facet: ${facetName} to version ${upgradeVersion} via RPC`));
|
|
456
|
+
}
|
|
457
|
+
try {
|
|
458
|
+
// Deploy the facet contract using RPC
|
|
459
|
+
const facetContractName = await (0, utils_1.getContractName)(facetName, diamond);
|
|
460
|
+
const facetContract = await this.deployContract(facetContractName, [], diamond);
|
|
461
|
+
const facetAddress = await facetContract.getAddress();
|
|
462
|
+
const facetTxHash = facetContract.deploymentTransaction()?.hash;
|
|
463
|
+
const facetSelectors = [];
|
|
464
|
+
facetContract.interface.forEachFunction((func) => {
|
|
465
|
+
facetSelectors.push(func.selector);
|
|
466
|
+
});
|
|
467
|
+
// Initializer function Registry
|
|
468
|
+
const deployInit = facetConfig.versions?.[upgradeVersion]?.deployInit || "";
|
|
469
|
+
const upgradeInit = facetConfig.versions?.[upgradeVersion]?.upgradeInit || "";
|
|
470
|
+
const initFn = diamond.newDeployment ? deployInit : upgradeInit;
|
|
471
|
+
if (initFn && facetName !== deployConfig.protocolInitFacet) {
|
|
472
|
+
diamond.initializerRegistry.set(facetName, initFn);
|
|
473
|
+
}
|
|
474
|
+
const newFacetData = {
|
|
475
|
+
priority: facetConfig.priority || 1000,
|
|
476
|
+
address: facetAddress,
|
|
477
|
+
tx_hash: facetTxHash || "",
|
|
478
|
+
version: upgradeVersion,
|
|
479
|
+
funcSelectors: facetSelectors,
|
|
480
|
+
deployInclude: facetConfig.versions?.[upgradeVersion]?.deployInclude || [],
|
|
481
|
+
deployExclude: facetConfig.versions?.[upgradeVersion]?.deployExclude || [],
|
|
482
|
+
initFunction: initFn,
|
|
483
|
+
verified: false,
|
|
484
|
+
};
|
|
485
|
+
diamond.updateNewDeployedFacets(facetName, newFacetData);
|
|
486
|
+
// Update step status with deployment info
|
|
487
|
+
this.updateStepStatus(facetStepName, 'completed', facetTxHash, facetAddress);
|
|
488
|
+
console.log(chalk_1.default.cyan(`⛵ ${facetName} deployed at ${facetAddress} with ${facetSelectors.length} selectors.`));
|
|
489
|
+
if (this.verbose) {
|
|
490
|
+
console.log(chalk_1.default.gray(` Selectors:`), facetSelectors);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
const errorMessage = error.message;
|
|
495
|
+
this.updateStepStatus(facetStepName, 'failed', undefined, undefined, undefined, errorMessage);
|
|
496
|
+
console.error(chalk_1.default.red(`❌ Failed to deploy facet ${facetName}: ${errorMessage}`));
|
|
497
|
+
throw error;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Override performDiamondCutTasks to use RPC instead of Hardhat
|
|
504
|
+
*/
|
|
505
|
+
async performDiamondCutTasks(diamond) {
|
|
506
|
+
const deployConfig = diamond.getDeployConfig();
|
|
507
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
508
|
+
const diamondCutStepName = 'perform-diamond-cut';
|
|
509
|
+
if (this.skipCompletedStep(diamondCutStepName, 'Perform diamond cut')) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
this.saveStep(diamondCutStepName, 'Perform diamond cut to add facets', 'in_progress');
|
|
513
|
+
try {
|
|
514
|
+
// Get diamond contract using RPC
|
|
515
|
+
const diamondAddress = deployedDiamondData.DiamondAddress;
|
|
516
|
+
// Load IDiamondCut ABI using Hardhat artifact resolution
|
|
517
|
+
const diamondCutArtifact = await (0, utils_1.getContractArtifact)("IDiamondCut", diamond);
|
|
518
|
+
const diamondContract = new ethers_1.Contract(diamondAddress, diamondCutArtifact.abi, this.signer);
|
|
519
|
+
// Setup initCallData with Atomic Protocol Initializer
|
|
520
|
+
const [initCalldata, initAddress] = await this.getInitCalldata(diamond);
|
|
521
|
+
// Extract facet cuts from the selector registry
|
|
522
|
+
const facetCuts = await this.getFacetCuts(diamond);
|
|
523
|
+
// Validate no orphaned selectors
|
|
524
|
+
await this.validateNoOrphanedSelectors(facetCuts);
|
|
525
|
+
if (this.verbose) {
|
|
526
|
+
console.log(chalk_1.default.yellowBright(`\n🪓 Performing DiamondCut with ${facetCuts.length} cut(s) via RPC:`));
|
|
527
|
+
for (const cut of facetCuts) {
|
|
528
|
+
console.log(chalk_1.default.bold(`- ${types_1.FacetCutAction[cut.action]} for facet ${cut.name} at ${cut.facetAddress}`));
|
|
529
|
+
console.log(chalk_1.default.gray(` Selectors:`), cut.functionSelectors);
|
|
530
|
+
}
|
|
531
|
+
if (initAddress !== ethers_1.ethers.ZeroAddress) {
|
|
532
|
+
console.log(chalk_1.default.cyan(`Initializing with functionSelector ${initCalldata} on ProtocolInitFacet ${deployConfig.protocolInitFacet} @ ${initAddress}`));
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
// Prepare the diamond cut transaction
|
|
536
|
+
const facetSelectorCutMap = facetCuts.map(fc => ({
|
|
537
|
+
facetAddress: fc.facetAddress,
|
|
538
|
+
action: fc.action,
|
|
539
|
+
functionSelectors: fc.functionSelectors
|
|
540
|
+
}));
|
|
541
|
+
// Estimate gas for diamond cut
|
|
542
|
+
const gasLimit = await this.estimateGasWithMultiplier(diamondContract, 'diamondCut', [facetSelectorCutMap, initAddress, initCalldata]);
|
|
543
|
+
// Get gas price
|
|
544
|
+
const gasPrice = await this.getGasPrice();
|
|
545
|
+
// Perform the diamond cut
|
|
546
|
+
const tx = await diamondContract.diamondCut(facetSelectorCutMap, initAddress, initCalldata, { gasLimit, gasPrice });
|
|
547
|
+
console.log(chalk_1.default.blueBright(`🔄 Waiting for DiamondCut transaction to be mined...`));
|
|
548
|
+
console.log(chalk_1.default.gray(` Transaction hash: ${tx.hash}`));
|
|
549
|
+
// Wait for transaction confirmation
|
|
550
|
+
const receipt = await tx.wait();
|
|
551
|
+
if (!receipt) {
|
|
552
|
+
throw new TransactionFailedError("DiamondCut transaction failed", tx.hash);
|
|
553
|
+
}
|
|
554
|
+
if (this.verbose) {
|
|
555
|
+
console.log(chalk_1.default.gray(` Gas used: ${receipt.gasUsed.toString()}`));
|
|
556
|
+
console.log(chalk_1.default.gray(` Block number: ${receipt.blockNumber}`));
|
|
557
|
+
}
|
|
558
|
+
// Update step status with transaction details
|
|
559
|
+
this.updateStepStatus(diamondCutStepName, 'completed', tx.hash, diamondAddress, receipt.gasUsed.toString());
|
|
560
|
+
// Update the deployed diamond data
|
|
561
|
+
const txHash = tx.hash;
|
|
562
|
+
await this.postDiamondCutDeployedDataUpdate(diamond, txHash);
|
|
563
|
+
console.log(chalk_1.default.green(`✅ DiamondCut executed: ${tx.hash}`));
|
|
564
|
+
// Execute initializer functions
|
|
565
|
+
await this.executeInitializerFunctions(diamond);
|
|
566
|
+
// Mark deployment as complete
|
|
567
|
+
if (this.store) {
|
|
568
|
+
this.store.markDeploymentComplete();
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
catch (error) {
|
|
572
|
+
const errorMessage = error.message;
|
|
573
|
+
this.updateStepStatus(diamondCutStepName, 'failed', undefined, undefined, undefined, errorMessage);
|
|
574
|
+
if (this.store) {
|
|
575
|
+
this.store.markDeploymentFailed(errorMessage);
|
|
576
|
+
}
|
|
577
|
+
console.error(chalk_1.default.red(`❌ Failed to perform diamond cut via RPC: ${error.message}`));
|
|
578
|
+
throw error;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Executes initializer functions for deployed facets
|
|
583
|
+
*/
|
|
584
|
+
async executeInitializerFunctions(diamond) {
|
|
585
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
586
|
+
const diamondAddress = deployedDiamondData.DiamondAddress;
|
|
587
|
+
for (const [facetName, initFunction] of diamond.initializerRegistry.entries()) {
|
|
588
|
+
const initStepName = `init-${facetName.toLowerCase()}`;
|
|
589
|
+
if (this.skipCompletedStep(initStepName, `Initialize ${facetName} facet`)) {
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
this.saveStep(initStepName, `Execute ${initFunction} from ${facetName} facet`, 'in_progress');
|
|
593
|
+
if (this.verbose) {
|
|
594
|
+
console.log(chalk_1.default.blueBright(`▶ Running ${initFunction} from the ${facetName} facet via RPC`));
|
|
595
|
+
}
|
|
596
|
+
try {
|
|
597
|
+
// Get facet contract name and load ABI using artifact resolution
|
|
598
|
+
const facetContractName = await (0, utils_1.getContractName)(facetName, diamond);
|
|
599
|
+
const facetArtifact = await (0, utils_1.getContractArtifact)(facetContractName, diamond);
|
|
600
|
+
const initContract = new ethers_1.Contract(diamondAddress, facetArtifact.abi, this.signer);
|
|
601
|
+
// Estimate gas for initializer function
|
|
602
|
+
const gasLimit = await this.estimateGasWithMultiplier(initContract, initFunction);
|
|
603
|
+
const gasPrice = await this.getGasPrice();
|
|
604
|
+
// Execute initializer function
|
|
605
|
+
const tx = await initContract[initFunction]({ gasLimit, gasPrice });
|
|
606
|
+
console.log(chalk_1.default.blueBright(`🔄 Waiting for ${facetName}.${initFunction} to be mined...`));
|
|
607
|
+
const receipt = await tx.wait();
|
|
608
|
+
if (!receipt) {
|
|
609
|
+
throw new TransactionFailedError(`${facetName}.${initFunction} transaction failed`, tx.hash);
|
|
610
|
+
}
|
|
611
|
+
if (this.verbose) {
|
|
612
|
+
console.log(chalk_1.default.gray(` Transaction hash: ${tx.hash}`));
|
|
613
|
+
console.log(chalk_1.default.gray(` Gas used: ${receipt.gasUsed.toString()}`));
|
|
614
|
+
}
|
|
615
|
+
// Update step status with transaction details
|
|
616
|
+
this.updateStepStatus(initStepName, 'completed', tx.hash, diamondAddress, receipt.gasUsed.toString());
|
|
617
|
+
console.log(chalk_1.default.green(`✅ ${facetName}.${initFunction} executed`));
|
|
618
|
+
}
|
|
619
|
+
catch (error) {
|
|
620
|
+
const errorMessage = error.message;
|
|
621
|
+
this.updateStepStatus(initStepName, 'failed', undefined, undefined, undefined, errorMessage);
|
|
622
|
+
console.error(chalk_1.default.red(`❌ Failed to execute ${facetName}.${initFunction}: ${errorMessage}`));
|
|
623
|
+
throw error;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Checks network connection and validates signer
|
|
629
|
+
*/
|
|
630
|
+
async validateConnection() {
|
|
631
|
+
try {
|
|
632
|
+
await this.withRetry(async () => {
|
|
633
|
+
// Check provider connection
|
|
634
|
+
const network = await this.provider.getNetwork();
|
|
635
|
+
const balance = await this.provider.getBalance(await this.signer.getAddress());
|
|
636
|
+
if (this.verbose) {
|
|
637
|
+
console.log(chalk_1.default.blue(`🌐 Connected to network: ${network.name} (Chain ID: ${network.chainId})`));
|
|
638
|
+
console.log(chalk_1.default.blue(`💰 Deployer balance: ${ethers_1.ethers.formatEther(balance)} ETH`));
|
|
639
|
+
}
|
|
640
|
+
// Verify minimum balance (0.01 ETH)
|
|
641
|
+
if (balance < (0, ethers_1.parseUnits)("0.01", 18)) {
|
|
642
|
+
console.warn(chalk_1.default.yellow(`⚠️ Low balance detected: ${ethers_1.ethers.formatEther(balance)} ETH`));
|
|
643
|
+
}
|
|
644
|
+
}, "Network connection validation");
|
|
645
|
+
}
|
|
646
|
+
catch (error) {
|
|
647
|
+
throw new RPCConnectionError(`Failed to validate RPC connection: ${error.message}`, error);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Gets the provider instance
|
|
652
|
+
*/
|
|
653
|
+
getProvider() {
|
|
654
|
+
return this.provider;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Gets the signer instance
|
|
658
|
+
*/
|
|
659
|
+
getSigner() {
|
|
660
|
+
return this.signer;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Gets deployment strategy configuration
|
|
664
|
+
*/
|
|
665
|
+
getConfig() {
|
|
666
|
+
return {
|
|
667
|
+
rpcUrl: this.rpcUrl,
|
|
668
|
+
signerAddress: this.signer.getAddress(),
|
|
669
|
+
gasLimitMultiplier: this.gasLimitMultiplier,
|
|
670
|
+
maxRetries: this.maxRetries,
|
|
671
|
+
retryDelayMs: this.retryDelayMs,
|
|
672
|
+
verbose: this.verbose
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
// Pre-deploy hooks with connection validation
|
|
676
|
+
async preDeployDiamond(diamond) {
|
|
677
|
+
await this.validateConnection();
|
|
678
|
+
await super.preDeployDiamond(diamond);
|
|
679
|
+
}
|
|
680
|
+
async preDeployFacetsTasks(diamond) {
|
|
681
|
+
console.log("🔍 DEBUG: preDeployFacetsTasks called for", diamond.diamondName);
|
|
682
|
+
// Initialize step tracking store for both new deployments and upgrades
|
|
683
|
+
if (!this.store) {
|
|
684
|
+
console.log("🔍 DEBUG: Initializing store...");
|
|
685
|
+
await this.initializeStore(diamond);
|
|
686
|
+
console.log("🔍 DEBUG: Store initialized:", !!this.store);
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
console.log("🔍 DEBUG: Store already exists:", !!this.store);
|
|
690
|
+
}
|
|
691
|
+
await this.validateConnection();
|
|
692
|
+
await super.preDeployFacetsTasks(diamond);
|
|
693
|
+
}
|
|
694
|
+
async prePerformDiamondCutTasks(diamond) {
|
|
695
|
+
console.log("🔍 DEBUG: prePerformDiamondCutTasks called for", diamond.diamondName);
|
|
696
|
+
await this.validateConnection();
|
|
697
|
+
// Initialize step tracking store for both new deployments and upgrades
|
|
698
|
+
if (!this.store) {
|
|
699
|
+
console.log("🔍 DEBUG: Initializing store...");
|
|
700
|
+
await this.initializeStore(diamond);
|
|
701
|
+
console.log("🔍 DEBUG: Store initialized:", !!this.store);
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
console.log("🔍 DEBUG: Store already exists:", !!this.store);
|
|
705
|
+
}
|
|
706
|
+
await super.prePerformDiamondCutTasks(diamond);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
exports.RPCDeploymentStrategy = RPCDeploymentStrategy;
|
|
710
|
+
//# sourceMappingURL=RPCDeploymentStrategy.js.map
|