Skip to content

Commit 97b6d94

Browse files
committed
chore: Add scripts to replace SnapShotExecutor
1 parent 57c4264 commit 97b6d94

File tree

3 files changed

+172
-2
lines changed

3 files changed

+172
-2
lines changed

scripts/yearnBorg.s.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ contract YearnBorgDeployScript is Script {
4444
uint256 snapShotWaitingPeriod = 3 days; // TODO Is it still necessary?
4545
uint256 snapShotCancelPeriod = 7 days;
4646
uint256 snapShotPendingProposalLimit = 3;
47-
uint256 snapShotTtl = 30 days;
47+
uint256 snapShotOracleTtl = 30 days;
4848
address oracle = 0xf00c0dE09574805389743391ada2A0259D6b7a00;
4949

5050
SafeTxHelper safeTxHelper;
@@ -109,7 +109,7 @@ contract YearnBorgDeployScript is Script {
109109
// Create SnapShotExecutor
110110

111111
executorAuth = new BorgAuth();
112-
snapShotExecutor = new SnapShotExecutor(executorAuth, address(oracle), snapShotWaitingPeriod, snapShotCancelPeriod, snapShotPendingProposalLimit, snapShotTtl);
112+
snapShotExecutor = new SnapShotExecutor(executorAuth, address(oracle), snapShotWaitingPeriod, snapShotCancelPeriod, snapShotPendingProposalLimit, snapShotOracleTtl);
113113

114114
// Add modules
115115

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// SPDX-License-Identifier: AGPL-3.0-only
2+
pragma solidity 0.8.20;
3+
4+
import {CommonBase} from "forge-std/Base.sol";
5+
import {Script} from "forge-std/Script.sol";
6+
import {StdChains} from "forge-std/StdChains.sol";
7+
import {StdCheatsSafe} from "forge-std/StdCheats.sol";
8+
import {StdUtils} from "forge-std/StdUtils.sol";
9+
import {console2} from "forge-std/console2.sol";
10+
import {ejectImplant} from "../src/implants/ejectImplant.sol";
11+
import {sudoImplant} from "../src/implants/sudoImplant.sol";
12+
import {BorgAuth} from "../src/libs/auth.sol";
13+
import {SnapShotExecutor} from "../src/libs/governance/snapShotExecutor.sol";
14+
import {IGnosisSafe} from "../test/libraries/safe.t.sol";
15+
16+
contract YearnBorgReplaceSnapShotExecutorScript is Script {
17+
18+
// Warning: review and update the following before run
19+
20+
IGnosisSafe ychadSafe = IGnosisSafe(0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52); // ychad.eth
21+
22+
ejectImplant eject = ejectImplant(0xe44f5c9EAFB87731906AB87156E4F4cB3fa0Eb74);
23+
sudoImplant sudo = sudoImplant(0x6766b727aa1489443b34A02ee89c34f39748600b);
24+
SnapShotExecutor oldSnapShotExecutor = SnapShotExecutor(0x77691936fb6337d4B71dc62643b05b6bBE19285c);
25+
26+
// Configs: SnapShowExecutor
27+
// Reuse the old one's parameters if we are just upgrading it to a newer version
28+
uint256 snapShotWaitingPeriod = oldSnapShotExecutor.waitingPeriod();
29+
uint256 snapShotCancelPeriod = oldSnapShotExecutor.proposalExpirySeconds();
30+
uint256 snapShotPendingProposalLimit = oldSnapShotExecutor.pendingProposalLimit();
31+
uint256 snapShotOracleTtl = oldSnapShotExecutor.oracleTtl();
32+
address oracle = oldSnapShotExecutor.oracle();
33+
34+
BorgAuth executorAuth = oldSnapShotExecutor.AUTH();
35+
BorgAuth implantAuth = eject.AUTH();
36+
37+
/// @dev For running from `forge script`. Provide the deployer private key through env var.
38+
function run() public returns(SnapShotExecutor, bytes memory, bytes memory) {
39+
return run(vm.envUint("DEPLOYER_PRIVATE_KEY"));
40+
}
41+
42+
/// @dev For running in tests
43+
function run(uint256 deployerPrivateKey) public returns(SnapShotExecutor, bytes memory, bytes memory) {
44+
console2.log("Configs:");
45+
console2.log(" Safe Multisig:", address(ychadSafe));
46+
console2.log(" Eject Implant:", address(eject));
47+
console2.log(" Sudo Implant:", address(sudo));
48+
console2.log(" Old SnapShotExecutor:", address(oldSnapShotExecutor));
49+
50+
address deployerAddress = vm.addr(deployerPrivateKey);
51+
console2.log("Deployer:", deployerAddress);
52+
53+
vm.startBroadcast(deployerPrivateKey);
54+
55+
// Deploy new SnapShotExecutor
56+
SnapShotExecutor newSnapShotExecutor = new SnapShotExecutor(executorAuth, address(oracle), snapShotWaitingPeriod, snapShotCancelPeriod, snapShotPendingProposalLimit, snapShotOracleTtl);
57+
58+
vm.stopBroadcast();
59+
60+
console2.log("Deployed addresses:");
61+
console2.log(" New SnapShotExecutor: ", address(newSnapShotExecutor));
62+
63+
// Generate the proposal calldata for old SnapShotExecutor to transfer its implant ownership to the new one.
64+
// We can't just do it here. The proposal must go through the co-approval process to take effect.
65+
66+
bytes memory grantNewOwnerData = abi.encodeWithSelector(
67+
implantAuth.updateRole.selector,
68+
address(newSnapShotExecutor),
69+
implantAuth.OWNER_ROLE()
70+
);
71+
72+
bytes memory revokeOldOwnerData = abi.encodeWithSelector(
73+
implantAuth.updateRole.selector,
74+
address(oldSnapShotExecutor),
75+
0
76+
);
77+
78+
console2.log("Tx proposal for the old SnapShotExecutor:");
79+
console2.log(" to:", address(implantAuth));
80+
console2.log(" value: 0");
81+
console2.log(" data:");
82+
console2.logBytes(grantNewOwnerData);
83+
console2.log("");
84+
85+
console2.log("Tx proposal for the new SnapShotExecutor:");
86+
console2.log(" to:", address(implantAuth));
87+
console2.log(" value: 0");
88+
console2.log(" data:");
89+
console2.logBytes(revokeOldOwnerData);
90+
console2.log("");
91+
92+
return (newSnapShotExecutor, grantNewOwnerData, revokeOldOwnerData);
93+
}
94+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: AGPL-3.0-only
2+
pragma solidity 0.8.20;
3+
4+
import "forge-std/Test.sol";
5+
import {console2} from "forge-std/console2.sol";
6+
import {BorgAuth} from "../src/libs/auth.sol";
7+
import {SnapShotExecutor} from "../src/libs/governance/snapShotExecutor.sol";
8+
import {YearnBorgDeployScript} from "../scripts/yearnBorg.s.sol";
9+
import {YearnBorgAcceptanceTest} from "./yearnBorgAcceptance.t.sol";
10+
import {GnosisTransaction} from "../test/libraries/safe.t.sol";
11+
import {YearnBorgReplaceSnapShotExecutorScript} from "../scripts/yearnBorgReplaceSnapShotExecutor.s.sol";
12+
13+
/// @dev Simulate replacing SnapShotExecutor of a normal Yearn BORG deployment. The Yearn BORG acceptance tests should still pass
14+
contract YearnBorgReplaceSnapShotExecutorTest is YearnBorgAcceptanceTest {
15+
SnapShotExecutor oldSnapShotExecutor;
16+
17+
function setUp() public override {
18+
// Assume Ethereum mainnet fork after block 22377182
19+
20+
// Simulate changing ychad.eth threshold and adding the test owner so we can run tests
21+
vm.prank(address(ychadSafe));
22+
ychadSafe.addOwnerWithThreshold(testSigner, 1);
23+
24+
// MetaLex to deploy new BORG contracts and generate corresponding Safe txs for ychad.eth
25+
GnosisTransaction[] memory safeTxs;
26+
(core, eject, sudo, oldSnapShotExecutor, safeTxs) = (new YearnBorgDeployScript()).run(testSignerPrivateKey);
27+
28+
// Simulate ychad.eth executing the provided Safe TXs (set guard & add module)
29+
safeTxHelper.executeBatch(safeTxs);
30+
31+
// MetaLex to run SnapShotExecutor replacing script
32+
bytes memory grantNewOwnerData;
33+
bytes memory revokeOldOwnerData;
34+
(snapShotExecutor, grantNewOwnerData, revokeOldOwnerData) = (new YearnBorgReplaceSnapShotExecutorScript()).run(testSignerPrivateKey);
35+
36+
BorgAuth implantAuth = eject.AUTH();
37+
38+
// Simulate proposing and executing the tx granting the new SnapShotExecutor as new owner
39+
vm.prank(oracle);
40+
bytes32 grantNewOwnerProposalId = oldSnapShotExecutor.propose(address(implantAuth), 0, grantNewOwnerData, "Grant new SnapShotExecutor as owner");
41+
skip(oldSnapShotExecutor.waitingPeriod()); // After waiting period
42+
safeTxHelper.executeSingle(GnosisTransaction({
43+
to: address(oldSnapShotExecutor),
44+
value: 0,
45+
data: abi.encodeWithSelector(
46+
oldSnapShotExecutor.execute.selector,
47+
grantNewOwnerProposalId
48+
)
49+
}));
50+
51+
// Simulate proposing and executing the tx revoking the old SnapShotExecutor ownership
52+
vm.prank(oracle);
53+
bytes32 revokeOldOwnerProposalId = snapShotExecutor.propose(address(implantAuth), 0, revokeOldOwnerData, "Revoke old SnapShotExecutor ownership");
54+
skip(snapShotExecutor.waitingPeriod()); // After waiting period
55+
safeTxHelper.executeSingle(GnosisTransaction({
56+
to: address(snapShotExecutor),
57+
value: 0,
58+
data: abi.encodeWithSelector(
59+
snapShotExecutor.execute.selector,
60+
revokeOldOwnerProposalId
61+
)
62+
}));
63+
}
64+
65+
function testReplaceSnapShotExecutorScript() public {
66+
BorgAuth implantAuth = eject.AUTH();
67+
68+
// Verify the ownership has been transferred
69+
uint256 ownerRole = implantAuth.OWNER_ROLE();
70+
implantAuth.onlyRole(ownerRole, address(snapShotExecutor));
71+
vm.expectRevert(abi.encodeWithSelector(BorgAuth.BorgAuth_NotAuthorized.selector, ownerRole, address(oldSnapShotExecutor)));
72+
implantAuth.onlyRole(ownerRole, address(oldSnapShotExecutor));
73+
}
74+
75+
// The acceptance tests will run against the overridden setup
76+
}

0 commit comments

Comments
 (0)