-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathBaseBurner.vy
229 lines (185 loc) · 6.26 KB
/
BaseBurner.vy
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# @version 0.3.3
"""
@title Base Burner
@notice Converts underlying coins to baoUSD and transfers to fee distributor
"""
from vyper.interfaces import ERC20
interface Stabilizer:
def buy(amount: uint256): nonpayable
baoUSD: constant(address) = 0x7945b0A6674b175695e5d1D08aE1e6F13744Abb0
ballast: constant(address) = 0x720282BB7e721634c95F0933636DE3171dc405de
is_approved: HashMap[address, bool]
receiver: public(address)
recovery: public(address)
is_killed: public(bool)
owner: public(address)
emergency_owner: public(address)
future_owner: public(address)
future_emergency_owner: public(address)
@external
def __init__(_receiver: address, _recovery: address, _owner: address, _emergency_owner: address):
"""
@notice Contract constructor
@param _receiver Address that converted tokens are transferred to. #FEE DISTRIBUTOR
Should be set to an `UnderlyingBurner` deployment.
@param _recovery Address that tokens are transferred to during an #EMERGENCY DAO MULTI-SIG
emergency token recovery.
@param _owner Owner address. Can kill the contract, recover tokens
and modify the recovery address.
@param _emergency_owner Emergency owner address. Can kill the contract
and recover tokens.
"""
self.receiver = _receiver
self.recovery = _recovery
self.owner = _owner
self.emergency_owner = _emergency_owner
# infinite approval for baoUSD
response: Bytes[32] = raw_call(
baoUSD,
concat(
method_id("approve(address,uint256)"),
convert(ballast, bytes32),
convert(MAX_UINT256, bytes32),
),
max_outsize=32,
)
if len(response) != 0:
assert convert(response, bool)
@payable
@external
def burn(_coin: address) -> bool:
"""
@notice Receive `_coin` and if not already baoUSD, swap for baoUSD using ballast
@param _coin Address of the coin being received
@return bool success
"""
assert not self.is_killed # dev: is killed
# transfer coins from caller
amount: uint256 = ERC20(_coin).balanceOf(msg.sender)
if amount != 0:
response: Bytes[32] = raw_call(
_coin,
concat(
method_id("transferFrom(address,address,uint256)"),
convert(msg.sender, bytes32),
convert(self, bytes32),
convert(amount, bytes32),
),
max_outsize=32,
)
if len(response) != 0:
assert convert(response, bool)
# if not baoUSD, swap it for baoUSD using the ballast
if _coin != baoUSD:
if not self.is_approved[_coin]:
response: Bytes[32] = raw_call(
_coin,
concat(
method_id("approve(address,uint256)"),
convert(ballast, bytes32),
convert(MAX_UINT256, bytes32),
),
max_outsize=32,
)
if len(response) != 0:
assert convert(response, bool)
self.is_approved[_coin] = True
# get actual balance in case of transfer fee or pre-existing balance
amount = ERC20(_coin).balanceOf(self)
if amount != 0:
Stabilizer(ballast).buy(amount)
return True
@external
def execute() -> bool:
"""
@notice transfer baoUSD to the fee distributor
@return bool success
"""
assert not self.is_killed # dev: is killed
amount: uint256 = ERC20(baoUSD).balanceOf(self)
if amount != 0:
ERC20(baoUSD).transfer(self.receiver, amount) #transfer baoUSD to fee distributor
return True
@external
def recover_balance(_coin: address) -> bool:
"""
@notice Recover ERC20 tokens from this contract
@dev Tokens are sent to the recovery address
@param _coin Token address
@return bool success
"""
assert msg.sender in [self.owner, self.emergency_owner] # dev: only owner
amount: uint256 = ERC20(_coin).balanceOf(self)
response: Bytes[32] = raw_call(
_coin,
concat(
method_id("transfer(address,uint256)"),
convert(self.recovery, bytes32),
convert(amount, bytes32),
),
max_outsize=32,
)
if len(response) != 0:
assert convert(response, bool)
return True
@external
def set_recovery(_recovery: address) -> bool:
"""
@notice Set the token recovery address
@param _recovery Token recovery address
@return bool success
"""
assert msg.sender == self.owner # dev: only owner
self.recovery = _recovery
return True
@external
def set_killed(_is_killed: bool) -> bool:
"""
@notice Set killed status for this contract
@dev When killed, the `burn` function cannot be called
@param _is_killed Killed status
@return bool success
"""
assert msg.sender in [self.owner, self.emergency_owner] # dev: only owner
self.is_killed = _is_killed
return True
@external
def commit_transfer_ownership(_future_owner: address) -> bool:
"""
@notice Commit a transfer of ownership
@dev Must be accepted by the new owner via `accept_transfer_ownership`
@param _future_owner New owner address
@return bool success
"""
assert msg.sender == self.owner # dev: only owner
self.future_owner = _future_owner
return True
@external
def accept_transfer_ownership() -> bool:
"""
@notice Accept a transfer of ownership
@return bool success
"""
assert msg.sender == self.future_owner # dev: only owner
self.owner = msg.sender
return True
@external
def commit_transfer_emergency_ownership(_future_owner: address) -> bool:
"""
@notice Commit a transfer of ownership
@dev Must be accepted by the new owner via `accept_transfer_ownership`
@param _future_owner New owner address
@return bool success
"""
assert msg.sender == self.emergency_owner # dev: only owner
self.future_emergency_owner = _future_owner
return True
@external
def accept_transfer_emergency_ownership() -> bool:
"""
@notice Accept a transfer of ownership
@return bool success
"""
assert msg.sender == self.future_emergency_owner # dev: only owner
self.emergency_owner = msg.sender
return True