-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathChangeOwnerToTimelock.t.sol
More file actions
150 lines (128 loc) · 4.8 KB
/
ChangeOwnerToTimelock.t.sol
File metadata and controls
150 lines (128 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
import "lib/forge-std/src/Test.sol";
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
import {HelperConfig} from "../../script/HelperConfig.s.sol";
import {LiquidityBridgeContract} from "../../src/legacy/LiquidityBridgeContract.sol";
import {LiquidityBridgeContractProxy} from "../../src/legacy/LiquidityBridgeContractProxy.sol";
import {LiquidityBridgeContractAdmin} from "../../src/legacy/LiquidityBridgeContractAdmin.sol";
contract ChangeOwnerToTimelockTest is Test {
bytes32 internal constant ADMIN_SLOT =
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
HelperConfig public helperConfig;
LiquidityBridgeContract public lbcImpl;
LiquidityBridgeContractProxy public proxy;
LiquidityBridgeContractAdmin public admin;
TimelockController public timelock;
address public proposer;
address public executor;
uint256 public minDelay;
function setUp() public {
helperConfig = new HelperConfig();
proposer = makeAddr("proposer");
executor = makeAddr("executor");
minDelay = 7 days;
HelperConfig.NetworkConfig memory cfg = helperConfig.getConfig();
lbcImpl = new LiquidityBridgeContract();
admin = new LiquidityBridgeContractAdmin();
bytes memory initData = abi.encodeCall(
LiquidityBridgeContract.initialize,
(
payable(cfg.bridge),
cfg.minimumCollateral,
cfg.minimumPegIn,
cfg.rewardPercentage,
cfg.resignDelayBlocks,
cfg.dustThreshold,
cfg.btcBlockTime,
cfg.mainnet
)
);
proxy = new LiquidityBridgeContractProxy(
address(lbcImpl),
address(admin),
initData
);
address[] memory proposers = new address[](1);
proposers[0] = proposer;
address[] memory executors = new address[](1);
executors[0] = executor;
timelock = new TimelockController(
minDelay,
proposers,
executors,
address(0)
);
}
function test_TransfersLegacyOwnershipsToTimelock() public {
LiquidityBridgeContract lbcProxy = LiquidityBridgeContract(
payable(address(proxy))
);
LiquidityBridgeContractAdmin actualAdmin = _getProxyAdmin();
lbcProxy.transferOwnership(address(timelock));
vm.prank(actualAdmin.owner());
actualAdmin.transferOwnership(address(timelock));
assertEq(lbcProxy.owner(), address(timelock), "LBC owner mismatch");
assertEq(
actualAdmin.owner(),
address(timelock),
"ProxyAdmin owner mismatch"
);
assertEq(timelock.getMinDelay(), minDelay, "minDelay mismatch");
assertTrue(
timelock.hasRole(timelock.PROPOSER_ROLE(), proposer),
"proposer missing"
);
assertTrue(
timelock.hasRole(timelock.EXECUTOR_ROLE(), executor),
"executor missing"
);
}
function test_OwnerOnlyOperationIsDelayedByTimelock() public {
LiquidityBridgeContract lbcProxy = LiquidityBridgeContract(
payable(address(proxy))
);
lbcProxy.transferOwnership(address(timelock));
address newOwner = makeAddr("newOwner");
bytes memory payload = abi.encodeWithSignature(
"transferOwnership(address)",
newOwner
);
bytes32 predecessor = bytes32(0);
bytes32 salt = keccak256("owner-op");
vm.expectRevert();
lbcProxy.transferOwnership(newOwner);
vm.prank(proposer);
timelock.schedule(
address(lbcProxy),
0,
payload,
predecessor,
salt,
minDelay
);
vm.prank(executor);
vm.expectRevert();
timelock.execute(address(lbcProxy), 0, payload, predecessor, salt);
vm.warp(block.timestamp + minDelay);
vm.prank(executor);
timelock.execute(address(lbcProxy), 0, payload, predecessor, salt);
assertEq(lbcProxy.owner(), newOwner, "timelocked owner-op failed");
}
function test_ProxyAdminStoredInExpectedSlot() public {
address proxyAdminAddress = address(
uint160(uint256(vm.load(address(proxy), ADMIN_SLOT)))
);
assertTrue(proxyAdminAddress != address(0), "EIP-1967 admin missing");
}
function _getProxyAdmin()
internal
view
returns (LiquidityBridgeContractAdmin)
{
address proxyAdminAddress = address(
uint160(uint256(vm.load(address(proxy), ADMIN_SLOT)))
);
return LiquidityBridgeContractAdmin(proxyAdminAddress);
}
}