Skip to content

Commit 1129987

Browse files
authored
Merge pull request #328 from golemfoundation/support/use-fixed-addresses-for-deployed-contracts
chore: modify deployment script to use officially deployed contracts
2 parents 9108009 + a6b9316 commit 1129987

File tree

3 files changed

+359
-39
lines changed

3 files changed

+359
-39
lines changed

script/deployment/staging/DeployProtocol.s.sol

Lines changed: 125 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { DeploySkyCompounderStrategyFactory } from "script/deploy/DeploySkyCompo
1515
import { DeployMorphoCompounderStrategyFactory } from "script/deploy/DeployMorphoCompounderStrategyFactory.sol";
1616
import { DeployRegenStakerFactory } from "script/deploy/DeployRegenStakerFactory.sol";
1717
import { DeployAllocationMechanismFactory } from "script/deploy/DeployAllocationMechanismFactory.sol";
18+
import { DeployedAddresses } from "script/helpers/DeployedAddresses.sol";
1819

1920
/**
2021
* @title DeployProtocol
@@ -35,6 +36,9 @@ contract DeployProtocol is Script {
3536
DeployRegenStakerFactory public deployRegenStakerFactory;
3637
DeployAllocationMechanismFactory public deployAllocationMechanismFactory;
3738

39+
// Address registry for network-specific deployments
40+
DeployedAddresses public immutable deployedAddresses;
41+
3842
// Deployed contract addresses
3943
address public moduleProxyFactoryAddress;
4044
address public linearAllowanceSingletonForGnosisSafeAddress;
@@ -50,9 +54,20 @@ contract DeployProtocol is Script {
5054
address public morphoCompounderStrategyFactoryAddress;
5155
address public regenStakerFactoryAddress;
5256
address public allocationMechanismFactoryAddress;
57+
// External strategy contracts (tracked for reference, not deployed by this script)
58+
address public yieldDonatingTokenizedStrategyAddress;
59+
address public yearnV3StrategyFactoryAddress;
5360

5461
error DeploymentFailed();
5562

63+
/**
64+
* @notice Constructor to initialize the deployed addresses registry
65+
* @dev Initializes the immutable deployedAddresses variable once
66+
*/
67+
constructor() {
68+
deployedAddresses = new DeployedAddresses();
69+
}
70+
5671
function setUp() public {
5772
// Initialize deployment scripts
5873
deployModuleProxyFactory = new DeployModuleProxyFactory(msg.sender, msg.sender, msg.sender);
@@ -68,66 +83,140 @@ contract DeployProtocol is Script {
6883
deployAllocationMechanismFactory = new DeployAllocationMechanismFactory();
6984
}
7085

86+
/**
87+
* @notice Load previously deployed contract addresses for the current network
88+
* @dev Uses DeployedAddresses helper to get network-specific addresses via DEPLOYMENT_NETWORK env var
89+
* Any address set to address(0) will trigger fresh deployment in the run() function
90+
* Set DEPLOYMENT_NETWORK to: "mainnet", "sepolia", "staging", or "anvil"
91+
*/
92+
function setUpDeployedContracts() public {
93+
DeployedAddresses.ContractAddresses memory addresses = deployedAddresses.getAddressesByEnv();
94+
95+
// Load all addresses from the centralized registry
96+
// Note: yieldDonatingTokenizedStrategy and yearnV3StrategyFactory are EXTERNAL dependencies,
97+
// not deployed by this script. They are pre-existing contracts we reference.
98+
moduleProxyFactoryAddress = addresses.moduleProxyFactory;
99+
linearAllowanceSingletonForGnosisSafeAddress = addresses.linearAllowanceSingleton;
100+
dragonTokenizedStrategyAddress = addresses.dragonTokenizedStrategy;
101+
dragonRouterAddress = addresses.dragonRouter;
102+
splitCheckerAddress = addresses.splitChecker;
103+
mockStrategySingletonAddress = addresses.mockStrategySingleton;
104+
mockTokenAddress = addresses.mockToken;
105+
mockYieldSourceAddress = addresses.mockYieldSource;
106+
hatsAddress = addresses.hats;
107+
paymentSplitterFactoryAddress = addresses.paymentSplitterFactory;
108+
skyCompounderStrategyFactoryAddress = addresses.skyCompounderStrategyFactory;
109+
morphoCompounderStrategyFactoryAddress = addresses.morphoCompounderStrategyFactory;
110+
regenStakerFactoryAddress = addresses.regenStakerFactory;
111+
allocationMechanismFactoryAddress = addresses.allocationMechanismFactory;
112+
yieldDonatingTokenizedStrategyAddress = addresses.yieldDonatingTokenizedStrategy;
113+
yearnV3StrategyFactoryAddress = addresses.yearnV3StrategyFactory;
114+
}
115+
71116
function run() public {
72117
string memory startingBlock = vm.toString(block.number);
73118

74119
setUp();
120+
setUpDeployedContracts();
75121

76122
// Deploy Module Proxy Factory
77-
deployModuleProxyFactory.deploy();
78-
moduleProxyFactoryAddress = address(deployModuleProxyFactory.moduleProxyFactory());
79-
if (moduleProxyFactoryAddress == address(0)) revert DeploymentFailed();
123+
if (moduleProxyFactoryAddress == address(0)) {
124+
deployModuleProxyFactory.deploy();
125+
moduleProxyFactoryAddress = address(deployModuleProxyFactory.moduleProxyFactory());
126+
if (moduleProxyFactoryAddress == address(0)) revert DeploymentFailed();
127+
}
80128

81129
// Deploy LinearAllowanceSingletonForGnosisSafe
82-
deployLinearAllowanceSingletonForGnosisSafe.deploy();
83-
linearAllowanceSingletonForGnosisSafeAddress = address(
84-
deployLinearAllowanceSingletonForGnosisSafe.linearAllowanceSingletonForGnosisSafe()
85-
);
86-
if (linearAllowanceSingletonForGnosisSafeAddress == address(0)) revert DeploymentFailed();
130+
if (linearAllowanceSingletonForGnosisSafeAddress == address(0)) {
131+
deployLinearAllowanceSingletonForGnosisSafe.deploy();
132+
linearAllowanceSingletonForGnosisSafeAddress = address(
133+
deployLinearAllowanceSingletonForGnosisSafe.linearAllowanceSingletonForGnosisSafe()
134+
);
135+
if (linearAllowanceSingletonForGnosisSafeAddress == address(0)) revert DeploymentFailed();
136+
}
87137

88138
// Deploy Dragon Tokenized Strategy Implementation
89-
deployDragonTokenizedStrategy.deploy();
90-
dragonTokenizedStrategyAddress = address(deployDragonTokenizedStrategy.dragonTokenizedStrategySingleton());
91-
if (dragonTokenizedStrategyAddress == address(0)) revert DeploymentFailed();
139+
if (dragonTokenizedStrategyAddress == address(0)) {
140+
deployDragonTokenizedStrategy.deploy();
141+
dragonTokenizedStrategyAddress = address(deployDragonTokenizedStrategy.dragonTokenizedStrategySingleton());
142+
if (dragonTokenizedStrategyAddress == address(0)) revert DeploymentFailed();
143+
}
92144

93145
// Deploy Dragon Router
94-
deployDragonRouter.deploy();
95-
dragonRouterAddress = address(deployDragonRouter.dragonRouterProxy());
96-
if (dragonRouterAddress == address(0)) revert DeploymentFailed();
97-
splitCheckerAddress = address(deployDragonRouter.splitCheckerProxy());
146+
if (dragonRouterAddress == address(0) || splitCheckerAddress == address(0)) {
147+
if (dragonRouterAddress != address(0) || splitCheckerAddress != address(0)) {
148+
revert DeploymentFailed();
149+
}
150+
deployDragonRouter.deploy();
151+
dragonRouterAddress = address(deployDragonRouter.dragonRouterProxy());
152+
if (dragonRouterAddress == address(0)) revert DeploymentFailed();
153+
splitCheckerAddress = address(deployDragonRouter.splitCheckerProxy());
154+
}
98155

99156
// Deploy Mock Strategy
100-
deployMockStrategy.deploy();
101-
mockStrategySingletonAddress = address(deployMockStrategy.mockStrategySingleton());
102-
if (mockStrategySingletonAddress == address(0)) revert DeploymentFailed();
103-
mockTokenAddress = address(deployMockStrategy.token());
104-
mockYieldSourceAddress = address(deployMockStrategy.mockYieldSource());
157+
if (
158+
mockStrategySingletonAddress == address(0) ||
159+
mockTokenAddress == address(0) ||
160+
mockYieldSourceAddress == address(0)
161+
) {
162+
if (
163+
mockStrategySingletonAddress != address(0) ||
164+
mockTokenAddress != address(0) ||
165+
mockYieldSourceAddress != address(0)
166+
) {
167+
revert DeploymentFailed();
168+
}
169+
deployMockStrategy.deploy();
170+
mockStrategySingletonAddress = address(deployMockStrategy.mockStrategySingleton());
171+
if (mockStrategySingletonAddress == address(0)) revert DeploymentFailed();
172+
mockTokenAddress = address(deployMockStrategy.token());
173+
mockYieldSourceAddress = address(deployMockStrategy.mockYieldSource());
174+
}
105175

106176
// Deploy HATS
107-
deployHatsProtocol.deploy();
108-
hatsAddress = address(deployHatsProtocol.hats());
177+
if (hatsAddress == address(0)) {
178+
deployHatsProtocol.deploy();
179+
hatsAddress = address(deployHatsProtocol.hats());
180+
}
109181

110182
// Deploy Payment Splitter Factory
111-
deployPaymentSplitterFactory.deploy();
112-
paymentSplitterFactoryAddress = address(deployPaymentSplitterFactory.paymentSplitterFactory());
183+
if (paymentSplitterFactoryAddress == address(0)) {
184+
deployPaymentSplitterFactory.deploy();
185+
paymentSplitterFactoryAddress = address(deployPaymentSplitterFactory.paymentSplitterFactory());
186+
if (paymentSplitterFactoryAddress == address(0)) revert DeploymentFailed();
187+
}
113188

114189
// Deploy Compounder Strategy Factories
115-
deploySkyCompounderStrategyFactory.deploy();
116-
skyCompounderStrategyFactoryAddress = address(
117-
deploySkyCompounderStrategyFactory.skyCompounderStrategyFactory()
118-
);
119-
deployMorphoCompounderStrategyFactory.deploy();
120-
morphoCompounderStrategyFactoryAddress = address(
121-
deployMorphoCompounderStrategyFactory.morphoCompounderStrategyFactory()
122-
);
190+
if (skyCompounderStrategyFactoryAddress == address(0)) {
191+
deploySkyCompounderStrategyFactory.deploy();
192+
skyCompounderStrategyFactoryAddress = address(
193+
deploySkyCompounderStrategyFactory.skyCompounderStrategyFactory()
194+
);
195+
if (skyCompounderStrategyFactoryAddress == address(0)) revert DeploymentFailed();
196+
}
197+
198+
// Deploy Morpho Compounder Strategy Factory
199+
if (morphoCompounderStrategyFactoryAddress == address(0)) {
200+
deployMorphoCompounderStrategyFactory.deploy();
201+
morphoCompounderStrategyFactoryAddress = address(
202+
deployMorphoCompounderStrategyFactory.morphoCompounderStrategyFactory()
203+
);
204+
if (morphoCompounderStrategyFactoryAddress == address(0)) revert DeploymentFailed();
205+
}
123206

124207
// Deploy Regen Staker Factory
125-
deployRegenStakerFactory.deploy();
126-
regenStakerFactoryAddress = address(deployRegenStakerFactory.regenStakerFactory());
208+
if (regenStakerFactoryAddress == address(0)) {
209+
deployRegenStakerFactory.deploy();
210+
regenStakerFactoryAddress = address(deployRegenStakerFactory.regenStakerFactory());
211+
if (regenStakerFactoryAddress == address(0)) revert DeploymentFailed();
212+
}
127213

128214
// Deploy Allocation Mechanism Factory
129-
deployAllocationMechanismFactory.deploy();
130-
allocationMechanismFactoryAddress = address(deployAllocationMechanismFactory.allocationMechanismFactory());
215+
if (allocationMechanismFactoryAddress == address(0)) {
216+
deployAllocationMechanismFactory.deploy();
217+
allocationMechanismFactoryAddress = address(deployAllocationMechanismFactory.allocationMechanismFactory());
218+
if (allocationMechanismFactoryAddress == address(0)) revert DeploymentFailed();
219+
}
131220

132221
// Log deployment addresses
133222
console2.log("\nDeployment Summary:");

script/deployment/staging/README.md

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,39 @@ The DeployProtocol script handles the sequential deployment of:
1212
4. Dragon Router
1313
5. Mock Strategy (for testing)
1414
6. Hats Protocol & Dragon Hatter
15-
7. Payment Splitter Factory
16-
8. Sky Compounder Strategy Factory
17-
9. Morpho Compounder Strategy Factory
15+
7. Payment Splitter Factory (conditional)
16+
8. Sky Compounder Strategy Factory (conditional)
17+
9. Morpho Compounder Strategy Factory (conditional)
1818
10. Regen Staker Factory
19+
11. Allocation Mechanism Factory
20+
21+
### Smart Deployment with Address Reuse
22+
23+
The deployment script uses a centralized address registry (`script/helpers/DeployedAddresses.sol`) that:
24+
25+
- Reads the `DEPLOYMENT_NETWORK` environment variable to select the network
26+
- Loads previously deployed contract addresses for that network
27+
- Skips redeployment for contracts with existing addresses (set to non-zero)
28+
- Deploys fresh instances for contracts with address(0)
29+
30+
**Why explicit network selection?**
31+
- Tenderly staging is a mainnet FORK (chain ID = 1)
32+
- Cannot distinguish between staging and production mainnet by chain ID alone
33+
- Explicit network selection via env var prevents deployment mistakes
34+
35+
**Supported Networks:**
36+
- `mainnet` - Ethereum mainnet (production)
37+
- `sepolia` - Sepolia testnet
38+
- `staging` - Tenderly virtual testnet (mainnet fork)
39+
- `anvil` - Local Anvil testnet
40+
41+
This approach:
42+
- Saves gas by reusing stable factory contracts
43+
- Ensures consistency across deployments
44+
- Makes network-specific configuration maintainable
45+
- Prevents accidental deployments to wrong network
46+
47+
To add addresses for a new network, edit `script/helpers/DeployedAddresses.sol` and add the addresses to the appropriate network function.
1948

2049
## Prerequisites
2150

@@ -27,14 +56,26 @@ The DeployProtocol script handles the sequential deployment of:
2756

2857
Create `.env` file:
2958
```
59+
# Network selection (mainnet, sepolia, staging, or anvil)
60+
DEPLOYMENT_NETWORK=staging
61+
62+
# Deployment credentials
3063
PRIVATE_KEY=(deployer private key ex. MetaMask account)
3164
RPC_URL=https://rpc.ov2sm.octant.build
3265
VERIFIER_URL=$RPC_URL/verify/etherscan
3366
VERIFIER_API_KEY=(your Personal Tenderly accessToken)
67+
68+
# Protocol parameters
3469
MAX_OPEX_SPLIT=5 # to confirm
3570
MIN_METAPOOL_SPLIT=0 # to confirm
3671
```
3772

73+
**Important:** Set `DEPLOYMENT_NETWORK` to match your target environment:
74+
- Use `staging` for Tenderly virtual testnet (default if not set)
75+
- Use `mainnet` for production Ethereum mainnet
76+
- Use `sepolia` for Sepolia testnet
77+
- Use `anvil` for local Anvil testnet
78+
3879
## Running the Deployment
3980

4081
### Automatically

0 commit comments

Comments
 (0)