@diamondslab/diamonds 1.3.0 → 1.4.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/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/repositories/FileDeploymentRepository.d.ts.map +1 -1
- package/dist/repositories/FileDeploymentRepository.js +5 -3
- package/dist/repositories/FileDeploymentRepository.js.map +1 -1
- 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 +4 -4
- package/dist/strategies/BaseDeploymentStrategy.d.ts.map +1 -1
- package/dist/strategies/BaseDeploymentStrategy.js +54 -157
- package/dist/strategies/BaseDeploymentStrategy.js.map +1 -1
- package/dist/utils/contractMapping.d.ts.map +1 -1
- package/dist/utils/contractMapping.js +36 -33
- package/dist/utils/contractMapping.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 +11 -5
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeFacetSelectors = computeFacetSelectors;
|
|
4
|
+
exports.resolveFunctionSelectorRegistry = resolveFunctionSelectorRegistry;
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
/**
|
|
8
|
+
* Compute a facet's candidate selectors: its raw ABI selectors **minus `deployExclude`**.
|
|
9
|
+
*
|
|
10
|
+
* `deployInclude` is **additive** (INV-3, M2-E1) — it does NOT reduce the candidate set; a facet keeps
|
|
11
|
+
* its other selectors. The override (force-ownership over a higher-priority facet) and the additive
|
|
12
|
+
* priority resolution both happen in `resolveFunctionSelectorRegistry`. Pure.
|
|
13
|
+
*
|
|
14
|
+
* @param facetSelectors the facet's raw ABI function selectors (4-byte, `0x…`)
|
|
15
|
+
* @param _deployInclude the facet's `deployInclude` signatures — accepted for API symmetry; additive
|
|
16
|
+
* (not used to filter the candidate set)
|
|
17
|
+
* @param deployExclude function signatures to remove
|
|
18
|
+
* @returns the candidate selector list (a new array; the input is not mutated)
|
|
19
|
+
*/
|
|
20
|
+
function computeFacetSelectors(facetSelectors, _deployInclude, deployExclude) {
|
|
21
|
+
const result = [...facetSelectors];
|
|
22
|
+
// Apply deployExclude (removal) only. deployInclude is additive — it does not filter here.
|
|
23
|
+
for (const excludeSelector of deployExclude) {
|
|
24
|
+
const selectorToExclude = ethers_1.ethers.id(excludeSelector).slice(0, 10);
|
|
25
|
+
const index = result.indexOf(selectorToExclude);
|
|
26
|
+
if (index !== -1) {
|
|
27
|
+
result.splice(index, 1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve ownership of every function selector across the newly-deployed facets and write
|
|
34
|
+
* the result (`Add`/`Replace`/`Remove`/`Deployed` actions) into `registry` **in place**.
|
|
35
|
+
* Pure — no Hardhat/provider. Extracted verbatim from
|
|
36
|
+
* `BaseDeploymentStrategy.updateFunctionSelectorRegistryTasks`.
|
|
37
|
+
*/
|
|
38
|
+
function resolveFunctionSelectorRegistry(args) {
|
|
39
|
+
const { registry, newDeployedFacets, facetNames } = args;
|
|
40
|
+
const zeroAddress = ethers_1.ethers.ZeroAddress;
|
|
41
|
+
const newDeployedFacetsByPriority = Object.entries(newDeployedFacets).sort(([, a], [, b]) => (a.priority || 1000) - (b.priority || 1000));
|
|
42
|
+
for (const [newFacetName, newFacetData] of newDeployedFacetsByPriority) {
|
|
43
|
+
const currentFacetAddress = newFacetData.address;
|
|
44
|
+
const priority = newFacetData.priority;
|
|
45
|
+
const includeFuncSelectors = newFacetData.deployInclude || [];
|
|
46
|
+
const excludeFuncSelectors = newFacetData.deployExclude || [];
|
|
47
|
+
// Convert function signatures to selectors
|
|
48
|
+
const includeFuncSelectorsAsSelectors = includeFuncSelectors.map((sig) => ethers_1.ethers.id(sig).slice(0, 10));
|
|
49
|
+
const excludeFuncSelectorsAsSelectors = excludeFuncSelectors.map((sig) => ethers_1.ethers.id(sig).slice(0, 10));
|
|
50
|
+
// Initialize funcSelectors if not present
|
|
51
|
+
if (!newFacetData.funcSelectors) {
|
|
52
|
+
newFacetData.funcSelectors = [];
|
|
53
|
+
}
|
|
54
|
+
const functionSelectors = newFacetData.funcSelectors;
|
|
55
|
+
/* ------------------ Exclusion Filter ------------------ */
|
|
56
|
+
for (const excludeFuncSelector of excludeFuncSelectorsAsSelectors) {
|
|
57
|
+
// remove from the facets functionSelectors
|
|
58
|
+
if (functionSelectors.includes(excludeFuncSelector)) {
|
|
59
|
+
functionSelectors.splice(functionSelectors.indexOf(excludeFuncSelector), 1);
|
|
60
|
+
}
|
|
61
|
+
// update action to remove if excluded from registry where a previous deployment associated with facetname
|
|
62
|
+
if (registry.has(excludeFuncSelector) &&
|
|
63
|
+
registry.get(excludeFuncSelector)?.facetName === newFacetName) {
|
|
64
|
+
const existing = registry.get(excludeFuncSelector);
|
|
65
|
+
if (existing?.facetName === newFacetName) {
|
|
66
|
+
registry.set(excludeFuncSelector, {
|
|
67
|
+
priority: priority,
|
|
68
|
+
// EIP-2535: a Remove cut MUST use address(0) (M3-E2 fix for M3-E1 S-3 —
|
|
69
|
+
// was currentFacetAddress, which reverts on-chain on deployExclude-on-upgrade).
|
|
70
|
+
address: zeroAddress,
|
|
71
|
+
action: types_1.RegistryFacetCutAction.Remove,
|
|
72
|
+
facetName: newFacetName,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/* ------------------ Inclusion Override Filter ------------------ */
|
|
78
|
+
for (const includeFuncSelector of includeFuncSelectorsAsSelectors) {
|
|
79
|
+
const existingEntry = registry.get(includeFuncSelector);
|
|
80
|
+
if (existingEntry?.address &&
|
|
81
|
+
existingEntry.address !== currentFacetAddress &&
|
|
82
|
+
existingEntry.action !== types_1.RegistryFacetCutAction.Add) {
|
|
83
|
+
// Selector already registered/deployed at a different facet address — a selector moved
|
|
84
|
+
// facets, or a redeployed facet at a new address (the upgrade case; verified M3-E1 S-1).
|
|
85
|
+
// Reconcile -> Replace, not Add (which would revert "Can't add function that already
|
|
86
|
+
// exists"). Subsumes the removed dead higherPrioritySplit branch (M3-E3).
|
|
87
|
+
registry.set(includeFuncSelector, {
|
|
88
|
+
priority: priority,
|
|
89
|
+
address: currentFacetAddress,
|
|
90
|
+
action: types_1.RegistryFacetCutAction.Replace,
|
|
91
|
+
facetName: newFacetName,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Add to the registry
|
|
96
|
+
registry.set(includeFuncSelector, {
|
|
97
|
+
priority: priority,
|
|
98
|
+
address: currentFacetAddress,
|
|
99
|
+
action: types_1.RegistryFacetCutAction.Add,
|
|
100
|
+
facetName: newFacetName,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// remove from the funcSels so it is not modified in Priority Resolution Pass
|
|
104
|
+
const existing = newDeployedFacets[newFacetName];
|
|
105
|
+
if (existing &&
|
|
106
|
+
existing.funcSelectors &&
|
|
107
|
+
existing.funcSelectors.includes(includeFuncSelector)) {
|
|
108
|
+
existing.funcSelectors.splice(existing.funcSelectors.indexOf(includeFuncSelector), 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/* ------------------ Replace Facet and Priority Resolution Pass ------------- */
|
|
112
|
+
for (const selector of functionSelectors) {
|
|
113
|
+
const existing = registry.get(selector);
|
|
114
|
+
if (existing) {
|
|
115
|
+
const existingPriority = existing.priority;
|
|
116
|
+
if (existing.facetName === newFacetName) {
|
|
117
|
+
// Same facet, update the address
|
|
118
|
+
registry.set(selector, {
|
|
119
|
+
priority: priority,
|
|
120
|
+
address: currentFacetAddress,
|
|
121
|
+
action: types_1.RegistryFacetCutAction.Replace,
|
|
122
|
+
facetName: newFacetName,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else if (priority < existingPriority) {
|
|
126
|
+
// Current facet has higher priority, Replace it
|
|
127
|
+
registry.set(selector, {
|
|
128
|
+
priority: priority,
|
|
129
|
+
address: currentFacetAddress,
|
|
130
|
+
action: types_1.RegistryFacetCutAction.Replace,
|
|
131
|
+
facetName: newFacetName,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// New selector, simply add
|
|
137
|
+
registry.set(selector, {
|
|
138
|
+
priority: priority,
|
|
139
|
+
address: currentFacetAddress,
|
|
140
|
+
action: types_1.RegistryFacetCutAction.Add,
|
|
141
|
+
facetName: newFacetName,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/* ---------------- Remove Old Function Selectors from facets -------------- */
|
|
146
|
+
// Set functionselectors with the newFacetName and still different address to Remove
|
|
147
|
+
for (const [selector, entry] of registry.entries()) {
|
|
148
|
+
if (entry.facetName === newFacetName && entry.address !== currentFacetAddress) {
|
|
149
|
+
registry.set(selector, {
|
|
150
|
+
priority: entry.priority,
|
|
151
|
+
address: zeroAddress,
|
|
152
|
+
action: types_1.RegistryFacetCutAction.Remove,
|
|
153
|
+
facetName: newFacetName,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// `Remove` function selectors for facets no longer in config (deleted facets)
|
|
159
|
+
for (const [selector, entry] of registry.entries()) {
|
|
160
|
+
if (!facetNames.includes(entry.facetName)) {
|
|
161
|
+
registry.set(selector, {
|
|
162
|
+
priority: entry.priority,
|
|
163
|
+
address: zeroAddress,
|
|
164
|
+
action: types_1.RegistryFacetCutAction.Remove,
|
|
165
|
+
facetName: entry.facetName,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=selectorResolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectorResolution.js","sourceRoot":"","sources":["../../src/resolution/selectorResolution.ts"],"names":[],"mappings":"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","sourcesContent":["import { ethers } from 'ethers';\nimport {\n\tFunctionSelectorRegistryEntry,\n\tNewDeployedFacets,\n\tRegistryFacetCutAction,\n} from '../types';\n\n/**\n * Pure selector-resolution core for ERC-2535 diamond deployments.\n *\n * Extracted from `BaseDeploymentStrategy` (M1-E1) so the resolution semantics can be\n * unit-tested without a chain and later promoted into the shared core used by both the\n * deployment strategy and the planned pre-launch config validator.\n *\n * Lifted from the strategy in M1-E1 (behavior-preserving). Status of the original quirks:\n * - the deploy-time `deployInclude` whitelist — **REMOVED in M2-E1**: `deployInclude` is now\n * **additive** (INV-3); a facet keeps its other selectors (the override is resolved below);\n * - the inverted/dead `registryHigherPrioritySplit` (`entry.priority > priority`) — **REMOVED in\n * M3-E3**: it never matched a real conflict; the cases it nominally handled fall through to the\n * `5b2f7af` Replace branch with the identical result;\n * - the `5b2f7af` `Replace`-instead-of-`Add` branch — **verified correct (M3-E1 S-1)**; kept as-is.\n *\n * The module takes NO Hardhat/provider dependency (only `ethers` for selector math).\n */\n\n/** Map<functionSelector, registry entry>. Mirrors `Diamond.functionSelectorRegistry`. */\nexport type SelectorRegistry = Map<string, FunctionSelectorRegistryEntry>;\n\n/**\n * Reserved for M3 upgrade/redeploy reconciliation. Today, prior deployed state is carried\n * by the pre-populated `registry` (entries whose action is `Deployed`). Shape aligned to\n * `DeployedDiamondData.DeployedFacets` to minimise adapter code when M3 wires it in.\n */\nexport type PriorDeployedState = Record<\n\tstring,\n\t{ address?: string; funcSelectors?: string[]; version?: number }\n>;\n\n/**\n * Compute a facet's candidate selectors: its raw ABI selectors **minus `deployExclude`**.\n *\n * `deployInclude` is **additive** (INV-3, M2-E1) — it does NOT reduce the candidate set; a facet keeps\n * its other selectors. The override (force-ownership over a higher-priority facet) and the additive\n * priority resolution both happen in `resolveFunctionSelectorRegistry`. Pure.\n *\n * @param facetSelectors the facet's raw ABI function selectors (4-byte, `0x…`)\n * @param _deployInclude the facet's `deployInclude` signatures — accepted for API symmetry; additive\n * (not used to filter the candidate set)\n * @param deployExclude function signatures to remove\n * @returns the candidate selector list (a new array; the input is not mutated)\n */\nexport function computeFacetSelectors(\n\tfacetSelectors: string[],\n\t_deployInclude: string[],\n\tdeployExclude: string[],\n): string[] {\n\tconst result = [...facetSelectors];\n\n\t// Apply deployExclude (removal) only. deployInclude is additive — it does not filter here.\n\tfor (const excludeSelector of deployExclude) {\n\t\tconst selectorToExclude = ethers.id(excludeSelector).slice(0, 10);\n\t\tconst index = result.indexOf(selectorToExclude);\n\t\tif (index !== -1) {\n\t\t\tresult.splice(index, 1);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport interface ResolveRegistryArgs {\n\t/** The selector registry to resolve into. Mutated IN PLACE (same contract as before). */\n\tregistry: SelectorRegistry;\n\t/** The newly-deployed facets (with addresses, priorities, include/exclude, funcSelectors). */\n\tnewDeployedFacets: NewDeployedFacets;\n\t/** All facet names currently in the deploy config (used to Remove deleted facets). */\n\tfacetNames: string[];\n\t/**\n\t * Reserved for M3 upgrade/redeploy reconciliation. Unused today — prior deployed state\n\t * is carried by the pre-populated `registry` (entries with action `Deployed`).\n\t */\n\tpriorDeployedState?: PriorDeployedState;\n}\n\n/**\n * Resolve ownership of every function selector across the newly-deployed facets and write\n * the result (`Add`/`Replace`/`Remove`/`Deployed` actions) into `registry` **in place**.\n * Pure — no Hardhat/provider. Extracted verbatim from\n * `BaseDeploymentStrategy.updateFunctionSelectorRegistryTasks`.\n */\nexport function resolveFunctionSelectorRegistry(args: ResolveRegistryArgs): void {\n\tconst { registry, newDeployedFacets, facetNames } = args;\n\tconst zeroAddress = ethers.ZeroAddress;\n\n\tconst newDeployedFacetsByPriority = Object.entries(newDeployedFacets).sort(\n\t\t([, a], [, b]) => (a.priority || 1000) - (b.priority || 1000),\n\t);\n\n\tfor (const [newFacetName, newFacetData] of newDeployedFacetsByPriority) {\n\t\tconst currentFacetAddress = newFacetData.address;\n\t\tconst priority: number = newFacetData.priority;\n\t\tconst includeFuncSelectors: string[] = newFacetData.deployInclude || [];\n\t\tconst excludeFuncSelectors: string[] = newFacetData.deployExclude || [];\n\n\t\t// Convert function signatures to selectors\n\t\tconst includeFuncSelectorsAsSelectors = includeFuncSelectors.map((sig) =>\n\t\t\tethers.id(sig).slice(0, 10),\n\t\t);\n\t\tconst excludeFuncSelectorsAsSelectors = excludeFuncSelectors.map((sig) =>\n\t\t\tethers.id(sig).slice(0, 10),\n\t\t);\n\n\t\t// Initialize funcSelectors if not present\n\t\tif (!newFacetData.funcSelectors) {\n\t\t\tnewFacetData.funcSelectors = [];\n\t\t}\n\t\tconst functionSelectors: string[] = newFacetData.funcSelectors;\n\n\t\t/* ------------------ Exclusion Filter ------------------ */\n\t\tfor (const excludeFuncSelector of excludeFuncSelectorsAsSelectors) {\n\t\t\t// remove from the facets functionSelectors\n\t\t\tif (functionSelectors.includes(excludeFuncSelector)) {\n\t\t\t\tfunctionSelectors.splice(functionSelectors.indexOf(excludeFuncSelector), 1);\n\t\t\t}\n\t\t\t// update action to remove if excluded from registry where a previous deployment associated with facetname\n\t\t\tif (\n\t\t\t\tregistry.has(excludeFuncSelector) &&\n\t\t\t\tregistry.get(excludeFuncSelector)?.facetName === newFacetName\n\t\t\t) {\n\t\t\t\tconst existing = registry.get(excludeFuncSelector);\n\t\t\t\tif (existing?.facetName === newFacetName) {\n\t\t\t\t\tregistry.set(excludeFuncSelector, {\n\t\t\t\t\t\tpriority: priority,\n\t\t\t\t\t\t// EIP-2535: a Remove cut MUST use address(0) (M3-E2 fix for M3-E1 S-3 —\n\t\t\t\t\t\t// was currentFacetAddress, which reverts on-chain on deployExclude-on-upgrade).\n\t\t\t\t\t\taddress: zeroAddress,\n\t\t\t\t\t\taction: RegistryFacetCutAction.Remove,\n\t\t\t\t\t\tfacetName: newFacetName,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* ------------------ Inclusion Override Filter ------------------ */\n\t\tfor (const includeFuncSelector of includeFuncSelectorsAsSelectors) {\n\t\t\tconst existingEntry = registry.get(includeFuncSelector);\n\t\t\tif (\n\t\t\t\texistingEntry?.address &&\n\t\t\t\texistingEntry.address !== currentFacetAddress &&\n\t\t\t\texistingEntry.action !== RegistryFacetCutAction.Add\n\t\t\t) {\n\t\t\t\t// Selector already registered/deployed at a different facet address — a selector moved\n\t\t\t\t// facets, or a redeployed facet at a new address (the upgrade case; verified M3-E1 S-1).\n\t\t\t\t// Reconcile -> Replace, not Add (which would revert \"Can't add function that already\n\t\t\t\t// exists\"). Subsumes the removed dead higherPrioritySplit branch (M3-E3).\n\t\t\t\tregistry.set(includeFuncSelector, {\n\t\t\t\t\tpriority: priority,\n\t\t\t\t\taddress: currentFacetAddress,\n\t\t\t\t\taction: RegistryFacetCutAction.Replace,\n\t\t\t\t\tfacetName: newFacetName,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Add to the registry\n\t\t\t\tregistry.set(includeFuncSelector, {\n\t\t\t\t\tpriority: priority,\n\t\t\t\t\taddress: currentFacetAddress,\n\t\t\t\t\taction: RegistryFacetCutAction.Add,\n\t\t\t\t\tfacetName: newFacetName,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// remove from the funcSels so it is not modified in Priority Resolution Pass\n\t\t\tconst existing = newDeployedFacets[newFacetName];\n\t\t\tif (\n\t\t\t\texisting &&\n\t\t\t\texisting.funcSelectors &&\n\t\t\t\texisting.funcSelectors.includes(includeFuncSelector)\n\t\t\t) {\n\t\t\t\texisting.funcSelectors.splice(\n\t\t\t\t\texisting.funcSelectors.indexOf(includeFuncSelector),\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t/* ------------------ Replace Facet and Priority Resolution Pass ------------- */\n\t\tfor (const selector of functionSelectors) {\n\t\t\tconst existing = registry.get(selector);\n\t\t\tif (existing) {\n\t\t\t\tconst existingPriority = existing.priority;\n\n\t\t\t\tif (existing.facetName === newFacetName) {\n\t\t\t\t\t// Same facet, update the address\n\t\t\t\t\tregistry.set(selector, {\n\t\t\t\t\t\tpriority: priority,\n\t\t\t\t\t\taddress: currentFacetAddress,\n\t\t\t\t\t\taction: RegistryFacetCutAction.Replace,\n\t\t\t\t\t\tfacetName: newFacetName,\n\t\t\t\t\t});\n\t\t\t\t} else if (priority < existingPriority) {\n\t\t\t\t\t// Current facet has higher priority, Replace it\n\t\t\t\t\tregistry.set(selector, {\n\t\t\t\t\t\tpriority: priority,\n\t\t\t\t\t\taddress: currentFacetAddress,\n\t\t\t\t\t\taction: RegistryFacetCutAction.Replace,\n\t\t\t\t\t\tfacetName: newFacetName,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// New selector, simply add\n\t\t\t\tregistry.set(selector, {\n\t\t\t\t\tpriority: priority,\n\t\t\t\t\taddress: currentFacetAddress,\n\t\t\t\t\taction: RegistryFacetCutAction.Add,\n\t\t\t\t\tfacetName: newFacetName,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t/* ---------------- Remove Old Function Selectors from facets -------------- */\n\t\t// Set functionselectors with the newFacetName and still different address to Remove\n\t\tfor (const [selector, entry] of registry.entries()) {\n\t\t\tif (entry.facetName === newFacetName && entry.address !== currentFacetAddress) {\n\t\t\t\tregistry.set(selector, {\n\t\t\t\t\tpriority: entry.priority,\n\t\t\t\t\taddress: zeroAddress,\n\t\t\t\t\taction: RegistryFacetCutAction.Remove,\n\t\t\t\t\tfacetName: newFacetName,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// `Remove` function selectors for facets no longer in config (deleted facets)\n\tfor (const [selector, entry] of registry.entries()) {\n\t\tif (!facetNames.includes(entry.facetName)) {\n\t\t\tregistry.set(selector, {\n\t\t\t\tpriority: entry.priority,\n\t\t\t\taddress: zeroAddress,\n\t\t\t\taction: RegistryFacetCutAction.Remove,\n\t\t\t\tfacetName: entry.facetName,\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Diamond } from
|
|
3
|
-
import { FacetCuts } from
|
|
4
|
-
import { DeploymentStrategy } from
|
|
1
|
+
import '@nomicfoundation/hardhat-ethers';
|
|
2
|
+
import { Diamond } from '../core/Diamond';
|
|
3
|
+
import { FacetCuts } from '../types';
|
|
4
|
+
import { DeploymentStrategy } from './DeploymentStrategy';
|
|
5
5
|
export declare class BaseDeploymentStrategy implements DeploymentStrategy {
|
|
6
6
|
protected verbose: boolean;
|
|
7
7
|
constructor(verbose?: boolean);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseDeploymentStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/BaseDeploymentStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,iCAAiC,CAAC;AAIzC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,OAAO,
|
|
1
|
+
{"version":3,"file":"BaseDeploymentStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/BaseDeploymentStrategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ const ethers_1 = require("ethers");
|
|
|
10
10
|
const hardhat_1 = __importDefault(require("hardhat"));
|
|
11
11
|
const types_1 = require("../types");
|
|
12
12
|
const utils_1 = require("../utils");
|
|
13
|
+
const resolution_1 = require("../resolution");
|
|
13
14
|
class BaseDeploymentStrategy {
|
|
14
15
|
verbose;
|
|
15
16
|
constructor(verbose = false) {
|
|
@@ -31,7 +32,7 @@ class BaseDeploymentStrategy {
|
|
|
31
32
|
async deployDiamondTasks(diamond) {
|
|
32
33
|
console.log(chalk_1.default.blueBright(`🚀 Explicitly deploying DiamondCutFacet and Diamond for ${diamond.diamondName}`));
|
|
33
34
|
// Deploy the DiamondCutFacet - use contract mapping to get correct name
|
|
34
|
-
const diamondCutContractName = await (0, utils_1.getContractName)(
|
|
35
|
+
const diamondCutContractName = await (0, utils_1.getContractName)('DiamondCutFacet', diamond);
|
|
35
36
|
const diamondCutFactory = await hardhat_1.default.ethers.getContractFactory(diamondCutContractName, diamond.getSigner());
|
|
36
37
|
const diamondCutFacet = await diamondCutFactory.deploy();
|
|
37
38
|
await diamondCutFacet.waitForDeployment();
|
|
@@ -51,7 +52,7 @@ class BaseDeploymentStrategy {
|
|
|
51
52
|
// Register the DiamondCutFacet function selectors
|
|
52
53
|
const diamondCutFacetSelectorsRegistry = diamondCutFacetFunctionSelectors.reduce((acc, selector) => {
|
|
53
54
|
acc[selector] = {
|
|
54
|
-
facetName:
|
|
55
|
+
facetName: 'DiamondCutFacet',
|
|
55
56
|
priority: diamond.getFacetsConfig()?.DiamondCutFacet?.priority || 1000, // Default priority if not set
|
|
56
57
|
address: diamondCutFacetAddress,
|
|
57
58
|
action: types_1.RegistryFacetCutAction.Deployed,
|
|
@@ -64,9 +65,9 @@ class BaseDeploymentStrategy {
|
|
|
64
65
|
deployedDiamondData.DeployerAddress = await diamond.getSigner().getAddress();
|
|
65
66
|
deployedDiamondData.DiamondAddress = diamondContractAddress;
|
|
66
67
|
deployedDiamondData.DeployedFacets = deployedDiamondData.DeployedFacets || {};
|
|
67
|
-
deployedDiamondData.DeployedFacets[
|
|
68
|
+
deployedDiamondData.DeployedFacets['DiamondCutFacet'] = {
|
|
68
69
|
address: diamondCutFacetAddress,
|
|
69
|
-
tx_hash: diamondCutFacet.deploymentTransaction()?.hash ||
|
|
70
|
+
tx_hash: diamondCutFacet.deploymentTransaction()?.hash || '',
|
|
70
71
|
version: 0,
|
|
71
72
|
funcSelectors: diamondCutFacetFunctionSelectors,
|
|
72
73
|
};
|
|
@@ -101,9 +102,9 @@ class BaseDeploymentStrategy {
|
|
|
101
102
|
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
102
103
|
const deployedFacets = deployedDiamondData.DeployedFacets || {};
|
|
103
104
|
const facetCuts = [];
|
|
104
|
-
const sortedFacetNames = Object.keys(deployConfig.facets)
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
const sortedFacetNames = Object.keys(deployConfig.facets).sort((a, b) => {
|
|
106
|
+
return ((deployConfig.facets[a].priority || 1000) -
|
|
107
|
+
(deployConfig.facets[b].priority || 1000));
|
|
107
108
|
});
|
|
108
109
|
// Save the facet deployment info
|
|
109
110
|
for (const facetName of sortedFacetNames) {
|
|
@@ -111,6 +112,8 @@ class BaseDeploymentStrategy {
|
|
|
111
112
|
const deployedVersion = deployedDiamondData.DeployedFacets?.[facetName]?.version ?? -1;
|
|
112
113
|
const availableVersions = Object.keys(facetConfig.versions || {}).map(Number);
|
|
113
114
|
const upgradeVersion = Math.max(...availableVersions);
|
|
115
|
+
// Find the original string key that matches the upgrade version number
|
|
116
|
+
const upgradeVersionKey = Object.keys(facetConfig.versions || {}).find((key) => Number(key) === upgradeVersion) || String(upgradeVersion);
|
|
114
117
|
if (upgradeVersion > deployedVersion || deployedVersion === -1) {
|
|
115
118
|
if (this.verbose) {
|
|
116
119
|
console.log(chalk_1.default.blueBright(`🚀 Deploying facet: ${facetName} to version ${upgradeVersion}`));
|
|
@@ -118,7 +121,9 @@ class BaseDeploymentStrategy {
|
|
|
118
121
|
// Deploy the facet contract - use contract mapping to get correct name
|
|
119
122
|
const signer = diamond.getSigner();
|
|
120
123
|
const facetContractName = await (0, utils_1.getContractName)(facetName, diamond);
|
|
121
|
-
const facetFactory = await hardhat_1.default.ethers.getContractFactory(facetContractName, {
|
|
124
|
+
const facetFactory = await hardhat_1.default.ethers.getContractFactory(facetContractName, {
|
|
125
|
+
signer,
|
|
126
|
+
});
|
|
122
127
|
const facetContract = await facetFactory.deploy();
|
|
123
128
|
await facetContract.waitForDeployment();
|
|
124
129
|
const deployedFacets = new Map();
|
|
@@ -127,9 +132,17 @@ class BaseDeploymentStrategy {
|
|
|
127
132
|
facetContract.interface.forEachFunction((func) => {
|
|
128
133
|
facetSelectors.push(func.selector);
|
|
129
134
|
});
|
|
135
|
+
// Apply deployExclude (removal) + deployInclude (whitelist) via the pure
|
|
136
|
+
// resolution core. Behavior-preserving (M1-E1); deployInclude stays a
|
|
137
|
+
// whitelist here — M2 makes it additive.
|
|
138
|
+
const excludeFuncSelectors = facetConfig.versions?.[upgradeVersionKey]?.deployExclude || [];
|
|
139
|
+
const includeFuncSelectors = facetConfig.versions?.[upgradeVersionKey]?.deployInclude || [];
|
|
140
|
+
const resolvedFacetSelectors = (0, resolution_1.computeFacetSelectors)(facetSelectors, includeFuncSelectors, excludeFuncSelectors);
|
|
141
|
+
facetSelectors.length = 0;
|
|
142
|
+
facetSelectors.push(...resolvedFacetSelectors);
|
|
130
143
|
// Initializer function Registry
|
|
131
|
-
const deployInit = facetConfig.versions?.[
|
|
132
|
-
const upgradeInit = facetConfig.versions?.[
|
|
144
|
+
const deployInit = facetConfig.versions?.[upgradeVersionKey]?.deployInit || '';
|
|
145
|
+
const upgradeInit = facetConfig.versions?.[upgradeVersionKey]?.upgradeInit || '';
|
|
133
146
|
const initFn = diamond.newDeployment ? deployInit : upgradeInit;
|
|
134
147
|
if (initFn && facetName !== deployConfig.protocolInitFacet) {
|
|
135
148
|
diamond.initializerRegistry.set(facetName, initFn);
|
|
@@ -137,11 +150,11 @@ class BaseDeploymentStrategy {
|
|
|
137
150
|
const newFacetData = {
|
|
138
151
|
priority: facetConfig.priority || 1000,
|
|
139
152
|
address: await facetContract.getAddress(),
|
|
140
|
-
tx_hash: facetContract.deploymentTransaction()?.hash ||
|
|
153
|
+
tx_hash: facetContract.deploymentTransaction()?.hash || '',
|
|
141
154
|
version: upgradeVersion,
|
|
142
155
|
funcSelectors: facetSelectors,
|
|
143
|
-
deployInclude: facetConfig.versions?.[
|
|
144
|
-
deployExclude: facetConfig.versions?.[
|
|
156
|
+
deployInclude: facetConfig.versions?.[upgradeVersionKey]?.deployInclude || [],
|
|
157
|
+
deployExclude: facetConfig.versions?.[upgradeVersionKey]?.deployExclude || [],
|
|
145
158
|
initFunction: initFn,
|
|
146
159
|
verified: false,
|
|
147
160
|
};
|
|
@@ -176,138 +189,14 @@ class BaseDeploymentStrategy {
|
|
|
176
189
|
this.updateFunctionSelectorRegistryTasks(diamond);
|
|
177
190
|
}
|
|
178
191
|
async updateFunctionSelectorRegistryTasks(diamond) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const includeFuncSelectors = newFacetData.deployInclude || [];
|
|
188
|
-
const excludeFuncSelectors = newFacetData.deployExclude || [];
|
|
189
|
-
/* ------------------ Exclusion Filter ------------------ */
|
|
190
|
-
for (const excludeFuncSelector of excludeFuncSelectors) {
|
|
191
|
-
// remove from the facets functionSelectors
|
|
192
|
-
if (excludeFuncSelector in functionSelectors) {
|
|
193
|
-
functionSelectors.splice(functionSelectors.indexOf(excludeFuncSelector), 1);
|
|
194
|
-
}
|
|
195
|
-
// update action to remove if excluded from registry where a previous deployment associated with facetname
|
|
196
|
-
if (excludeFuncSelector in registry && registry.get(excludeFuncSelector)?.facetName === newFacetName) {
|
|
197
|
-
const existing = registry.get(excludeFuncSelector);
|
|
198
|
-
if (existing && existing.facetName === newFacetName) {
|
|
199
|
-
registry.set(excludeFuncSelector, {
|
|
200
|
-
priority: priority,
|
|
201
|
-
address: currentFacetAddress,
|
|
202
|
-
action: types_1.RegistryFacetCutAction.Remove,
|
|
203
|
-
facetName: newFacetName,
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
/* ------------ Higher Priority Split of Registry ------------------ */
|
|
209
|
-
const registryHigherPrioritySplit = Array.from(registry.entries())
|
|
210
|
-
.filter(([_, entry]) => entry.priority > priority)
|
|
211
|
-
.reduce((acc, [selector, entry]) => {
|
|
212
|
-
if (!acc[entry.facetName]) {
|
|
213
|
-
acc[entry.facetName] = [];
|
|
214
|
-
}
|
|
215
|
-
acc[entry.facetName].push(selector);
|
|
216
|
-
return acc;
|
|
217
|
-
}, {});
|
|
218
|
-
/* ------------------ Inclusion Override Filter ------------------ */
|
|
219
|
-
for (const includeFuncSelector of includeFuncSelectors) {
|
|
220
|
-
// Force Replace if already registered by higher priority facet
|
|
221
|
-
if (includeFuncSelector in registryHigherPrioritySplit) {
|
|
222
|
-
const higherPriorityFacet = Object.keys(registryHigherPrioritySplit).find(facetName => {
|
|
223
|
-
return registryHigherPrioritySplit[facetName].includes(includeFuncSelector);
|
|
224
|
-
});
|
|
225
|
-
if (higherPriorityFacet) {
|
|
226
|
-
registry.set(includeFuncSelector, {
|
|
227
|
-
priority: priority,
|
|
228
|
-
address: currentFacetAddress,
|
|
229
|
-
action: types_1.RegistryFacetCutAction.Replace,
|
|
230
|
-
facetName: newFacetName,
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
// Add to the registry
|
|
236
|
-
registry.set(includeFuncSelector, {
|
|
237
|
-
priority: priority,
|
|
238
|
-
address: currentFacetAddress,
|
|
239
|
-
action: types_1.RegistryFacetCutAction.Add,
|
|
240
|
-
facetName: newFacetName,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
// remove from the funcSels so it is not modified in Priority Resolution Pass
|
|
244
|
-
if (includeFuncSelector in newDeployedFacets) {
|
|
245
|
-
const existing = newDeployedFacets[newFacetName];
|
|
246
|
-
if (existing && existing.funcSelectors) {
|
|
247
|
-
existing.funcSelectors.splice(existing.funcSelectors.indexOf(includeFuncSelector), 1);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
/* ------------------ Replace Facet and Priority Resolution Pass ------------- */
|
|
252
|
-
for (const selector of functionSelectors) {
|
|
253
|
-
const existing = registry.get(selector);
|
|
254
|
-
if (existing) {
|
|
255
|
-
const existingPriority = existing.priority;
|
|
256
|
-
if (existing.facetName === newFacetName) {
|
|
257
|
-
// Same facet, update the address
|
|
258
|
-
registry.set(selector, {
|
|
259
|
-
priority: priority,
|
|
260
|
-
address: currentFacetAddress,
|
|
261
|
-
action: types_1.RegistryFacetCutAction.Replace,
|
|
262
|
-
facetName: newFacetName,
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
else if (priority < existingPriority) {
|
|
266
|
-
// Current facet has higher priority, Replace it
|
|
267
|
-
registry.set(selector, {
|
|
268
|
-
priority: priority,
|
|
269
|
-
address: currentFacetAddress,
|
|
270
|
-
action: types_1.RegistryFacetCutAction.Replace,
|
|
271
|
-
facetName: newFacetName,
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
// New selector, simply add
|
|
277
|
-
registry.set(selector, {
|
|
278
|
-
priority: priority,
|
|
279
|
-
address: currentFacetAddress,
|
|
280
|
-
action: types_1.RegistryFacetCutAction.Add,
|
|
281
|
-
facetName: newFacetName,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
/* ---------------- Remove Old Function Selectors from facets -------------- */
|
|
286
|
-
// Set functionselectors with the newFacetName and still different address to Remove
|
|
287
|
-
for (const [selector, entry] of registry.entries()) {
|
|
288
|
-
if (entry.facetName === newFacetName && entry.address !== currentFacetAddress) {
|
|
289
|
-
registry.set(selector, {
|
|
290
|
-
priority: entry.priority,
|
|
291
|
-
address: zeroAddress,
|
|
292
|
-
action: types_1.RegistryFacetCutAction.Remove,
|
|
293
|
-
facetName: newFacetName,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
// `Remove` function selectors for facets no longer in config (deleted facets)
|
|
299
|
-
const facetsConfig = diamond.getDeployConfig().facets;
|
|
300
|
-
const facetNames = Object.keys(facetsConfig);
|
|
301
|
-
for (const [selector, entry] of registry.entries()) {
|
|
302
|
-
if (!facetNames.includes(entry.facetName)) {
|
|
303
|
-
registry.set(selector, {
|
|
304
|
-
priority: entry.priority,
|
|
305
|
-
address: zeroAddress,
|
|
306
|
-
action: types_1.RegistryFacetCutAction.Remove,
|
|
307
|
-
facetName: entry.facetName,
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}
|
|
192
|
+
// Delegates to the pure resolution core (M1-E1). Behavior-preserving: the dead
|
|
193
|
+
// `higherPrioritySplit` and the `5b2f7af` Replace branch live there verbatim and are
|
|
194
|
+
// reconciled in M3. The registry Map is mutated in place, exactly as before.
|
|
195
|
+
(0, resolution_1.resolveFunctionSelectorRegistry)({
|
|
196
|
+
registry: diamond.functionSelectorRegistry,
|
|
197
|
+
newDeployedFacets: diamond.getNewDeployedFacets(),
|
|
198
|
+
facetNames: Object.keys(diamond.getDeployConfig().facets),
|
|
199
|
+
});
|
|
311
200
|
}
|
|
312
201
|
async postUpdateFunctionSelectorRegistry(diamond) {
|
|
313
202
|
if (this.verbose) {
|
|
@@ -335,13 +224,13 @@ class BaseDeploymentStrategy {
|
|
|
335
224
|
async performDiamondCutTasks(diamond) {
|
|
336
225
|
const diamondSignerAddress = await diamond.getSigner()?.getAddress();
|
|
337
226
|
const signer = await hardhat_1.default.ethers.getSigner(diamondSignerAddress);
|
|
338
|
-
const diamondContract = await hardhat_1.default.ethers.getContractAt(
|
|
227
|
+
const diamondContract = await hardhat_1.default.ethers.getContractAt('IDiamondCut', diamond.getDeployedDiamondData().DiamondAddress);
|
|
339
228
|
const signerDiamondContract = diamondContract.connect(signer);
|
|
340
229
|
const deployConfig = diamond.getDeployConfig();
|
|
341
230
|
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
342
231
|
// Setup initCallData with Atomic Protocol Initializer
|
|
343
232
|
const [initCalldata, initAddress] = await this.getInitCalldata(diamond);
|
|
344
|
-
// extract facet cuts from the selector registry
|
|
233
|
+
// extract facet cuts from the selector registry
|
|
345
234
|
const facetCuts = await this.getFacetCuts(diamond);
|
|
346
235
|
// Validate no orphaned selectors, i.e. 'Add', 'Replace' or 'Deployed' selectors with the same facetNames but different addresses
|
|
347
236
|
await this.validateNoOrphanedSelectors(facetCuts);
|
|
@@ -356,7 +245,11 @@ class BaseDeploymentStrategy {
|
|
|
356
245
|
}
|
|
357
246
|
}
|
|
358
247
|
/* -------------------------- Perform the diamond cut -----------------------*/
|
|
359
|
-
const facetSelectorCutMap = facetCuts.map(fc => ({
|
|
248
|
+
const facetSelectorCutMap = facetCuts.map((fc) => ({
|
|
249
|
+
facetAddress: fc.facetAddress,
|
|
250
|
+
action: fc.action,
|
|
251
|
+
functionSelectors: fc.functionSelectors,
|
|
252
|
+
}));
|
|
360
253
|
const tx = await signerDiamondContract.diamondCut(facetSelectorCutMap, initAddress, initCalldata);
|
|
361
254
|
/* --------------------- Update the deployed diamond data ------------------ */
|
|
362
255
|
const txHash = tx.hash;
|
|
@@ -364,7 +257,7 @@ class BaseDeploymentStrategy {
|
|
|
364
257
|
const ifaceList = (0, utils_1.getDeployedFacetInterfaces)(deployedDiamondData);
|
|
365
258
|
// Log the transaction
|
|
366
259
|
if (this.verbose) {
|
|
367
|
-
await (0, utils_1.logTx)(tx,
|
|
260
|
+
await (0, utils_1.logTx)(tx, 'DiamondCut', ifaceList);
|
|
368
261
|
}
|
|
369
262
|
else {
|
|
370
263
|
console.log(chalk_1.default.blueBright(`🔄 Waiting for DiamondCut transaction to be mined...`));
|
|
@@ -400,13 +293,15 @@ class BaseDeploymentStrategy {
|
|
|
400
293
|
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
401
294
|
const deployConfig = diamond.getDeployConfig();
|
|
402
295
|
let initAddress = ethers_1.ethers.ZeroAddress;
|
|
403
|
-
let initCalldata =
|
|
404
|
-
const protocolInitFacet = deployConfig.protocolInitFacet ||
|
|
296
|
+
let initCalldata = '0x';
|
|
297
|
+
const protocolInitFacet = deployConfig.protocolInitFacet || '';
|
|
405
298
|
const protocolVersion = deployConfig.protocolVersion;
|
|
406
299
|
const protocolFacetInfo = diamond.getNewDeployedFacets()[protocolInitFacet];
|
|
407
300
|
if (protocolInitFacet && protocolFacetInfo) {
|
|
408
301
|
const versionCfg = deployConfig.facets[protocolInitFacet]?.versions?.[protocolVersion];
|
|
409
|
-
const initFn = diamond.newDeployment
|
|
302
|
+
const initFn = diamond.newDeployment
|
|
303
|
+
? versionCfg?.deployInit
|
|
304
|
+
: versionCfg?.upgradeInit;
|
|
410
305
|
if (initFn) {
|
|
411
306
|
const iface = new ethers_1.ethers.Interface([`function ${initFn}`]);
|
|
412
307
|
initAddress = protocolFacetInfo.address;
|
|
@@ -426,7 +321,7 @@ class BaseDeploymentStrategy {
|
|
|
426
321
|
const deployConfig = diamond.getDeployConfig();
|
|
427
322
|
const selectorRegistry = diamond.functionSelectorRegistry;
|
|
428
323
|
/* -------------------------- Prepare the facet cuts -----------------------*/
|
|
429
|
-
// extract facet cuts from the selector registry
|
|
324
|
+
// extract facet cuts from the selector registry
|
|
430
325
|
const facetCuts = Array.from(selectorRegistry.entries())
|
|
431
326
|
.filter(([_, entry]) => entry.action !== types_1.RegistryFacetCutAction.Deployed)
|
|
432
327
|
.map(([selector, entry]) => {
|
|
@@ -441,8 +336,8 @@ class BaseDeploymentStrategy {
|
|
|
441
336
|
}
|
|
442
337
|
async validateNoOrphanedSelectors(facetCuts) {
|
|
443
338
|
// Validate no orphaned selectors, i.e. 'Add', 'Replace' or 'Deployed' selectors with the same facetNames but different addresses
|
|
444
|
-
const orphanedSelectors = facetCuts.filter(facetCut => {
|
|
445
|
-
return facetCuts.some(otherFacetCut => {
|
|
339
|
+
const orphanedSelectors = facetCuts.filter((facetCut) => {
|
|
340
|
+
return facetCuts.some((otherFacetCut) => {
|
|
446
341
|
return (otherFacetCut.facetAddress !== facetCut.facetAddress &&
|
|
447
342
|
otherFacetCut.name === facetCut.name &&
|
|
448
343
|
(otherFacetCut.action === types_1.RegistryFacetCutAction.Add ||
|
|
@@ -469,7 +364,9 @@ class BaseDeploymentStrategy {
|
|
|
469
364
|
if (!facetSelectorsMap[facetName]) {
|
|
470
365
|
facetSelectorsMap[facetName] = { address: entry.address, selectors: [] };
|
|
471
366
|
}
|
|
472
|
-
if (entry.action === types_1.RegistryFacetCutAction.Add ||
|
|
367
|
+
if (entry.action === types_1.RegistryFacetCutAction.Add ||
|
|
368
|
+
entry.action === types_1.RegistryFacetCutAction.Replace ||
|
|
369
|
+
entry.action === types_1.RegistryFacetCutAction.Deployed) {
|
|
473
370
|
facetSelectorsMap[facetName].selectors.push(selector);
|
|
474
371
|
}
|
|
475
372
|
}
|
|
@@ -497,7 +394,7 @@ class BaseDeploymentStrategy {
|
|
|
497
394
|
}
|
|
498
395
|
// Remove facets with no selectors
|
|
499
396
|
for (const facetName of Object.keys(deployedDiamondData.DeployedFacets)) {
|
|
500
|
-
if (
|
|
397
|
+
if (facetSelectorsMap[facetName]?.selectors.length === 0) {
|
|
501
398
|
delete deployedDiamondData.DeployedFacets[facetName];
|
|
502
399
|
}
|
|
503
400
|
}
|