Contract con_liq_mining_weth_wp


Contract Code


  
1 # Imports
2
3 # Reward Token
4 import con_uwarriors_lst001
5
6 # AMM Contract
7 import con_rocketswap_official_v1_1
8
9 # Setup Tokens
10
11 DEX = con_rocketswap_official_v1_1
12 LIQUIDITY_TOKEN = "con_weth_lst001"
13 YIELD_TOKEN = con_uwarriors_lst001
14
15 # State
16
17 Owner = Variable()
18 DevRewardWallet = Variable()
19 EmissionRatePerHour = Variable()
20 DevRewardPct = Variable()
21 StartTime = Variable()
22 EndTime = Variable()
23 OpenForBusiness = Variable() # If false, users will be unable to join the pool
24
25 Deposits = Hash(default_value=False)
26 Withdrawals = Hash(default_value=0)
27 CurrentEpochIndex = Variable()
28 Epochs = Hash(default_value=False)
29 StakedBalance = Variable() # The total amount of farming token in the vault.
30 WithdrawnBalance = Variable()
31 EpochMinTime = Variable() # The minimum amount of seconds in Epoch
32 EpochMaxRatioIncrease = (
33 Variable()
34 ) # The maximum ratio which the Epoch can increase by since last Epoch before incrementing.
35 meta = Hash(default_value=False)
36 decimal_converter_var = Variable()
37 TrustedImporters = Variable()
38
39 # Vtoken
40 balances = Hash(default_value=0)
41
42 @construct
43 def seed():
44 Owner.set(ctx.caller)
45 DevRewardWallet.set(ctx.caller)
46 CurrentEpochIndex.set(0)
47 StakedBalance.set(0)
48 WithdrawnBalance.set(0)
49 EpochMaxRatioIncrease.set(10)
50 EpochMinTime.set(86000)
51 TrustedImporters.set([])
52
53 Epochs[0] = {"time": now, "staked": 0, "amt_per_hr": 38}
54 EmissionRatePerHour.set(38) # 11507 / 24 * 0.8
55
56 meta["version"] = "0.5"
57 meta["type"] = "liquidity_mining_smart_epoch"
58 meta["STAKING_TOKEN"] = "con_uwarriors_lst001"
59 meta["YIELD_TOKEN"] = "con_uwarriors_lst001"
60
61 DevRewardPct.set(1 / 20)
62
63 StartTime.set(datetime.datetime(year=2021, month=8, day=7, hour=23))
64 EndTime.set(datetime.datetime(year=2022, month=8, day=7, hour=23))
65
66 OpenForBusiness.set(True)
67
68
69 @export
70 def addStakingTokens(amount: float):
71 user = ctx.caller
72 deposit = Deposits[user]
73
74 if deposit is False:
75 return createNewDeposit(amount=amount)
76 else:
77 return increaseDeposit(amount=amount)
78
79
80 def createNewDeposit(
81 amount: float
82 ):
83 assert OpenForBusiness.get() == True, "This staking pool is not open right now."
84 assert amount > 0, "You must stake something."
85
86 user = ctx.caller
87
88 # Take the staking tokens from the user's wallet
89 DEX.transfer_liquidity_from(
90 contract=LIQUIDITY_TOKEN, to=ctx.this, main_account=user, amount=amount
91 )
92
93 # Update the Staked amount
94 staked = StakedBalance.get()
95 new_staked_amount = staked + amount
96 StakedBalance.set(new_staked_amount)
97
98 # Update the Epoch
99 epoch_index = decideIncrementEpoch(new_staked_amount=new_staked_amount)
100
101 # Create a record of the user's deposit
102
103 Deposits[user] = {
104 "starting_epoch": epoch_index,
105 "time": now,
106 "amount": amount,
107 "user_yield": 0,
108 }
109
110 # mint vtoken equal to the deposit.
111 mintVToken(amount=amount)
112 return Deposits[user]
113
114
115 @export
116 def increaseDeposit(
117 amount: float
118 ):
119
120 user = ctx.caller
121 assert OpenForBusiness.get() == True, "This staking pool is not open right now."
122 assert amount > 0, "You cannot stake a negative balance."
123
124 deposit = Deposits[user]
125
126 assert deposit is not False, "This user has no deposit to add to."
127
128 # Take the staking tokens from the user's wallet
129 DEX.transfer_liquidity_from(
130 contract=LIQUIDITY_TOKEN, to=ctx.this, main_account=user, amount=amount
131 )
132
133 withdrawn_yield = Withdrawals[user]
134 user_yield = deposit["user_yield"]
135 existing_stake = deposit["amount"]
136 start_time = False
137
138 user_yield += calculateYield(deposit=deposit)
139 start_time = deposit["time"]
140 existing_stake = deposit["amount"]
141
142 total_deposit_amount = existing_stake + amount
143 global_amount_staked = StakedBalance.get()
144 new_global_staked = global_amount_staked + amount
145 StakedBalance.set(new_global_staked)
146
147 mintVToken(amount=amount)
148
149 Deposits[user] = {
150 "starting_epoch": decideIncrementEpoch(new_staked_amount=new_global_staked),
151 "time": now,
152 "amount": total_deposit_amount,
153 "user_yield": user_yield,
154 }
155
156 return Deposits[user]
157
158
159 @export
160 def withdrawYield(amount: float):
161 assert amount > 0, "You cannot harvest a negative balance"
162
163 user = ctx.caller
164 deposit = Deposits[user]
165
166 assert deposit is not False, "You have no deposit to withdraw yield from."
167
168 # Calculate how much yield is due per deposit account
169 withdrawn_yield = Withdrawals[user]
170 harvestable_yield = deposit["user_yield"]
171
172 harvestable_yield += calculateYield(deposit=deposit)
173
174 # Determine maximum amount of yield user can withdraw
175 harvestable_yield -= withdrawn_yield
176
177 yield_to_harvest = amount if amount < harvestable_yield else harvestable_yield
178
179 assert yield_to_harvest > 0, "There is no yield to harvest right now :("
180
181 # Take % of Yield Tokens, send it to dev fund
182 dev_share = yield_to_harvest * DevRewardPct.get()
183
184 if dev_share > 0:
185 YIELD_TOKEN.transfer(to=DevRewardWallet.get(), amount=dev_share)
186 # DEX.transfer_liquidity(contract=LIQUIDITY_TOKEN, to=user, amount=amount)
187
188 # Send remanding Yield Tokens to user
189 user_share = yield_to_harvest - dev_share
190 YIELD_TOKEN.transfer(to=user, amount=user_share)
191
192 Withdrawals[user] = withdrawn_yield + yield_to_harvest
193
194 new_withdrawn_amount = WithdrawnBalance.get() + yield_to_harvest
195 WithdrawnBalance.set(new_withdrawn_amount)
196
197
198 @export
199 def withdrawTokensAndYield():
200 user = ctx.caller
201 deposit = Deposits[user]
202
203 assert deposit is not False, "You have no deposit to withdraw"
204
205 # Calculate how much yield is due per deposit account
206 withdrawn_yield = Withdrawals[user]
207 stake_to_return = deposit["amount"]
208 yield_to_harvest = deposit["user_yield"]
209
210 yield_to_harvest += calculateYield(deposit=deposit)
211
212 # Send Staking Tokens to user
213 DEX.transfer_liquidity(contract=LIQUIDITY_TOKEN, to=user, amount=stake_to_return)
214
215 # check that the user has yield left to harvest (this should never be negative, but let's check here just in case)
216 yield_to_harvest -= withdrawn_yield
217 if yield_to_harvest > 0:
218
219 # Take % of Yield Tokens, send it to dev fund
220 dev_share = yield_to_harvest * DevRewardPct.get()
221 if dev_share > 0:
222 YIELD_TOKEN.transfer(to=DevRewardWallet.get(), amount=dev_share)
223
224 # Send remanding Yield Tokens to user
225 user_share = yield_to_harvest - dev_share
226 YIELD_TOKEN.transfer(to=user, amount=user_share)
227
228 # Reset User's Deposits
229 Deposits[user] = False
230
231 # Reset User's Withdrawal
232 Withdrawals[user] = 0
233
234 # Remove token amount from Staked
235 new_staked_amount = StakedBalance.get() - stake_to_return
236 returnAndBurnVToken(amount=stake_to_return)
237 StakedBalance.set(new_staked_amount)
238 new_withdrawn_amount = WithdrawnBalance.get() + yield_to_harvest
239 WithdrawnBalance.set(new_withdrawn_amount)
240
241 # Increment Epoch
242 decideIncrementEpoch(new_staked_amount=new_staked_amount)
243
244
245 # This runs over each of the items in the user's Deposit
246 def calculateYield(deposit):
247 starting_epoch_index = deposit.get("starting_epoch")
248 start_time = deposit.get("time")
249 amount = deposit.get("amount")
250
251 current_epoch_index = getCurrentEpochIndex()
252 this_epoch_index = starting_epoch_index
253 y = 0
254 while this_epoch_index <= current_epoch_index:
255 this_epoch = Epochs[this_epoch_index]
256 next_epoch = Epochs[this_epoch_index + 1]
257
258 delta = 0
259
260 if starting_epoch_index == current_epoch_index:
261 delta = fitTimeToRange(now) - fitTimeToRange(start_time)
262 elif this_epoch_index == starting_epoch_index:
263 delta = fitTimeToRange(next_epoch["time"]) - fitTimeToRange(start_time)
264 elif this_epoch_index == current_epoch_index:
265 delta = fitTimeToRange(now) - fitTimeToRange(this_epoch["time"])
266 else:
267 delta = fitTimeToRange(next_epoch["time"]) - fitTimeToRange(
268 this_epoch["time"]
269 )
270
271 pct_share_of_stake = 0
272 if amount is not 0 and this_epoch["staked"] is not 0:
273 pct_share_of_stake = amount / this_epoch["staked"]
274
275 # These two lines below were causing some problems, until I used the decimal method. get a python expert to review.
276 emission_rate_per_hour = this_epoch["amt_per_hr"]
277 global_yield_this_epoch = delta.seconds * getEmissionRatePerSecond(
278 emission_rate_per_hour
279 )
280 decimal_converter_var.set(pct_share_of_stake)
281 pct_share_of_stake = decimal_converter_var.get()
282 deposit_yield_this_epoch = global_yield_this_epoch * pct_share_of_stake
283 y += deposit_yield_this_epoch
284
285 this_epoch_index += 1
286
287 return y
288
289
290 def fitTimeToRange(time: Any):
291 if time < StartTime.get():
292 time = StartTime.get()
293 elif time > EndTime.get():
294 time = EndTime.get()
295 return time
296
297
298 def getCurrentEpochIndex():
299 current_epoch_index = CurrentEpochIndex.get()
300 return current_epoch_index
301
302
303 def decideIncrementEpoch(new_staked_amount: float):
304 epoch_index = getCurrentEpochIndex()
305 this_epoch = Epochs[epoch_index]
306 this_epoch_staked = this_epoch["staked"]
307 delta = now - this_epoch["time"]
308 delta_seconds = delta.seconds if delta.seconds > 0 else 0
309 if (
310 delta_seconds >= EpochMinTime.get()
311 or this_epoch_staked is 0
312 or maxStakedChangeRatioExceeded(
313 new_staked_amount=new_staked_amount, this_epoch_staked=this_epoch_staked
314 )
315 ):
316 epoch_index = incrementEpoch(new_staked_amount)
317 return epoch_index
318
319
320 def maxStakedChangeRatioExceeded(new_staked_amount: float, this_epoch_staked: float):
321 if this_epoch_staked < 0.0001 :
322 return true
323 smaller = (
324 new_staked_amount
325 if new_staked_amount <= this_epoch_staked
326 else this_epoch_staked
327 )
328 bigger = (
329 new_staked_amount
330 if new_staked_amount >= this_epoch_staked
331 else this_epoch_staked
332 )
333 dif = bigger - smaller
334 return (dif) / this_epoch_staked >= EpochMaxRatioIncrease.get()
335
336
337 def incrementEpoch(new_staked_amount: float):
338 current_epoch = getCurrentEpochIndex()
339 new_epoch_idx = current_epoch + 1
340 CurrentEpochIndex.set(new_epoch_idx)
341 Epochs[new_epoch_idx] = {
342 "time": now,
343 "staked": new_staked_amount,
344 "amt_per_hr": Epochs[current_epoch]["amt_per_hr"],
345 }
346 return new_epoch_idx
347
348
349 @export
350 def changeAmountPerHour(amount_per_hour: float):
351 assertOwner()
352 current_epoch = getCurrentEpochIndex()
353 new_epoch_idx = current_epoch + 1
354 CurrentEpochIndex.set(new_epoch_idx)
355 setEmissionRatePerHour(amount=amount_per_hour)
356
357 Epochs[new_epoch_idx] = {
358 "time": now,
359 "staked": StakedBalance.get(),
360 "amt_per_hr": amount_per_hour,
361 }
362
363
364 @export
365 def setEpochMinTime(min_seconds: float):
366 assertOwner()
367 assert min_seconds >= 0, "you must choose a positive value."
368 EpochMinTime.set(min_seconds)
369
370
371 @export
372 def setEpochMaxRatioIncrease(ratio: float):
373 assertOwner()
374 assert ratio > 0, "must be a positive value"
375 EpochMaxRatioIncrease.set(ratio)
376
377
378 def getEmissionRatePerSecond(emission_rate_per_hour: float):
379 emission_rate_per_minute = emission_rate_per_hour / 60
380 emission_rate_per_second = emission_rate_per_minute / 60
381 return emission_rate_per_second
382
383
384 @export
385 def setOwner(vk: str):
386 assertOwner()
387 Owner.set(vk)
388
389
390 @export
391 def setDevWallet(vk: str):
392 assertOwner()
393 DevRewardWallet.set(vk)
394
395
396 @export
397 def setDevRewardPct(amount: float):
398 assertOwner()
399 assert amount < 1 and amount >= 0, "Amount must be a value between 0 and 1"
400 DevRewardPct.set(amount)
401
402
403 @export
404 def setEmissionRatePerHour(amount: float):
405 assertOwner()
406 EmissionRatePerHour.set(amount)
407
408
409 @export
410 def recoverYieldToken(amount: float):
411 assertOwner()
412 YIELD_TOKEN.transfer(amount=amount, to=Owner.get())
413
414
415 @export
416 def allowStaking(is_open: bool):
417 assertOwner()
418 OpenForBusiness.set(is_open)
419
420
421 @export
422 def setStartTime(year: int, month: int, day: int, hour: int):
423 assertOwner()
424 time = datetime.datetime(year, month, day, hour)
425 StartTime.set(time)
426
427
428 @export
429 def setEndTime(year: int, month: int, day: int, hour: int):
430 assertOwner()
431 time = datetime.datetime(year, month, day, hour)
432 EndTime.set(time)
433
434
435 def assertOwner():
436 assert Owner.get() == ctx.caller, "You must be the owner to call this function."
437
438
439 # This is only to be called in emergencies - the user will forgo their yield when calling this FN.
440
441
442 @export
443 def emergencyReturnStake():
444
445 user = ctx.caller
446 deposit = Deposits[user]
447
448 assert Deposits[user] is not False, "This account has no deposits to return."
449
450 stake_to_return = deposit["amount"]
451
452 DEX.transfer_liquidity(contract=LIQUIDITY_TOKEN, to=user, amount=stake_to_return)
453 returnAndBurnVToken(amount=stake_to_return)
454 Deposits[user] = False
455 Withdrawals[user] = 0
456
457 # Remove token amount from Staked
458 new_staked_amount = StakedBalance.get() - stake_to_return
459 StakedBalance.set(new_staked_amount)
460 decideIncrementEpoch(new_staked_amount=new_staked_amount)
461
462
463 @export
464 def exportYieldToForeignContract():
465 calling_contract = ctx.caller
466 user = ctx.signer
467 withdrawn_yield = Withdrawals[user]
468
469 # verify that the contract is calling it is trusted.
470 assert (
471 calling_contract in TrustedImporters.get()
472 ), "The calling contract is not in the trusted importers list."
473
474 transferred = sendYieldToTarget(
475 amount=999999999999,
476 target=calling_contract,
477 user=user, # big number - transfers all yield.
478 )
479 return transferred
480
481
482 def sendYieldToTarget(amount: float, target: str, user: str):
483
484 deposit = Deposits[user]
485 assert deposit is not False, "You have no deposit to withdraw yield from."
486
487 # Calculate how much yield is due per deposit account
488 withdrawn_yield = Withdrawals[user]
489 harvestable_yield = 0
490
491 harvestable_yield += calculateYield(deposit=deposit)
492
493 # Determine maximum amount of yield user can withdraw
494 harvestable_yield -= withdrawn_yield
495
496 yield_to_harvest = amount if amount < harvestable_yield else harvestable_yield
497
498 assert yield_to_harvest > 0, "There is no yield to harvest right now :("
499
500 # Take % of Yield Tokens, send it to dev fund
501 dev_share = yield_to_harvest * DevRewardPct.get()
502
503 if dev_share > 0:
504 YIELD_TOKEN.transfer(to=DevRewardWallet.get(), amount=dev_share)
505
506 # Send remanding Yield Tokens to user
507 user_share = yield_to_harvest - dev_share
508 YIELD_TOKEN.transfer(to=target, amount=user_share)
509
510 Withdrawals[user] = withdrawn_yield + yield_to_harvest
511
512 new_withdrawn_amount = WithdrawnBalance.get() + yield_to_harvest
513 WithdrawnBalance.set(new_withdrawn_amount)
514
515 return user_share
516
517
518 @export
519 def addToTrustedImporters(contract: str):
520 assertOwner()
521 trusted_importers = TrustedImporters.get()
522 trusted_importers.append(contract)
523 TrustedImporters.set(trusted_importers)
524
525
526 @export
527 def removeFromTrustedImporters(contract: str):
528 assertOwner()
529 trusted_importers = TrustedImporters.get()
530 trusted_importers.remove(contract)
531 TrustedImporters.set(trusted_importers)
532
533
534 # VTOKEN METHODS
535 @export
536 def transfer(amount: float, to: str):
537 assert amount > 0, "Cannot send negative balances!"
538 assert balances[ctx.caller] >= amount, "Not enough VTOKENS to send!"
539 balances[ctx.caller] -= amount
540 balances[to] += amount
541
542
543 @export
544 def approve(amount: float, to: str):
545 assert amount > 0, "Cannot send negative balances!"
546 balances[ctx.caller, to] += amount
547
548
549 @export
550 def transfer_from(amount: float, to: str, main_account: str):
551 assert amount > 0, "Cannot send negative balances!"
552
553 assert (
554 balances[main_account, ctx.caller] >= amount
555 ), "Not enough coins approved to send! You have {} and are trying to spend {}".format(
556 balances[main_account, ctx.caller], amount
557 )
558 assert balances[main_account] >= amount, "Not enough coins to send!"
559 balances[main_account, ctx.caller] -= amount
560 balances[main_account] -= amount
561 balances[to] += amount
562
563
564 def returnAndBurnVToken(amount: float):
565 user = ctx.caller
566 assert (
567 balances[user] >= amount
568 ), "Your VTOKEN balance is too low to unstake, recover your VTOKENS and try again."
569 balances[user] -= amount
570
571
572 def mintVToken(amount: float):
573 user = ctx.caller
574 balances[user] += amount

