-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtest_transparent.py
148 lines (125 loc) · 4.89 KB
/
test_transparent.py
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
import pytest
from brownie import (
LogicContractV1,
LogicContractV2,
TransparentUpgradeableProxy,
ProxyAdmin,
Contract,
reverts,
ZERO_ADDRESS,
)
from scripts.helpful_scripts import get_account, encode_function_data
from scripts.deploy_transparent_upgradeable_proxy import *
# test that the proxy delegate the call to the implementation
def test_proxy_delegates_calls():
# Deploy
account = get_account()
logic_contract = LogicContractV1.deploy(
99,
{"from": account},
)
proxy_admin = ProxyAdmin.deploy(
{"from": account},
)
logic_contract_encoded_initializer_function = encode_function_data()
## Proxy
proxy = TransparentUpgradeableProxy.deploy(
logic_contract.address,
proxy_admin.address,
logic_contract_encoded_initializer_function,
{"from": account, "gas_limit": 1_000_000},
)
## Implementation
proxy_logic_contract = Contract.from_abi(
"LogicContractV1", proxy.address, LogicContractV1.abi
)
proxy_logic_contract.store(1, {"from": account})
assert proxy_logic_contract.retrieve() == 1
assert proxy_logic_contract.square(2, {"from": account}) != 4
# test that when we upgrade the proxy, the implementation of proxy changes and the call get delegate to the new impl.
def test_proxy_upgrades():
# Deploy
account = get_account()
logic_contract = LogicContractV1.deploy(
99,
{"from": account},
)
proxy_admin = ProxyAdmin.deploy(
{"from": account},
)
logic_contract_encoded_initializer_function = encode_function_data()
## Proxy
proxy = TransparentUpgradeableProxy.deploy(
logic_contract.address,
proxy_admin.address,
logic_contract_encoded_initializer_function,
{"from": account, "gas_limit": 1_000_000},
)
## Implementatin V1
proxy_logic_contract = Contract.from_abi(
"LogicContractV1", proxy.address, LogicContractV1.abi
)
proxy_logic_contract.store(1, {"from": account})
## Implementatin V2
logic_contract_v2 = LogicContractV2.deploy(
{"from": account},
)
proxy_logic_contract = Contract.from_abi(
"LogicContractV2", proxy.address, LogicContractV2.abi
)
# Upgrade
proxy_admin.upgrade(proxy.address, logic_contract_v2.address, {"from": account})
# storage remains
assert proxy_logic_contract.retrieve() == 1
# implementation change
assert (
proxy.implementation({"from": proxy_admin}).return_value
== logic_contract_v2.address
)
# delegate call to new implementation
assert proxy_logic_contract.square(2, {"from": account}) == 4
# test that only the owner can call proxy function and owner cant call the implementation through the proxy
# and selector clashes are handle correctly
def test_proxy_selector_clashing():
user = get_account(2)
# Deploy everything and upgrade
proxy_admin, _, logic_contract_v2, proxy = deploy_and_upgrade_to_V2()
proxy_logic_contract = Contract.from_abi(
"LogicContractV2", proxy.address, LogicContractV2.abi
)
# user shouldn't be able to call a function which belong to the proxy
with reverts():
proxy.implementation({"from": user})
# owner shouldn't be able to call a function which belong to the logic
with reverts("TransparentUpgradeableProxy: admin cannot fallback to proxy target"):
proxy_logic_contract.retrieve({"from": proxy_admin})
# owner can still call the implementation directly, but will get the wrong storage
proxy_logic_contract.store(1, {"from": user})
assert logic_contract_v2.retrieve({"from": proxy_admin}) == 0
assert proxy_logic_contract.retrieve({"from": user}) == 1
# Selector clashing
# user calls LogicContractV2.admin which return address(0)
assert proxy_logic_contract.admin({"from": user}) == ZERO_ADDRESS
# admin calls TransparentUpradeableProxy.admin which return the admin of the proxy
assert proxy_logic_contract.admin({"from": proxy_admin}) == proxy_admin
# test that the values given in the constructor are not set in the proxy storage
def test_constructor():
_, v1, proxy = deploy_proxy_V1()
proxy_logic_contract = Contract.from_abi(
"LogicContractV1", proxy.address, LogicContractV1.abi
)
assert v1.retrieve() == 99
assert proxy_logic_contract.retrieve() != 99
# test the initialize function
def test_initialize():
user = get_account(2)
admin, v1, proxy = deploy_proxy_V1()
proxy_logic_contract = Contract.from_abi(
"LogicContractV2", proxy.address, LogicContractV2.abi
)
v2 = deploy_logic_contractV2()
initialize_data = encode_function_data(v2.initialize, 33)
upgrade_and_call(proxy, v2, admin, initialize_data)
assert proxy_logic_contract.retrieve() == 33
with reverts("Initializable: contract is already initialized"):
proxy_logic_contract.initialize(1, {"from": user})