Skip to content

Commit 84b9871

Browse files
authored
Adding deployment script for performance staking (#913)
* Adding deployment script * Update script with test runs * update to mainnet addrs * updates with latest runs and separate out deployments that are still needed * deployed pools * fix nitro * fmt * add script used to deploy updated contracts * add pause test * forge fmt
1 parent 361d090 commit 84b9871

File tree

6 files changed

+277
-86
lines changed

6 files changed

+277
-86
lines changed

synd-contracts/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,7 @@ airdrop-dry-run :; DRY_RUN=true AIRDROP_CONTRACT=${AIRDROP_CONTRACT} TOKEN_ADDRE
8888
airdrop-execute :; AIRDROP_CONTRACT=${AIRDROP_CONTRACT} TOKEN_ADDRESS=${TOKEN_ADDRESS} RPC_URL=${RPC_URL} ACCOUNT=${ACCOUNT} DEV_PUB_ADDRESS=${DEV_PUB_ADDRESS} ./script/airdrop/airdrop.sh
8989

9090
# Deploy emissions contracts
91-
deploy-emissions :; forge script script/DeployStakingContracts.s.sol:DeployStakingContracts --private-key ${PRIVATE_KEY} --rpc-url eth --broadcast -vvv
91+
deploy-emissions :; forge script script/DeployStakingContracts.s.sol:DeployStakingContracts --private-key ${PRIVATE_KEY} --rpc-url eth --broadcast -vvv
92+
93+
# Deploy performance staking
94+
deploy-performance-staking :; forge script script/DeployPerformanceStaking.s.sol:DeployPerformanceStaking --rpc-url commons --keystore ${ETH_KEYSTORE} --broadcast -vv

synd-contracts/script/DeployBlockHashRelayer.s.sol

Lines changed: 0 additions & 33 deletions
This file was deleted.

synd-contracts/script/DeployGasArchive.s.sol

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.28;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import {console2} from "forge-std/console2.sol";
6+
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
7+
8+
import {GasAggregator} from "../src/staking/GasAggregator.sol";
9+
import {BlockHashRelayer, IArbInbox, IERC20} from "../src/staking/BlockHashRelayer.sol";
10+
import {GasArchive} from "../src/staking/GasArchive.sol";
11+
import {PerformancePool} from "../src/staking/PerformancePool.sol";
12+
import {AppchainPool} from "../src/staking/AppchainPool.sol";
13+
import {Splitter} from "../src/staking/Splitter.sol";
14+
import {EmissionsReceiver} from "../src/staking/EmissionsReceiver.sol";
15+
16+
contract DeployPerformanceStaking is Script {
17+
uint256 public seqChainID = 510;
18+
uint256 public baseChainID = 8453;
19+
uint256 public commonsChainID = 510003;
20+
21+
uint256 public startingEpoch = 4;
22+
23+
address public seqChainAdmin = address(0xccc32F51073B0B1EB15746f5a2b1EE76add65CCC);
24+
25+
// Ethereum Contracts
26+
address public seqChainOutbox = address(0xf555Bc86D1C953414F676479Bf7C979b1A737E8C);
27+
28+
// Base Contracts
29+
address public arbInbox = address(0xAE824E2d20F21B222932aFC6079cDaA1EB5b2F00);
30+
address public syndToken = address(0x11dC28D01984079b7efE7763b533e6ed9E3722B9);
31+
32+
// Commons Contracts
33+
uint256 public settlementChainID = baseChainID;
34+
address public commonsAdmin = address(0x03F8b8f48a3F22109bf1F4b54b54d0fdc96E7A67);
35+
address public staking = address(0xF9637B60f27AF139FC46EAa655cFBbe4E731BCdF);
36+
address public basePool = address(0x71cF8bf70Bb4f5ba8e4B4588bacB5ee108f3Ed10);
37+
38+
// Filled in after deployment
39+
address public gasAggregatorDeployment = address(0x1aCc3a26FCB9751D5E3b698D009b9C944eb98F9e);
40+
address public blockHashSenderDeployment = address(0xD77Aa8b1743326Baeb548357f8334df911A4E58f);
41+
address public gasArchiveDeployment = address(0xAb5390d3708C78e84b82de12D3e07d94145a3C0b);
42+
address public appchainPoolDeployment = address(0xEd582132C33DE5B5A661De3D2dCe5FB8F2d8F33D);
43+
address public splitterDeployment = address(0x0000000000000000000000000000000000000000);
44+
45+
uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
46+
47+
function applyArbRollupAlias(address l1Address) internal pure returns (address l2Address) {
48+
unchecked {
49+
l2Address = address(uint160(l1Address) + offset);
50+
}
51+
}
52+
53+
function run() public {
54+
vm.startBroadcast();
55+
56+
// useTestnetValues();
57+
58+
if (block.chainid == seqChainID) {
59+
console2.log("Deploying Performance Staking Contracts on Syndicate...");
60+
deploySeqChains();
61+
} else if (block.chainid == baseChainID) {
62+
console2.log("Deploying Performance Staking Contracts on Base...");
63+
deployBase();
64+
} else if (block.chainid == commonsChainID) {
65+
console2.log("Deploying Performance Staking Contracts on Commons...");
66+
// deployCommons();
67+
// deployCommonsPools();
68+
redeployCommonsPools();
69+
} else if (block.chainid == 1) {
70+
actionsOnMainnet();
71+
} else {
72+
console2.log("Invalid chain ID:", block.chainid);
73+
revert("Invalid chain ID");
74+
}
75+
76+
vm.stopBroadcast();
77+
}
78+
79+
function useTestnetValues() public {
80+
seqChainID = 51014; // Risa
81+
baseChainID = 84532; // Base Sepolia
82+
commonsChainID = 510002; // Cheesesteak
83+
84+
startingEpoch = 2;
85+
86+
seqChainAdmin = address(0xb6235EAEADfA5839CdA207B454d98b328dFE2F3A);
87+
88+
// Ethereum Contracts
89+
seqChainOutbox = address(0x11A06E54971d7a61Ba7BCd47663Af3680E6582F9);
90+
91+
// Base Contracts
92+
arbInbox = address(0x633de5dE5a1cDfF2e9Fb62Fc955618606366dbCe);
93+
syndToken = address(0x234Faa9cdeE5822767076495A9E258Dd8F21fFD8);
94+
95+
// Commons Contracts
96+
settlementChainID = 84532;
97+
commonsAdmin = address(0xb6235EAEADfA5839CdA207B454d98b328dFE2F3A);
98+
staking = address(0x503CF45e4376fC0c8d852f96c540fFF3c1487425);
99+
basePool = address(0x55040e6DB9BC79f158d8aF5d3Ed5BB62Ddf05d9f);
100+
101+
// Filled in after deployment
102+
gasAggregatorDeployment = address(0xF37a28C21A72eCf75fde856Ed18D28D1A49fA21d);
103+
blockHashSenderDeployment = address(0x28F62871025e78a4a7C03c7287425b2eDE304E3A);
104+
gasArchiveDeployment = address(0x9D01b45D73fb63442509F3Ed757e176174811949);
105+
splitterDeployment = address(0x0000000000000000000000000000000000000000);
106+
}
107+
108+
function actionsOnMainnet() public {
109+
require(splitterDeployment != address(0), "Splitter deployment not set");
110+
console2.log("Actions on Mainnet...");
111+
console2.log("These need to be done using the admin Gnosis Safe");
112+
113+
console2.log(
114+
"1. Call 'setRelayDestinationL3(address)' on the EmissionsScheduler contract to set the relay destination to:",
115+
splitterDeployment
116+
);
117+
console2.log("2. Call 'unpause()' on EmissionsScheduler contract");
118+
}
119+
120+
function deploySeqChains() public {
121+
require(seqChainAdmin != address(0), "SeqChainAdmin not set");
122+
123+
console2.log("Deploying Sequencing Chains...");
124+
GasAggregator gasAggregator = new GasAggregator(startingEpoch, 0, 0);
125+
console2.log("GasAggregator deployed to:", address(gasAggregator));
126+
127+
if (seqChainID == 510) {
128+
console2.log("Adding mainnet chains to GasAggregator");
129+
// Only setup mainnet chains if we are on Syndicate mainnet
130+
gasAggregator.addLegacyChain(510003, address(0xbf4139c8332261d10A40b79274A4170a6B50Fc3A)); // Commons
131+
gasAggregator.addLegacyChain(63829, address(0xa8BDf301Fc4E8abC6857816220e77E4600A8C582)); // CMMT
132+
gasAggregator.addLegacyChain(510525, address(0x328dD1B8FA8ea7654520DC0C03B464aa5b7eAb89)); // Clankermon
133+
gasAggregator.addLegacyChain(574014, address(0x4F576256b2A9472677ebf271140429820a13A186)); // Stadium
134+
} else if (seqChainID == 51014) {
135+
console2.log("Adding testnet chains to GasAggregator");
136+
gasAggregator.addLegacyChain(510001, address(0x601530cF8595535746063423395b9DB1e98a801b)); // Burrata
137+
gasAggregator.addLegacyChain(510000, address(0xA9D785D1EcA06cB9Abc105a68F281044002FA903)); // Manchego
138+
gasAggregator.addLegacyChain(510002, address(0x6723cfa6de616e20e35dba0775c92FC53bB0fE15)); // Cheesesteak
139+
}
140+
141+
console2.log("=== Transfer Ownership ===");
142+
143+
gasAggregator.transferOwnership(seqChainAdmin);
144+
console2.log("GasAggregator ownership transferred to admin");
145+
}
146+
147+
function deployBase() public {
148+
console2.log("Deploying Base...");
149+
150+
BlockHashRelayer blockHashRelayer = new BlockHashRelayer(IArbInbox(arbInbox), IERC20(syndToken));
151+
console2.log("BlockHashRelayer deployed to:", address(blockHashRelayer));
152+
}
153+
154+
function deployCommons() public {
155+
require(gasAggregatorDeployment != address(0), "GasAggregator deployment not set");
156+
require(blockHashSenderDeployment != address(0), "BlockHashSender deployment not set");
157+
require(commonsAdmin != address(0), "CommonsAdmin not set");
158+
console2.log("Deploying Commons...");
159+
160+
GasArchive gasArchiveImpl = new GasArchive(applyArbRollupAlias(blockHashSenderDeployment), settlementChainID);
161+
console2.log("GasArchive implementation deployed to:", address(gasArchiveImpl));
162+
163+
bytes memory initData = abi.encodeCall(GasArchive.initialize, (startingEpoch));
164+
GasArchive gasArchive = GasArchive(address(new ERC1967Proxy(address(gasArchiveImpl), initData)));
165+
console2.log("GasArchive proxy deployed to:", address(gasArchive));
166+
167+
console2.log("=== Setup ===");
168+
169+
gasArchive.addSequencingChain(seqChainID, gasAggregatorDeployment, seqChainOutbox, false);
170+
console2.log("Sequencing Chain added to GasArchive");
171+
172+
console2.log("=== Transfer Ownership ===");
173+
174+
gasArchive.transferOwnership(commonsAdmin);
175+
console2.log("Gas Archive ownership transferred to admin");
176+
}
177+
178+
function deployCommonsPools() public {
179+
require(gasArchiveDeployment != address(0), "GasArchive deployment not set");
180+
require(commonsAdmin != address(0), "CommonsAdmin not set");
181+
console2.log("Deploying Commons (Part 2)...");
182+
183+
EmissionsReceiver emissionsReceiver = new EmissionsReceiver();
184+
console2.log("EmissionsReceiver deployed to:", address(emissionsReceiver));
185+
186+
PerformancePool performancePool = new PerformancePool(commonsAdmin, staking, gasArchiveDeployment);
187+
console2.log("PerformancePool deployed to:", address(performancePool));
188+
189+
AppchainPool appchainPool =
190+
new AppchainPool(commonsAdmin, staking, gasArchiveDeployment, address(emissionsReceiver));
191+
console2.log("AppchainPool deployed to:", address(appchainPool));
192+
193+
Splitter splitter = new Splitter(basePool, address(performancePool), address(appchainPool));
194+
console2.log("Splitter deployed to:", address(splitter));
195+
196+
console2.log("=== Add emission receivers ===");
197+
198+
if (commonsChainID == 510003) {
199+
// Only setup mainnet chains if we are on commons
200+
// emissionsReceiver.setAppchainEmissionsReceiver(510003, address(0x0000000000000000000000000000000000000000)); // Commons
201+
// emissionsReceiver.setAppchainEmissionsReceiver(63829, address(0x0000000000000000000000000000000000000000)); // CMMT
202+
emissionsReceiver.setAppchainEmissionsReceiver(510525, address(0xec0e25aBc32e5dcee851133c59a0bE9Fe6BA452A)); // Clankermon
203+
emissionsReceiver.setAppchainEmissionsReceiver(574014, address(0x6c43da7CD9f68CfEfC626155D52805d66308835c)); // Stadium
204+
emissionsReceiver.setAppchainEmissionsReceiver(88899, address(0xa0055EFF3f0f17309C09685c1417Ec4Fb9899A31)); // Unite
205+
emissionsReceiver.setAppchainEmissionsReceiver(510530, address(0xF86883ab3E6341C51B67caFFdba3cE687a5c83ff)); // OpenLoot
206+
}
207+
208+
console2.log("=== Transfer Ownership ===");
209+
210+
emissionsReceiver.transferOwnership(commonsAdmin);
211+
console2.log("EmissionsReceiver ownership transferred to admin");
212+
213+
// EmissionsReceiver deployed to: 0xf8CA1551b6878779e4F4e60fffF07EF74Ac6051e
214+
// AppchainPool deployed to: 0xEd582132C33DE5B5A661De3D2dCe5FB8F2d8F33D
215+
216+
// DEPRECATED
217+
// Splitter deployed to: 0xF37a28C21A72eCf75fde856Ed18D28D1A49fA21d
218+
}
219+
220+
function redeployCommonsPools() public {
221+
require(gasArchiveDeployment != address(0), "GasArchive deployment not set");
222+
require(commonsAdmin != address(0), "CommonsAdmin not set");
223+
require(appchainPoolDeployment != address(0), "AppchainPool deployment not set");
224+
console2.log("Redeploying Commons (Part 3)...");
225+
226+
PerformancePool performancePool = new PerformancePool(commonsAdmin, staking, gasArchiveDeployment);
227+
console2.log("PerformancePool deployed to:", address(performancePool));
228+
229+
Splitter splitter = new Splitter(basePool, address(performancePool), appchainPoolDeployment);
230+
console2.log("Splitter deployed to:", address(splitter));
231+
232+
// PerformancePool deployed to: 0x5A25d511b8cCF2894950243D1C57CA9F1447cabA
233+
// Splitter deployed to: 0x789D425A45557a9743029F937A3BA9aAC0827008
234+
}
235+
}

synd-contracts/src/staking/GasArchive.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ contract GasArchive is Initializable, OwnableUpgradeable, IGasDataProvider, UUPS
130130
* 3. Therefore, the immutable values from the implementation are used during proxy execution
131131
* 4. Storage variables, however, must be initialized through the proxy to affect proxy storage
132132
*
133-
* @param _blockHashSender Address authorized to send block hashes (immutable - part of bytecode)
133+
* @param _blockHashSender Address authorized to send block hashes (immutable - part of bytecode) IMPORTANT: This address must be the alias of the actual block hash sender address on Base
134134
* @param _settlementChainID Chain ID of the settlement chain (immutable - part of bytecode)
135135
*/
136136
constructor(address _blockHashSender, uint256 _settlementChainID) {

synd-contracts/test/gas-tracking/GasTrackingTest.t.sol

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
1313
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
1414
import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol";
1515
import {Comparators} from "@openzeppelin/contracts/utils/Comparators.sol";
16+
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
1617

1718
contract MockGasCounter {
1819
mapping(uint256 => uint256) public tokensUsedPerEpoch;
@@ -314,6 +315,42 @@ contract GasAggregatorTest is Test {
314315
gasAggregator.aggregateTokens(new uint256[](0), new uint256[](0));
315316
}
316317

318+
function test_pause() public {
319+
// Set up chains 1, 2, and 3
320+
uint256[] memory chains = new uint256[](3);
321+
chains[0] = 1;
322+
chains[1] = 2;
323+
chains[2] = 3;
324+
setupChainsWithOverrides(chains);
325+
326+
uint256[] memory gasUsage = new uint256[](3);
327+
gasUsage[0] = 100;
328+
gasUsage[1] = 101;
329+
gasUsage[2] = 100;
330+
331+
// Set gas usage for current epoch
332+
uint256 epoch = 1;
333+
mockGasCounter1.setTokensForEpoch(epoch, gasUsage[0]);
334+
mockGasCounter2.setTokensForEpoch(epoch, gasUsage[1]);
335+
mockGasCounter3.setTokensForEpoch(epoch, gasUsage[2]);
336+
337+
// Move to next epoch
338+
vm.warp(block.timestamp + EPOCH_DURATION);
339+
340+
vm.prank(admin);
341+
gasAggregator.pause();
342+
assertEq(gasAggregator.paused(), true);
343+
344+
vm.expectRevert(Pausable.EnforcedPause.selector);
345+
gasAggregator.aggregateTokens(new uint256[](0), new uint256[](0));
346+
347+
vm.prank(admin);
348+
gasAggregator.unpause();
349+
assertEq(gasAggregator.paused(), false);
350+
351+
gasAggregator.aggregateTokens(new uint256[](0), new uint256[](0));
352+
}
353+
317354
function test_quickSort() public pure {
318355
uint256[] memory keys = new uint256[](5);
319356
keys[0] = 0;

0 commit comments

Comments
 (0)