Byte Code

e300000000000000000000000006000000400000007398030000640064016c005a00640064016c015a0165015a0264025a0365005a0465056403640464058d025a0665056403640664058d025a0765056403640764058d025a0865056403640864058d025a0965056403640964058d025a0a65056403640a64058d025a0b65056403640b64058d025a0c650d640c6403640d640e8d035a0e650d64006403640f640e8d035a0f65056403641064058d025a10650d640c64036411640e8d035a1165056403641264058d025a1265056403641364058d025a1365056403641464058d025a1465056403641564058d025a15650d640c64036416640e8d035a1665056403641764058d025a1765056403641864058d025a18650d640064036419640e8d035a19641a641b84005a1a651b64038301651c641c9c01641d641e840483015a1d651c641c9c01641f642084045a1e651b64038301651c641c9c0164216422840483015a1f651b64038301651c641c9c0164236424840483015a20651b6403830164256426840083015a216427642884005a22652364299c01642a642b84045a24642c642d84005a25651c642e9c01642f643084045a26651c651c64319c026432643384045a27651c642e9c016434643584045a28651b64038301651c64369c0164376438840483015a29651b64038301651c64399c01643a643b840483015a2a651b64038301651c643c9c01643d643e840483015a2b651c643f9c016440644184045a2c651b64038301652d64429c0164436444840483015a2e651b64038301652d64429c0164456446840483015a2f651b64038301651c641c9c0164476448840483015a30651b64038301651c641c9c016449644a840483015a31651b64038301651c641c9c01644b644c840483015a32651b640383016533644d9c01644e644f840483015a34651b64038301653565356535653564509c0464516452840483015a36651b64038301653565356535653564509c0464536454840483015a376455645684005a38651b6403830164576458840083015a39651b640383016459645a840083015a3a651c652d652d645b9c03645c645d84045a3b651b64038301652d645e9c01645f6460840483015a3c651b64038301652d645e9c0164616462840483015a3d651b64038301651c652d64639c0264646465840483015a3e651b64038301651c652d64639c0264666467840483015a3f651b64038301651c652d652d64689c036469646a840483015a40651c641c9c01646b646c84045a41651c641c9c01646d646e84045a4264015300296fe9000000004eda0f636f6e5f776574685f6c7374303031da16636f6e5f6c69715f6d696e696e675f776574685f7770da054f776e65722902da08636f6e7472616374da046e616d65da0f44657652657761726457616c6c6574da13456d697373696f6e52617465506572486f7572da0c446576526577617264506374da09537461727454696d65da07456e6454696d65da0f4f70656e466f72427573696e65737346da084465706f736974732903da0d64656661756c745f76616c756572050000007206000000da0b5769746864726177616c73da1143757272656e7445706f6368496e646578da0645706f636873da0d5374616b656442616c616e6365da1057697468647261776e42616c616e6365da0c45706f63684d696e54696d65da1545706f63684d6178526174696f496e637265617365da046d657461da15646563696d616c5f636f6e7665727465725f766172da1054727573746564496d706f7274657273da0862616c616e63657363000000000000000000000000070000004300000073d600000074006a0174026a038301010074046a0174026a038301010074056a0164018301010074066a0164018301010074076a0164018301010074086a0164028301010074096a01640383010100740a6a01670083010100740b6401640464059c03740c64013c00740d6a016404830101006406740e64073c006408740e64093c00640a740e640b3c00640a740e640c3c00740f6a0164168301010074106a0174116a11640f64106411641264138d048301010074126a0174116a11641464106411641264138d048301010074136a016415830101006400530029174e7201000000e90a00000069f04f0100e9260000002903da0474696d65da067374616b6564da0a616d745f7065725f68727a03302e35da0776657273696f6eda1c6c69717569646974795f6d696e696e675f736d6172745f65706f6368da0474797065da14636f6e5f7577617272696f72735f6c7374303031da0d5354414b494e475f544f4b454eda0b5949454c445f544f4b454ee901000000e91400000069e5070000e908000000e907000000e9170000002904da0479656172da056d6f6e7468da03646179da04686f757269e607000054679a9999999999a93f2914da075f5f4f776e6572da03736574da03637478da0663616c6c6572da115f5f44657652657761726457616c6c6574da135f5f43757272656e7445706f6368496e646578da0f5f5f5374616b656442616c616e6365da125f5f57697468647261776e42616c616e6365da175f5f45706f63684d6178526174696f496e637265617365da0e5f5f45706f63684d696e54696d65da125f5f54727573746564496d706f7274657273da036e6f77da085f5f45706f636873da155f5f456d697373696f6e52617465506572486f7572da065f5f6d657461da0e5f5f446576526577617264506374da0b5f5f537461727454696d65da086461746574696d65da095f5f456e6454696d65da115f5f4f70656e466f72427573696e657373a90072420000007242000000da00da045f5f5f5f2b000000732400000000010c010c010a010a010a010a010a010a0110010a0108010801080108010a011801180172440000002901da06616d6f756e74630100000000000000030000000300000043000000732e00000074006a017d0174027c0119007d027c0264016b08722074037c0064028d01530074047c0064028d0153006400530029034e4629017245000000290572300000007231000000da0a5f5f4465706f73697473da125f5f6372656174654e65774465706f736974da0f696e6372656173654465706f73697429037245000000da0475736572da076465706f736974724200000072420000007243000000da106164645374616b696e67546f6b656e7340000000730a00000000020601080108010a02724b000000630100000000000000050000000600000043000000738600000074006a01830064016b02731474026402830182017c0064036b047324740264048301820174036a047d0174056a06740774036a087c017c0064058d04010074096a0183007d027c027c0017007d0374096a0a7c0383010100740b7c0364068d017d047c04740c7c00640364079c04740d7c013c00740e7c0064088d010100740d7c011900530029094e547a2854686973207374616b696e6720706f6f6c206973206e6f74206f70656e207269676874206e6f772e72010000007a19596f75206d757374207374616b6520736f6d657468696e672e29047205000000da02746fda0c6d61696e5f6163636f756e7472450000002901da116e65775f7374616b65645f616d6f756e742904da0e7374617274696e675f65706f6368721c0000007245000000da0a757365725f7969656c6429017245000000290f7241000000da03676574da0e417373657274696f6e4572726f7272300000007231000000da03444558da177472616e736665725f6c69717569646974795f66726f6dda0f4c49515549444954595f544f4b454eda04746869737234000000722f000000da165f5f646563696465496e6372656d656e7445706f636872390000007246000000da0c5f5f6d696e7456546f6b656e290572450000007249000000721d000000724e000000da0b65706f63685f696e64657872420000007242000000724300000072470000004a000000731c000000000106010e01100106010a010a01080108010a010a0104010e010a0172470000006301000000000000000a000000060000004300000073dc00000074006a017d0174026a03830064016b02731a74046402830182017c0064036b04732a740464048301820174057c0119007d027c0264056b097342740464068301820174066a07740874006a097c017c0064078d040100740a7c0119007d037c02640819007d047c02640919007d0564057d067c04740b7c02640a8d0137007d047c02640b19007d067c02640919007d057c057c0017007d07740c6a0383007d087c087c0017007d09740c6a0d7c0983010100740e7c00640c8d010100740f7c09640d8d0174107c077c04640e9c0474057c013c0074057c0119005300290f4e547a2854686973207374616b696e6720706f6f6c206973206e6f74206f70656e207269676874206e6f772e72010000007a24596f752063616e6e6f74207374616b652061206e656761746976652062616c616e63652e467a2354686973207573657220686173206e6f206465706f73697420746f2061646420746f2e29047205000000724c000000724d0000007245000000725000000072450000002901724a000000721c000000290172450000002901724e0000002904724f000000721c0000007245000000725000000029117230000000723100000072410000007251000000725200000072460000007253000000725400000072550000007256000000da0d5f5f5769746864726177616c73da105f5f63616c63756c6174655969656c647234000000722f000000725800000072570000007239000000290a72450000007249000000724a000000da0f77697468647261776e5f7969656c647250000000da0e6578697374696e675f7374616b65da0a73746172745f74696d65da14746f74616c5f6465706f7369745f616d6f756e74da14676c6f62616c5f616d6f756e745f7374616b6564da116e65775f676c6f62616c5f7374616b656472420000007242000000724300000072480000005b00000073300000000002060106010e011001080110010a010a0108010801080104010e01080108010801080108010a010a01020108010e01724800000063010000000000000009000000040000004300000073d60000007c0064016b047310740064028301820174016a027d0174037c0119007d027c0264036b09732e740064048301820174047c0119007d037c02640519007d047c0474057c0264068d0137007d047c047c0338007d047c007c046b0072607c006e027c047d057c0564016b04737474006407830182017c0574066a07830014007d067c0664016b04729a74086a09740a6a0783007c0664088d0201007c057c0618007d0774086a097c017c0764088d0201007c037c05170074047c013c00740b6a0783007c0517007d08740b6a0c7c08830101006400530029094e72010000007a25596f752063616e6e6f7420686172766573742061206e656761746976652062616c616e6365467a2b596f752068617665206e6f206465706f73697420746f207769746864726177207969656c642066726f6d2e72500000002901724a0000007a295468657265206973206e6f207969656c6420746f2068617276657374207269676874206e6f77203a282902724c0000007245000000290d7252000000723000000072310000007246000000725a000000725b000000723d00000072510000007224000000da087472616e7366657272320000007235000000722f000000290972450000007249000000724a000000725c000000da116861727665737461626c655f7969656c64da107969656c645f746f5f68617276657374da096465765f7368617265da0a757365725f7368617265da146e65775f77697468647261776e5f616d6f756e74724200000072420000007243000000da0d77697468647261775969656c6477000000732600000000021001060108011001080108010e0108010c01040110010c010801120108010e010c010c01726800000063000000000000000009000000050000004300000073f400000074006a017d0074027c0019007d017c0164016b09731e740364028301820174047c0019007d027c01640319007d037c01640419007d047c0474057c0164058d0137007d0474066a0774087c007c0364068d0301007c047c0238007d047c0464076b0472a07c0474096a0a830014007d057c0564076b04728a740b6a0c740d6a0a83007c0564088d0201007c047c0518007d06740b6a0c7c007c0664088d020100640174027c003c00640774047c003c00740e6a0a83007c0318007d07740f7c0364098d010100740e6a107c078301010074116a0a83007c0417007d0874116a107c088301010074127c07640a8d01010064005300290b4e467a1f596f752068617665206e6f206465706f73697420746f207769746864726177724500000072500000002901724a00000029037205000000724c000000724500000072010000002902724c0000007245000000290172450000002901724e00000029137230000000723100000072460000007252000000725a000000725b0000007253000000da127472616e736665725f6c69717569646974797255000000723d00000072510000007224000000726200000072320000007234000000da155f5f72657475726e416e644275726e56546f6b656e722f0000007235000000725700000029097249000000724a000000725c000000da0f7374616b655f746f5f72657475726e726400000072650000007266000000724e0000007267000000724200000072420000007243000000da167769746864726177546f6b656e73416e645969656c648e000000733000000000020601080110010801080108010e0108010801080108010c010801120108010e01080108010c010a010a010c010a01726c0000006301000000000000000e0000000400000043000000732a0100007c006a00640183017d017c006a00640283017d027c006a00640383017d03740183007d047c017d0564047d0678f87c057c046b019001722474027c0519007d0774027c056405170019007d0864047d097c017c046b02726a74037404830174037c02830118007d096e547c057c016b02728874037c0864021900830174037c02830118007d096e367c057c046b0272a674037404830174037c0764021900830118007d096e1874037c0864021900830174037c0764021900830118007d0964047d0a7c0364046b0972e27c076406190064046b0972e27c037c07640619001b007d0a7c07640719007d0b7c096a0574067c0b830114007d0c74076a087c0a8301010074076a0083007d0a7c0c7c0a14007d0d7c067c0d37007d067c05640537007d05712e57007c06530029084e724f000000721c000000724500000072010000007225000000721d000000721e00000029097251000000da165f5f67657443757272656e7445706f6368496e646578723a000000da105f5f66697454696d65546f52616e67657239000000da077365636f6e6473da1a5f5f676574456d697373696f6e526174655065725365636f6e64da175f5f646563696d616c5f636f6e7665727465725f766172722f000000290e724a000000da147374617274696e675f65706f63685f696e646578725e0000007245000000da1363757272656e745f65706f63685f696e646578da10746869735f65706f63685f696e646578da0179da0a746869735f65706f6368da0a6e6578745f65706f6368da0564656c7461da127063745f73686172655f6f665f7374616b65da16656d697373696f6e5f726174655f7065725f686f7572da17676c6f62616c5f7969656c645f746869735f65706f6368da186465706f7369745f7969656c645f746869735f65706f6368724200000072420000007243000000725b000000aa000000733e00000000010a010a010a010601040104010c0108010c0104010801120108010c010a01080116030c010c01040114010c010801060108010a010801080108010c01725b0000002901721c000000630100000000000000010000000200000043000000732e0000007c0074006a0183006b00721674006a0183007d006e147c0074026a0183006b04722a74026a0183007d007c00530029014e2903723e000000725100000072400000002901721c000000724200000072420000007243000000726e000000ce000000730a00000000010c010a010c010801726e000000630000000000000000010000000100000043000000730c00000074006a0183007d007c00530029014e29027233000000725100000029017273000000724200000072420000007243000000726d000000d6000000730400000000010801726d0000002901724e0000006301000000000000000600000004000000430000007362000000740083007d0174017c0119007d027c02640119007d0374027c026402190018007d047c046a0364036b0472327c046a036e0264037d057c0574046a0583006b0573567c0364036b08735674067c007c0364048d02725e74077c0083017d017c01530029054e721d000000721c00000072010000002902724e000000da11746869735f65706f63685f7374616b65642908726d000000723a0000007239000000726f00000072370000007251000000da1e5f5f6d61785374616b65644368616e6765526174696f4578636565646564da105f5f696e6372656d656e7445706f63682906724e00000072590000007276000000727d0000007278000000da0d64656c74615f7365636f6e64737242000000724200000072430000007257000000db000000731600000000010601080108010c0114010c010a0102010801080172570000002902724e000000727d00000063020000000000000005000000030000004300000073480000007c017400640183016b007210740153007c007c016b01721c7c006e027c017d027c007c016b05722c7c006e027c017d037c037c0218007d047c047c011b0074026a0383006b05530029024e7a06302e303030312904da07646563696d616cda0474727565723600000072510000002905724e000000727d000000da07736d616c6c6572da06626967676572da03646966724200000072420000007243000000727e000000e9000000731000000000020c0104010c0104010c0104010801727e0000006301000000000000000300000004000000430000007334000000740083007d017c01640117007d0274016a027c028301010074037c0074047c0119006402190064039c0374047c023c007c02530029044e7225000000721e0000002903721c000000721d000000721e0000002905726d0000007233000000722f0000007239000000723a0000002903724e000000da0d63757272656e745f65706f6368da0d6e65775f65706f63685f696478724200000072420000007243000000727f000000f5000000730c0000000001060108010a0104011401727f0000002901da0f616d6f756e745f7065725f686f75726301000000000000000300000004000000430000007340000000740083000100740183007d017c01640117007d0274026a037c028301010074047c0064028d010100740574066a0783007c0064039c0374087c023c006400530029044e7225000000290172450000002903721c000000721d000000721e0000002909da0d5f5f6173736572744f776e6572726d0000007233000000722f000000da16736574456d697373696f6e52617465506572486f7572723900000072340000007251000000723a0000002903728800000072860000007287000000724200000072420000007243000000da136368616e6765416d6f756e74506572486f7572fe000000730e00000000020601060108010a010a010801728b0000002901da0b6d696e5f7365636f6e647363010000000000000001000000020000004300000073240000007400830001007c0064016b057316740164028301820174026a037c00830101006400530029034e72010000007a21796f75206d7573742063686f6f7365206120706f7369746976652076616c75652e2904728900000072520000007237000000722f0000002901728c000000724200000072420000007243000000da0f73657445706f63684d696e54696d65090100007306000000000206011001728d0000002901da05726174696f63010000000000000001000000020000004300000073240000007400830001007c0064016b047316740164028301820174026a037c00830101006400530029034e72010000007a186d757374206265206120706f7369746976652076616c75652904728900000072520000007236000000722f0000002901728e000000724200000072420000007243000000da1873657445706f63684d6178526174696f496e637265617365100100007306000000000206011001728f0000002901727a00000063010000000000000003000000020000004300000073140000007c0064011b007d017c0164011b007d027c02530029024ee93c00000072420000002903727a000000da18656d697373696f6e5f726174655f7065725f6d696e757465da18656d697373696f6e5f726174655f7065725f7365636f6e64724200000072420000007243000000727000000017010000730600000000010801080172700000002901da02766b630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e29037289000000722e000000722f00000029017293000000724200000072420000007243000000da087365744f776e65721d0100007304000000000206017294000000630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e290372890000007232000000722f00000029017293000000724200000072420000007243000000da0c73657444657657616c6c6574230100007304000000000206017295000000630100000000000000010000000200000043000000732c0000007400830001007c0064016b0072167c0064026b05731e740164038301820174026a037c00830101006400530029044e722500000072010000007a26416d6f756e74206d75737420626520612076616c7565206265747765656e203020616e642031290472890000007252000000723d000000722f00000029017245000000724200000072420000007243000000da0f7365744465765265776172645063742901000073060000000002060118017296000000630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e29037289000000723b000000722f00000029017245000000724200000072420000007243000000728a00000030010000730400000000020601728a000000630100000000000000010000000400000043000000731c00000074008300010074016a027c0074036a04830064018d0201006400530029024e29027245000000724c0000002905728900000072240000007262000000722e000000725100000029017245000000724200000072420000007243000000da117265636f7665725969656c64546f6b656e3601000073040000000002060172970000002901da0769735f6f70656e630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e290372890000007241000000722f00000029017298000000724200000072420000007243000000da0c616c6c6f775374616b696e673c01000073040000000002060172990000002904722a000000722b000000722c000000722d000000630400000000000000050000000500000043000000732400000074008300010074016a017c007c017c027c0383047d0474026a037c04830101006400530029014e29047289000000723f000000723e000000722f0000002905722a000000722b000000722c000000722d000000721c000000724200000072420000007243000000da0c736574537461727454696d65420100007306000000000206011001729a000000630400000000000000050000000500000043000000732400000074008300010074016a017c007c017c027c0383047d0474026a037c04830101006400530029014e29047289000000723f0000007240000000722f0000002905722a000000722b000000722c000000722d000000721c000000724200000072420000007243000000da0a736574456e6454696d65490100007306000000000206011001729b000000630000000000000000000000000200000043000000731a00000074006a01830074026a036b02731674046401830182016400530029024e7a2c596f75206d75737420626520746865206f776e657220746f2063616c6c20746869732066756e6374696f6e2e2905722e000000725100000072300000007231000000725200000072420000007242000000724200000072430000007289000000500100007304000000000106017289000000630000000000000000040000000500000043000000737800000074006a017d0074027c0019007d0174027c00190064016b09732274036402830182017c01640319007d0274046a0574067c007c0264048d03010074077c0264058d010100640174027c003c00640674087c003c0074096a0a83007c0218007d0374096a0b7c0383010100740c7c0364078d0101006400530029084e467a2754686973206163636f756e7420686173206e6f206465706f7369747320746f2072657475726e2e724500000029037205000000724c00000072450000002901724500000072010000002901724e000000290d7230000000723100000072460000007252000000725300000072690000007255000000726a000000725a00000072340000007251000000722f000000725700000029047249000000724a000000726b000000724e000000724200000072420000007243000000da14656d657267656e637952657475726e5374616b6555010000731a00000000020601080106010e010801080108010a01080108010c010a01729c000000630000000000000000040000000500000043000000733a00000074006a017d0074006a027d0174037c0119007d027c0074046a0583006b0673287406640183018201740764027c007c0164038d037d037c03530029044e7a3a5468652063616c6c696e6720636f6e7472616374206973206e6f7420696e20746865207472757374656420696d706f7274657273206c6973742e6c03000000ff0f4a29a30329037245000000da067461726765747249000000290872300000007231000000da067369676e6572725a000000723800000072510000007252000000da135f5f73656e645969656c64546f5461726765742904da1063616c6c696e675f636f6e74726163747249000000725c000000da0b7472616e73666572726564724200000072420000007243000000da1c6578706f72745969656c64546f466f726569676e436f6e747261637466010000731000000000020601060108010e01060104010a0172a200000029037245000000729d00000072490000006303000000000000000a000000040000004300000073bc00000074007c0219007d037c0364016b097318740164028301820174027c0219007d0464037d057c0574037c0364048d0137007d057c057c0438007d057c007c056b0072467c006e027c057d067c0664036b04735a74016405830182017c0674046a05830014007d077c0764036b04728074066a0774086a0583007c0764068d0201007c067c0718007d0874066a077c017c0864068d0201007c047c06170074027c023c0074096a0583007c0617007d0974096a0a7c09830101007c08530029074e467a2b596f752068617665206e6f206465706f73697420746f207769746864726177207969656c642066726f6d2e72010000002901724a0000007a295468657265206973206e6f207969656c6420746f2068617276657374207269676874206e6f77203a282902724c0000007245000000290b72460000007252000000725a000000725b000000723d00000072510000007224000000726200000072320000007235000000722f000000290a7245000000729d0000007249000000724a000000725c00000072630000007264000000726500000072660000007267000000724200000072420000007243000000729f000000720100007324000000000108011001080104010e0108010c01040110010c010801120108010e010c010c010a01729f00000029017205000000630100000000000000020000000200000043000000732600000074008300010074016a0283007d017c016a037c008301010074016a047c01830101006400530029014e2905728900000072380000007251000000da06617070656e64722f00000029027205000000da11747275737465645f696d706f7274657273724200000072420000007243000000da15616464546f54727573746564496d706f72746572738701000073080000000002060108010a0172a5000000630100000000000000020000000200000043000000732600000074008300010074016a0283007d017c016a037c008301010074016a047c01830101006400530029014e2905728900000072380000007251000000da0672656d6f7665722f0000002902720500000072a4000000724200000072420000007243000000da1a72656d6f766546726f6d54727573746564496d706f72746572738f01000073080000000002060108010a0172a700000029027245000000724c000000630200000000000000020000000400000043000000734c0000007c0064016b0473107400640283018201740174026a0319007c006b0573267400640383018201740174026a03050019007c00380003003c0074017c01050019007c00370003003c006400530029044e72010000007a1e43616e6e6f742073656e64206e656761746976652062616c616e636573217a1b4e6f7420656e6f7567682056544f4b454e5320746f2073656e642129047252000000da0a5f5f62616c616e6365737230000000723100000029027245000000724c000000724200000072420000007243000000726200000097010000730800000000021001160112017262000000630200000000000000020000000400000043000000732a0000007c0064016b0473107400640283018201740174026a037c016602050019007c00370003003c006400530029034e72010000007a1e43616e6e6f742073656e64206e656761746976652062616c616e636573212904725200000072a80000007230000000723100000029027245000000724c000000724200000072420000007243000000da07617070726f76659f01000073040000000002100172a900000029037245000000724c000000724d000000630300000000000000030000000500000043000000738a0000007c0064016b047310740064028301820174017c0274026a03660219007c006b05733c740064036a0474017c0274026a03660219007c0083028301820174017c0219007c006b057350740064048301820174017c0274026a036602050019007c00380003003c0074017c02050019007c00380003003c0074017c01050019007c00370003003c006400530029054e72010000007a1e43616e6e6f742073656e64206e656761746976652062616c616e636573217a494e6f7420656e6f75676820636f696e7320617070726f76656420746f2073656e642120596f752068617665207b7d20616e642061726520747279696e6720746f207370656e64207b7d7a194e6f7420656e6f75676820636f696e7320746f2073656e64212905725200000072a800000072300000007231000000da06666f726d617429037245000000724c000000724d000000724200000072420000007243000000da0d7472616e736665725f66726f6da50100007310000000000210010c010c01140114011601100172ab000000630100000000000000020000000400000043000000732e00000074006a017d0174027c0119007c006b05731a740364018301820174027c01050019007c00380003003c006400530029024e7a4e596f75722056544f4b454e2062616c616e636520697320746f6f206c6f7720746f20756e7374616b652c207265636f76657220796f75722056544f4b454e5320616e642074727920616761696e2e29047230000000723100000072a80000007252000000290272450000007249000000724200000072420000007243000000726a000000b101000073080000000001060106010e01726a000000630100000000000000020000000400000043000000731a00000074006a017d0174027c01050019007c00370003003c006400530029014e29037230000000723100000072a80000002902724500000072490000007242000000724200000072430000007258000000b8010000730400000000010601725800000029437222000000da1c636f6e5f726f636b6574737761705f6f6666696369616c5f76315f31725300000072550000007224000000da085661726961626c65722e0000007232000000723b000000723d000000723e00000072400000007241000000da04486173687246000000725a0000007233000000723a0000007234000000723500000072370000007236000000723c0000007271000000723800000072a80000007244000000da085f5f6578706f7274da05666c6f6174724b000000724700000072480000007268000000726c000000725b000000da03416e79726e000000726d0000007257000000727e000000727f000000728b000000728d000000728f0000007270000000da03737472729400000072950000007296000000728a0000007297000000da04626f6f6c7299000000da03696e74729a000000729b0000007289000000729c00000072a2000000729f00000072a500000072a7000000726200000072a900000072ab000000726a00000072580000007242000000724200000072420000007243000000da083c6d6f64756c653e0100000073bc000000080108010401040104010c010401080104010801040108010c010c01040108010601080106010801040108010601080104010801040108010401080104010801060108010401080104010801060108030815060110090e110601101b06011016101c08240e0808050e0e02010e0b0e090601100a06011006060110060e06060110050601100506011006060110050601100506011005060116060601160608051011100c1215060110070601100706011207060112050601140b0e07