@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,649 @@
|
|
|
1
|
+
import "@nomicfoundation/hardhat-ethers";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { ethers } from "ethers";
|
|
4
|
+
import hre from "hardhat";
|
|
5
|
+
import { Diamond } from "../core/Diamond";
|
|
6
|
+
import { DeployedFacet } from "../schemas";
|
|
7
|
+
import {
|
|
8
|
+
CallbackArgs,
|
|
9
|
+
FacetCutAction,
|
|
10
|
+
FacetCuts,
|
|
11
|
+
FacetDeploymentInfo,
|
|
12
|
+
FunctionSelectorRegistryEntry,
|
|
13
|
+
NewDeployedFacet,
|
|
14
|
+
RegistryFacetCutAction
|
|
15
|
+
} from "../types";
|
|
16
|
+
import { getContractName, getDeployedFacetInterfaces, getDiamondContractName, logTx } from "../utils";
|
|
17
|
+
import { DeploymentStrategy } from "./DeploymentStrategy";
|
|
18
|
+
|
|
19
|
+
export class BaseDeploymentStrategy implements DeploymentStrategy {
|
|
20
|
+
constructor(protected verbose: boolean = false) { }
|
|
21
|
+
|
|
22
|
+
async preDeployDiamond(diamond: Diamond): Promise<void> {
|
|
23
|
+
if (this.verbose) {
|
|
24
|
+
console.log(chalk.gray(`🔧 Running pre-deploy logic for diamond ${diamond.diamondName}`));
|
|
25
|
+
}
|
|
26
|
+
await this.preDeployDiamondTasks(diamond);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected async preDeployDiamondTasks(diamond: Diamond): Promise<void> { }
|
|
30
|
+
|
|
31
|
+
async deployDiamond(diamond: Diamond): Promise<void> {
|
|
32
|
+
if (this.verbose) {
|
|
33
|
+
console.log(chalk.yellowBright(`\n🪓 Deploying diamond ${diamond.diamondName} with DiamondCutFacet...`));
|
|
34
|
+
}
|
|
35
|
+
await this.deployDiamondTasks(diamond);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
protected async deployDiamondTasks(diamond: Diamond): Promise<void> {
|
|
39
|
+
console.log(chalk.blueBright(`🚀 Explicitly deploying DiamondCutFacet and Diamond for ${diamond.diamondName}`));
|
|
40
|
+
|
|
41
|
+
// Deploy the DiamondCutFacet - use contract mapping to get correct name
|
|
42
|
+
const diamondCutContractName = await getContractName("DiamondCutFacet", diamond);
|
|
43
|
+
const diamondCutFactory = await hre.ethers.getContractFactory(diamondCutContractName, diamond.getSigner()!);
|
|
44
|
+
const diamondCutFacet = await diamondCutFactory.deploy();
|
|
45
|
+
await diamondCutFacet.waitForDeployment();
|
|
46
|
+
|
|
47
|
+
// Deploy the Diamond - use contract mapping to get correct name
|
|
48
|
+
const diamondContractName = await getDiamondContractName(diamond.diamondName, diamond);
|
|
49
|
+
const diamondFactory = await hre.ethers.getContractFactory(diamondContractName, diamond.getSigner()!);
|
|
50
|
+
const diamondContract = await diamondFactory.deploy(await diamond.getSigner()!.getAddress(), await diamondCutFacet.getAddress());
|
|
51
|
+
await diamondContract.waitForDeployment();
|
|
52
|
+
|
|
53
|
+
// Get function selectors for DiamondCutFacet
|
|
54
|
+
const diamondCutFacetFunctionSelectors: string[] = [];
|
|
55
|
+
diamondCutFacet.interface.forEachFunction((func: ethers.FunctionFragment) => {
|
|
56
|
+
diamondCutFacetFunctionSelectors.push(func.selector);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Get addresses for later use
|
|
60
|
+
const diamondCutFacetAddress = await diamondCutFacet.getAddress();
|
|
61
|
+
const diamondContractAddress = await diamondContract.getAddress();
|
|
62
|
+
|
|
63
|
+
// Register the DiamondCutFacet function selectors
|
|
64
|
+
const diamondCutFacetSelectorsRegistry = diamondCutFacetFunctionSelectors.reduce((acc, selector) => {
|
|
65
|
+
acc[selector] = {
|
|
66
|
+
facetName: "DiamondCutFacet",
|
|
67
|
+
priority: diamond.getFacetsConfig()?.DiamondCutFacet?.priority || 1000, // Default priority if not set
|
|
68
|
+
address: diamondCutFacetAddress,
|
|
69
|
+
action: RegistryFacetCutAction.Deployed,
|
|
70
|
+
};
|
|
71
|
+
return acc;
|
|
72
|
+
}, {} as Record<string, Omit<FunctionSelectorRegistryEntry, "selector">>);
|
|
73
|
+
|
|
74
|
+
diamond.registerFunctionSelectors(diamondCutFacetSelectorsRegistry);
|
|
75
|
+
|
|
76
|
+
// Update deployed diamond data
|
|
77
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
78
|
+
deployedDiamondData.DeployerAddress = await diamond.getSigner()!.getAddress();
|
|
79
|
+
deployedDiamondData.DiamondAddress = diamondContractAddress;
|
|
80
|
+
deployedDiamondData.DeployedFacets = deployedDiamondData.DeployedFacets || {};
|
|
81
|
+
deployedDiamondData.DeployedFacets["DiamondCutFacet"] = {
|
|
82
|
+
address: diamondCutFacetAddress,
|
|
83
|
+
tx_hash: diamondCutFacet.deploymentTransaction()?.hash || "",
|
|
84
|
+
version: 0,
|
|
85
|
+
funcSelectors: diamondCutFacetFunctionSelectors,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
diamond.updateDeployedDiamondData(deployedDiamondData);
|
|
89
|
+
|
|
90
|
+
console.log(chalk.green(`✅ Diamond deployed at ${await diamondContract.getAddress()}, DiamondCutFacet at ${await diamondCutFacet.getAddress()}`));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async postDeployDiamond(diamond: Diamond): Promise<void> {
|
|
94
|
+
if (this.verbose) {
|
|
95
|
+
console.log(chalk.gray(`✅ Running post-deploy logic for diamond ${diamond.diamondName}`));
|
|
96
|
+
}
|
|
97
|
+
await this.postDeployDiamondTasks(diamond);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected async postDeployDiamondTasks(diamond: Diamond): Promise<void> { }
|
|
101
|
+
|
|
102
|
+
async preDeployFacets(diamond: Diamond): Promise<void> {
|
|
103
|
+
if (this.verbose) {
|
|
104
|
+
console.log(chalk.gray(`🔧 Running pre-deploy logic for facets of diamond ${diamond.diamondName}`));
|
|
105
|
+
}
|
|
106
|
+
await this.preDeployFacetsTasks(diamond);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
protected async preDeployFacetsTasks(diamond: Diamond): Promise<void> {
|
|
110
|
+
// This can be overridden by subclasses for custom pre-deploy logic
|
|
111
|
+
if (this.verbose) {
|
|
112
|
+
console.log(chalk.gray(`🔧 No pre-deploy tasks defined for facets of diamond ${diamond.diamondName}`));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async deployFacets(diamond: Diamond): Promise<void> {
|
|
117
|
+
await this.deployFacetsTasks(diamond);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
protected async deployFacetsTasks(diamond: Diamond) {
|
|
121
|
+
const deployConfig = diamond.getDeployConfig();
|
|
122
|
+
const facetsConfig = diamond.getDeployConfig().facets;
|
|
123
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
124
|
+
const deployedFacets = deployedDiamondData.DeployedFacets || {};
|
|
125
|
+
const facetCuts: FacetDeploymentInfo[] = [];
|
|
126
|
+
|
|
127
|
+
const sortedFacetNames = Object.keys(deployConfig.facets)
|
|
128
|
+
.sort((a, b) => {
|
|
129
|
+
return (deployConfig.facets[a].priority || 1000) - (deployConfig.facets[b].priority || 1000);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Save the facet deployment info
|
|
133
|
+
for (const facetName of sortedFacetNames) {
|
|
134
|
+
const facetConfig = facetsConfig[facetName];
|
|
135
|
+
const deployedVersion = deployedDiamondData.DeployedFacets?.[facetName]?.version ?? -1;
|
|
136
|
+
const availableVersions = Object.keys(facetConfig.versions || {}).map(Number);
|
|
137
|
+
const upgradeVersion = Math.max(...availableVersions);
|
|
138
|
+
|
|
139
|
+
if (upgradeVersion > deployedVersion || deployedVersion === -1) {
|
|
140
|
+
if (this.verbose) {
|
|
141
|
+
console.log(chalk.blueBright(`🚀 Deploying facet: ${facetName} to version ${upgradeVersion}`));
|
|
142
|
+
}
|
|
143
|
+
// Deploy the facet contract - use contract mapping to get correct name
|
|
144
|
+
const signer = diamond.getSigner()!;
|
|
145
|
+
const facetContractName = await getContractName(facetName, diamond);
|
|
146
|
+
const facetFactory = await hre.ethers.getContractFactory(facetContractName, { signer });
|
|
147
|
+
const facetContract = await facetFactory.deploy();
|
|
148
|
+
await facetContract.waitForDeployment();
|
|
149
|
+
|
|
150
|
+
const deployedFacets = new Map<string, DeployedFacet>();
|
|
151
|
+
const availableVersions = Object.keys(facetConfig.versions ?? {}).map(Number);
|
|
152
|
+
const facetSelectors: string[] = [];
|
|
153
|
+
facetContract.interface.forEachFunction((func: ethers.FunctionFragment) => {
|
|
154
|
+
facetSelectors.push(func.selector);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Initializer function Registry
|
|
158
|
+
const deployInit = facetConfig.versions?.[upgradeVersion]?.deployInit || "";
|
|
159
|
+
const upgradeInit = facetConfig.versions?.[upgradeVersion]?.upgradeInit || "";
|
|
160
|
+
|
|
161
|
+
const initFn = diamond.newDeployment ? deployInit : upgradeInit;
|
|
162
|
+
if (initFn && facetName !== deployConfig.protocolInitFacet) {
|
|
163
|
+
diamond.initializerRegistry.set(facetName, initFn);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const newFacetData: NewDeployedFacet = {
|
|
167
|
+
priority: facetConfig.priority || 1000,
|
|
168
|
+
address: await facetContract.getAddress(),
|
|
169
|
+
tx_hash: facetContract.deploymentTransaction()?.hash || "",
|
|
170
|
+
version: upgradeVersion,
|
|
171
|
+
funcSelectors: facetSelectors,
|
|
172
|
+
deployInclude: facetConfig.versions?.[upgradeVersion]?.deployInclude || [],
|
|
173
|
+
deployExclude: facetConfig.versions?.[upgradeVersion]?.deployExclude || [],
|
|
174
|
+
initFunction: initFn,
|
|
175
|
+
verified: false,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
diamond.updateNewDeployedFacets(facetName, newFacetData);
|
|
179
|
+
|
|
180
|
+
console.log(chalk.cyan(`⛵ ${facetName} deployed at ${await facetContract.getAddress()} with ${facetSelectors.length} selectors.`));
|
|
181
|
+
// Log the deployment transaction and selectors
|
|
182
|
+
if (this.verbose) {
|
|
183
|
+
console.log(chalk.gray(` Selectors:`), facetSelectors);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async postDeployFacets(diamond: Diamond): Promise<void> {
|
|
191
|
+
if (this.verbose) {
|
|
192
|
+
console.log(chalk.gray(`✅ Running post-deploy logic for facets of diamond ${diamond.diamondName}`));
|
|
193
|
+
}
|
|
194
|
+
await this.postDeployFacetsTasks(diamond);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Used by subclasses for facet post-deployment tasks
|
|
198
|
+
protected async postDeployFacetsTasks(diamond: Diamond): Promise<void> { }
|
|
199
|
+
|
|
200
|
+
// Pre-hook for updating function selector registry (can be overridden by subclasses)
|
|
201
|
+
async preUpdateFunctionSelectorRegistry(diamond: Diamond): Promise<void> {
|
|
202
|
+
if (this.verbose) {
|
|
203
|
+
console.log(chalk.gray(`🔧 Running pre-update logic for function selector registry of diamond ${diamond.diamondName}`));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
protected async preUpdateFunctionSelectorRegistryTasks(diamond: Diamond): Promise<void> { }
|
|
208
|
+
|
|
209
|
+
async updateFunctionSelectorRegistry(diamond: Diamond) {
|
|
210
|
+
if (this.verbose) {
|
|
211
|
+
console.log(chalk.yellowBright(`\n🪓 Updating function selector registry for diamond ${diamond.diamondName}...`));
|
|
212
|
+
}
|
|
213
|
+
this.updateFunctionSelectorRegistryTasks(diamond);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
protected async updateFunctionSelectorRegistryTasks(
|
|
217
|
+
diamond: Diamond,
|
|
218
|
+
): Promise<void> {
|
|
219
|
+
const registry = diamond.functionSelectorRegistry;
|
|
220
|
+
const zeroAddress = ethers.ZeroAddress;
|
|
221
|
+
|
|
222
|
+
const newDeployedFacets = diamond.getNewDeployedFacets();
|
|
223
|
+
const newDeployedFacetsByPriority = Object.entries(newDeployedFacets).sort(([, a], [, b]) =>
|
|
224
|
+
(a.priority || 1000) - (b.priority || 1000)
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
for (const [newFacetName, newFacetData] of newDeployedFacetsByPriority) {
|
|
228
|
+
const currentFacetAddress = newFacetData.address;
|
|
229
|
+
const priority: number = newFacetData.priority;
|
|
230
|
+
const functionSelectors: string[] = newFacetData.funcSelectors || [];
|
|
231
|
+
const includeFuncSelectors: string[] = newFacetData.deployInclude || [];
|
|
232
|
+
const excludeFuncSelectors: string[] = newFacetData.deployExclude || [];
|
|
233
|
+
|
|
234
|
+
/* ------------------ Exclusion Filter ------------------ */
|
|
235
|
+
for (const excludeFuncSelector of excludeFuncSelectors) {
|
|
236
|
+
// remove from the facets functionSelectors
|
|
237
|
+
if (excludeFuncSelector in functionSelectors) {
|
|
238
|
+
functionSelectors.splice(functionSelectors.indexOf(excludeFuncSelector), 1);
|
|
239
|
+
}
|
|
240
|
+
// update action to remove if excluded from registry where a previous deployment associated with facetname
|
|
241
|
+
if (excludeFuncSelector in registry && registry.get(excludeFuncSelector)?.facetName === newFacetName) {
|
|
242
|
+
const existing = registry.get(excludeFuncSelector);
|
|
243
|
+
if (existing && existing.facetName === newFacetName) {
|
|
244
|
+
registry.set(excludeFuncSelector, {
|
|
245
|
+
priority: priority,
|
|
246
|
+
address: currentFacetAddress,
|
|
247
|
+
action: RegistryFacetCutAction.Remove,
|
|
248
|
+
facetName: newFacetName,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* ------------ Higher Priority Split of Registry ------------------ */
|
|
255
|
+
const registryHigherPrioritySplit = Array.from(registry.entries())
|
|
256
|
+
.filter(([_, entry]) => entry.priority > priority)
|
|
257
|
+
.reduce((acc, [selector, entry]) => {
|
|
258
|
+
if (!acc[entry.facetName]) {
|
|
259
|
+
acc[entry.facetName] = [];
|
|
260
|
+
}
|
|
261
|
+
acc[entry.facetName].push(selector);
|
|
262
|
+
return acc;
|
|
263
|
+
}, {} as Record<string, string[]>);
|
|
264
|
+
|
|
265
|
+
/* ------------------ Inclusion Override Filter ------------------ */
|
|
266
|
+
for (const includeFuncSelector of includeFuncSelectors) {
|
|
267
|
+
// Force Replace if already registered by higher priority facet
|
|
268
|
+
if (includeFuncSelector in registryHigherPrioritySplit) {
|
|
269
|
+
const higherPriorityFacet = Object.keys(registryHigherPrioritySplit).find(facetName => {
|
|
270
|
+
return registryHigherPrioritySplit[facetName].includes(includeFuncSelector);
|
|
271
|
+
});
|
|
272
|
+
if (higherPriorityFacet) {
|
|
273
|
+
registry.set(includeFuncSelector, {
|
|
274
|
+
priority: priority,
|
|
275
|
+
address: currentFacetAddress,
|
|
276
|
+
action: RegistryFacetCutAction.Replace,
|
|
277
|
+
facetName: newFacetName,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
// Add to the registry
|
|
282
|
+
registry.set(includeFuncSelector, {
|
|
283
|
+
priority: priority,
|
|
284
|
+
address: currentFacetAddress,
|
|
285
|
+
action: RegistryFacetCutAction.Add,
|
|
286
|
+
facetName: newFacetName,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// remove from the funcSels so it is not modified in Priority Resolution Pass
|
|
291
|
+
if (includeFuncSelector in newDeployedFacets) {
|
|
292
|
+
const existing = newDeployedFacets[newFacetName];
|
|
293
|
+
if (existing && existing.funcSelectors) {
|
|
294
|
+
existing.funcSelectors.splice(existing.funcSelectors.indexOf(includeFuncSelector), 1);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* ------------------ Replace Facet and Priority Resolution Pass ------------- */
|
|
300
|
+
for (const selector of functionSelectors) {
|
|
301
|
+
const existing = registry.get(selector);
|
|
302
|
+
if (existing) {
|
|
303
|
+
const existingPriority = existing.priority;
|
|
304
|
+
|
|
305
|
+
if (existing.facetName === newFacetName) {
|
|
306
|
+
// Same facet, update the address
|
|
307
|
+
registry.set(selector, {
|
|
308
|
+
priority: priority,
|
|
309
|
+
address: currentFacetAddress,
|
|
310
|
+
action: RegistryFacetCutAction.Replace,
|
|
311
|
+
facetName: newFacetName,
|
|
312
|
+
});
|
|
313
|
+
} else if (priority < existingPriority) {
|
|
314
|
+
// Current facet has higher priority, Replace it
|
|
315
|
+
registry.set(selector, {
|
|
316
|
+
priority: priority,
|
|
317
|
+
address: currentFacetAddress,
|
|
318
|
+
action: RegistryFacetCutAction.Replace,
|
|
319
|
+
facetName: newFacetName,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
} else {
|
|
324
|
+
// New selector, simply add
|
|
325
|
+
registry.set(selector, {
|
|
326
|
+
priority: priority,
|
|
327
|
+
address: currentFacetAddress,
|
|
328
|
+
action: RegistryFacetCutAction.Add,
|
|
329
|
+
facetName: newFacetName,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/* ---------------- Remove Old Function Selectors from facets -------------- */
|
|
335
|
+
// Set functionselectors with the newFacetName and still different address to Remove
|
|
336
|
+
for (const [selector, entry] of registry.entries()) {
|
|
337
|
+
if (entry.facetName === newFacetName && entry.address !== currentFacetAddress) {
|
|
338
|
+
registry.set(selector, {
|
|
339
|
+
priority: entry.priority,
|
|
340
|
+
address: zeroAddress,
|
|
341
|
+
action: RegistryFacetCutAction.Remove,
|
|
342
|
+
facetName: newFacetName,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// `Remove` function selectors for facets no longer in config (deleted facets)
|
|
349
|
+
const facetsConfig = diamond.getDeployConfig().facets;
|
|
350
|
+
const facetNames = Object.keys(facetsConfig);
|
|
351
|
+
for (const [selector, entry] of registry.entries()) {
|
|
352
|
+
if (!facetNames.includes(entry.facetName)) {
|
|
353
|
+
registry.set(selector, {
|
|
354
|
+
priority: entry.priority,
|
|
355
|
+
address: zeroAddress,
|
|
356
|
+
action: RegistryFacetCutAction.Remove,
|
|
357
|
+
facetName: entry.facetName,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async postUpdateFunctionSelectorRegistry(diamond: Diamond): Promise<void> {
|
|
364
|
+
if (this.verbose) {
|
|
365
|
+
console.log(chalk.gray(`✅ Running post-update logic for function selector registry of diamond ${diamond.diamondName}`));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async prePerformDiamondCut(diamond: Diamond): Promise<void> {
|
|
370
|
+
if (this.verbose) {
|
|
371
|
+
console.log(chalk.gray(`🔧 Running pre-diamond cut logic for diamond ${diamond.diamondName}`));
|
|
372
|
+
}
|
|
373
|
+
await this.prePerformDiamondCutTasks(diamond);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
protected async prePerformDiamondCutTasks(diamond: Diamond): Promise<void> {
|
|
377
|
+
// This can be overridden by subclasses for custom pre-diamond cut logic
|
|
378
|
+
if (this.verbose) {
|
|
379
|
+
console.log(chalk.gray(`🔧 No pre-diamond cut tasks defined for diamond ${diamond.diamondName}`));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async performDiamondCut(diamond: Diamond): Promise<void> {
|
|
384
|
+
if (this.verbose) {
|
|
385
|
+
console.log(chalk.yellowBright(`\n🪓 Performing diamond cut for diamond ${diamond.diamondName}...`));
|
|
386
|
+
}
|
|
387
|
+
await this.performDiamondCutTasks(diamond);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
protected async performDiamondCutTasks(diamond: Diamond): Promise<void> {
|
|
391
|
+
const diamondSignerAddress = await diamond.getSigner()?.getAddress()!;
|
|
392
|
+
const signer = await hre.ethers.getSigner(diamondSignerAddress!);
|
|
393
|
+
const diamondContract = await hre.ethers.getContractAt("IDiamondCut", diamond.getDeployedDiamondData().DiamondAddress!);
|
|
394
|
+
const signerDiamondContract = diamondContract.connect(signer);
|
|
395
|
+
const deployConfig = diamond.getDeployConfig();
|
|
396
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
397
|
+
|
|
398
|
+
// Setup initCallData with Atomic Protocol Initializer
|
|
399
|
+
const [initCalldata, initAddress] = await this.getInitCalldata(diamond);
|
|
400
|
+
|
|
401
|
+
// extract facet cuts from the selector registry
|
|
402
|
+
const facetCuts: FacetCuts = await this.getFacetCuts(diamond);
|
|
403
|
+
|
|
404
|
+
// Validate no orphaned selectors, i.e. 'Add', 'Replace' or 'Deployed' selectors with the same facetNames but different addresses
|
|
405
|
+
await this.validateNoOrphanedSelectors(facetCuts);
|
|
406
|
+
|
|
407
|
+
if (this.verbose) {
|
|
408
|
+
console.log(chalk.yellowBright(`\n🪓 Performing DiamondCut with ${facetCuts.length} cut(s):`));
|
|
409
|
+
for (const cut of facetCuts) {
|
|
410
|
+
console.log(chalk.bold(`- ${FacetCutAction[cut.action]} for facet ${cut.name} at ${cut.facetAddress}`));
|
|
411
|
+
console.log(chalk.gray(` Selectors:`), cut.functionSelectors);
|
|
412
|
+
}
|
|
413
|
+
if (initAddress !== ethers.ZeroAddress) {
|
|
414
|
+
console.log(chalk.cyan(`Initializing with functionSelector ${initCalldata} on ProtocolInitFacet ${deployConfig.protocolInitFacet} @ ${initAddress}`));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* -------------------------- Perform the diamond cut -----------------------*/
|
|
419
|
+
const facetSelectorCutMap = facetCuts.map(fc => ({ facetAddress: fc.facetAddress, action: fc.action, functionSelectors: fc.functionSelectors }));
|
|
420
|
+
const tx = await (signerDiamondContract as any).diamondCut(
|
|
421
|
+
facetSelectorCutMap,
|
|
422
|
+
initAddress,
|
|
423
|
+
initCalldata
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
/* --------------------- Update the deployed diamond data ------------------ */
|
|
427
|
+
const txHash = tx.hash;
|
|
428
|
+
await this.postDiamondCutDeployedDataUpdate(diamond, txHash);
|
|
429
|
+
|
|
430
|
+
const ifaceList = getDeployedFacetInterfaces(deployedDiamondData);
|
|
431
|
+
// Log the transaction
|
|
432
|
+
if (this.verbose) {
|
|
433
|
+
await logTx(tx, "DiamondCut", ifaceList);
|
|
434
|
+
} else {
|
|
435
|
+
console.log(chalk.blueBright(`🔄 Waiting for DiamondCut transaction to be mined...`));
|
|
436
|
+
await tx.wait();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
console.log(chalk.green(`✅ DiamondCut executed: ${tx.hash}`));
|
|
441
|
+
|
|
442
|
+
for (const [facetName, initFunction] of diamond.initializerRegistry.entries()) {
|
|
443
|
+
console.log(chalk.blueBright(`▶ Running ${initFunction} from the ${facetName} facet`));
|
|
444
|
+
// const contract = await ethers.getContractAt(facetName, diamondSignerAddress!);
|
|
445
|
+
const facetContractName = await getContractName(facetName, diamond);
|
|
446
|
+
const initContract = await hre.ethers.getContractAt(facetContractName, diamond.getDeployedDiamondData().DiamondAddress!);
|
|
447
|
+
const signerDiamondContract = initContract.connect(signer);
|
|
448
|
+
|
|
449
|
+
const tx = await initContract[initFunction]();
|
|
450
|
+
// const tx = await signerDiamondContract.initFunction;
|
|
451
|
+
if (this.verbose) {
|
|
452
|
+
logTx(tx, `${facetName}.${initFunction}`, ifaceList);
|
|
453
|
+
} else {
|
|
454
|
+
console.log(chalk.blueBright(`🔄 Waiting for ${facetName}.${initFunction}} mined...`));
|
|
455
|
+
await tx.wait();
|
|
456
|
+
}
|
|
457
|
+
console.log(chalk.green(`✅ ${facetName}.${initFunction} executed`));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async postPerformDiamondCut(diamond: Diamond): Promise<void> {
|
|
462
|
+
if (this.verbose) {
|
|
463
|
+
console.log(chalk.gray(`✅ Running post-diamond cut logic for diamond ${diamond.diamondName}`));
|
|
464
|
+
}
|
|
465
|
+
await this.postPerformDiamondCutTasks(diamond);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
protected async postPerformDiamondCutTasks(diamond: Diamond): Promise<void> { }
|
|
469
|
+
|
|
470
|
+
async getInitCalldata(diamond: Diamond): Promise<[string, string]> {
|
|
471
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
472
|
+
const deployConfig = diamond.getDeployConfig();
|
|
473
|
+
|
|
474
|
+
let initAddress = ethers.ZeroAddress;
|
|
475
|
+
let initCalldata = "0x";
|
|
476
|
+
|
|
477
|
+
const protocolInitFacet = deployConfig.protocolInitFacet || "";
|
|
478
|
+
const protocolVersion = deployConfig.protocolVersion;
|
|
479
|
+
const protocolFacetInfo = diamond.getNewDeployedFacets()[protocolInitFacet];
|
|
480
|
+
|
|
481
|
+
if (protocolInitFacet && protocolFacetInfo) {
|
|
482
|
+
const versionCfg = deployConfig.facets[protocolInitFacet]?.versions?.[protocolVersion];
|
|
483
|
+
const initFn = diamond.newDeployment ? versionCfg?.deployInit : versionCfg?.upgradeInit;
|
|
484
|
+
|
|
485
|
+
if (initFn) {
|
|
486
|
+
const iface = new ethers.Interface([`function ${initFn}`]);
|
|
487
|
+
initAddress = protocolFacetInfo.address!;
|
|
488
|
+
initCalldata = iface.encodeFunctionData(initFn);
|
|
489
|
+
if (this.verbose) {
|
|
490
|
+
console.log(
|
|
491
|
+
chalk.cyan(`🔧 Using protocol-wide initializer: ${protocolInitFacet}.${initFn}()`)
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (initAddress === ethers.ZeroAddress) {
|
|
498
|
+
console.log(chalk.yellow(`⚠️ No protocol-wide initializer found. Using zero address.`));
|
|
499
|
+
}
|
|
500
|
+
diamond.setInitAddress(initAddress);
|
|
501
|
+
return [initCalldata, initAddress];
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async getFacetCuts(diamond: Diamond): Promise<FacetCuts> {
|
|
505
|
+
const deployConfig = diamond.getDeployConfig();
|
|
506
|
+
const selectorRegistry = diamond.functionSelectorRegistry;
|
|
507
|
+
/* -------------------------- Prepare the facet cuts -----------------------*/
|
|
508
|
+
// extract facet cuts from the selector registry
|
|
509
|
+
const facetCuts = Array.from(selectorRegistry.entries())
|
|
510
|
+
.filter(([_, entry]) => entry.action !== RegistryFacetCutAction.Deployed)
|
|
511
|
+
.map(([selector, entry]) => {
|
|
512
|
+
return {
|
|
513
|
+
facetAddress: entry.address,
|
|
514
|
+
action: entry.action,
|
|
515
|
+
functionSelectors: [selector],
|
|
516
|
+
name: entry.facetName,
|
|
517
|
+
};
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
return facetCuts;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async validateNoOrphanedSelectors(facetCuts: FacetCuts): Promise<void> {
|
|
524
|
+
// Validate no orphaned selectors, i.e. 'Add', 'Replace' or 'Deployed' selectors with the same facetNames but different addresses
|
|
525
|
+
const orphanedSelectors = facetCuts.filter(facetCut => {
|
|
526
|
+
return facetCuts.some(otherFacetCut => {
|
|
527
|
+
return (
|
|
528
|
+
otherFacetCut.facetAddress !== facetCut.facetAddress &&
|
|
529
|
+
otherFacetCut.name === facetCut.name &&
|
|
530
|
+
(otherFacetCut.action === RegistryFacetCutAction.Add ||
|
|
531
|
+
otherFacetCut.action === RegistryFacetCutAction.Replace ||
|
|
532
|
+
otherFacetCut.action === RegistryFacetCutAction.Deployed)
|
|
533
|
+
);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
if (orphanedSelectors.length > 0) {
|
|
538
|
+
console.error(chalk.redBright(`❌ Orphaned selectors found for facet ${orphanedSelectors[0].name} at address ${orphanedSelectors[0].facetAddress}`));
|
|
539
|
+
console.error(chalk.redBright(` - ${orphanedSelectors[0].functionSelectors}`));
|
|
540
|
+
throw new Error(`Orphaned selectors found for facet ${orphanedSelectors[0].name} at address ${orphanedSelectors[0].facetAddress}`);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
async postDiamondCutDeployedDataUpdate(diamond: Diamond, txHash: string): Promise<void> {
|
|
545
|
+
const deployConfig = diamond.getDeployConfig();
|
|
546
|
+
const deployedDiamondData = diamond.getDeployedDiamondData();
|
|
547
|
+
const selectorRegistry = diamond.functionSelectorRegistry;
|
|
548
|
+
const newDeployedFacets = diamond.getNewDeployedFacets();
|
|
549
|
+
|
|
550
|
+
deployedDiamondData.protocolVersion = deployConfig.protocolVersion;
|
|
551
|
+
|
|
552
|
+
// Aggregate selectors for each facet
|
|
553
|
+
const facetSelectorsMap: Record<string, { address: string, selectors: string[] }> = {};
|
|
554
|
+
|
|
555
|
+
for (const [selector, entry] of selectorRegistry.entries()) {
|
|
556
|
+
const facetName = entry.facetName;
|
|
557
|
+
if (!facetSelectorsMap[facetName]) {
|
|
558
|
+
facetSelectorsMap[facetName] = { address: entry.address, selectors: [] };
|
|
559
|
+
}
|
|
560
|
+
if (entry.action === RegistryFacetCutAction.Add || entry.action === RegistryFacetCutAction.Replace || entry.action === RegistryFacetCutAction.Deployed) {
|
|
561
|
+
facetSelectorsMap[facetName].selectors.push(selector);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Update deployed facets with aggregated selectors
|
|
566
|
+
deployedDiamondData.DeployedFacets = deployedDiamondData.DeployedFacets || {};
|
|
567
|
+
for (const [facetName, { address, selectors }] of Object.entries(facetSelectorsMap)) {
|
|
568
|
+
if (selectors.length > 0) {
|
|
569
|
+
let facetVersion: number;
|
|
570
|
+
|
|
571
|
+
if (newDeployedFacets[facetName]) {
|
|
572
|
+
// Use the version from newly deployed facet
|
|
573
|
+
facetVersion = newDeployedFacets[facetName].version;
|
|
574
|
+
} else {
|
|
575
|
+
// For facets not in newDeployedFacets (like existing deployed facets),
|
|
576
|
+
// preserve their existing version or use 0 as default
|
|
577
|
+
facetVersion = deployedDiamondData.DeployedFacets[facetName]?.version ?? 0;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
deployedDiamondData.DeployedFacets[facetName] = {
|
|
581
|
+
address,
|
|
582
|
+
tx_hash: txHash,
|
|
583
|
+
version: facetVersion,
|
|
584
|
+
funcSelectors: selectors,
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Remove facets with no selectors
|
|
590
|
+
for (const facetName of Object.keys(deployedDiamondData.DeployedFacets)) {
|
|
591
|
+
if (!facetSelectorsMap[facetName] || facetSelectorsMap[facetName].selectors.length === 0) {
|
|
592
|
+
delete deployedDiamondData.DeployedFacets[facetName];
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
diamond.updateDeployedDiamondData(deployedDiamondData);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async preRunPostDeployCallbacks(diamond: Diamond): Promise<void> {
|
|
600
|
+
if (this.verbose) {
|
|
601
|
+
console.log(chalk.gray(`🔧 Running pre-post-deploy logic for diamond ${diamond.diamondName}`));
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async runPostDeployCallbacks(diamond: Diamond): Promise<void> {
|
|
606
|
+
await this.runPostDeployCallbacksTasks(diamond);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
protected async runPostDeployCallbacksTasks(diamond: Diamond): Promise<void> {
|
|
610
|
+
console.log(`🔄 Running post-deployment callbacks...`);
|
|
611
|
+
|
|
612
|
+
const deployConfig = diamond.getDeployConfig();
|
|
613
|
+
|
|
614
|
+
for (const [facetName, facetConfig] of Object.entries(deployConfig.facets)) {
|
|
615
|
+
if (!facetConfig.versions) continue;
|
|
616
|
+
|
|
617
|
+
for (const [version, config] of Object.entries(facetConfig.versions)) {
|
|
618
|
+
if (config.callbacks) {
|
|
619
|
+
const args: CallbackArgs = {
|
|
620
|
+
diamond: diamond,
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
console.log(chalk.cyanBright(`Executing callback ${config.callbacks} for facet ${facetName}...`));
|
|
624
|
+
await diamond.callbackManager.executeCallback(
|
|
625
|
+
facetName,
|
|
626
|
+
config.callbacks,
|
|
627
|
+
args
|
|
628
|
+
);
|
|
629
|
+
|
|
630
|
+
console.log(chalk.magenta(`✅ Callback ${config.callbacks} executed for facet ${facetName}`));
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
console.log(chalk.greenBright`✅ All post-deployment callbacks executed.`);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
async postRunPostDeployCallbacks(diamond: Diamond): Promise<void> {
|
|
639
|
+
if (this.verbose) {
|
|
640
|
+
console.log(chalk.gray(`✅ Running post-post-deploy logic for diamond ${diamond.diamondName}`));
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
protected async postRunPostDeployCallbacksTasks(diamond: Diamond): Promise<void> {
|
|
645
|
+
if (this.verbose) {
|
|
646
|
+
console.log(chalk.gray(`✅ Running post-post-deploy logic for diamond ${diamond.diamondName}`));
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FacetDeploymentInfo } from "../types";
|
|
2
|
+
import { Diamond } from "../core/Diamond";
|
|
3
|
+
import { DeployedFacet, FacetsConfig } from "../schemas";
|
|
4
|
+
|
|
5
|
+
export interface DeploymentStrategy {
|
|
6
|
+
preDeployDiamond(diamond: Diamond): Promise<void>;
|
|
7
|
+
deployDiamond(diamond: Diamond): Promise<void>;
|
|
8
|
+
postDeployDiamond(diamond: Diamond): Promise<void>;
|
|
9
|
+
|
|
10
|
+
preDeployFacets(diamond: Diamond): Promise<void>;
|
|
11
|
+
deployFacets(diamond: Diamond): Promise<void>;
|
|
12
|
+
postDeployFacets(diamond: Diamond): Promise<void>;
|
|
13
|
+
|
|
14
|
+
preUpdateFunctionSelectorRegistry(diamond: Diamond): Promise<void>;
|
|
15
|
+
updateFunctionSelectorRegistry(diamond: Diamond): Promise<void>;
|
|
16
|
+
postUpdateFunctionSelectorRegistry(diamond: Diamond): Promise<void>;
|
|
17
|
+
|
|
18
|
+
prePerformDiamondCut(diamond: Diamond): Promise<void>;
|
|
19
|
+
performDiamondCut(diamond: Diamond): Promise<void>;
|
|
20
|
+
postPerformDiamondCut(diamond: Diamond): Promise<void>;
|
|
21
|
+
|
|
22
|
+
preRunPostDeployCallbacks(diamond: Diamond): Promise<void>;
|
|
23
|
+
runPostDeployCallbacks(diamond: Diamond): Promise<void>;
|
|
24
|
+
postRunPostDeployCallbacks(diamond: Diamond): Promise<void>;
|
|
25
|
+
}
|