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