Contract con_staking_gold_gold_1


Contract Code

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

Byte Code

e300000000000000000000000006000000400000007358030000640064016c005a0065015a0265005a0365005a0465056402640364048d025a0665056402640564048d025a0765056402640664048d025a0865056402640764048d025a0965056402640864048d025a0a65056402640964048d025a0b65056402640a64048d025a0c650d640b6402640c640d8d035a0e650d64006402640e640d8d035a0f65056402640f64048d025a10650d640b64026410640d8d035a1165056402641164048d025a1265056402641264048d025a1365056402641364048d025a1465056402641464048d025a15650d640b64026415640d8d035a1665056402641664048d025a1765056402641764048d025a1865056402641864048d025a19650d640064026419640d8d035a1a641a641b84005a1b651c64028301651d641c9c01641d641e840483015a1e651d651f6520641f9c036420642184045a21651d651f6520641f9c036422642384045a22651d651f651f64249c036425642684045a23651c64028301651d641c9c0164276428840483015a24651c640283016429642a840083015a25642b642c84005a266527642d9c01642e642f84045a286430643184005a29651d64329c016433643484045a2a651d651d64359c026436643784045a2b651d64329c016438643984045a2c651c64028301651d643a9c01643b643c840483015a2d651c64028301651d643d9c01643e643f840483015a2e651c64028301651d64409c0164416442840483015a2f651d64439c016444644584045a30651c64028301651f64469c0164476448840483015a31651c64028301651f64469c016449644a840483015a32651c64028301651d641c9c01644b644c840483015a33651d641c9c01644d644e84045a34651c64028301651d641c9c01644f6450840483015a35651c64028301652064519c0164526453840483015a36651c64028301653765376537653764549c0464556456840483015a38651c64028301653765376537653764549c0464576458840483015a396459645a84005a3a651c64028301645b645c840083015a3b651c64028301651d651f645d9c02645e645f840483015a3c651c64028301651d651f645d9c0264606461840483015a3d651c64028301651d651f651f64629c0364636464840483015a3e651d641c9c016465646684045a3f651d641c9c016467646884045a40640153002969e9000000004eda17636f6e5f7374616b696e675f676f6c645f676f6c645f31da054f776e65722902da08636f6e7472616374da046e616d65da0f44657652657761726457616c6c6574da13456d697373696f6e52617465506572486f7572da0c446576526577617264506374da09537461727454696d65da07456e6454696d65da0f4f70656e466f72427573696e65737346da084465706f736974732903da0d64656661756c745f76616c756572040000007205000000da0b5769746864726177616c73da1143757272656e7445706f6368496e646578da0645706f636873da0d5374616b656442616c616e6365da1057697468647261776e42616c616e6365da0c45706f63684d696e54696d65da1545706f63684d6178526174696f496e637265617365da046d657461da15646563696d616c5f636f6e7665727465725f766172da0e54696d6552616d7056616c756573da0b55736554696d6552616d70da0862616c616e636573630000000000000000000000000e00000043000000736601000074006a0174026a038301010074046a0164018301010074056a0164028301010074066a0164028301010074076a0164028301010074086a01642d8301010074096a01640583010100740a6402640664079c03740b64023c006408740c64093c00640a740c640b3c00640c740c640d3c00640c740c640e3c00740d6a01640683010100740e6a01642e83010100740f6a0174106a10640f64106411641264138d048301010074116a0174106a10641464156404641664138d048301010074126a0164178301010074136a0164188301010074146a01640264197415641a8301641b9c036419641c7415641d8301641b9c03641c641e7415641f8301641b9c03641e6420741564218301641b9c0364206422741564238301641b9c0364226424741564258301641b9c0364246426741564278301641b9c0364266428741564298301641b9c036428642a7415642b8301641b9c03642a642c6403641b9c03670a8301010064005300292f4eda40393663643861323463343933303638613265613534393164626337396437333863313261623030643761633161356530653235616663383935626234666166317201000000e901000000e90400000069100e000069228f04002903da0474696d65da067374616b6564da0a616d745f7065725f68727a05302e302e31da0776657273696f6eda287374616b696e675f736d6172745f65706f63685f636f6d706f756e64696e675f74696d6572616d70da0474797065da11636f6e5f676f6c645f636f6e7472616374da0d5354414b494e475f544f4b454eda0b5949454c445f544f4b454e69e5070000e907000000e905000000e9170000002904da0479656172da056d6f6e7468da03646179da04686f757269e6070000e90c000000e9160000005446e90b0000007a03302e312903da056c6f776572da057570706572da0a6d756c7469706c696572e9150000007a03302e32e91f0000007a03302e33e9290000007a03302e34e9330000007a03302e35e93d0000007a03302e36e9470000007a03302e37e9510000007a03302e38e95b0000007a03302e39e96500000067000000000000d03f67000000000000d03f2916da075f5f4f776e6572da03736574da03637478da0663616c6c6572da115f5f44657652657761726457616c6c6574da135f5f43757272656e7445706f6368496e646578da0f5f5f5374616b656442616c616e6365da125f5f57697468647261776e42616c616e6365da175f5f45706f63684d6178526174696f496e637265617365da0e5f5f45706f63684d696e54696d65da036e6f77da085f5f45706f636873da065f5f6d657461da155f5f456d697373696f6e52617465506572486f7572da0e5f5f446576526577617264506374da0b5f5f537461727454696d65da086461746574696d65da095f5f456e6454696d65da115f5f4f70656e466f72427573696e657373da0d5f5f55736554696d6552616d70da105f5f54696d6552616d7056616c756573da07646563696d616ca90072520000007252000000da00da045f5f5f5f2c000000733a00000000010c01040106010a010a010a010a010a01100108010801080108010a010a01180118010a010a010a0116010e0110010e0110010e010e010e0172540000002901da06616d6f756e74630100000000000000030000000500000043000000733600000074006a017d0174027c0119007d027c0264016b08722474037c006402640164038d03530074047c006402640164038d0353006400530029044e46723f00000029037255000000da08757365725f637478da0d66726f6d5f636f6e74726163742905723e000000723f000000da0a5f5f4465706f73697473da125f5f6372656174654e65774465706f736974da115f5f696e6372656173654465706f73697429037255000000da0475736572da076465706f736974725200000072520000007253000000da106164645374616b696e67546f6b656e734c000000730e0000000002060108010801060108020601725d0000002903725500000072560000007257000000630300000000000000070000000500000043000000738a00000074006a01830064016b02731474026402830182017c0064036b047324740264048301820174036a047d037c0264056b08724474056a067c0074036a077c0364068d03010074086a0183007d047c047c0017007d0574086a097c0583010100740a7c0564078d017d067c06740b7c0064089c03740c7c033c00740d7c0064098d010100740c7c0319005300290a4e547a2854686973207374616b696e6720706f6f6c206973206e6f74206f70656e207269676874206e6f772e72010000007a19596f75206d757374207374616b6520736f6d657468696e672e4629037255000000da02746fda0c6d61696e5f6163636f756e742901da116e65775f7374616b65645f616d6f756e742903da0e7374617274696e675f65706f6368721d000000725500000029017255000000290e724e000000da03676574da0e417373657274696f6e4572726f72723e000000723f0000007224000000da0d7472616e736665725f66726f6dda04746869737242000000723d000000da165f5f646563696465496e6372656d656e7445706f636872460000007258000000da0c5f5f6d696e7456546f6b656e2907725500000072560000007257000000725b000000721e0000007260000000da0b65706f63685f696e646578725200000072520000007253000000725900000058000000731e000000000106010e011001060108010a010801080108010a010a0104010c010a0172590000006303000000000000000e0000000500000043000000735c0100007c0164016b08720e74006a016e0474006a027d0374036a04830064026b02732874056403830182017c0064046b057338740564058301820174067c0319007d047c0464066b09735074056407830182017c0064046b0472727c0264066b08727274076a087c0074006a097c0364088d030100740a7c0319007d0564047d0664047d0764047d0864067d097c06740b7c0464098d0137007d067c04640a19007d097c04640b19007d077c067c0538007d067c0664046b0472e67c06740c6a04830014007d0a7c0a64046b0472de740d6a0e740f6a0483007c0a640c8d0201007c067c0a18007d087c087c0717007c0017007d0b74106a0483007d0c7c0c7c0817007c0017007d0d74106a117c0d8301010074126a1174126a0483007c0617008301010074137c087c001700640d8d0101006404740a7c033c0074147c0d640e8d017c097c0b74157c091800640f9c0474067c033c0074067c031900530029104e723f000000547a2854686973207374616b696e6720706f6f6c206973206e6f74206f70656e207269676874206e6f772e72010000007a24596f752063616e6e6f74207374616b652061206e656761746976652062616c616e63652e467a2354686973207573657220686173206e6f206465706f73697420746f2061646420746f2e29037255000000725e000000725f0000002901725c000000721d00000072550000002902725e0000007255000000290172550000002901726000000029047261000000721d0000007255000000da0b737465705f6f66667365742916723e000000723f000000da067369676e6572724e000000726200000072630000007258000000722400000072640000007265000000da0d5f5f5769746864726177616c73da105f5f63616c63756c6174655969656c64724a0000007225000000da087472616e7366657272400000007242000000723d0000007243000000726700000072660000007246000000290e725500000072560000007257000000725b000000725c000000da0f77697468647261776e5f7969656c64da107969656c645f746f5f68617276657374da0e6578697374696e675f7374616b65da10757365725f7969656c645f7368617265da0a73746172745f74696d65da096465765f7368617265da14746f74616c5f6465706f7369745f616d6f756e74da14676c6f62616c5f616d6f756e745f7374616b6564da116e65775f676c6f62616c5f7374616b6564725200000072520000007253000000725a0000006a00000073440000000001140106010e0110010801100110010a010801080104010401040104010e0108010801080108010c010801120108010c0108010c010a0112010e010801020108011201725a00000029037255000000da06746172676574725b0000006303000000000000000a000000040000004300000073bc00000074007c0219007d037c0364016b097318740164028301820174027c0219007d0464037d057c0574037c0364048d0137007d057c057c0438007d057c007c056b0072467c006e027c057d067c0664036b04735a74016405830182017c0674046a05830014007d077c0764036b04728074066a0774086a0583007c0764068d0201007c067c0718007d0874066a077c017c0864068d0201007c047c06170074027c023c0074096a0583007c0617007d0974096a0a7c09830101007c08530029074e467a2b596f752068617665206e6f206465706f73697420746f207769746864726177207969656c642066726f6d2e72010000002901725c0000007a295468657265206973206e6f207969656c6420746f2068617276657374207269676874206e6f77203a282902725e0000007255000000290b72580000007263000000726b000000726c000000724a00000072620000007225000000726d00000072400000007243000000723d000000290a72550000007277000000725b000000725c000000726e000000da116861727665737461626c655f7969656c64726f0000007273000000da0a757365725f7368617265da146e65775f77697468647261776e5f616d6f756e74725200000072520000007253000000da135f5f73656e645969656c64546f5461726765748f0000007324000000000108011001080104010e0108010c01040110010c010801120108010e010c010c010a01727b00000063010000000000000002000000050000004300000073240000007c0064016b047310740064028301820174016a027d0174037c007c017c0164038d03530029044e72010000007a25596f752063616e6e6f7420686172766573742061206e656761746976652062616c616e6365290372550000007277000000725b00000029047263000000723e000000723f000000727b00000029027255000000725b000000725200000072520000007253000000da0d77697468647261775969656c64a40000007306000000000210010601727c00000063000000000000000009000000040000004300000073fa00000074006a017d0074027c0019007d017c0164016b09731e740364028301820174047c0019007d0264037d0364037d0464037d057c0474057c0164048d0137007d047c037c016405190037007d0374066a077c007c0364068d02010074087c0364078d0101007c047c0238007d047c0464036b0472b07c0474096a0a830014007d067c0664036b04729a740b6a07740c6a0a83007c0664068d0201007c047c0618007d05740b6a077c007c0564068d020100640174027c003c00640374047c003c00740d6a0a83007c0318007d07740d6a0e7c0783010100740f6a0a83007c0417007d08740f6a0e7c088301010074107c0764088d0101007c05530029094e467a1f596f752068617665206e6f206465706f73697420746f20776974686472617772010000002901725c00000072550000002902725e000000725500000029017255000000290172600000002911723e000000723f00000072580000007263000000726b000000726c0000007224000000726d000000da155f5f72657475726e416e644275726e56546f6b656e724a0000007262000000722500000072400000007242000000723d000000724300000072660000002909725b000000725c000000726e000000da0f7374616b655f746f5f72657475726e726f000000727900000072730000007260000000727a000000725200000072520000007253000000da167769746864726177546f6b656e73416e645969656c64ab0000007334000000000206010801100108010401040104010e010c010e010a01080108010c010801120108010e01080108010c010a010c010a010a01727f0000006301000000000000000f000000040000004300000073500100007c006a00640183017d017c006a00640283017d027c006a00640383017d037c006a00640483017d047c0464006b09723a7c027c0417007d026e087401740118007d04740283007d057c017d0664057d0778fa7c067c056b019001724a74037c0619007d0874037c066406170019007d0964057d0a7c017c056b02728e74047401830174047c02830118007d0a6e547c067c016b0272ac74047c0964021900830174047c02830118007d0a6e367c067c056b0272ca74047401830174047c0864021900830118007d0a6e1874047c0964021900830174047c0864021900830118007d0a64057d0b7c0364056b096ff87c086407190064056b09900172087c037c08640719001b007d0b7c08640819007d0c7c0a6a0574067c0c830114007d0d74076a087c0b8301010074076a0083007d0b7c0d7c0b14007d0e7c077c0e37007d077c06640637007d06715257007c07530029094e7261000000721d000000725500000072690000007201000000721b000000721e000000721f000000290972620000007246000000da165f5f67657443757272656e7445706f6368496e6465787247000000da105f5f66697454696d65546f52616e6765da077365636f6e6473da1a5f5f676574456d697373696f6e526174655065725365636f6e64da175f5f646563696d616c5f636f6e7665727465725f766172723d000000290f725c000000da147374617274696e675f65706f63685f696e646578da126465706f7369745f73746172745f74696d6572550000007269000000da1363757272656e745f65706f63685f696e646578da10746869735f65706f63685f696e646578da0179da0a746869735f65706f6368da0a6e6578745f65706f6368da0564656c7461da127063745f73686172655f6f665f7374616b65da16656d697373696f6e5f726174655f7065725f686f7572da17676c6f62616c5f7969656c645f746869735f65706f6368da186465706f7369745f7969656c645f746869735f65706f6368725200000072520000007253000000726c000000c9000000734600000000010a010a010a010a0108010a0208010601040104010c0108010c0104010801120208010c010a01080116030c010c01040116010c010801060108010a010801080108010c01726c0000002901721d000000630100000000000000010000000200000043000000732e0000007c0074006a0183006b00721674006a0183007d006e147c0074026a0183006b04722a74026a0183007d007c00530029014e2903724b0000007262000000724d0000002901721d0000007252000000725200000072530000007281000000f3000000730a00000000010c010a010c0108017281000000630000000000000000010000000100000043000000730c00000074006a0183007d007c00530029014e290272410000007262000000290172870000007252000000725200000072530000007280000000fb0000007304000000000108017280000000290172600000006301000000000000000600000004000000430000007362000000740083007d0174017c0119007d027c02640119007d0374027c026402190018007d047c046a0364036b0472327c046a036e0264037d057c0574046a0583006b0573567c0364036b08735674067c007c0364048d02725e74077c0083017d017c01530029054e721e000000721d000000720100000029027260000000da11746869735f65706f63685f7374616b65642908728000000072470000007246000000728200000072450000007262000000da1e5f5f6d61785374616b65644368616e6765526174696f4578636565646564da105f5f696e6372656d656e7445706f6368290672600000007268000000728a0000007291000000728c000000da0d64656c74615f7365636f6e6473725200000072520000007253000000726600000000010000731600000000010601080108010c0114010c010a01020108010801726600000029027260000000729100000063020000000000000005000000030000004300000073480000007c007c016b01720c7c006e027c017d027c007c016b05721c7c006e027c017d037c037c0218007d047c017400640183016b007238740153007c047c011b0074026a0383006b05530029024e7a05302e30303129047251000000da047472756572440000007262000000290572600000007291000000da07736d616c6c6572da06626967676572da0364696672520000007252000000725300000072920000000e010000731000000000020c0104010c01040108010c0104017292000000630100000000000000030000000400000043000000733600000074006a0183007d017c01640117007d0274006a027c028301010074037c0074047c0119006402190064039c0374047c023c007c02530029044e721b000000721f0000002903721d000000721e000000721f000000290572410000007262000000723d0000007246000000724700000029037260000000da0d63757272656e745f65706f6368da0d6e65775f65706f63685f69647872520000007252000000725300000072930000001a010000730c0000000001080108010a010401140172930000002901da0f616d6f756e745f7065725f686f75726301000000000000000300000004000000430000007340000000740083000100740183007d017c01640117007d0274026a037c028301010074047c0064028d010100740574066a0783007c0064039c0374087c023c006400530029044e721b000000290172550000002903721d000000721e000000721f0000002909da0d5f5f6173736572744f776e657272800000007241000000723d000000da185f5f736574456d697373696f6e52617465506572486f757272460000007242000000726200000072470000002903729b0000007299000000729a000000725200000072520000007253000000da136368616e6765416d6f756e74506572486f757223010000730e00000000020601060108010a010a010801729e0000002901da0b6d696e5f7365636f6e647363010000000000000001000000020000004300000073240000007400830001007c0064016b057316740164028301820174026a037c00830101006400530029034e72010000007a21796f75206d7573742063686f6f7365206120706f7369746976652076616c75652e2904729c00000072630000007245000000723d0000002901729f000000725200000072520000007253000000da0f73657445706f63684d696e54696d652e010000730600000000020601100172a00000002901da05726174696f63010000000000000001000000020000004300000073240000007400830001007c0064016b047316740164028301820174026a037c00830101006400530029034e72010000007a186d757374206265206120706f7369746976652076616c75652904729c00000072630000007244000000723d000000290172a1000000725200000072520000007253000000da1873657445706f63684d6178526174696f496e63726561736535010000730600000000020601100172a20000002901728e00000063010000000000000003000000020000004300000073140000007c0064011b007d017c0164011b007d027c02530029024ee93c00000072520000002903728e000000da18656d697373696f6e5f726174655f7065725f6d696e757465da18656d697373696f6e5f726174655f7065725f7365636f6e6472520000007252000000725300000072830000003c010000730600000000010801080172830000002901da02766b630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e2903729c000000723c000000723d000000290172a6000000725200000072520000007253000000da087365744f776e65724201000073040000000002060172a7000000630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e2903729c0000007240000000723d000000290172a6000000725200000072520000007253000000da0c73657444657657616c6c65744801000073040000000002060172a8000000630100000000000000010000000200000043000000732c0000007400830001007c0064016b0072167c0064026b05731e740164038301820174026a037c00830101006400530029044e721b00000072010000007a26416d6f756e74206d75737420626520612076616c7565206265747765656e203020616e6420312904729c0000007263000000724a000000723d00000029017255000000725200000072520000007253000000da0f7365744465765265776172645063744e010000730600000000020601180172a9000000630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e2903729c0000007249000000723d00000029017255000000725200000072520000007253000000729d00000055010000730400000000010601729d00000063010000000000000006000000060000004300000073660000007400830001007c0064016b047316740164028301820174026a0383007d01740474056403190064046405640664078d047d027c0274066a0719007d037c037d047c007c046b01724c7c006e027c047d0574086a097c05740a6a03830064088d0201006400530029094e72010000007a295969656c6420746f6b656e20616d6f756e74206d7573742062652067726561746572207468616e2030722500000072190000007202000000da0e7969656c645f62616c616e6365732904da10666f726569676e5f636f6e7472616374da0c666f726569676e5f6e616d657204000000720500000029027255000000725e000000290b729c000000726300000072420000007262000000da0b466f726569676e486173687248000000723e00000072650000007225000000726d000000723c00000029067255000000da0e7374616b65645f62616c616e6365da105f5f7969656c645f62616c616e636573da11746f74616c5f696e5f636f6e7472616374da0f746f74616c5f617661696c61626c65da11616d6f756e745f746f5f7265636f766572725200000072520000007253000000da117265636f7665725969656c64546f6b656e5a010000731600000000020601100108010801040108010a0104010c01040172b30000002901da0769735f6f70656e630100000000000000010000000200000043000000731400000074008300010074016a027c00830101006400530029014e2903729c000000724e000000723d000000290172b4000000725200000072520000007253000000da0c616c6c6f775374616b696e676901000073040000000002060172b500000029047229000000722a000000722b000000722c000000630400000000000000050000000500000043000000732400000074008300010074016a017c007c017c027c0383047d0474026a037c04830101006400530029014e2904729c000000724c000000724b000000723d00000029057229000000722a000000722b000000722c000000721d000000725200000072520000007253000000da0c736574537461727454696d656f010000730600000000020601100172b6000000630400000000000000050000000500000043000000732400000074008300010074016a017c007c017c027c0383047d0474026a037c04830101006400530029014e2904729c000000724c000000724d000000723d00000029057229000000722a000000722b000000722c000000721d000000725200000072520000007253000000da0a736574456e6454696d6576010000730600000000020601100172b7000000630000000000000000000000000200000043000000731a00000074006a01830074026a036b02731674046401830182016400530029024e7a2c596f75206d75737420626520746865206f776e657220746f2063616c6c20746869732066756e6374696f6e2e2905723c0000007262000000723e000000723f00000072630000007252000000725200000072520000007253000000729c0000007d010000730400000000010601729c000000630000000000000000040000000400000043000000737e00000074006a017d0074027c0019007d0174027c00190064016b097322740364028301820164037d027c027c016404190037007d0274046a057c007c0264058d02010074067c0264068d010100640174027c003c00640374077c003c0074086a0983007c0218007d0374086a0a7c0383010100740b7c0364078d0101006400530029084e467a2754686973206163636f756e7420686173206e6f206465706f7369747320746f2072657475726e2e720100000072550000002902725e00000072550000002901725500000029017260000000290c723e000000723f000000725800000072630000007224000000726d000000727d000000726b00000072420000007262000000723d00000072660000002904725b000000725c000000727e0000007260000000725200000072520000007253000000da14656d657267656e637952657475726e5374616b6582010000731a00000000020601080106010e0104010c010e010a01080108010c010a0172b800000029027255000000725e000000630200000000000000020000000400000043000000734c0000007c0064016b0473107400640283018201740174026a0319007c006b0573267400640383018201740174026a03050019007c00380003003c0074017c01050019007c00370003003c006400530029044e72010000007a1e43616e6e6f742073656e64206e656761746976652062616c616e636573217a1b4e6f7420656e6f7567682056544f4b454e5320746f2073656e642129047263000000da0a5f5f62616c616e636573723e000000723f00000029027255000000725e000000725200000072520000007253000000726d0000009301000073080000000002100116011201726d000000630200000000000000020000000400000043000000732a0000007c0064016b0473107400640283018201740174026a037c016602050019007c00370003003c006400530029034e72010000007a1e43616e6e6f742073656e64206e656761746976652062616c616e636573212904726300000072b9000000723e000000723f00000029027255000000725e000000725200000072520000007253000000da07617070726f76659b01000073040000000002100172ba00000029037255000000725e000000725f000000630300000000000000030000000500000043000000738a0000007c0064016b047310740064028301820174017c0274026a03660219007c006b05733c740064036a0474017c0274026a03660219007c0083028301820174017c0219007c006b057350740064048301820174017c0274026a036602050019007c00380003003c0074017c02050019007c00380003003c0074017c01050019007c00370003003c006400530029054e72010000007a1e43616e6e6f742073656e64206e656761746976652062616c616e636573217a494e6f7420656e6f75676820636f696e7320617070726f76656420746f2073656e642120596f752068617665207b7d20616e642061726520747279696e6720746f207370656e64207b7d7a194e6f7420656e6f75676820636f696e7320746f2073656e64212905726300000072b9000000723e000000723f000000da06666f726d617429037255000000725e000000725f0000007252000000725200000072530000007264000000a10100007310000000000210010c010c0114011401160110017264000000630100000000000000020000000400000043000000732e00000074006a017d0174027c0119007c006b05731a740364018301820174027c01050019007c00380003003c006400530029024e7a4e596f75722056544f4b454e2062616c616e636520697320746f6f206c6f7720746f20756e7374616b652c207265636f76657220796f75722056544f4b454e5320616e642074727920616761696e2e2904723e000000723f00000072b9000000726300000029027255000000725b000000725200000072520000007253000000727d000000ad01000073080000000001060106010e01727d000000630100000000000000020000000400000043000000731a00000074006a017d0174027c01050019007c00370003003c006400530029014e2903723e000000726a00000072b900000029027255000000725b0000007252000000725200000072530000007267000000b4010000730400000000010601726700000029417223000000da09696d706f72746c6962da014972240000007225000000da085661726961626c65723c00000072400000007249000000724a000000724b000000724d000000724e000000da04486173687258000000726b000000724100000072470000007242000000724300000072450000007244000000724800000072840000007250000000724f00000072b90000007254000000da085f5f6578706f7274da05666c6f6174725d000000da03737472da04626f6f6c7259000000725a000000727b000000727c000000727f000000726c000000da03416e7972810000007280000000726600000072920000007293000000729e00000072a000000072a2000000728300000072a700000072a800000072a9000000729d00000072b300000072b5000000da03696e7472b600000072b7000000729c00000072b8000000726d00000072ba0000007264000000727d00000072670000007252000000725200000072520000007253000000da083c6d6f64756c653e0100000073ae00000008010401040104010c010401080104010801040108010c010c010401080106010801060108010401080106010801040108010401080104010801040108010601080104010801040108010c020601080308200601100b12121225121506011006101e082a0e0808050e0e02010e0b0e090601100a06011006060110060e060601100506011005060110060e050601100e0601100506011606060116060805101106011207060112050601140b0e07