@diamondslab/diamonds 1.3.2 โ 1.4.1
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/CHANGELOG.md +43 -0
- package/LICENSE +21 -0
- package/README.md +214 -369
- package/dist/cli/diamond-abi-cli.d.ts +3 -0
- package/dist/cli/diamond-abi-cli.d.ts.map +1 -0
- package/dist/cli/diamond-abi-cli.js +377 -0
- package/dist/cli/diamond-abi-cli.js.map +1 -0
- package/dist/resolution/index.d.ts +2 -0
- package/dist/resolution/index.d.ts.map +1 -0
- package/dist/resolution/index.js +18 -0
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/selectorResolution.d.ts +65 -0
- package/dist/resolution/selectorResolution.d.ts.map +1 -0
- package/dist/resolution/selectorResolution.js +170 -0
- package/dist/resolution/selectorResolution.js.map +1 -0
- package/dist/strategies/BaseDeploymentStrategy.d.ts.map +1 -1
- package/dist/strategies/BaseDeploymentStrategy.js +15 -156
- package/dist/strategies/BaseDeploymentStrategy.js.map +1 -1
- package/dist/strategies/OZDefenderDeploymentStrategy.d.ts +2 -2
- package/dist/strategies/OZDefenderDeploymentStrategy.d.ts.map +1 -1
- package/dist/strategies/OZDefenderDeploymentStrategy.js +12 -2
- package/dist/strategies/OZDefenderDeploymentStrategy.js.map +1 -1
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js.map +1 -1
- package/dist/utils/defenderClients.d.ts +2 -4
- package/dist/utils/defenderClients.d.ts.map +1 -1
- package/dist/utils/defenderClients.js +36 -15
- package/dist/utils/defenderClients.js.map +1 -1
- package/dist/utils/signer.d.ts.map +1 -1
- package/dist/utils/signer.js +11 -2
- package/dist/utils/signer.js.map +1 -1
- package/package.json +15 -9
package/README.md
CHANGED
|
@@ -1,115 +1,122 @@
|
|
|
1
1
|
# Diamonds Module
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@diamondslab/diamonds)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
[](https://hardhat.org/)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
`@diamondslab/diamonds` is a TypeScript framework for deploying, upgrading, and
|
|
9
|
+
managing [ERC-2535 Diamond Proxy](https://eips.ethereum.org/EIPS/eip-2535)
|
|
10
|
+
contracts. It provides a pluggable deployment-strategy system, automatic function
|
|
11
|
+
selector management, configuration-driven facet versioning, and ABI tooling.
|
|
12
|
+
|
|
13
|
+
> **Package manager:** this project uses **Yarn 4** (`packageManager: yarn@4.x`).
|
|
14
|
+
> The examples below use `yarn`. npm/pnpm work for consuming the published package
|
|
15
|
+
> but the repo scripts assume Yarn.
|
|
9
16
|
|
|
10
17
|
## โจ Key Features
|
|
11
18
|
|
|
12
|
-
### ๐๏ธ
|
|
19
|
+
### ๐๏ธ Complete Diamond Implementation
|
|
13
20
|
|
|
14
21
|
- Full ERC-2535 Diamond Proxy Standard support
|
|
15
22
|
- Modular facet architecture with automated function selector management
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
### ๐ก๏ธ **Enterprise Security**
|
|
23
|
+
- Selector collision detection and resolution
|
|
24
|
+
- State management and validation
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
- **Multi-signature Support**: Gnosis Safe and custom multisig workflows
|
|
23
|
-
- **Automated Verification**: Contract verification on Etherscan and other explorers
|
|
24
|
-
- **Access Control**: Role-based deployment permissions
|
|
26
|
+
### ๐ Deployment Management
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
- **Strategy Pattern**: pluggable deployment strategies (Local, RPC, Base, Defender)
|
|
29
|
+
- **Version Control**: configuration-driven versioning for facets and protocols
|
|
30
|
+
- **Upgrade Automation**: `DiamondDeployer` detects an existing deployment and
|
|
31
|
+
performs an upgrade instead of a fresh deploy
|
|
32
|
+
- **Post-deployment Callbacks**: run custom initialization after a cut
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
- **Version Control**: Sophisticated versioning for facets and protocols
|
|
30
|
-
- **Upgrade Automation**: Intelligent upgrade detection and execution
|
|
31
|
-
- **Rollback Support**: Safe rollback mechanisms
|
|
34
|
+
### ๐ญ Production Ready
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **Comprehensive Testing**: Unit, integration, and end-to-end test suites
|
|
38
|
-
- **CLI Tools**: Command-line interface for deployment operations
|
|
36
|
+
- **Repository Pattern**: pluggable persistence (file-based out of the box)
|
|
37
|
+
- **Configuration Management**: JSON configuration with Zod validation
|
|
38
|
+
- **ABI Tooling**: combined Diamond ABI generation, preview, compare, and validate
|
|
39
|
+
- **Comprehensive Testing**: unit and integration test suites
|
|
39
40
|
|
|
40
41
|
## ๐ Quick Start
|
|
41
42
|
|
|
42
43
|
### Installation
|
|
43
44
|
|
|
44
45
|
```bash
|
|
45
|
-
|
|
46
|
+
yarn add @diamondslab/diamonds
|
|
47
|
+
# peer deps (if not already present)
|
|
48
|
+
yarn add --dev hardhat @nomicfoundation/hardhat-ethers ethers
|
|
46
49
|
```
|
|
47
50
|
|
|
48
51
|
### Basic Usage
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
import { Diamond, DiamondDeployer, FileDeploymentRepository } from '@geniusventures/diamonds';
|
|
52
|
-
import { LocalDeploymentStrategy } from '@geniusventures/diamonds/strategies';
|
|
53
|
-
import { ethers } from 'hardhat';
|
|
53
|
+
Everything is exported from the package root (`@diamondslab/diamonds`):
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
```typescript
|
|
56
|
+
import {
|
|
57
|
+
Diamond,
|
|
58
|
+
DiamondDeployer,
|
|
59
|
+
FileDeploymentRepository,
|
|
60
|
+
LocalDeploymentStrategy,
|
|
61
|
+
} from "@diamondslab/diamonds";
|
|
62
|
+
import { ethers } from "hardhat";
|
|
63
|
+
|
|
64
|
+
// Diamond configuration
|
|
56
65
|
const config = {
|
|
57
|
-
diamondName:
|
|
58
|
-
networkName:
|
|
66
|
+
diamondName: "MyDiamond",
|
|
67
|
+
networkName: "localhost",
|
|
59
68
|
chainId: 31337,
|
|
60
|
-
deploymentsPath:
|
|
61
|
-
contractsPath:
|
|
69
|
+
deploymentsPath: "./diamonds",
|
|
70
|
+
contractsPath: "./contracts",
|
|
62
71
|
};
|
|
63
72
|
|
|
64
|
-
//
|
|
73
|
+
// Set up diamond + deployment components
|
|
65
74
|
const repository = new FileDeploymentRepository(config);
|
|
66
75
|
const diamond = new Diamond(config, repository);
|
|
67
76
|
|
|
68
|
-
//
|
|
77
|
+
// Provide a provider and signer
|
|
69
78
|
diamond.setProvider(ethers.provider);
|
|
70
|
-
|
|
79
|
+
const [signer] = await ethers.getSigners();
|
|
80
|
+
diamond.setSigner(signer);
|
|
71
81
|
|
|
72
|
-
// Deploy using local strategy
|
|
73
|
-
const strategy = new LocalDeploymentStrategy(true);
|
|
82
|
+
// Deploy using the local strategy (verbose logging on)
|
|
83
|
+
const strategy = new LocalDeploymentStrategy(true);
|
|
74
84
|
const deployer = new DiamondDeployer(diamond, strategy);
|
|
75
85
|
|
|
86
|
+
// Deploys if new, upgrades if already deployed
|
|
76
87
|
await deployer.deployDiamond();
|
|
77
88
|
```
|
|
78
89
|
|
|
79
90
|
## ๐ Project Structure
|
|
80
91
|
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
โโโ
|
|
84
|
-
โ โโโ
|
|
85
|
-
โ
|
|
86
|
-
โ
|
|
87
|
-
โ
|
|
88
|
-
|
|
89
|
-
โ โโโ
|
|
90
|
-
โ
|
|
91
|
-
โ
|
|
92
|
-
โ
|
|
93
|
-
โ
|
|
94
|
-
|
|
95
|
-
โ
|
|
96
|
-
โ
|
|
97
|
-
โ
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
โโโ docs/ # Documentation
|
|
103
|
-
โโโ examples/ # Usage examples
|
|
104
|
-
โโโ test/ # Test suites
|
|
105
|
-
โโโ scripts/ # CLI and utility scripts
|
|
92
|
+
```text
|
|
93
|
+
src/
|
|
94
|
+
โโโ core/ # Core classes
|
|
95
|
+
โ โโโ Diamond.ts # Diamond state + selector registry
|
|
96
|
+
โ โโโ DiamondDeployer.ts # Deploy/upgrade orchestration
|
|
97
|
+
โ โโโ DeploymentManager.ts # Deployment lifecycle
|
|
98
|
+
โ โโโ CallbackManager.ts # Post-deployment callbacks
|
|
99
|
+
โโโ strategies/ # Deployment strategies
|
|
100
|
+
โ โโโ DeploymentStrategy.ts # Strategy interface
|
|
101
|
+
โ โโโ BaseDeploymentStrategy.ts
|
|
102
|
+
โ โโโ LocalDeploymentStrategy.ts
|
|
103
|
+
โ โโโ RPCDeploymentStrategy.ts
|
|
104
|
+
โ โโโ OZDefenderDeploymentStrategy.ts # legacy (see note below)
|
|
105
|
+
โโโ repositories/ # Data persistence
|
|
106
|
+
โ โโโ DeploymentRepository.ts
|
|
107
|
+
โ โโโ FileDeploymentRepository.ts
|
|
108
|
+
โ โโโ jsonFileHandler.ts
|
|
109
|
+
โโโ schemas/ # Zod validation schemas
|
|
110
|
+
โโโ types/ # TypeScript definitions
|
|
111
|
+
โโโ utils/ # Utilities (ABI generation, loupe, selectors, โฆ)
|
|
112
|
+
โโโ cli/ # `diamond-abi` CLI
|
|
106
113
|
```
|
|
107
114
|
|
|
108
115
|
## ๐ง Configuration
|
|
109
116
|
|
|
110
117
|
### Diamond Configuration
|
|
111
118
|
|
|
112
|
-
Create a diamond configuration file (`myDiamond.config.json`):
|
|
119
|
+
Create a diamond configuration file (e.g. `myDiamond.config.json`):
|
|
113
120
|
|
|
114
121
|
```json
|
|
115
122
|
{
|
|
@@ -118,15 +125,11 @@ Create a diamond configuration file (`myDiamond.config.json`):
|
|
|
118
125
|
"facets": {
|
|
119
126
|
"DiamondCutFacet": {
|
|
120
127
|
"priority": 10,
|
|
121
|
-
"versions": {
|
|
122
|
-
"1.0": {}
|
|
123
|
-
}
|
|
128
|
+
"versions": { "1.0": {} }
|
|
124
129
|
},
|
|
125
130
|
"DiamondLoupeFacet": {
|
|
126
131
|
"priority": 20,
|
|
127
|
-
"versions": {
|
|
128
|
-
"1.0": {}
|
|
129
|
-
}
|
|
132
|
+
"versions": { "1.0": {} }
|
|
130
133
|
},
|
|
131
134
|
"MyCustomFacet": {
|
|
132
135
|
"priority": 30,
|
|
@@ -152,105 +155,87 @@ NETWORK_NAME=sepolia
|
|
|
152
155
|
CHAIN_ID=11155111
|
|
153
156
|
RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
|
|
154
157
|
|
|
155
|
-
# OpenZeppelin Defender (
|
|
158
|
+
# OpenZeppelin Defender (only for the legacy Defender strategy)
|
|
156
159
|
DEFENDER_API_KEY=your_api_key
|
|
157
160
|
DEFENDER_API_SECRET=your_api_secret
|
|
158
161
|
DEFENDER_RELAYER_ADDRESS=0x...
|
|
159
162
|
DEFENDER_SAFE_ADDRESS=0x...
|
|
160
163
|
|
|
161
164
|
# Deployment Options
|
|
162
|
-
AUTO_APPROVE_DEFENDER_PROPOSALS=false
|
|
163
165
|
VERBOSE_DEPLOYMENT=true
|
|
164
166
|
```
|
|
165
167
|
|
|
166
|
-
## ๐ก๏ธ OpenZeppelin Defender Integration
|
|
167
|
-
|
|
168
|
-
The Diamonds module provides seamless integration with OpenZeppelin Defender for enterprise-grade deployments.
|
|
169
|
-
|
|
170
|
-
### Setup Defender
|
|
171
|
-
|
|
172
|
-
1. **Create Defender Account**: Visit [OpenZeppelin Defender](https://defender.openzeppelin.com/)
|
|
173
|
-
2. **Generate API Credentials**: Create API keys with Deploy and Admin permissions
|
|
174
|
-
3. **Configure Environment**: Set your API credentials in `.env`
|
|
175
|
-
|
|
176
|
-
### Deploy with Defender
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
import { OZDefenderDeploymentStrategy } from '@geniusventures/diamonds/strategies';
|
|
180
|
-
|
|
181
|
-
const strategy = new OZDefenderDeploymentStrategy(
|
|
182
|
-
process.env.DEFENDER_API_KEY!,
|
|
183
|
-
process.env.DEFENDER_API_SECRET!,
|
|
184
|
-
process.env.DEFENDER_RELAYER_ADDRESS!,
|
|
185
|
-
false, // manual approval for production
|
|
186
|
-
process.env.DEFENDER_SAFE_ADDRESS!,
|
|
187
|
-
'Safe'
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
const deployer = new DiamondDeployer(diamond, strategy);
|
|
191
|
-
await deployer.deployDiamond();
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Features
|
|
195
|
-
|
|
196
|
-
- **Secure Deployments**: All deployments go through Defender's secure infrastructure
|
|
197
|
-
- **Multi-signature Support**: Integrate with Gnosis Safe for production deployments
|
|
198
|
-
- **Automated Monitoring**: Real-time deployment tracking and status updates
|
|
199
|
-
- **Gas Optimization**: Automatic gas price optimization and retry logic
|
|
200
|
-
|
|
201
168
|
## ๐ Deployment Strategies
|
|
202
169
|
|
|
170
|
+
All strategies extend `BaseDeploymentStrategy` and accept an optional `verbose`
|
|
171
|
+
flag. Pass a strategy instance to `DiamondDeployer`.
|
|
172
|
+
|
|
203
173
|
### Local Strategy
|
|
204
174
|
|
|
205
|
-
For development and testing:
|
|
175
|
+
For development and testing against a local/forked node:
|
|
206
176
|
|
|
207
177
|
```typescript
|
|
208
|
-
import { LocalDeploymentStrategy } from
|
|
178
|
+
import { LocalDeploymentStrategy } from "@diamondslab/diamonds";
|
|
209
179
|
|
|
210
|
-
const strategy = new LocalDeploymentStrategy(true); // verbose
|
|
180
|
+
const strategy = new LocalDeploymentStrategy(true); // verbose
|
|
211
181
|
```
|
|
212
182
|
|
|
213
|
-
###
|
|
183
|
+
### RPC Strategy
|
|
214
184
|
|
|
215
|
-
For
|
|
185
|
+
For deploying through a configured RPC endpoint / signer:
|
|
216
186
|
|
|
217
187
|
```typescript
|
|
218
|
-
import {
|
|
188
|
+
import { RPCDeploymentStrategy } from "@diamondslab/diamonds";
|
|
219
189
|
|
|
220
|
-
const strategy =
|
|
221
|
-
|
|
222
|
-
apiSecret,
|
|
223
|
-
relayerAddress,
|
|
224
|
-
autoApprove,
|
|
225
|
-
viaAddress,
|
|
226
|
-
viaType,
|
|
227
|
-
verbose
|
|
228
|
-
);
|
|
190
|
+
const strategy =
|
|
191
|
+
new RPCDeploymentStrategy(/* see RPCDeploymentStrategy options */);
|
|
229
192
|
```
|
|
230
193
|
|
|
231
194
|
### Custom Strategy
|
|
232
195
|
|
|
233
|
-
Implement your own
|
|
196
|
+
Implement your own by extending `BaseDeploymentStrategy` and overriding the
|
|
197
|
+
protected task hooks:
|
|
234
198
|
|
|
235
199
|
```typescript
|
|
236
|
-
import { BaseDeploymentStrategy } from
|
|
200
|
+
import { BaseDeploymentStrategy, Diamond } from "@diamondslab/diamonds";
|
|
237
201
|
|
|
238
202
|
export class CustomDeploymentStrategy extends BaseDeploymentStrategy {
|
|
239
203
|
protected async deployDiamondTasks(diamond: Diamond): Promise<void> {
|
|
240
204
|
// Custom deployment logic
|
|
241
205
|
}
|
|
242
|
-
|
|
206
|
+
|
|
243
207
|
protected async performDiamondCutTasks(diamond: Diamond): Promise<void> {
|
|
244
208
|
// Custom diamond cut logic
|
|
245
209
|
}
|
|
246
210
|
}
|
|
247
211
|
```
|
|
248
212
|
|
|
213
|
+
### OpenZeppelin Defender Strategy (legacy)
|
|
214
|
+
|
|
215
|
+
> โ ๏ธ **Deprecated / legacy.** `OZDefenderDeploymentStrategy` is being phased out
|
|
216
|
+
> and is not recommended for new work. It remains exported for backward
|
|
217
|
+
> compatibility. Prefer `LocalDeploymentStrategy` / `RPCDeploymentStrategy` or a
|
|
218
|
+
> custom strategy.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { OZDefenderDeploymentStrategy } from "@diamondslab/diamonds";
|
|
222
|
+
|
|
223
|
+
const strategy = new OZDefenderDeploymentStrategy(
|
|
224
|
+
process.env.DEFENDER_API_KEY!,
|
|
225
|
+
process.env.DEFENDER_API_SECRET!,
|
|
226
|
+
process.env.DEFENDER_RELAYER_ADDRESS!,
|
|
227
|
+
false, // auto-approve
|
|
228
|
+
process.env.DEFENDER_SAFE_ADDRESS!,
|
|
229
|
+
"Safe",
|
|
230
|
+
);
|
|
231
|
+
```
|
|
232
|
+
|
|
249
233
|
## ๐ Advanced Features
|
|
250
234
|
|
|
251
235
|
### Version Management
|
|
252
236
|
|
|
253
|
-
|
|
237
|
+
Facets are versioned in the configuration; upgrades declare which prior versions
|
|
238
|
+
they apply from:
|
|
254
239
|
|
|
255
240
|
```json
|
|
256
241
|
{
|
|
@@ -258,10 +243,7 @@ The Diamonds module provides sophisticated version management:
|
|
|
258
243
|
"MyFacet": {
|
|
259
244
|
"priority": 100,
|
|
260
245
|
"versions": {
|
|
261
|
-
"1.0": {
|
|
262
|
-
"deployInit": "initialize()",
|
|
263
|
-
"upgradeInit": "upgradeToV1()"
|
|
264
|
-
},
|
|
246
|
+
"1.0": { "deployInit": "initialize()", "upgradeInit": "upgradeToV1()" },
|
|
265
247
|
"2.0": {
|
|
266
248
|
"deployInit": "initialize()",
|
|
267
249
|
"upgradeInit": "upgradeToV2()",
|
|
@@ -275,344 +257,207 @@ The Diamonds module provides sophisticated version management:
|
|
|
275
257
|
|
|
276
258
|
### Function Selector Management
|
|
277
259
|
|
|
278
|
-
Automatic
|
|
260
|
+
Automatic selector management with collision detection:
|
|
279
261
|
|
|
280
|
-
- **Priority-based
|
|
281
|
-
- **Include/Exclude
|
|
282
|
-
- **Collision
|
|
283
|
-
- **Orphaned
|
|
262
|
+
- **Priority-based resolution**: higher-priority facets take precedence
|
|
263
|
+
- **Include/Exclude lists**: fine-grained selector control (`deployInclude` / `deployExclude`)
|
|
264
|
+
- **Collision detection**: automatic detection and resolution of selector conflicts
|
|
265
|
+
- **Orphaned selector prevention**: validation guards against bad cuts
|
|
284
266
|
|
|
285
267
|
### Post-Deployment Callbacks
|
|
286
268
|
|
|
287
|
-
Execute custom logic after deployment:
|
|
288
|
-
|
|
289
269
|
```typescript
|
|
290
270
|
// In your callbacks directory
|
|
291
271
|
export async function postDeployCallback(args: CallbackArgs) {
|
|
292
272
|
const { diamond } = args;
|
|
293
|
-
console.log(`Post-deployment callback
|
|
294
|
-
|
|
273
|
+
console.log(`Post-deployment callback for ${diamond.diamondName}`);
|
|
295
274
|
// Custom post-deployment logic
|
|
296
|
-
await customInitialization();
|
|
297
275
|
}
|
|
298
276
|
```
|
|
299
277
|
|
|
300
|
-
##
|
|
301
|
-
|
|
302
|
-
### Running Tests
|
|
303
|
-
|
|
304
|
-
```bash
|
|
305
|
-
# Install dependencies
|
|
306
|
-
npm install
|
|
307
|
-
|
|
308
|
-
# Run all tests
|
|
309
|
-
npm test
|
|
310
|
-
|
|
311
|
-
# Run unit tests only
|
|
312
|
-
npm run test:unit
|
|
313
|
-
|
|
314
|
-
# Run integration tests
|
|
315
|
-
npm run test:integration
|
|
316
|
-
|
|
317
|
-
# Run with coverage
|
|
318
|
-
npm run test:coverage
|
|
319
|
-
|
|
320
|
-
# Test specific network
|
|
321
|
-
TEST_NETWORK=sepolia npm test
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Test Categories
|
|
325
|
-
|
|
326
|
-
- **Unit Tests**: Individual component testing
|
|
327
|
-
- **Integration Tests**: Component interaction testing
|
|
328
|
-
- **Defender Integration**: End-to-end Defender testing
|
|
329
|
-
- **Performance Tests**: Deployment speed and resource usage
|
|
330
|
-
|
|
331
|
-
### Example Test
|
|
332
|
-
|
|
333
|
-
```typescript
|
|
334
|
-
describe('Diamond Deployment', () => {
|
|
335
|
-
let diamond: Diamond;
|
|
336
|
-
let strategy: LocalDeploymentStrategy;
|
|
337
|
-
|
|
338
|
-
beforeEach(() => {
|
|
339
|
-
const config = {
|
|
340
|
-
diamondName: 'TestDiamond',
|
|
341
|
-
networkName: 'hardhat',
|
|
342
|
-
chainId: 31337,
|
|
343
|
-
deploymentsPath: './test-diamonds',
|
|
344
|
-
contractsPath: './contracts'
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
const repository = new FileDeploymentRepository(config);
|
|
348
|
-
diamond = new Diamond(config, repository);
|
|
349
|
-
strategy = new LocalDeploymentStrategy();
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
it('should deploy diamond successfully', async () => {
|
|
353
|
-
const deployer = new DiamondDeployer(diamond, strategy);
|
|
354
|
-
await deployer.deployDiamond();
|
|
355
|
-
|
|
356
|
-
const deployedData = diamond.getDeployedDiamondData();
|
|
357
|
-
expect(deployedData.DiamondAddress).to.not.be.undefined;
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
## ๐ ๏ธ CLI Tools
|
|
278
|
+
## ๐ Diamond ABI Tooling
|
|
363
279
|
|
|
364
|
-
|
|
280
|
+
This package ships a `diamond-abi` CLI for working with the combined Diamond ABI.
|
|
365
281
|
|
|
366
282
|
```bash
|
|
367
|
-
#
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
# Deploy a diamond
|
|
371
|
-
diamonds deploy --diamond MyDiamond --network sepolia
|
|
372
|
-
|
|
373
|
-
# Upgrade a diamond
|
|
374
|
-
diamonds upgrade --diamond MyDiamond
|
|
283
|
+
# Generate the combined ABI for a deployed diamond (requires a Hardhat project)
|
|
284
|
+
npx diamond-abi generate --diamond MyDiamond --network localhost
|
|
375
285
|
|
|
376
|
-
#
|
|
377
|
-
|
|
286
|
+
# Preview the ABI changes implied by planned cuts (requires a Hardhat project)
|
|
287
|
+
npx diamond-abi preview --diamond MyDiamond --verbose
|
|
378
288
|
|
|
379
|
-
#
|
|
380
|
-
|
|
289
|
+
# Compare two ABI files (no chain / Hardhat needed)
|
|
290
|
+
npx diamond-abi compare old-abi.json new-abi.json
|
|
381
291
|
|
|
382
|
-
#
|
|
383
|
-
|
|
292
|
+
# Validate an ABI artifact file (no chain / Hardhat needed)
|
|
293
|
+
npx diamond-abi validate diamond-abi.json
|
|
384
294
|
```
|
|
385
295
|
|
|
386
|
-
|
|
296
|
+
> `generate` and `preview` connect to a chain and load your project's Hardhat
|
|
297
|
+
> config (run them inside a Hardhat project). `compare` and `validate` operate on
|
|
298
|
+
> ABI JSON files and run standalone. Run `npx diamond-abi <command> --help` for
|
|
299
|
+
> all options.
|
|
387
300
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
- `--config <path>`: Configuration file path
|
|
391
|
-
- `--auto-approve`: Auto-approve Defender proposals
|
|
392
|
-
- `--verbose`: Verbose output
|
|
393
|
-
- `--batch <path>`: Batch deployment configuration
|
|
301
|
+
The same combined ABI can also be produced programmatically via
|
|
302
|
+
`generateDiamondAbi` / `previewDiamondAbi` from `@diamondslab/diamonds`.
|
|
394
303
|
|
|
395
304
|
## ๐ Examples
|
|
396
305
|
|
|
397
306
|
### Basic Diamond Deployment
|
|
398
307
|
|
|
399
308
|
```typescript
|
|
400
|
-
import {
|
|
401
|
-
|
|
309
|
+
import {
|
|
310
|
+
Diamond,
|
|
311
|
+
DiamondDeployer,
|
|
312
|
+
FileDeploymentRepository,
|
|
313
|
+
LocalDeploymentStrategy,
|
|
314
|
+
} from "@diamondslab/diamonds";
|
|
315
|
+
import { ethers } from "hardhat";
|
|
402
316
|
|
|
403
317
|
async function deployBasicDiamond() {
|
|
404
318
|
const config = {
|
|
405
|
-
diamondName:
|
|
406
|
-
networkName:
|
|
319
|
+
diamondName: "BasicDiamond",
|
|
320
|
+
networkName: "localhost",
|
|
407
321
|
chainId: 31337,
|
|
408
|
-
deploymentsPath:
|
|
409
|
-
contractsPath:
|
|
322
|
+
deploymentsPath: "./diamonds",
|
|
323
|
+
contractsPath: "./contracts",
|
|
410
324
|
};
|
|
411
325
|
|
|
412
326
|
const repository = new FileDeploymentRepository(config);
|
|
413
327
|
const diamond = new Diamond(config, repository);
|
|
414
|
-
|
|
328
|
+
|
|
415
329
|
diamond.setProvider(ethers.provider);
|
|
416
|
-
|
|
330
|
+
const [signer] = await ethers.getSigners();
|
|
331
|
+
diamond.setSigner(signer);
|
|
417
332
|
|
|
418
333
|
const strategy = new LocalDeploymentStrategy();
|
|
419
334
|
const deployer = new DiamondDeployer(diamond, strategy);
|
|
420
335
|
|
|
421
336
|
await deployer.deployDiamond();
|
|
422
|
-
console.log(
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Production Deployment with Defender
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
import { OZDefenderDeploymentStrategy } from '@geniusventures/diamonds/strategies';
|
|
430
|
-
|
|
431
|
-
async function deployProductionDiamond() {
|
|
432
|
-
const config = {
|
|
433
|
-
diamondName: 'ProductionDiamond',
|
|
434
|
-
networkName: 'mainnet',
|
|
435
|
-
chainId: 1,
|
|
436
|
-
deploymentsPath: './diamonds',
|
|
437
|
-
contractsPath: './contracts'
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
const repository = new FileDeploymentRepository(config);
|
|
441
|
-
const diamond = new Diamond(config, repository);
|
|
442
|
-
|
|
443
|
-
// Setup provider and signer for mainnet
|
|
444
|
-
diamond.setProvider(mainnetProvider);
|
|
445
|
-
diamond.setSigner(productionSigner);
|
|
446
|
-
|
|
447
|
-
const strategy = new OZDefenderDeploymentStrategy(
|
|
448
|
-
process.env.DEFENDER_API_KEY!,
|
|
449
|
-
process.env.DEFENDER_API_SECRET!,
|
|
450
|
-
process.env.DEFENDER_RELAYER_ADDRESS!,
|
|
451
|
-
false, // manual approval for production
|
|
452
|
-
process.env.DEFENDER_SAFE_ADDRESS!,
|
|
453
|
-
'Safe'
|
|
454
|
-
);
|
|
455
|
-
|
|
456
|
-
const deployer = new DiamondDeployer(diamond, strategy);
|
|
457
|
-
await deployer.deployDiamond();
|
|
337
|
+
console.log("Diamond deployed successfully!");
|
|
458
338
|
}
|
|
459
339
|
```
|
|
460
340
|
|
|
461
|
-
###
|
|
341
|
+
### Multi-Facet Upgrade
|
|
462
342
|
|
|
463
343
|
```typescript
|
|
464
|
-
async function
|
|
465
|
-
//
|
|
466
|
-
const diamond = await loadExistingDiamond('MyDiamond');
|
|
467
|
-
|
|
468
|
-
// Update configuration for new version
|
|
344
|
+
async function performUpgrade(diamond: Diamond) {
|
|
345
|
+
// Update configuration for the new version
|
|
469
346
|
const config = diamond.repository.loadDeployConfig();
|
|
470
347
|
config.protocolVersion = 2.0;
|
|
471
|
-
|
|
472
|
-
// Add new facet
|
|
348
|
+
|
|
349
|
+
// Add a new facet
|
|
473
350
|
config.facets.NewFeatureFacet = {
|
|
474
351
|
priority: 150,
|
|
475
352
|
versions: {
|
|
476
|
-
"2.0": {
|
|
477
|
-
|
|
478
|
-
callbacks: ["setupNewFeature"]
|
|
479
|
-
}
|
|
480
|
-
}
|
|
353
|
+
"2.0": { deployInit: "initialize()", callbacks: ["setupNewFeature"] },
|
|
354
|
+
},
|
|
481
355
|
};
|
|
482
|
-
|
|
483
|
-
// Upgrade existing facet
|
|
356
|
+
|
|
357
|
+
// Upgrade an existing facet
|
|
484
358
|
config.facets.ExistingFacet.versions["2.0"] = {
|
|
485
359
|
upgradeInit: "upgradeToV2()",
|
|
486
|
-
fromVersions: [1.0]
|
|
360
|
+
fromVersions: [1.0],
|
|
487
361
|
};
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
//
|
|
492
|
-
const
|
|
493
|
-
const deployer = new DiamondDeployer(diamond, strategy);
|
|
362
|
+
|
|
363
|
+
diamond.repository.saveDeployConfig(config);
|
|
364
|
+
|
|
365
|
+
// DiamondDeployer detects the existing deployment and performs the upgrade
|
|
366
|
+
const deployer = new DiamondDeployer(diamond, new LocalDeploymentStrategy());
|
|
494
367
|
await deployer.deployDiamond();
|
|
495
368
|
}
|
|
496
369
|
```
|
|
497
370
|
|
|
498
371
|
## ๐ Monitoring and Debugging
|
|
499
372
|
|
|
500
|
-
###
|
|
501
|
-
|
|
502
|
-
```typescript
|
|
503
|
-
const strategy = new LocalDeploymentStrategy(true); // Enable verbose mode
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
### Debug Function Selectors
|
|
373
|
+
### Inspect Function Selectors
|
|
507
374
|
|
|
508
375
|
```typescript
|
|
509
|
-
import { getSighash } from
|
|
376
|
+
import { getSighash } from "@diamondslab/diamonds";
|
|
510
377
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
console.log('Selector:', selector);
|
|
378
|
+
const selector = getSighash("transfer(address,uint256)");
|
|
379
|
+
console.log("Selector:", selector);
|
|
514
380
|
|
|
515
|
-
|
|
516
|
-
const isRegistered = diamond.isFunctionSelectorRegistered(selector);
|
|
517
|
-
console.log('Is registered:', isRegistered);
|
|
381
|
+
console.log("Registered:", diamond.isFunctionSelectorRegistered(selector));
|
|
518
382
|
```
|
|
519
383
|
|
|
520
|
-
###
|
|
384
|
+
### Compare On-Chain vs. Local State
|
|
521
385
|
|
|
522
386
|
```typescript
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
console.log('Diamond address:', deployedData.DiamondAddress);
|
|
526
|
-
console.log('Deployed facets:', Object.keys(deployedData.DeployedFacets || {}));
|
|
387
|
+
import { diffDeployedFacets } from "@diamondslab/diamonds";
|
|
388
|
+
import { ethers } from "hardhat";
|
|
527
389
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
390
|
+
const deployedData = diamond.getDeployedDiamondData();
|
|
391
|
+
console.log("Diamond address:", deployedData.DiamondAddress);
|
|
392
|
+
console.log("Deployed facets:", Object.keys(deployedData.DeployedFacets ?? {}));
|
|
393
|
+
|
|
394
|
+
// Returns true when on-chain facets match the local deployment record
|
|
395
|
+
const isConsistent = await diffDeployedFacets(
|
|
396
|
+
deployedData,
|
|
397
|
+
ethers.provider,
|
|
398
|
+
true,
|
|
399
|
+
);
|
|
531
400
|
```
|
|
532
401
|
|
|
533
|
-
##
|
|
534
|
-
|
|
535
|
-
### Production Best Practices
|
|
402
|
+
## ๐งช Testing & Development
|
|
536
403
|
|
|
537
|
-
|
|
538
|
-
2. **Test Thoroughly**: Test all upgrades on testnets first
|
|
539
|
-
3. **Verify Contracts**: Ensure all contracts are verified on Etherscan
|
|
540
|
-
4. **Monitor Deployments**: Use Defender monitoring for production systems
|
|
541
|
-
5. **Access Control**: Implement proper role-based access controls
|
|
404
|
+
Run from the package directory:
|
|
542
405
|
|
|
543
|
-
|
|
406
|
+
```bash
|
|
407
|
+
yarn install # install dependencies (Yarn 4)
|
|
408
|
+
yarn build # compile TypeScript to dist/
|
|
409
|
+
yarn test # run the Hardhat test suite
|
|
410
|
+
yarn test:unit # unit tests only
|
|
411
|
+
yarn test:integration # integration tests only
|
|
412
|
+
yarn test:coverage # tests with coverage
|
|
413
|
+
yarn lint # lint
|
|
414
|
+
```
|
|
544
415
|
|
|
545
|
-
|
|
546
|
-
// Production configuration example
|
|
547
|
-
const productionConfig = {
|
|
548
|
-
diamondName: 'ProductionDiamond',
|
|
549
|
-
networkName: 'mainnet',
|
|
550
|
-
chainId: 1,
|
|
551
|
-
deploymentsPath: './production-diamonds',
|
|
552
|
-
contractsPath: './contracts',
|
|
553
|
-
writeDeployedDiamondData: true
|
|
554
|
-
};
|
|
416
|
+
## ๐ Security Considerations
|
|
555
417
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
process.env.PROD_SAFE_ADDRESS!,
|
|
562
|
-
'Safe'
|
|
563
|
-
);
|
|
564
|
-
```
|
|
418
|
+
1. **Use multi-signature wallets** for mainnet deployments.
|
|
419
|
+
2. **Test upgrades on a testnet/fork first.**
|
|
420
|
+
3. **Verify contracts** on the relevant block explorer.
|
|
421
|
+
4. **Apply role-based access control** to privileged diamond functions.
|
|
422
|
+
5. **Never commit secrets** โ deployment records may contain addresses/keys and are gitignored.
|
|
565
423
|
|
|
566
424
|
## ๐ค Contributing
|
|
567
425
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
### Development Setup
|
|
426
|
+
Contributions are welcome. Please open an issue or pull request on
|
|
427
|
+
[GitHub](https://github.com/DiamondsLab/diamonds).
|
|
571
428
|
|
|
572
429
|
```bash
|
|
573
|
-
|
|
574
|
-
git clone https://github.com/geniusventures/diamonds.git
|
|
430
|
+
git clone https://github.com/DiamondsLab/diamonds.git
|
|
575
431
|
cd diamonds
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
# Run tests
|
|
581
|
-
npm test
|
|
582
|
-
|
|
583
|
-
# Build the project
|
|
584
|
-
npm run build
|
|
585
|
-
|
|
586
|
-
# Run linting
|
|
587
|
-
npm run lint
|
|
432
|
+
yarn install
|
|
433
|
+
yarn test
|
|
434
|
+
yarn build
|
|
435
|
+
yarn lint
|
|
588
436
|
```
|
|
589
437
|
|
|
590
438
|
### Coding Standards
|
|
591
439
|
|
|
592
|
-
- Follow TypeScript
|
|
593
|
-
-
|
|
594
|
-
-
|
|
440
|
+
- Follow the existing TypeScript style
|
|
441
|
+
- Use Conventional Commits
|
|
442
|
+
- Add tests for new functionality
|
|
595
443
|
- Update documentation for new features
|
|
596
|
-
- Add comprehensive tests for new functionality
|
|
597
444
|
|
|
598
445
|
## ๐ License
|
|
599
446
|
|
|
600
|
-
|
|
447
|
+
MIT โ see the [LICENSE](LICENSE) file.
|
|
601
448
|
|
|
602
449
|
## ๐ Acknowledgments
|
|
603
450
|
|
|
604
|
-
- [OpenZeppelin](https://openzeppelin.com/) for Defender platform and security tools
|
|
605
451
|
- [ERC-2535 Diamond Standard](https://eips.ethereum.org/EIPS/eip-2535) authors
|
|
606
452
|
- [Hardhat](https://hardhat.org/) development framework
|
|
607
|
-
-
|
|
453
|
+
- [OpenZeppelin](https://openzeppelin.com/) for security tooling
|
|
454
|
+
- The Ethereum community
|
|
608
455
|
|
|
609
456
|
## ๐ Support
|
|
610
457
|
|
|
611
|
-
- **Documentation**: [
|
|
612
|
-
- **
|
|
613
|
-
- **Discord**: [Join our Community](https://discord.gg/geniusventures)
|
|
614
|
-
- **Email**: <support@geniusventures.com>
|
|
458
|
+
- **Documentation**: see the [`docs/`](docs/) directory
|
|
459
|
+
- **Issues**: [github.com/DiamondsLab/diamonds/issues](https://github.com/DiamondsLab/diamonds/issues)
|
|
615
460
|
|
|
616
461
|
---
|
|
617
462
|
|
|
618
|
-
**Built with โค๏ธ for the Ethereum ecosystem by [
|
|
463
|
+
**Built with โค๏ธ for the Ethereum ecosystem by [DiamondsLab](https://github.com/DiamondsLab)**
|