@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,415 @@
|
|
|
1
|
+
# Defender Deployment Example
|
|
2
|
+
|
|
3
|
+
This example demonstrates how to deploy and upgrade a Diamond proxy contract using OpenZeppelin Defender.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This example includes:
|
|
8
|
+
|
|
9
|
+
- A complete Diamond implementation with multiple facets
|
|
10
|
+
- Configuration for Defender deployment
|
|
11
|
+
- Deployment and upgrade scripts
|
|
12
|
+
- Step-by-step instructions
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
1. OpenZeppelin Defender account with API credentials
|
|
17
|
+
2. Testnet ETH for gas fees
|
|
18
|
+
3. Node.js 16+ and npm
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
1. **Clone and Install Dependencies**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cd examples/defender-deployment
|
|
26
|
+
npm install
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
2. **Configure Environment**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cp .env.example .env
|
|
33
|
+
# Edit .env with your Defender credentials
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
3. **Review Diamond Configuration**
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cat diamond-config.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Diamond Structure
|
|
43
|
+
|
|
44
|
+
### Contracts
|
|
45
|
+
|
|
46
|
+
- `ExampleDiamond.sol`: Main diamond contract
|
|
47
|
+
- `ExampleFacet1.sol`: Basic functionality facet
|
|
48
|
+
- `ExampleFacet2.sol`: Advanced functionality facet
|
|
49
|
+
- `UpgradeFacet.sol`: New facet for upgrade demonstration
|
|
50
|
+
|
|
51
|
+
### Configuration
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"protocolVersion": 0.0,
|
|
56
|
+
"protocolInitFacet": "ExampleFacet1",
|
|
57
|
+
"facets": {
|
|
58
|
+
"DiamondCutFacet": {
|
|
59
|
+
"priority": 10,
|
|
60
|
+
"versions": { "0.0": {} }
|
|
61
|
+
},
|
|
62
|
+
"DiamondLoupeFacet": {
|
|
63
|
+
"priority": 20,
|
|
64
|
+
"versions": { "0.0": {} }
|
|
65
|
+
},
|
|
66
|
+
"ExampleFacet1": {
|
|
67
|
+
"priority": 30,
|
|
68
|
+
"versions": {
|
|
69
|
+
"0.0": {
|
|
70
|
+
"deployInit": "initialize()",
|
|
71
|
+
"callbacks": ["logDeployment"]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"ExampleFacet2": {
|
|
76
|
+
"priority": 40,
|
|
77
|
+
"versions": {
|
|
78
|
+
"0.0": {
|
|
79
|
+
"deployInit": "setup()",
|
|
80
|
+
"callbacks": ["validateSetup"]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Deployment Steps
|
|
89
|
+
|
|
90
|
+
### 1. Initial Deployment
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Deploy to Sepolia testnet
|
|
94
|
+
npm run deploy:sepolia
|
|
95
|
+
|
|
96
|
+
# Or deploy to local hardhat network
|
|
97
|
+
npm run deploy:local
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This will:
|
|
101
|
+
|
|
102
|
+
1. Deploy DiamondCutFacet through Defender
|
|
103
|
+
2. Deploy the main Diamond contract
|
|
104
|
+
3. Deploy all configured facets
|
|
105
|
+
4. Create a Defender proposal for the diamond cut
|
|
106
|
+
5. Execute the proposal (if auto-approval is enabled)
|
|
107
|
+
|
|
108
|
+
### 2. Verify Deployment
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Check deployment status
|
|
112
|
+
npm run status
|
|
113
|
+
|
|
114
|
+
# Verify on block explorer
|
|
115
|
+
npm run verify
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. Upgrade Example
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# This adds UpgradeFacet and upgrades ExampleFacet1 to v1.0
|
|
122
|
+
npm run upgrade
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Script Explanations
|
|
126
|
+
|
|
127
|
+
### deploy-script.ts
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { ethers } from 'hardhat';
|
|
131
|
+
import { Diamond, DiamondDeployer, FileDeploymentRepository } from '@diamonds/core';
|
|
132
|
+
import { OZDefenderDeploymentStrategy } from '@diamonds/strategies';
|
|
133
|
+
|
|
134
|
+
async function main() {
|
|
135
|
+
console.log('🚀 Starting Defender deployment...');
|
|
136
|
+
|
|
137
|
+
// Load configuration
|
|
138
|
+
const config = {
|
|
139
|
+
diamondName: 'ExampleDiamond',
|
|
140
|
+
networkName: 'sepolia',
|
|
141
|
+
chainId: 11155111,
|
|
142
|
+
deploymentsPath: './deployments',
|
|
143
|
+
contractsPath: './contracts',
|
|
144
|
+
callbacksPath: './callbacks',
|
|
145
|
+
configFilePath: './diamond-config.json',
|
|
146
|
+
deployedDiamondDataFilePath: './deployments/exampledianmond-sepolia-11155111.json'
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Create diamond instance
|
|
150
|
+
const repository = new FileDeploymentRepository(config);
|
|
151
|
+
const diamond = new Diamond(config, repository);
|
|
152
|
+
|
|
153
|
+
// Setup provider and signer
|
|
154
|
+
diamond.setProvider(ethers.provider);
|
|
155
|
+
diamond.setSigner(await ethers.getSigners()[0]);
|
|
156
|
+
|
|
157
|
+
// Create Defender strategy
|
|
158
|
+
const strategy = new OZDefenderDeploymentStrategy(
|
|
159
|
+
process.env.DEFENDER_API_KEY!,
|
|
160
|
+
process.env.DEFENDER_API_SECRET!,
|
|
161
|
+
process.env.DEFENDER_RELAYER_ADDRESS!,
|
|
162
|
+
process.env.AUTO_APPROVE === 'true',
|
|
163
|
+
process.env.DEFENDER_SAFE_ADDRESS!,
|
|
164
|
+
'Safe',
|
|
165
|
+
true // verbose logging
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// Execute deployment
|
|
169
|
+
const deployer = new DiamondDeployer(diamond, strategy);
|
|
170
|
+
await deployer.deployDiamond();
|
|
171
|
+
|
|
172
|
+
console.log('✅ Deployment completed!');
|
|
173
|
+
|
|
174
|
+
// Output deployment information
|
|
175
|
+
const deployedData = diamond.getDeployedDiamondData();
|
|
176
|
+
console.log('\n📊 Deployment Summary:');
|
|
177
|
+
console.log(`Diamond Address: ${deployedData.DiamondAddress}`);
|
|
178
|
+
console.log(`Deployer Address: ${deployedData.DeployerAddress}`);
|
|
179
|
+
console.log('\n📋 Deployed Facets:');
|
|
180
|
+
|
|
181
|
+
Object.entries(deployedData.DeployedFacets || {}).forEach(([name, facet]) => {
|
|
182
|
+
console.log(` ${name}: ${facet.address} (v${facet.version})`);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
main()
|
|
187
|
+
.then(() => process.exit(0))
|
|
188
|
+
.catch((error) => {
|
|
189
|
+
console.error('❌ Deployment failed:', error);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### upgrade-script.ts
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { ethers } from 'hardhat';
|
|
198
|
+
import { Diamond, DiamondDeployer, FileDeploymentRepository } from '@diamonds/core';
|
|
199
|
+
import { OZDefenderDeploymentStrategy } from '@diamonds/strategies';
|
|
200
|
+
import * as fs from 'fs-extra';
|
|
201
|
+
|
|
202
|
+
async function main() {
|
|
203
|
+
console.log('♻️ Starting upgrade process...');
|
|
204
|
+
|
|
205
|
+
// Load and update configuration
|
|
206
|
+
const configPath = './diamond-config.json';
|
|
207
|
+
const config = await fs.readJson(configPath);
|
|
208
|
+
|
|
209
|
+
// Add new facet for upgrade
|
|
210
|
+
config.protocolVersion = 1.0;
|
|
211
|
+
config.facets['UpgradeFacet'] = {
|
|
212
|
+
priority: 50,
|
|
213
|
+
versions: {
|
|
214
|
+
"1.0": {
|
|
215
|
+
deployInit: "initialize()",
|
|
216
|
+
callbacks: ["logUpgrade"]
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// Upgrade existing facet
|
|
222
|
+
config.facets['ExampleFacet1'].versions["1.0"] = {
|
|
223
|
+
upgradeInit: "upgradeToV1()",
|
|
224
|
+
callbacks: ["validateUpgrade"]
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// Save updated configuration
|
|
228
|
+
await fs.writeJson(configPath, config, { spaces: 2 });
|
|
229
|
+
|
|
230
|
+
// Setup diamond with existing deployment data
|
|
231
|
+
const diamondConfig = {
|
|
232
|
+
diamondName: 'ExampleDiamond',
|
|
233
|
+
networkName: 'sepolia',
|
|
234
|
+
chainId: 11155111,
|
|
235
|
+
deploymentsPath: './deployments',
|
|
236
|
+
contractsPath: './contracts',
|
|
237
|
+
callbacksPath: './callbacks',
|
|
238
|
+
configFilePath: configPath,
|
|
239
|
+
deployedDiamondDataFilePath: './deployments/exampledianmond-sepolia-11155111.json'
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const repository = new FileDeploymentRepository(diamondConfig);
|
|
243
|
+
const diamond = new Diamond(diamondConfig, repository);
|
|
244
|
+
|
|
245
|
+
diamond.setProvider(ethers.provider);
|
|
246
|
+
diamond.setSigner(await ethers.getSigners()[0]);
|
|
247
|
+
|
|
248
|
+
// Create strategy and execute upgrade
|
|
249
|
+
const strategy = new OZDefenderDeploymentStrategy(
|
|
250
|
+
process.env.DEFENDER_API_KEY!,
|
|
251
|
+
process.env.DEFENDER_API_SECRET!,
|
|
252
|
+
process.env.DEFENDER_RELAYER_ADDRESS!,
|
|
253
|
+
process.env.AUTO_APPROVE === 'true',
|
|
254
|
+
process.env.DEFENDER_SAFE_ADDRESS!,
|
|
255
|
+
'Safe',
|
|
256
|
+
true
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const deployer = new DiamondDeployer(diamond, strategy);
|
|
260
|
+
await deployer.deployDiamond(); // Automatically detects upgrade scenario
|
|
261
|
+
|
|
262
|
+
console.log('✅ Upgrade completed!');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
main()
|
|
266
|
+
.then(() => process.exit(0))
|
|
267
|
+
.catch((error) => {
|
|
268
|
+
console.error('❌ Upgrade failed:', error);
|
|
269
|
+
process.exit(1);
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Callback Examples
|
|
274
|
+
|
|
275
|
+
### callbacks/logDeployment.ts
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
export async function logDeployment(args: any) {
|
|
279
|
+
console.log('📝 Deployment callback executed');
|
|
280
|
+
console.log('Diamond Address:', args.diamondAddress);
|
|
281
|
+
console.log('Facet Address:', args.facetAddress);
|
|
282
|
+
console.log('Timestamp:', new Date().toISOString());
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### callbacks/validateSetup.ts
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { ethers } from 'hardhat';
|
|
290
|
+
|
|
291
|
+
export async function validateSetup(args: any) {
|
|
292
|
+
console.log('🔍 Validating setup...');
|
|
293
|
+
|
|
294
|
+
// Connect to deployed diamond
|
|
295
|
+
const diamond = await ethers.getContractAt('ExampleFacet2', args.diamondAddress);
|
|
296
|
+
|
|
297
|
+
// Validate initialization
|
|
298
|
+
const isSetup = await diamond.isSetupComplete();
|
|
299
|
+
if (!isSetup) {
|
|
300
|
+
throw new Error('Setup validation failed');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
console.log('✅ Setup validation passed');
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Expected Output
|
|
308
|
+
|
|
309
|
+
### Successful Deployment
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
🚀 Starting Defender deployment...
|
|
313
|
+
|
|
314
|
+
🪓 Pre-deploy diamond tasks for ExampleDiamond from OZDefenderDeploymentStrategy...
|
|
315
|
+
📡 Submitted DiamondCutFacet deploy to Defender: defender-deploy-id-1
|
|
316
|
+
✅ Deployment succeeded for deploy-diamondcutfacet.
|
|
317
|
+
📡 Submitted Diamond deploy to Defender: defender-deploy-id-2
|
|
318
|
+
✅ Deployment succeeded for deploy-diamond.
|
|
319
|
+
|
|
320
|
+
🚀 Deploying facet: DiamondLoupeFacet to version 0
|
|
321
|
+
📡 Submitted deployment for facet DiamondLoupeFacet: defender-deploy-id-3
|
|
322
|
+
✅ Deployment succeeded for deploy-DiamondLoupeFacet.
|
|
323
|
+
|
|
324
|
+
🚀 Deploying facet: ExampleFacet1 to version 0
|
|
325
|
+
📡 Submitted deployment for facet ExampleFacet1: defender-deploy-id-4
|
|
326
|
+
✅ Deployment succeeded for deploy-ExampleFacet1.
|
|
327
|
+
|
|
328
|
+
🚀 Deploying facet: ExampleFacet2 to version 0
|
|
329
|
+
📡 Submitted deployment for facet ExampleFacet2: defender-deploy-id-5
|
|
330
|
+
✅ Deployment succeeded for deploy-ExampleFacet2.
|
|
331
|
+
|
|
332
|
+
🪓 Performing DiamondCut with 3 cut(s):
|
|
333
|
+
- Add for facet DiamondLoupeFacet at 0x3456789012345678901234567890123456789012
|
|
334
|
+
- Add for facet ExampleFacet1 at 0x4567890123456789012345678901234567890123
|
|
335
|
+
- Add for facet ExampleFacet2 at 0x5678901234567890123456789012345678901234
|
|
336
|
+
|
|
337
|
+
📡 Defender Proposal created: https://defender.openzeppelin.com/proposal/test-proposal-123
|
|
338
|
+
⏳ Auto-approval enabled. Waiting for proposal to be ready for execution...
|
|
339
|
+
✅ Proposal executed successfully.
|
|
340
|
+
|
|
341
|
+
📝 Deployment callback executed
|
|
342
|
+
🔍 Validating setup...
|
|
343
|
+
✅ Setup validation passed
|
|
344
|
+
|
|
345
|
+
✅ Deployment completed!
|
|
346
|
+
|
|
347
|
+
📊 Deployment Summary:
|
|
348
|
+
Diamond Address: 0x1234567890123456789012345678901234567890
|
|
349
|
+
Deployer Address: 0x742d35Cc6634C0532925a3b8D50d97e7
|
|
350
|
+
|
|
351
|
+
📋 Deployed Facets:
|
|
352
|
+
DiamondCutFacet: 0x2345678901234567890123456789012345678901 (v0)
|
|
353
|
+
DiamondLoupeFacet: 0x3456789012345678901234567890123456789012 (v0)
|
|
354
|
+
ExampleFacet1: 0x4567890123456789012345678901234567890123 (v0)
|
|
355
|
+
ExampleFacet2: 0x5678901234567890123456789012345678901234 (v0)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Troubleshooting
|
|
359
|
+
|
|
360
|
+
### Common Issues
|
|
361
|
+
|
|
362
|
+
1. **API Authentication Error**
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
Error: Invalid API credentials
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Solution**: Verify your `DEFENDER_API_KEY` and `DEFENDER_API_SECRET` in `.env`
|
|
369
|
+
|
|
370
|
+
2. **Insufficient Balance**
|
|
371
|
+
|
|
372
|
+
```bash
|
|
373
|
+
Error: insufficient funds for gas
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Solution**: Add testnet ETH to your deployer address
|
|
377
|
+
|
|
378
|
+
3. **Network Configuration**
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
Error: could not detect network
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Solution**: Verify your RPC URL and network settings
|
|
385
|
+
|
|
386
|
+
4. **Multi-sig Approval Required**
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
Warning: Proposal awaiting approval
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Solution**: Check Defender dashboard for pending proposals
|
|
393
|
+
|
|
394
|
+
### Debug Mode
|
|
395
|
+
|
|
396
|
+
Enable verbose logging:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
DEBUG=diamonds:* npm run deploy:sepolia
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Next Steps
|
|
403
|
+
|
|
404
|
+
1. **Customize Facets**: Modify the example facets for your use case
|
|
405
|
+
2. **Add More Facets**: Extend the diamond with additional functionality
|
|
406
|
+
3. **Production Deployment**: Configure for mainnet deployment
|
|
407
|
+
4. **Monitoring**: Set up monitoring and alerting through Defender
|
|
408
|
+
5. **Automation**: Create automated deployment pipelines
|
|
409
|
+
|
|
410
|
+
## Resources
|
|
411
|
+
|
|
412
|
+
- [OpenZeppelin Defender Documentation](https://docs.openzeppelin.com/defender/)
|
|
413
|
+
- [ERC-2535 Diamond Standard](https://eips.ethereum.org/EIPS/eip-2535)
|
|
414
|
+
- [Hardhat Documentation](https://hardhat.org/docs)
|
|
415
|
+
- [Diamonds Module Documentation](../../docs/defender-integration.md)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.17;
|
|
3
|
+
|
|
4
|
+
import "../../../test/mocks/contracts/interfaces/IDiamondCut.sol";
|
|
5
|
+
|
|
6
|
+
contract ExampleDiamond {
|
|
7
|
+
address public owner;
|
|
8
|
+
|
|
9
|
+
event DiamondCreated(address indexed diamond, address indexed owner);
|
|
10
|
+
|
|
11
|
+
constructor(address _contractOwner, address _diamondCutFacet) {
|
|
12
|
+
owner = _contractOwner;
|
|
13
|
+
|
|
14
|
+
// Add the diamondCut external function from the diamondCutFacet
|
|
15
|
+
IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);
|
|
16
|
+
bytes4[] memory functionSelectors = new bytes4[](1);
|
|
17
|
+
functionSelectors[0] = IDiamondCut.diamondCut.selector;
|
|
18
|
+
cut[0] = IDiamondCut.FacetCut({
|
|
19
|
+
facetAddress: _diamondCutFacet,
|
|
20
|
+
action: IDiamondCut.FacetCutAction.Add,
|
|
21
|
+
functionSelectors: functionSelectors
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
emit DiamondCreated(address(this), _contractOwner);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Fallback function to delegate calls to facets
|
|
28
|
+
fallback() external payable {
|
|
29
|
+
address facet = address(0); // This would be looked up from storage in a real implementation
|
|
30
|
+
assembly {
|
|
31
|
+
calldatacopy(0, 0, calldatasize())
|
|
32
|
+
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
|
|
33
|
+
returndatacopy(0, 0, returndatasize())
|
|
34
|
+
switch result
|
|
35
|
+
case 0 { revert(0, returndatasize()) }
|
|
36
|
+
default { return(0, returndatasize()) }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
receive() external payable {}
|
|
41
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.17;
|
|
3
|
+
|
|
4
|
+
contract ExampleFacet1 {
|
|
5
|
+
bytes32 constant STORAGE_POSITION = keccak256("example.facet1.storage");
|
|
6
|
+
|
|
7
|
+
struct FacetStorage {
|
|
8
|
+
uint256 value;
|
|
9
|
+
bool initialized;
|
|
10
|
+
address owner;
|
|
11
|
+
string name;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function facetStorage() internal pure returns (FacetStorage storage fs) {
|
|
15
|
+
bytes32 position = STORAGE_POSITION;
|
|
16
|
+
assembly {
|
|
17
|
+
fs.slot := position
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
event Initialized(address indexed owner, string name);
|
|
22
|
+
event ValueSet(uint256 oldValue, uint256 newValue);
|
|
23
|
+
event UpgradedToV1(uint256 timestamp);
|
|
24
|
+
|
|
25
|
+
function initialize() external {
|
|
26
|
+
FacetStorage storage fs = facetStorage();
|
|
27
|
+
require(!fs.initialized, "Already initialized");
|
|
28
|
+
|
|
29
|
+
fs.initialized = true;
|
|
30
|
+
fs.owner = msg.sender;
|
|
31
|
+
fs.name = "ExampleFacet1";
|
|
32
|
+
fs.value = 100;
|
|
33
|
+
|
|
34
|
+
emit Initialized(msg.sender, fs.name);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function setValue(uint256 _value) external {
|
|
38
|
+
FacetStorage storage fs = facetStorage();
|
|
39
|
+
require(fs.initialized, "Not initialized");
|
|
40
|
+
require(msg.sender == fs.owner, "Not owner");
|
|
41
|
+
|
|
42
|
+
uint256 oldValue = fs.value;
|
|
43
|
+
fs.value = _value;
|
|
44
|
+
|
|
45
|
+
emit ValueSet(oldValue, _value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getValue() external view returns (uint256) {
|
|
49
|
+
FacetStorage storage fs = facetStorage();
|
|
50
|
+
return fs.value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getName() external view returns (string memory) {
|
|
54
|
+
FacetStorage storage fs = facetStorage();
|
|
55
|
+
return fs.name;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getOwner() external view returns (address) {
|
|
59
|
+
FacetStorage storage fs = facetStorage();
|
|
60
|
+
return fs.owner;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isInitialized() external view returns (bool) {
|
|
64
|
+
FacetStorage storage fs = facetStorage();
|
|
65
|
+
return fs.initialized;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Version 1.0 upgrade function
|
|
69
|
+
function upgradeToV1() external {
|
|
70
|
+
FacetStorage storage fs = facetStorage();
|
|
71
|
+
require(fs.initialized, "Not initialized");
|
|
72
|
+
require(msg.sender == fs.owner, "Not owner");
|
|
73
|
+
|
|
74
|
+
// Upgrade logic here
|
|
75
|
+
fs.name = "ExampleFacet1_V1";
|
|
76
|
+
|
|
77
|
+
emit UpgradedToV1(block.timestamp);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Version selector for upgrades
|
|
81
|
+
function version() external pure returns (string memory) {
|
|
82
|
+
return "1.0.0";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.17;
|
|
3
|
+
|
|
4
|
+
contract ExampleFacet2 {
|
|
5
|
+
bytes32 constant STORAGE_POSITION = keccak256("example.facet2.storage");
|
|
6
|
+
|
|
7
|
+
struct FacetStorage {
|
|
8
|
+
mapping(address => uint256) balances;
|
|
9
|
+
uint256 totalSupply;
|
|
10
|
+
bool setupComplete;
|
|
11
|
+
uint256 setupTimestamp;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function facetStorage() internal pure returns (FacetStorage storage fs) {
|
|
15
|
+
bytes32 position = STORAGE_POSITION;
|
|
16
|
+
assembly {
|
|
17
|
+
fs.slot := position
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
event Setup(uint256 timestamp);
|
|
22
|
+
event BalanceUpdated(address indexed account, uint256 oldBalance, uint256 newBalance);
|
|
23
|
+
event Transfer(address indexed from, address indexed to, uint256 amount);
|
|
24
|
+
|
|
25
|
+
function setup() external {
|
|
26
|
+
FacetStorage storage fs = facetStorage();
|
|
27
|
+
require(!fs.setupComplete, "Already setup");
|
|
28
|
+
|
|
29
|
+
fs.setupComplete = true;
|
|
30
|
+
fs.setupTimestamp = block.timestamp;
|
|
31
|
+
fs.totalSupply = 1000000; // 1M tokens
|
|
32
|
+
fs.balances[msg.sender] = fs.totalSupply;
|
|
33
|
+
|
|
34
|
+
emit Setup(block.timestamp);
|
|
35
|
+
emit BalanceUpdated(msg.sender, 0, fs.totalSupply);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isSetupComplete() external view returns (bool) {
|
|
39
|
+
FacetStorage storage fs = facetStorage();
|
|
40
|
+
return fs.setupComplete;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getSetupTimestamp() external view returns (uint256) {
|
|
44
|
+
FacetStorage storage fs = facetStorage();
|
|
45
|
+
return fs.setupTimestamp;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function balanceOf(address account) external view returns (uint256) {
|
|
49
|
+
FacetStorage storage fs = facetStorage();
|
|
50
|
+
return fs.balances[account];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function totalSupply() external view returns (uint256) {
|
|
54
|
+
FacetStorage storage fs = facetStorage();
|
|
55
|
+
return fs.totalSupply;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function transfer(address to, uint256 amount) external returns (bool) {
|
|
59
|
+
FacetStorage storage fs = facetStorage();
|
|
60
|
+
require(fs.setupComplete, "Not setup");
|
|
61
|
+
require(fs.balances[msg.sender] >= amount, "Insufficient balance");
|
|
62
|
+
|
|
63
|
+
uint256 fromBalance = fs.balances[msg.sender];
|
|
64
|
+
uint256 toBalance = fs.balances[to];
|
|
65
|
+
|
|
66
|
+
fs.balances[msg.sender] = fromBalance - amount;
|
|
67
|
+
fs.balances[to] = toBalance + amount;
|
|
68
|
+
|
|
69
|
+
emit BalanceUpdated(msg.sender, fromBalance, fs.balances[msg.sender]);
|
|
70
|
+
emit BalanceUpdated(to, toBalance, fs.balances[to]);
|
|
71
|
+
emit Transfer(msg.sender, to, amount);
|
|
72
|
+
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function mint(address to, uint256 amount) external returns (bool) {
|
|
77
|
+
FacetStorage storage fs = facetStorage();
|
|
78
|
+
require(fs.setupComplete, "Not setup");
|
|
79
|
+
|
|
80
|
+
uint256 oldBalance = fs.balances[to];
|
|
81
|
+
fs.balances[to] = oldBalance + amount;
|
|
82
|
+
fs.totalSupply += amount;
|
|
83
|
+
|
|
84
|
+
emit BalanceUpdated(to, oldBalance, fs.balances[to]);
|
|
85
|
+
emit Transfer(address(0), to, amount);
|
|
86
|
+
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function burn(uint256 amount) external returns (bool) {
|
|
91
|
+
FacetStorage storage fs = facetStorage();
|
|
92
|
+
require(fs.setupComplete, "Not setup");
|
|
93
|
+
require(fs.balances[msg.sender] >= amount, "Insufficient balance");
|
|
94
|
+
|
|
95
|
+
uint256 oldBalance = fs.balances[msg.sender];
|
|
96
|
+
fs.balances[msg.sender] = oldBalance - amount;
|
|
97
|
+
fs.totalSupply -= amount;
|
|
98
|
+
|
|
99
|
+
emit BalanceUpdated(msg.sender, oldBalance, fs.balances[msg.sender]);
|
|
100
|
+
emit Transfer(msg.sender, address(0), amount);
|
|
101
|
+
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|