tx · NikU2HtwDrDMMz7vAwjBDCKzkc88iYNNprZ5rbWBydo

3M7kUnsoH4WfcWabsDyqVchxTkDTRb4Mj6F:  -0.06000000 Waves

2026.08.28 19:28 [1314673] smart account 3M7kUnsoH4WfcWabsDyqVchxTkDTRb4Mj6F > SELF 0.00000000 Waves

{ "type": 13, "id": "NikU2HtwDrDMMz7vAwjBDCKzkc88iYNNprZ5rbWBydo", "fee": 6000000, "feeAssetId": null, "timestamp": 1787934505344, "version": 2, "chainId": 82, "sender": "3M7kUnsoH4WfcWabsDyqVchxTkDTRb4Mj6F", "senderPublicKey": "GGMRWgXLHW9qoeCEJCL8u3DSiQUvq6E3zTmV9URU4NsR", "proofs": [ "3tgmPtpVMsaiocrLPy6ymfmVEiRr6bR9dYPzr4hK8YZ5QDXTsLkv4u2LS2E7A9e91sJyNXTnuYvoW4BXV7TaYDS2" ], "script": "base64:BgIRCAISABIECgIIARIFCgMICAEDAQl0cnlHZXRJbnQBA2tleQQHJG1hdGNoMAkAmggCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIDSW50BAF2BQckbWF0Y2gwBQF2AAABDmdldEFzc2V0U3RyaW5nAQdhc3NldElkBAckbWF0Y2gwBQdhc3NldElkAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAWIFByRtYXRjaDAJANgEAQUBYgIFV0FWRVMBDWdldEFzc2V0Qnl0ZXMBCmFzc2V0SWRTdHIDCQAAAgUKYXNzZXRJZFN0cgIFV0FWRVMFBHVuaXQJANkEAQUKYXNzZXRJZFN0cgMBaQEHc3Rha2VMUAADCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEJAAIBAiNzdGFrZUxQOiBleGFjdGx5IDEgcGF5bWVudCByZXF1aXJlZAQKYXNzZXRJZFN0cgkBDmdldEFzc2V0U3RyaW5nAQgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAZhbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAdjdXJyZW50CQEJdHJ5R2V0SW50AQkArAICAgdzdGFrZWRfBQphc3NldElkU3RyCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICB3N0YWtlZF8FCmFzc2V0SWRTdHIJAGQCBQdjdXJyZW50BQZhbW91bnQFA25pbAFpAQl1bnN0YWtlTFACCmFzc2V0SWRTdHIGYW1vdW50BAdjdXJyZW50CQEJdHJ5R2V0SW50AQkArAICAgdzdGFrZWRfBQphc3NldElkU3RyAwkAZgIFBmFtb3VudAUHY3VycmVudAkAAgECJnVuc3Rha2VMUDogaW5zdWZmaWNpZW50IHN0YWtlZCBiYWxhbmNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICB3N0YWtlZF8FCmFzc2V0SWRTdHIJAGUCBQdjdXJyZW50BQZhbW91bnQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQZhbW91bnQJAQ1nZXRBc3NldEJ5dGVzAQUKYXNzZXRJZFN0cgUDbmlsAWkBD3RyaWdnZXJJbnRlcmVzdAMKbWFya2V0QWRkcgphc3NldElkU3RyBmFtb3VudAQGbWFya2V0CQERQGV4dHJOYXRpdmUoMTA2MikBBQptYXJrZXRBZGRyBANpbnYJAPwHBAUGbWFya2V0AgthZGRJbnRlcmVzdAkAzAgCBQphc3NldElkU3RyCQDMCAIFBmFtb3VudAUDbmlsBQNuaWwDCQAAAgUDaW52BQNpbnYFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgAQ6mbi", "height": 1314673, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 693xcpqq623ZGHGkpiJLHhgysuP2VNWavafLRh562vrH Next: none Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let CONTRACT_TYPE = "LEND-LP-MARKET"
5-
6-let VERSION = "PLP-1.4.0"
7-
8-func getAddressFromState (key) = valueOrElse(addressFromString(valueOrElse(getString(this, ("setup_address_" + key)), "3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h")), Address(base58'3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h'))
9-
10-
11-func getAddressesFromState (key) = {
12- func f (accum,next) = (accum ++ [valueOrElse(addressFromString(next), Address(base58'3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h'))])
13-
14- let $l = split_4C(valueOrElse(getString(this, ("setup_address_" + key)), "3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h"), ",")
15- let $s = size($l)
16- let $acc0 = nil
17- func $f0_1 ($a,$i) = if (($i >= $s))
18- then $a
19- else f($a, $l[$i])
20-
21- func $f0_2 ($a,$i) = if (($i >= $s))
22- then $a
23- else throw("List size exceeds 15")
24-
25- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15)
26- }
27-
28-
29-let reserveFundAddress = getAddressFromState("reserveFund")
30-
31-let oracleAddress = getAddressFromState("oracle")
32-
33-let aggregatorAddress = getAddressFromState("aggregator")
34-
35-let adminAddress = getAddressFromState("admin")
36-
37-let stableFundAddress = getAddressFromState("stableFund")
38-
39-let feeCollectorAddressStr = getString(this, "setup_address_feeCollector")
40-
41-let shutdownWhitelist = getAddressesFromState("shutdownCallers")
42-
43-let liquidatorsWhitelist = getAddressesFromState("liquidators")
44-
45-func verifyLiquidatorRights (address) = (indexOf(liquidatorsWhitelist, address) != unit)
46-
47-
48-let reserveFund = min([max([valueOrElse(getInteger(this, "setup_reserveFundFee"), 20), 0]), 100])
49-
50-let stablesIdStr = split(valueOrElse(getString(this, "setup_stablesIds"), "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi,HGgabTqUS8WtVFUJzfmrTDMgEccJuZLBPhFgQFxvnsoW"), ",")
51-
52-func getRateCurve (assetIdStr) = {
53- let curveRateStrLi = split(valueOrElse(getString(this, ("setup_rateCurve_" + assetIdStr)), "20000000,100000000,60000000,400000000"), ",")
54- $Tuple4(parseIntValue(curveRateStrLi[0]), parseIntValue(curveRateStrLi[1]), parseIntValue(curveRateStrLi[2]), parseIntValue(curveRateStrLi[3]))
55- }
56-
57-
58-func getRewardsSplitting (assetIdStr) = {
59- let rewardsSplittingStrLi = split(valueOrElse(getString(this, ("setup_rewardsSplitting_" + assetIdStr)), "30,50,20"), ",")
60- $Tuple3(parseIntValue(rewardsSplittingStrLi[0]), parseIntValue(rewardsSplittingStrLi[1]), parseIntValue(rewardsSplittingStrLi[2]))
61- }
62-
63-
64-let sentinels = [Address(base58'3PMcMiMEs6w56NRGacksXtFG5zS7doE9fpL'), Address(base58'3PQdNxynJy5mche2kxMVc5shXWzK8Gstq3o'), Address(base58'3P8auNWJkxxByyJtwErFXaxiXcGM45qQ1hA'), Address(base58'3P8qVX189qpoTJZQQQdKS9endHK5sxWsvrd')]
65-
66-let Scale8 = 100000000
67-
68-let Scale10 = 10000000000
69-
70-let Scale16 = (Scale8 * Scale8)
71-
72-let dayBlocks = 1440
73-
74-let withdrawalLimitBlocks = valueOrElse(getInteger(this, "setup_withdrawalLimitBlocks"), 100)
75-
76-func tryGetInteger (key) = match getInteger(this, key) {
77- case b: Int =>
78- b
4+func tryGetInt (key) = match getInteger(this, key) {
5+ case v: Int =>
6+ v
797 case _ =>
808 0
81-}
82-
83-
84-func tryGetBoolean (key) = match getBoolean(this, key) {
85- case b: Boolean =>
86- b
87- case _ =>
88- false
89-}
90-
91-
92-func tryGetString (key) = match getString(this, key) {
93- case b: String =>
94- b
95- case _ =>
96- ""
97-}
98-
99-
100-func tryGetBinary (key) = match getBinary(this, key) {
101- case b: ByteVector =>
102- b
103- case _ =>
104- base58''
1059 }
10610
10711
11822 else fromBase58String(assetIdStr)
11923
12024
121-func getBalance (assetIdStr) = if ((assetIdStr == "WAVES"))
122- then wavesBalance(this).available
123- else assetBalance(this, fromBase58String(assetIdStr))
124-
125-
126-func getMarketAssets () = split(tryGetString("setup_tokens"), ",")
127-
128-
129-func getOutdatedUr (assetIdStr) = {
130- let down = fraction(tryGetInteger(("total_supplied_" + assetIdStr)), tryGetInteger((assetIdStr + "_sRate")), Scale16)
131- if ((down == 0))
132- then 0
133- else fraction(Scale8, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), tryGetInteger((assetIdStr + "_bRate")), Scale16), down)
134- }
135-
136-
137-func getInterest (assetIdStr) = {
138- let ur = getOutdatedUr(assetIdStr)
139- let curve = getRateCurve(assetIdStr)
140- let rate = (curve._1 + (if ((curve._3 >= ur))
141- then fraction(ur, curve._2, curve._3)
142- else (curve._2 + fraction((ur - curve._3), curve._4, (100000000 - curve._3)))))
143- max([fraction(rate, Scale8, (dayBlocks * 365)), 1])
144- }
145-
146-
147-func tokenRatesRecalc (assetIdStr) = {
148- let interest = getInterest(assetIdStr)
149- let ur = getOutdatedUr(assetIdStr)
150- let lastRecalcHeight = tryGetInteger("lastRateHeight")
151- let lastBRate = max([tryGetInteger((assetIdStr + "_bRate")), Scale16])
152- let newBRate = (lastBRate + ((height - lastRecalcHeight) * interest))
153- let lastSRate = max([tryGetInteger((assetIdStr + "_sRate")), Scale16])
154- let newSRate = (lastSRate + fraction(((((height - lastRecalcHeight) * fraction(interest, ur, Scale8)) * (100 - reserveFund)) / 100), lastSRate, lastBRate))
155-[IntegerEntry((assetIdStr + "_sRate"), newSRate), IntegerEntry((assetIdStr + "_bRate"), newBRate), IntegerEntry("lastRateHeight", height)]
156- }
157-
158-
159-func getActualRate (assetIdStr,rateType) = {
160- func f (accum,token) = {
161- let recalc = tokenRatesRecalc(token)
162- let rawSRate = tryGetInteger((token + "_sRate"))
163- let rawBRate = tryGetInteger((token + "_bRate"))
164- let rateEntries = ((if ((recalc[0].value != rawSRate))
165- then [recalc[0]]
166- else nil) ++ (if ((recalc[1].value != rawBRate))
167- then [recalc[1]]
168- else nil))
169- let lastBRate = max([rawBRate, Scale16])
170- let feeDelta = fraction(reserveFund, fraction(tryGetInteger(("total_borrowed_" + token)), (recalc[1].value - lastBRate), Scale16), 100)
171- let feeEntries = if ((feeDelta != 0))
172- then [IntegerEntry((("fee_" + token) + "_interest"), (tryGetInteger((("fee_" + token) + "_interest")) + feeDelta))]
173- else nil
174- $Tuple3(if ((token != assetIdStr))
175- then accum._1
176- else if ((rateType == "sRate"))
177- then recalc[0].value
178- else recalc[1].value, (accum._2 ++ rateEntries), (accum._3 ++ feeEntries))
25+@Callable(i)
26+func stakeLP () = if ((size(i.payments) != 1))
27+ then throw("stakeLP: exactly 1 payment required")
28+ else {
29+ let assetIdStr = getAssetString(i.payments[0].assetId)
30+ let amount = i.payments[0].amount
31+ let current = tryGetInt(("staked_" + assetIdStr))
32+[IntegerEntry(("staked_" + assetIdStr), (current + amount))]
17933 }
180-
181- let r = {
182- let $l = getMarketAssets()
183- let $s = size($l)
184- let $acc0 = $Tuple3(0, nil, nil)
185- func $f0_1 ($a,$i) = if (($i >= $s))
186- then $a
187- else f($a, $l[$i])
188-
189- func $f0_2 ($a,$i) = if (($i >= $s))
190- then $a
191- else throw("List size exceeds 12")
192-
193- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
194- }
195- let lrhEntries = if ((tryGetInteger("lastRateHeight") != height))
196- then [IntegerEntry("lastRateHeight", height)]
197- else nil
198- $Tuple2(r._1, ((r._2 ++ r._3) ++ lrhEntries))
199- }
200-
201-
202-func getUr (assetIdStr) = {
203- let rates = tokenRatesRecalc(assetIdStr)
204- let down = fraction(tryGetInteger(("total_supplied_" + assetIdStr)), rates[0].value, Scale16)
205- fraction(Scale8, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), rates[1].value, Scale16), down)
206- }
207-
208-
209-func ratesRecalc () = {
210- func f (accum,token) = (accum ++ tokenRatesRecalc(token))
211-
212- let $l = getMarketAssets()
213- let $s = size($l)
214- let $acc0 = nil
215- func $f0_1 ($a,$i) = if (($i >= $s))
216- then $a
217- else f($a, $l[$i])
218-
219- func $f0_2 ($a,$i) = if (($i >= $s))
220- then $a
221- else throw("List size exceeds 12")
222-
223- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
224- }
225-
226-
227-func getTokenPriceWithRisk (assetIdStr,riskAversity) = if ((indexOf(stablesIdStr, assetIdStr) != unit))
228- then $Tuple2(1000000, 1000000)
229- else {
230- let price = getIntegerValue(oracleAddress, (assetIdStr + "_twap5B"))
231- let riskLevel = getIntegerValue(oracleAddress, (assetIdStr + "_riskLevel"))
232- if ((riskAversity >= riskLevel))
233- then $Tuple2(price, price)
234- else throw((("oracle prices don't match: " + toString(price)) + " is the price, but risk is too high"))
235- }
236-
237-
238-func getTokenPrice (assetIdStr) = getTokenPriceWithRisk(assetIdStr, 3)
239-
240-
241-func getTokenPriceCapped (assetIdStr) = {
242- let $t01208112144 = getTokenPriceWithRisk(assetIdStr, 3)
243- let minPrice = $t01208112144._1
244- let maxPrice = $t01208112144._2
245- let maxAllowedPrice = valueOrElse(getInteger(this, ("setup_maxPrice_" + assetIdStr)), -1)
246- let minAllowedPrice = valueOrElse(getInteger(this, ("setup_minPrice_" + assetIdStr)), -1)
247- if (if ((maxAllowedPrice != -1))
248- then (maxPrice > maxAllowedPrice)
249- else false)
250- then $Tuple2(maxAllowedPrice, maxAllowedPrice)
251- else if (if ((minAllowedPrice != -1))
252- then (minAllowedPrice > minPrice)
253- else false)
254- then $Tuple2(minAllowedPrice, minAllowedPrice)
255- else $Tuple2(minPrice, maxPrice)
256- }
257-
258-
259-func getTokenPriceForHealth (assetIdStr) = {
260- let price = getTokenPriceWithRisk(assetIdStr, 3)._1
261- let maxAllowedPrice = valueOrElse(getInteger(this, ("setup_maxPrice_" + assetIdStr)), -1)
262- let minAllowedPrice = valueOrElse(getInteger(this, ("setup_minPrice_" + assetIdStr)), -1)
263- let collatPrice = if (if ((maxAllowedPrice != -1))
264- then (price > maxAllowedPrice)
265- else false)
266- then maxAllowedPrice
267- else price
268- let debtPrice = if (if ((minAllowedPrice != -1))
269- then (minAllowedPrice > price)
270- else false)
271- then minAllowedPrice
272- else price
273- $Tuple2(collatPrice, debtPrice)
274- }
275-
276-
277-func calcAssetScale (assetIdStr) = {
278- let decimals = if ((assetIdStr == "WAVES"))
279- then 8
280- else value(assetInfo(fromBase58String(assetIdStr))).decimals
281- pow(10, 0, decimals, 0, 0, DOWN)
282- }
283-
284-
285-func calcUserCollateral (address) = {
286- let userCollateralInvoke = invoke(this, "getUserCollateral", [false, address, true, ""], nil)
287- if ((userCollateralInvoke == userCollateralInvoke))
288- then {
289- let userCollateralValue = match userCollateralInvoke {
290- case x: Int =>
291- x
292- case _ =>
293- throw("issue while doing in-dapp invocation")
294- }
295- if ((userCollateralValue == userCollateralValue))
296- then userCollateralValue
297- else throw("Strict value is not equal to itself.")
298- }
299- else throw("Strict value is not equal to itself.")
300- }
301-
302-
303-func checkWithdrawalLimit (address,assetIdStr,amountInternal,sRate) = {
304- let withdrawalLimit = valueOrElse(getInteger(this, (("setup_" + assetIdStr) + "_maxWithdrawPer100B")), -1)
305- if ((withdrawalLimit == -1))
306- then nil
307- else {
308- let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
309- let limitCap = fraction(totalSupplied, withdrawalLimit, 100)
310- let lastH = tryGetInteger(((address + "_withdrawLimitHeight_") + assetIdStr))
311- let elapsed = (height - lastH)
312- let windowExpired = (elapsed > withdrawalLimitBlocks)
313- let currentUsed = if (windowExpired)
314- then 0
315- else tryGetInteger(((address + "_withdrawLimitUsed_") + assetIdStr))
316- let blocksToReset = if (windowExpired)
317- then withdrawalLimitBlocks
318- else (withdrawalLimitBlocks - elapsed)
319- let available = (limitCap - currentUsed)
320- let availableScaled = fraction(available, sRate, Scale16, CEILING)
321- if ((amountInternal > available))
322- then throw(((((("withdrawal limit exceeded for " + assetIdStr) + ", available: ") + toString(availableScaled)) + ", blocks to reset: ") + toString(blocksToReset)))
323- else ((if (windowExpired)
324- then [IntegerEntry(((address + "_withdrawLimitHeight_") + assetIdStr), height)]
325- else nil) ++ [IntegerEntry(((address + "_withdrawLimitUsed_") + assetIdStr), (currentUsed + amountInternal))])
326- }
327- }
328-
329-
330-func checkBorrowLimit (address,assetIdStr,amountInternal,bRate,sRate) = {
331- let borrowLimit = valueOrElse(getInteger(this, (("setup_" + assetIdStr) + "_maxBorrowPer100B")), -1)
332- if ((borrowLimit == -1))
333- then nil
334- else {
335- let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
336- let limitCapSupply = fraction(totalSupplied, borrowLimit, 100)
337- let limitCap = fraction(fraction(limitCapSupply, sRate, Scale16), Scale16, bRate)
338- let lastH = tryGetInteger(((address + "_borrowLimitHeight_") + assetIdStr))
339- let elapsed = (height - lastH)
340- let windowExpired = (elapsed > withdrawalLimitBlocks)
341- let currentUsed = if (windowExpired)
342- then 0
343- else tryGetInteger(((address + "_borrowLimitUsed_") + assetIdStr))
344- let blocksToReset = if (windowExpired)
345- then withdrawalLimitBlocks
346- else (withdrawalLimitBlocks - elapsed)
347- let available = (limitCap - currentUsed)
348- let availableScaled = fraction(available, bRate, Scale16, CEILING)
349- if ((amountInternal > available))
350- then throw(((((("borrow limit exceeded for " + assetIdStr) + ", available: ") + toString(availableScaled)) + ", blocks to reset: ") + toString(blocksToReset)))
351- else ((if (windowExpired)
352- then [IntegerEntry(((address + "_borrowLimitHeight_") + assetIdStr), height)]
353- else nil) ++ [IntegerEntry(((address + "_borrowLimitUsed_") + assetIdStr), (currentUsed + amountInternal))])
354- }
355- }
356-
357-
358-@Callable(i)
359-func supply () = if (!(tryGetBoolean("setup_active")))
360- then throw("market is stopped")
361- else if (if ((size(i.payments) != 1))
362- then true
363- else (i.payments[0].amount == 0))
364- then throw("1 payment has to be attached")
365- else {
366- let assetIdStr = getAssetString(i.payments[0].assetId)
367- let assetAmount = i.payments[0].amount
368- let $t01748217549 = getActualRate(assetIdStr, "sRate")
369- let sRate = $t01748217549._1
370- let ratesRecalcResult = $t01748217549._2
371- let amount = fraction(assetAmount, Scale16, sRate, DOWN)
372- let address = toString(i.caller)
373- let maxSupply = match getString(("setup_maxSupply_" + assetIdStr)) {
374- case x: String =>
375- parseIntValue(x)
376- case _ =>
377- tryGetInteger(("setup_maxSupply_" + assetIdStr))
378- }
379- let assetPrice = getTokenPriceCapped(assetIdStr)
380- let newAddressSupplied = (tryGetInteger(((address + "_supplied_") + assetIdStr)) + amount)
381- let newTotalSupplied = (tryGetInteger(("total_supplied_" + assetIdStr)) + amount)
382- let assetScale = calcAssetScale(assetIdStr)
383- let newTotalSuppliedUsd = fraction(fraction(newTotalSupplied, sRate, Scale16), assetPrice._1, assetScale)
384- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
385- then throw("this asset is not supported by the market")
386- else if (if ((maxSupply != 0))
387- then (newTotalSuppliedUsd > maxSupply)
388- else false)
389- then throw("max total supply for this token reached in the pool")
390- else if ((tryGetInteger(("setup_paused_" + assetIdStr)) > 0))
391- then throw("this asset can't be supplied or borrowed")
392- else {
393- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
394- then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
395- else unit
396- if ((inv == inv))
397- then ([IntegerEntry(((address + "_supplied_") + assetIdStr), newAddressSupplied), IntegerEntry(("total_supplied_" + assetIdStr), newTotalSupplied)] ++ ratesRecalcResult)
398- else throw("Strict value is not equal to itself.")
399- }
400- }
40134
40235
40336
40437 @Callable(i)
405-func withdraw (assetIdStr,assetAmount) = {
406- let $t01906419131 = getActualRate(assetIdStr, "sRate")
407- let sRate = $t01906419131._1
408- let ratesRecalcResult = $t01906419131._2
409- let amount = fraction(assetAmount, Scale16, sRate, CEILING)
410- let address = toString(i.caller)
411- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
412- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
413- let userAssetSupplied = tryGetInteger(((address + "_supplied_") + assetIdStr))
414- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
415- let collateralValueInv = invoke(this, "getUserCollateral", [false, address, true, ((assetIdStr + ",supplied,") + toString(-(amount)))], nil)
416- if ((collateralValueInv == collateralValueInv))
417- then {
418- let collateralValue = match collateralValueInv {
419- case x: Int =>
420- x
421- case _ =>
422- throw("can't get user collateral value")
423- }
424- if (!(tryGetBoolean("setup_active")))
425- then throw("market is stopped")
426- else if ((0 > collateralValue))
427- then throw("you dont have enough collateral for this operation")
428- else if ((amount > (assetSupplied - assetBorrowed)))
429- then throw("this amount is not available on the market")
430- else if ((amount > (userAssetSupplied - userAssetBorrowed)))
431- then throw("this amount is not available for this user")
432- else {
433- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
434- then invoke(this, "unstakeToken", [assetIdStr, assetAmount], nil)
435- else unit
436- if ((inv == inv))
437- then {
438- let limitCheckActions = checkWithdrawalLimit(address, assetIdStr, amount, sRate)
439- if ((limitCheckActions == limitCheckActions))
440- then (([IntegerEntry(((address + "_supplied_") + assetIdStr), (tryGetInteger(((address + "_supplied_") + assetIdStr)) - amount)), IntegerEntry(("total_supplied_" + assetIdStr), (tryGetInteger(("total_supplied_" + assetIdStr)) - amount)), ScriptTransfer(i.caller, assetAmount, getAssetBytes(assetIdStr))] ++ ratesRecalcResult) ++ limitCheckActions)
441- else throw("Strict value is not equal to itself.")
442- }
443- else throw("Strict value is not equal to itself.")
444- }
445- }
446- else throw("Strict value is not equal to itself.")
38+func unstakeLP (assetIdStr,amount) = {
39+ let current = tryGetInt(("staked_" + assetIdStr))
40+ if ((amount > current))
41+ then throw("unstakeLP: insufficient staked balance")
42+ else [IntegerEntry(("staked_" + assetIdStr), (current - amount)), ScriptTransfer(i.caller, amount, getAssetBytes(assetIdStr))]
44743 }
44844
44945
45046
45147 @Callable(i)
452-func borrow (assetIdStr,assetAmount) = {
453- let address = toString(i.caller)
454- let $t02089520962 = getActualRate(assetIdStr, "bRate")
455- let bRate = $t02089520962._1
456- let ratesRecalcResult = $t02089520962._2
457- let amount = fraction(assetAmount, Scale16, bRate, CEILING)
458- let collateralValueInv = invoke(this, "getUserCollateral", [false, address, true, ((assetIdStr + ",borrowed,") + toString(amount))], nil)
459- if ((collateralValueInv == collateralValueInv))
460- then {
461- let collateralValue = match collateralValueInv {
462- case x: Int =>
463- x
464- case _ =>
465- throw("can't get user collateral value")
466- }
467- if (!(tryGetBoolean("setup_active")))
468- then throw("market is stopped")
469- else if ((0 > collateralValue))
470- then throw("you have to supply more to borrow")
471- else if ((tryGetInteger(("setup_borrowEnabled_" + assetIdStr)) == 0))
472- then throw("this asset can't be borrowed")
473- else if ((tryGetInteger(("setup_paused_" + assetIdStr)) > 0))
474- then throw("this asset can't be supplied or borrowed")
475- else {
476- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
477- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
478- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
479- if ((amount > (assetSupplied - assetBorrowed)))
480- then throw("this amount is not available")
481- else {
482- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
483- then invoke(this, "unstakeToken", [assetIdStr, assetAmount], nil)
484- else unit
485- if ((inv == inv))
486- then {
487- let sRate = tokenRatesRecalc(assetIdStr)[0].value
488- let limitCheckActions = checkBorrowLimit(address, assetIdStr, amount, bRate, sRate)
489- if ((limitCheckActions == limitCheckActions))
490- then (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed + amount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed + amount)), ScriptTransfer(i.caller, assetAmount, getAssetBytes(assetIdStr))] ++ ratesRecalcResult) ++ limitCheckActions)
491- else throw("Strict value is not equal to itself.")
492- }
493- else throw("Strict value is not equal to itself.")
494- }
495- }
496- }
497- else throw("Strict value is not equal to itself.")
498- }
499-
500-
501-
502-@Callable(i)
503-func repay () = if (!(tryGetBoolean("setup_active")))
504- then throw("market is stopped")
505- else if (if ((size(i.payments) != 1))
506- then true
507- else (i.payments[0].amount == 0))
508- then throw("1 payment has to be attached")
509- else {
510- let assetIdStr = getAssetString(i.payments[0].assetId)
511- let assetAmount = i.payments[0].amount
512- let $t02310623790 = getActualRate(assetIdStr, "bRate")
513- let bRate = $t02310623790._1
514- let ratesRecalcResult = $t02310623790._2
515- let amount = fraction(assetAmount, Scale16, bRate, CEILING)
516- let address = toString(i.caller)
517- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
518- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
519- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
520- let amountLeft = (userAssetBorrowed - amount)
521- let repayAmount = if ((amountLeft >= 0))
522- then amount
523- else userAssetBorrowed
524- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
525- then throw("this asset is not supported by the market")
526- else {
527- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
528- then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
529- else unit
530- if ((inv == inv))
531- then {
532- let excessTokens = (assetAmount - fraction(repayAmount, bRate, Scale16))
533- (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed - repayAmount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed - repayAmount))] ++ ratesRecalcResult) ++ (if ((amountLeft >= 0))
534- then nil
535- else [ScriptTransfer(i.caller, excessTokens, i.payments[0].assetId)]))
536- }
537- else throw("Strict value is not equal to itself.")
538- }
539- }
540-
541-
542-
543-@Callable(i)
544-func repayFor (address) = if (!(tryGetBoolean("setup_active")))
545- then throw("market is stopped")
546- else if ((i.caller != reserveFundAddress))
547- then throw("available only for reserve fund address")
548- else if ((address == "global"))
549- then throw("you can't repay for everyone :_)")
550- else if (if ((size(i.payments) != 1))
551- then true
552- else (i.payments[0].amount == 0))
553- then throw("1 payment has to be attached")
554- else {
555- let assetIdStr = getAssetString(i.payments[0].assetId)
556- let assetAmount = i.payments[0].amount
557- let $t02546626150 = getActualRate(assetIdStr, "bRate")
558- let bRate = $t02546626150._1
559- let ratesRecalcResult = $t02546626150._2
560- let amount = fraction(assetAmount, Scale16, bRate, CEILING)
561- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
562- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
563- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
564- let amountLeft = (userAssetBorrowed - amount)
565- let repayAmount = if ((amountLeft >= 0))
566- then amount
567- else userAssetBorrowed
568- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
569- then throw("this asset is not supported by the market")
570- else {
571- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
572- then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
573- else unit
574- if ((inv == inv))
575- then {
576- let excessTokens = (assetAmount - fraction(repayAmount, bRate, Scale16))
577- (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed - repayAmount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed - repayAmount))] ++ ratesRecalcResult) ++ (if ((amountLeft >= 0))
578- then nil
579- else [ScriptTransfer(i.caller, excessTokens, i.payments[0].assetId)]))
580- }
581- else throw("Strict value is not equal to itself.")
582- }
583- }
584-
585-
586-
587-@Callable(i)
588-func stakeToken (assetIdStr,amount) = {
589- let autostakeAddress = valueOrElse(addressFromString(tryGetString(("setup_autostake_" + assetIdStr))), Address(base58'3PDDRRS5gKyDQRpJskzWTdxREHGu1FNpdwg'))
590- let stakerSupportedAssets = getStringValue(autostakeAddress, "setup_supportedAssets")
591- if ((i.caller != this))
592- then throw("only for internal smart contract invocations")
593- else if ((indexOf(stakerSupportedAssets, assetIdStr) == unit))
594- then nil
595- else {
596- let amountStaked = tryGetInteger(("autostake_amount_" + assetIdStr))
597- let stakeInv = reentrantInvoke(autostakeAddress, "stakeLP", nil, [AttachedPayment(getAssetBytes(assetIdStr), amount)])
598- if ((stakeInv == stakeInv))
599- then [IntegerEntry(("autostake_amount_" + assetIdStr), (amountStaked + amount))]
600- else throw("Strict value is not equal to itself.")
601- }
602- }
603-
604-
605-
606-@Callable(i)
607-func stakeTokenAll (assetIdStr) = if ((i.caller != this))
608- then throw("only for internal smart contract invocations")
609- else {
610- let amount = getBalance(assetIdStr)
611- let inv = reentrantInvoke(this, "stakeToken", [assetIdStr, amount], nil)
612- if ((inv == inv))
613- then nil
614- else throw("Strict value is not equal to itself.")
615- }
616-
617-
618-
619-@Callable(i)
620-func unstakeToken (assetIdStr,amount) = {
621- let autostakeAddress = valueOrElse(addressFromString(tryGetString(("setup_autostake_" + assetIdStr))), Address(base58'3PDDRRS5gKyDQRpJskzWTdxREHGu1FNpdwg'))
622- let stakerSupportedAssets = getStringValue(autostakeAddress, "setup_supportedAssets")
623- if ((i.caller != this))
624- then throw("only for internal smart contract invocations")
625- else if ((indexOf(stakerSupportedAssets, assetIdStr) == unit))
626- then nil
627- else {
628- let amountStaked = tryGetInteger(("autostake_amount_" + assetIdStr))
629- let stakeInv = reentrantInvoke(autostakeAddress, "unstakeLP", [assetIdStr, amount], nil)
630- if ((stakeInv == stakeInv))
631- then [IntegerEntry(("autostake_amount_" + assetIdStr), (amountStaked - amount))]
632- else throw("Strict value is not equal to itself.")
633- }
634- }
635-
636-
637-
638-@Callable(i)
639-func addInterest (assetIdStr,amount) = if ((i.caller != this))
640- then throw("only for self invocation")
641- else {
642- let earned = tryGetInteger(("autostake_lastEarned_" + assetIdStr))
643- let lastHeight = tryGetInteger(("autostake_lastBlock_" + assetIdStr))
644- let cleanAmount = fraction(amount, 80, 100)
645- let stakingFee = (amount - cleanAmount)
646- let stateChanges = if (if ((lastHeight == height))
647- then true
648- else (amount == 0))
649- then nil
650- else [IntegerEntry(("autostake_preLastEarned_" + assetIdStr), earned), IntegerEntry(("autostake_preLastBlock_" + assetIdStr), lastHeight), IntegerEntry(("autostake_lastEarned_" + assetIdStr), (earned + cleanAmount)), IntegerEntry(("autostake_lastBlock_" + assetIdStr), height)]
651- (stateChanges ++ [IntegerEntry((assetIdStr + "_sRate"), (tryGetInteger((assetIdStr + "_sRate")) + fraction(Scale16, cleanAmount, tryGetInteger(("total_supplied_" + assetIdStr))))), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (tryGetInteger((("fee_" + assetIdStr) + "_staking")) + stakingFee))])
652- }
653-
654-
655-
656-@Callable(i)
657-func addInterestEXTERNAL () = if ((size(i.payments) != 1))
658- then throw("exactly 1 payment has to be attached")
659- else {
660- let assetId = i.payments[0].assetId
661- let assetIdStr = getAssetString(assetId)
662- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
663- then throw("this asset is not supported by the market")
664- else {
665- let splitting = getRewardsSplitting(assetIdStr)
666- let amount = fraction(i.payments[0].amount, splitting._2, 100)
667- let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
668- let supplierAmount = if ((totalSupplied > 0))
669- then amount
670- else 0
671- let stakingFeeAdd = (fraction(i.payments[0].amount, splitting._3, 100) + (amount - supplierAmount))
672- let earned = tryGetInteger(("autostake_lastEarned_" + assetIdStr))
673- let lastHeight = tryGetInteger(("autostake_lastBlock_" + assetIdStr))
674- let stateChanges = if (if ((lastHeight == height))
675- then true
676- else (supplierAmount == 0))
677- then nil
678- else [IntegerEntry(("autostake_preLastEarned_" + assetIdStr), earned), IntegerEntry(("autostake_preLastBlock_" + assetIdStr), lastHeight), IntegerEntry(("autostake_lastEarned_" + assetIdStr), (earned + supplierAmount)), IntegerEntry(("autostake_lastBlock_" + assetIdStr), height)]
679- ((stateChanges ++ (if ((supplierAmount > 0))
680- then [IntegerEntry((assetIdStr + "_sRate"), (tryGetInteger((assetIdStr + "_sRate")) + fraction(Scale16, supplierAmount, totalSupplied)))]
681- else nil)) ++ [ScriptTransfer(stableFundAddress, fraction(i.payments[0].amount, splitting._1, 100), assetId), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (tryGetInteger((("fee_" + assetIdStr) + "_staking")) + stakingFeeAdd))])
682- }
683- }
684-
685-
686-
687-@Callable(i)
688-func preInit (tokens,ltvs,lts,penalties) = {
689- func f (accum,token) = (accum ++ [IntegerEntry((token + "_bRate"), Scale16), IntegerEntry((token + "_sRate"), Scale16)])
690-
691- if ((i.caller != this))
692- then throw("admin only")
693- else {
694- let rates = {
695- let $l = split(tokens, ",")
696- let $s = size($l)
697- let $acc0 = nil
698- func $f0_1 ($a,$i) = if (($i >= $s))
699- then $a
700- else f($a, $l[$i])
701-
702- func $f0_2 ($a,$i) = if (($i >= $s))
703- then $a
704- else throw("List size exceeds 12")
705-
706- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
707- }
708- ([StringEntry("setup_tokens", tokens), StringEntry("setup_ltvs", ltvs), StringEntry("setup_lts", lts), StringEntry("setup_penalties", penalties), BooleanEntry("setup_active", true)] ++ rates)
709- }
710- }
711-
712-
713-
714-@Callable(i)
715-func initNewToken (token,ltv,lt,penalty) = if ((i.caller != this))
716- then throw("admin only")
717- else [StringEntry("setup_tokens", ((tryGetString("setup_tokens") + ",") + token)), StringEntry("setup_ltvs", ((tryGetString("setup_ltvs") + ",") + ltv)), StringEntry("setup_lts", ((tryGetString("setup_lts") + ",") + lt)), StringEntry("setup_penalties", ((tryGetString("setup_penalties") + ",") + penalty)), IntegerEntry((token + "_bRate"), Scale16), IntegerEntry((token + "_sRate"), Scale16)]
718-
719-
720-
721-@Callable(i)
722-func updateParameter (key,val) = if (if ((i.caller != this))
723- then (i.caller != adminAddress)
724- else false)
725- then throw("admin only")
726- else [IntegerEntry(key, parseIntValue(val))]
727-
728-
729-
730-@Callable(i)
731-func updateString (key,val) = if (if ((i.caller != this))
732- then (i.caller != adminAddress)
733- else false)
734- then throw("admin only")
735- else [StringEntry(key, val)]
736-
737-
738-
739-@Callable(i)
740-func claimFees (assetIdStr) = if ((feeCollectorAddressStr == unit))
741- then throw("fee collector not configured")
742- else if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
743- then throw("this asset is not supported by the market")
744- else {
745- let interest = tryGetInteger((("fee_" + assetIdStr) + "_interest"))
746- let stk = tryGetInteger((("fee_" + assetIdStr) + "_staking"))
747- let liq = tryGetInteger((("fee_" + assetIdStr) + "_liquidation"))
748- let total = ((interest + stk) + liq)
749- if ((0 >= total))
750- then nil
751- else {
752- let bal = getBalance(assetIdStr)
753- let isStaked = (tryGetString(("setup_autostake_" + assetIdStr)) != "")
754- let unstakeInv = if (if (isStaked)
755- then (total > bal)
756- else false)
757- then invoke(this, "unstakeToken", [assetIdStr, (total - bal)], nil)
758- else unit
759- if ((unstakeInv == unstakeInv))
760- then {
761- let liquid = getBalance(assetIdStr)
762- let payable = min([total, liquid])
763- let payInterest = min([max([interest, 0]), payable])
764- let payStk = min([max([stk, 0]), (payable - payInterest)])
765- let payLiq = min([max([liq, 0]), ((payable - payInterest) - payStk)])
766- let pay = ((payInterest + payStk) + payLiq)
767- if ((0 >= pay))
768- then nil
769- else {
770- let recordInv = invoke(addressFromStringValue(value(feeCollectorAddressStr)), "processFees", [assetIdStr, payInterest, payStk, payLiq], [AttachedPayment(getAssetBytes(assetIdStr), pay)])
771- if ((recordInv == recordInv))
772- then [IntegerEntry((("fee_" + assetIdStr) + "_interest"), (interest - payInterest)), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (stk - payStk)), IntegerEntry((("fee_" + assetIdStr) + "_liquidation"), (liq - payLiq))]
773- else throw("Strict value is not equal to itself.")
774- }
775- }
776- else throw("Strict value is not equal to itself.")
777- }
778- }
779-
780-
781-
782-@Callable(i)
783-func claimFeesAll (tokensList) = {
784- let tokens = if ((tokensList == ""))
785- then getMarketAssets()
786- else split(tokensList, ",")
787- func f (accum,token) = {
788- let inv = invoke(this, "claimFees", [token], nil)
789- if ((inv == inv))
790- then accum
791- else throw("Strict value is not equal to itself.")
792- }
793-
794- let done = {
795- let $l = tokens
796- let $s = size($l)
797- let $acc0 = unit
798- func $f0_1 ($a,$i) = if (($i >= $s))
799- then $a
800- else f($a, $l[$i])
801-
802- func $f0_2 ($a,$i) = if (($i >= $s))
803- then $a
804- else throw("List size exceeds 12")
805-
806- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
807- }
808- if ((done == done))
48+func triggerInterest (marketAddr,assetIdStr,amount) = {
49+ let market = addressFromStringValue(marketAddr)
50+ let inv = invoke(market, "addInterest", [assetIdStr, amount], nil)
51+ if ((inv == inv))
80952 then nil
81053 else throw("Strict value is not equal to itself.")
81154 }
81255
81356
814-
815-@Callable(i)
816-func claimLiquidatorRewards (assetIdStr) = {
817- let liqProxyStr = valueOrElse(getString(this, "setup_address_liquidatorProxy"), "")
818- if ((liqProxyStr == ""))
819- then throw("liquidator proxy not configured")
820- else if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
821- then throw("this asset is not supported by the market")
822- else {
823- let reward = tryGetInteger(("liqReward_" + assetIdStr))
824- if ((0 >= reward))
825- then nil
826- else {
827- let bal = getBalance(assetIdStr)
828- let isStaked = (tryGetString(("setup_autostake_" + assetIdStr)) != "")
829- let unstakeInv = if (if (isStaked)
830- then (reward > bal)
831- else false)
832- then invoke(this, "unstakeToken", [assetIdStr, (reward - bal)], nil)
833- else unit
834- if ((unstakeInv == unstakeInv))
835- then {
836- let liquid = getBalance(assetIdStr)
837- let pay = min([reward, liquid])
838- if ((0 >= pay))
839- then nil
840- else [ScriptTransfer(addressFromStringValue(liqProxyStr), pay, getAssetBytes(assetIdStr)), IntegerEntry(("liqReward_" + assetIdStr), (reward - pay))]
841- }
842- else throw("Strict value is not equal to itself.")
843- }
844- }
845- }
846-
847-
848-
849-@Callable(i)
850-func reSetup (assetIdStr) = if (true)
851- then throw("Resetup disabled")
852- else {
853- let lastResetup = tryGetInteger("resetup_lastUpdate")
854- if ((dayBlocks > (height - lastResetup)))
855- then throw("can be updated only once per day")
856- else {
857- let lts = split(tryGetString("setup_lts"), ",")
858- let assets = getMarketAssets()
859- let ur = getUr(assetIdStr)
860- let tempLT = tryGetInteger((("setup_" + assetIdStr) + "_tempLT"))
861- let lt = parseIntValue(assets[value(indexOf(assets, assetIdStr))])
862- if ((ur > 90000000))
863- then [IntegerEntry((("setup_" + assetIdStr) + "_tempLT"), fraction(tempLT, 9975, 10000))]
864- else if (if ((lt > tempLT))
865- then (90000000 > ur)
866- else false)
867- then [IntegerEntry((("setup_" + assetIdStr) + "_tempLT"), fraction(tempLT, 10025, 10000))]
868- else nil
869- }
870- }
871-
872-
873-
874-@Callable(i)
875-func shutdown (shutdown) = if ((indexOf(shutdownWhitelist, i.caller) == unit))
876- then throw("user not in a whitelist")
877- else [BooleanEntry("setup_active", !(shutdown))]
878-
879-
880-
881-@Callable(i)
882-func liquidate (debug,address,assetAmount,sAssetIdStr,bAssetIdStr,routeStr) = if (!(verifyLiquidatorRights(i.caller)))
883- then throw("temporarily available for whitelist only")
884- else if (!(tryGetBoolean("setup_active")))
885- then throw("market is stopped")
886- else {
887- let userCollateral = calcUserCollateral(address)
888- if ((userCollateral == userCollateral))
889- then {
890- let sRate = tokenRatesRecalc(sAssetIdStr)[0].value
891- let $t04188541954 = getActualRate(bAssetIdStr, "bRate")
892- let bRate = $t04188541954._1
893- let ratesRecalcResult2 = $t04188541954._2
894- let sAssetAmount = fraction(assetAmount, Scale16, sRate)
895- let currentSPosition = tryGetInteger(((address + "_supplied_") + sAssetIdStr))
896- let currentBPositionVal = tryGetInteger(((address + "_borrowed_") + bAssetIdStr))
897- let currentBPosition = if ((currentBPositionVal > 0))
898- then currentBPositionVal
899- else throw("user has no borrow in this token")
900- if ((userCollateral > 0))
901- then throw("user can't be liquidated")
902- else if ((sAssetAmount > currentSPosition))
903- then throw("position to liquidate is bigger than user's supply")
904- else {
905- let inv = if ((tryGetString(("setup_autostake_" + sAssetIdStr)) != ""))
906- then invoke(this, "unstakeToken", [sAssetIdStr, assetAmount], nil)
907- else unit
908- if ((inv == inv))
909- then {
910- let balance0Before = getBalance(sAssetIdStr)
911- if ((balance0Before == balance0Before))
912- then {
913- let balance1Before = getBalance(bAssetIdStr)
914- if ((balance1Before == balance1Before))
915- then {
916- let exchangeInvoke = invoke(aggregatorAddress, "swap", [routeStr, 0], [AttachedPayment(getAssetBytes(sAssetIdStr), assetAmount)])
917- if ((exchangeInvoke == exchangeInvoke))
918- then {
919- let asset0Sold = (balance0Before - getBalance(sAssetIdStr))
920- if ((asset0Sold == asset0Sold))
921- then {
922- let asset1Bought = (getBalance(bAssetIdStr) - balance1Before)
923- if ((asset1Bought == asset1Bought))
924- then {
925- let asset0Price = getTokenPriceCapped(sAssetIdStr)._1
926- let asset0Scale = calcAssetScale(sAssetIdStr)
927- let asset0Usd = fraction(asset0Sold, asset0Price, asset0Scale)
928- let asset1Price = getTokenPriceCapped(bAssetIdStr)._2
929- let asset1Scale = calcAssetScale(bAssetIdStr)
930- let asset1Usd = fraction(asset1Bought, asset1Price, asset1Scale)
931- let penalty = parseIntValue(split(tryGetString("setup_penalties"), ",")[value(indexOf(getMarketAssets(), bAssetIdStr))])
932- let liquidationProfit = (asset1Usd - fraction(asset0Usd, (Scale8 - penalty), Scale8))
933- let sAssetChange = fraction(asset0Sold, Scale16, sRate)
934- let bAssetChange = fraction(fraction(asset1Bought, Scale16, bRate), (Scale8 - fraction(liquidationProfit, Scale8, asset1Usd)), Scale8)
935- let penaltyTokens = (asset1Bought - fraction(bAssetChange, bRate, Scale16))
936- let liqProxyStr = valueOrElse(getString(this, "setup_address_liquidatorProxy"), "")
937- let liquidatorShare = if (if ((liqProxyStr != ""))
938- then (toString(i.caller) == liqProxyStr)
939- else false)
940- then min([max([valueOrElse(getInteger(addressFromStringValue(liqProxyStr), "setup_penaltyShare"), 0), 0]), 10000])
941- else 0
942- let liquidatorPart = fraction(penaltyTokens, liquidatorShare, 10000)
943- if ((asset0Sold > assetAmount))
944- then throw("more assets exchanged than expected")
945- else if ((0 > liquidationProfit))
946- then throw("price impact is bigger than liquidation penalty")
947- else if ((bAssetChange > currentBPosition))
948- then throw("debt reduction exceeds user's borrow")
949- else $Tuple2((([IntegerEntry(((address + "_supplied_") + sAssetIdStr), (currentSPosition - sAssetChange)), IntegerEntry(((address + "_borrowed_") + bAssetIdStr), (currentBPosition - bAssetChange)), IntegerEntry(("total_supplied_" + sAssetIdStr), (tryGetInteger(("total_supplied_" + sAssetIdStr)) - sAssetChange)), IntegerEntry(("total_borrowed_" + bAssetIdStr), (tryGetInteger(("total_borrowed_" + bAssetIdStr)) - bAssetChange)), IntegerEntry((("fee_" + bAssetIdStr) + "_liquidation"), (tryGetInteger((("fee_" + bAssetIdStr) + "_liquidation")) + (penaltyTokens - liquidatorPart)))] ++ (if ((liquidatorPart > 0))
950- then [IntegerEntry(("liqReward_" + bAssetIdStr), (tryGetInteger(("liqReward_" + bAssetIdStr)) + liquidatorPart))]
951- else nil)) ++ ratesRecalcResult2), liquidatorPart)
952- }
953- else throw("Strict value is not equal to itself.")
954- }
955- else throw("Strict value is not equal to itself.")
956- }
957- else throw("Strict value is not equal to itself.")
958- }
959- else throw("Strict value is not equal to itself.")
960- }
961- else throw("Strict value is not equal to itself.")
962- }
963- else throw("Strict value is not equal to itself.")
964- }
965- }
966- else throw("Strict value is not equal to itself.")
967- }
968-
969-
970-
971-@Callable(i)
972-func liquidateV2 (debug,address,sAssetIdStr) = if (!(verifyLiquidatorRights(i.caller)))
973- then throw("temporarily available for whitelist only")
974- else if (!(tryGetBoolean("setup_active")))
975- then throw("market is stopped")
976- else if ((size(i.payments) != 1))
977- then throw("exactly 1 payment has to be attached")
978- else {
979- let bAssetId = i.payments[0].assetId
980- let bAssetIdStr = getAssetString(bAssetId)
981- let bAssetAmount = i.payments[0].amount
982- let userCollateral = calcUserCollateral(address)
983- if ((userCollateral == userCollateral))
984- then if ((userCollateral > 0))
985- then throw("user can't be liquidated")
986- else {
987- let marketAssets = getMarketAssets()
988- let asset1Num = value(indexOf(marketAssets, bAssetIdStr))
989- let $t04835548417 = getActualRate(bAssetIdStr, "bRate")
990- let bRate = $t04835548417._1
991- let ratesResult = $t04835548417._2
992- let currentSPosition = tryGetInteger(((address + "_supplied_") + sAssetIdStr))
993- let currentBPositionVal = tryGetInteger(((address + "_borrowed_") + bAssetIdStr))
994- let currentBPosition = if ((currentBPositionVal > 0))
995- then currentBPositionVal
996- else throw("user has no borrow in this token")
997- let bAmountRaw = fraction(bAssetAmount, Scale16, bRate)
998- let bAmount = min([bAmountRaw, currentBPosition])
999- let bAssetAmountEff = if ((currentBPosition >= bAmountRaw))
1000- then bAssetAmount
1001- else fraction(bAmount, bRate, Scale16, CEILING)
1002- let refund = (bAssetAmount - bAssetAmountEff)
1003- let asset1Price = getTokenPriceCapped(bAssetIdStr)._2
1004- let asset1Scale = calcAssetScale(bAssetIdStr)
1005- let bAmountUsd = fraction(bAssetAmountEff, asset1Price, asset1Scale)
1006- let penalty = parseIntValue(value(split(tryGetString("setup_penalties"), ",")[asset1Num]))
1007- let asset0Price = getTokenPriceCapped(sAssetIdStr)._1
1008- let asset0Scale = calcAssetScale(sAssetIdStr)
1009- let sAmountUsd = fraction(bAmountUsd, (Scale8 + penalty), Scale8)
1010- let sAssetAmount = fraction(sAmountUsd, asset0Scale, asset0Price)
1011- let sAmount = fraction(sAssetAmount, Scale16, tokenRatesRecalc(sAssetIdStr)[0].value)
1012- if ((sAmount > currentSPosition))
1013- then throw("position to liquidate is bigger than user's supply")
1014- else {
1015- let inv = if ((tryGetString(("setup_autostake_" + sAssetIdStr)) != ""))
1016- then invoke(this, "unstakeToken", [sAssetIdStr, sAssetAmount], nil)
1017- else unit
1018- if ((inv == inv))
1019- then if (debug)
1020- then throw("liquidation will pass")
1021- else (([ScriptTransfer(i.caller, sAssetAmount, getAssetBytes(sAssetIdStr)), IntegerEntry(((address + "_supplied_") + sAssetIdStr), (currentSPosition - sAmount)), IntegerEntry(((address + "_borrowed_") + bAssetIdStr), (currentBPosition - bAmount)), IntegerEntry(("total_supplied_" + sAssetIdStr), (tryGetInteger(("total_supplied_" + sAssetIdStr)) - sAmount)), IntegerEntry(("total_borrowed_" + bAssetIdStr), (tryGetInteger(("total_borrowed_" + bAssetIdStr)) - bAmount))] ++ ratesResult) ++ (if ((refund > 0))
1022- then [ScriptTransfer(i.caller, refund, bAssetId)]
1023- else nil))
1024- else throw("Strict value is not equal to itself.")
1025- }
1026- }
1027- else throw("Strict value is not equal to itself.")
1028- }
1029-
1030-
1031-
1032-@Callable(i)
1033-func getUserCollateral (debug,address,minusBorrowed,afterChange) = {
1034- let assets = getMarketAssets()
1035- let ltvs = split(tryGetString("setup_ltvs"), ",")
1036- let lts = split(tryGetString("setup_lts"), ",")
1037- let changeHandler = split(afterChange, ",")
1038- func f (accum,next) = if ((next >= size(assets)))
1039- then accum
1040- else {
1041- let userSupplied = tryGetInteger(((address + "_supplied_") + assets[next]))
1042- let userBorrowed = tryGetInteger(((address + "_borrowed_") + assets[next]))
1043- let needTokenAccounting = if ((afterChange == ""))
1044- then if (if ((userBorrowed != 0))
1045- then true
1046- else (userSupplied != 0))
1047- then true
1048- else false
1049- else true
1050- if (needTokenAccounting)
1051- then {
1052- let assetScale = calcAssetScale(assets[next])
1053- let assetPrice = getTokenPriceForHealth(assets[next])
1054- let assetRates = tokenRatesRecalc(assets[next])
1055- ((accum + fraction(fraction(fraction((userSupplied + (if (if (if ((afterChange != ""))
1056- then (changeHandler[0] == assets[next])
1057- else false)
1058- then (changeHandler[1] == "supplied")
1059- else false)
1060- then parseIntValue(changeHandler[2])
1061- else 0)), assetRates[0].value, Scale16), parseIntValue(ltvs[next]), Scale8), assetPrice._1, assetScale)) - (if (minusBorrowed)
1062- then fraction(fraction(fraction((userBorrowed + (if (if (if ((afterChange != ""))
1063- then (changeHandler[0] == assets[next])
1064- else false)
1065- then (changeHandler[1] == "borrowed")
1066- else false)
1067- then parseIntValue(changeHandler[2])
1068- else 0)), assetRates[1].value, Scale16), Scale8, parseIntValue(lts[next])), assetPrice._2, assetScale)
1069- else 0))
1070- }
1071- else accum
1072- }
1073-
1074- let result = {
1075- let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
1076- let $s = size($l)
1077- let $acc0 = 0
1078- func $f0_1 ($a,$i) = if (($i >= $s))
1079- then $a
1080- else f($a, $l[$i])
1081-
1082- func $f0_2 ($a,$i) = if (($i >= $s))
1083- then $a
1084- else throw("List size exceeds 12")
1085-
1086- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1087- }
1088- if (debug)
1089- then throw(toString(result))
1090- else $Tuple2(nil, result)
1091- }
1092-
1093-
1094-
1095-@Callable(i)
1096-func getPrices (debug) = {
1097- let assets = getMarketAssets()
1098- func f (accum,next) = if ((next >= size(assets)))
1099- then accum
1100- else {
1101- let assetPrice = getTokenPriceWithRisk(assets[next], 3)
1102- ((((accum + toString(assetPrice._1)) + ",") + toString(assetPrice._2)) + "|")
1103- }
1104-
1105- let result = {
1106- let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
1107- let $s = size($l)
1108- let $acc0 = ""
1109- func $f0_1 ($a,$i) = if (($i >= $s))
1110- then $a
1111- else f($a, $l[$i])
1112-
1113- func $f0_2 ($a,$i) = if (($i >= $s))
1114- then $a
1115- else throw("List size exceeds 12")
1116-
1117- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1118- }
1119- if (debug)
1120- then throw(result)
1121- else $Tuple2(nil, result)
1122- }
1123-
1124-
1125-
1126-@Callable(i)
1127-func calculateUtilizationRatio (assetIdStr,debug) = if (debug)
1128- then throw(toString(getUr(assetIdStr)))
1129- else $Tuple2(nil, getUr(assetIdStr))
1130-
1131-
1132-
1133-@Callable(i)
1134-func calculateOutdatedUR (assetIdStr,debug) = if (debug)
1135- then throw(toString(getOutdatedUr(assetIdStr)))
1136- else $Tuple2(nil, getOutdatedUr(assetIdStr))
1137-
1138-
1139-
1140-@Callable(i)
1141-func calculateTokenRates (debug) = {
1142- func f (accum,assetIdStr) = {
1143- let rates = tokenRatesRecalc(assetIdStr)
1144- let rawSRate = tryGetInteger((assetIdStr + "_sRate"))
1145- let rawBRate = tryGetInteger((assetIdStr + "_bRate"))
1146- let rateEntries = ((if ((rates[0].value != rawSRate))
1147- then [rates[0]]
1148- else nil) ++ (if ((rates[1].value != rawBRate))
1149- then [rates[1]]
1150- else nil))
1151- let lastBRate = max([rawBRate, Scale16])
1152- let feeDelta = fraction(reserveFund, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), (rates[1].value - lastBRate), Scale16), 100)
1153- let feeEntries = if ((feeDelta != 0))
1154- then [IntegerEntry((("fee_" + assetIdStr) + "_interest"), (tryGetInteger((("fee_" + assetIdStr) + "_interest")) + feeDelta))]
1155- else nil
1156- $Tuple3(((((accum._1 + toString(rates[1].value)) + "|") + toString(rates[0].value)) + ","), (accum._2 ++ rateEntries), (accum._3 ++ feeEntries))
1157- }
1158-
1159- let parameter = {
1160- let $l = getMarketAssets()
1161- let $s = size($l)
1162- let $acc0 = $Tuple3("", nil, nil)
1163- func $f0_1 ($a,$i) = if (($i >= $s))
1164- then $a
1165- else f($a, $l[$i])
1166-
1167- func $f0_2 ($a,$i) = if (($i >= $s))
1168- then $a
1169- else throw("List size exceeds 12")
1170-
1171- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1172- }
1173- let lrhEntries = if ((tryGetInteger("lastRateHeight") != height))
1174- then [IntegerEntry("lastRateHeight", height)]
1175- else nil
1176- if (debug)
1177- then throw(parameter._1)
1178- else $Tuple2(((parameter._2 ++ parameter._3) ++ lrhEntries), parameter._1)
1179- }
1180-
1181-
1182-
1183-@Callable(i)
1184-func calculateTokensInterest (debug) = {
1185- func f (accum,assetIdStr) = {
1186- let rate = fraction(getInterest(assetIdStr), dayBlocks, Scale8)
1187- ((accum + toString(rate)) + ",")
1188- }
1189-
1190- let parameter = {
1191- let $l = getMarketAssets()
1192- let $s = size($l)
1193- let $acc0 = ""
1194- func $f0_1 ($a,$i) = if (($i >= $s))
1195- then $a
1196- else f($a, $l[$i])
1197-
1198- func $f0_2 ($a,$i) = if (($i >= $s))
1199- then $a
1200- else throw("List size exceeds 12")
1201-
1202- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1203- }
1204- if (debug)
1205- then throw(parameter)
1206- else $Tuple2(nil, parameter)
1207- }
1208-
1209-
1210-
1211-@Callable(i)
1212-func setApproverAddress (approverAddress) = {
1213- let isSelf = if ((i.caller == this))
1214- then true
1215- else throw("Only self invoke")
1216- if ((isSelf == isSelf))
1217- then {
1218- let _approverAddress = addressFromString(approverAddress)
1219- let approverOk = match _approverAddress {
1220- case t: Address =>
1221- true
1222- case _ =>
1223- false
1224- }
1225- let canSetApprover = if (if (approverOk)
1226- then true
1227- else (approverAddress == ""))
1228- then true
1229- else throw("Wrong approver address")
1230- if ((canSetApprover == canSetApprover))
1231- then {
1232- let isInited = valueOrElse(getBoolean(value(_approverAddress), "INITED"), false)
1233- let hasAdmins = (valueOrElse(getString(value(_approverAddress), "ADMINS_PBKS"), "") != "")
1234- let isApproverContract = if (if ((approverAddress == ""))
1235- then true
1236- else if (isInited)
1237- then hasAdmins
1238- else false)
1239- then true
1240- else throw("Address is not approver contract")
1241- if ((isApproverContract == isApproverContract))
1242- then [StringEntry("APPROVER_ADDRESS", approverAddress)]
1243- else throw("Strict value is not equal to itself.")
1244- }
1245- else throw("Strict value is not equal to itself.")
1246- }
1247- else throw("Strict value is not equal to itself.")
1248- }
1249-
1250-
1251-
1252-@Callable(i)
1253-func initNewMaster (master) = {
1254- let addressOK = match addressFromString(master) {
1255- case a: Address =>
1256- true
1257- case _ =>
1258- false
1259- }
1260- if (!(addressOK))
1261- then throw(("incorrect address " + master))
1262- else if ((i.caller != this))
1263- then throw("available for self call only")
1264- else [StringEntry("verifier_master", master)]
1265- }
1266-
1267-
1268-
1269-@Callable(i)
1270-func requestNewMaster (newMaster) = {
1271- let addressOK = match addressFromString(newMaster) {
1272- case a: Address =>
1273- true
1274- case _ =>
1275- false
1276- }
1277- if (!(addressOK))
1278- then throw(("incorrect address " + newMaster))
1279- else if ((indexOf(sentinels, i.caller) == unit))
1280- then throw("whitelist only")
1281- else [StringEntry("verifier_newMaster", newMaster), IntegerEntry("verifier_newMasterEligibleAfter", (height + 10000))]
1282- }
1283-
1284-
1285-
1286-@Callable(i)
1287-func activateNewMaster () = {
1288- let eligibleHeight = getIntegerValue(this, "verifier_newMasterEligibleAfter")
1289- let newMaster = getStringValue(this, "verifier_newMaster")
1290- if ((indexOf(sentinels, i.caller) == unit))
1291- then throw("whitelist only")
1292- else if ((eligibleHeight > height))
1293- then throw("new master cannot be activated yet")
1294- else [DeleteEntry("verifier_newMaster"), DeleteEntry("verifier_newMasterEligibleAfter"), StringEntry("verifier_master", newMaster)]
1295- }
1296-
1297-
1298-@Verifier(tx)
1299-func verify () = {
1300- let multisigStr = valueOrElse(getString("APPROVER_ADDRESS"), "")
1301- let multisigAddress = addressFromString(multisigStr)
1302- let multisigOk = match multisigAddress {
1303- case t: Address =>
1304- true
1305- case _ =>
1306- false
1307- }
1308- let isInited = if (multisigOk)
1309- then valueOrElse(getBoolean(value(multisigAddress), "INITED"), false)
1310- else false
1311- let hasAdmins = if (multisigOk)
1312- then (valueOrElse(getString(value(multisigAddress), "ADMINS_PBKS"), "") != "")
1313- else false
1314- if (if (if (multisigOk)
1315- then isInited
1316- else false)
1317- then hasAdmins
1318- else false)
1319- then match tx {
1320- case ttx: SetScriptTransaction =>
1321- match ttx.script {
1322- case script: ByteVector =>
1323- let scriptHasha = toBase58String(blake2b256(script))
1324- let validFrom = valueOrErrorMessage(getInteger(value(multisigAddress), (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validFrom")), "validFrom not set")
1325- let validTo = valueOrErrorMessage(getInteger(value(multisigAddress), (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validTo")), "validTo not set")
1326- if (if (if ((height >= validFrom))
1327- then (validTo >= height)
1328- else false)
1329- then (12000000 >= ttx.fee)
1330- else false)
1331- then (scriptHash(this) != blake2b256(script))
1332- else false
1333- case _ =>
1334- false
1335- }
1336- case otx =>
1337- let taskId = ((("tx_" + toString(this)) + "_") + toBase58String(otx.id))
1338- let isApproved = valueOrElse(getBoolean(value(multisigAddress), (((toString(this) + "_") + toBase58String(otx.id)) + "__approved")), false)
1339- let approvedFrom = valueOrElse(getInteger(value(multisigAddress), (taskId + "__approvedFrom")), 0)
1340- if (isApproved)
1341- then (height >= approvedFrom)
1342- else false
1343- }
1344- else {
1345- let masterAddress = getString("verifier_master")
1346- let approvedByMaster = match masterAddress {
1347- case x: String =>
1348- match getInteger(addressFromStringValue(x), ("approvedTx_" + toBase58String(tx.id))) {
1349- case y: Int =>
1350- y
1351- case _ =>
1352- 0
1353- }
1354- case _ =>
1355- 1
1356- }
1357- if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
1358- then (approvedByMaster > 0)
1359- else false
1360- }
1361- }
1362-
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let CONTRACT_TYPE = "LEND-LP-MARKET"
5-
6-let VERSION = "PLP-1.4.0"
7-
8-func getAddressFromState (key) = valueOrElse(addressFromString(valueOrElse(getString(this, ("setup_address_" + key)), "3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h")), Address(base58'3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h'))
9-
10-
11-func getAddressesFromState (key) = {
12- func f (accum,next) = (accum ++ [valueOrElse(addressFromString(next), Address(base58'3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h'))])
13-
14- let $l = split_4C(valueOrElse(getString(this, ("setup_address_" + key)), "3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h"), ",")
15- let $s = size($l)
16- let $acc0 = nil
17- func $f0_1 ($a,$i) = if (($i >= $s))
18- then $a
19- else f($a, $l[$i])
20-
21- func $f0_2 ($a,$i) = if (($i >= $s))
22- then $a
23- else throw("List size exceeds 15")
24-
25- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15)
26- }
27-
28-
29-let reserveFundAddress = getAddressFromState("reserveFund")
30-
31-let oracleAddress = getAddressFromState("oracle")
32-
33-let aggregatorAddress = getAddressFromState("aggregator")
34-
35-let adminAddress = getAddressFromState("admin")
36-
37-let stableFundAddress = getAddressFromState("stableFund")
38-
39-let feeCollectorAddressStr = getString(this, "setup_address_feeCollector")
40-
41-let shutdownWhitelist = getAddressesFromState("shutdownCallers")
42-
43-let liquidatorsWhitelist = getAddressesFromState("liquidators")
44-
45-func verifyLiquidatorRights (address) = (indexOf(liquidatorsWhitelist, address) != unit)
46-
47-
48-let reserveFund = min([max([valueOrElse(getInteger(this, "setup_reserveFundFee"), 20), 0]), 100])
49-
50-let stablesIdStr = split(valueOrElse(getString(this, "setup_stablesIds"), "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi,HGgabTqUS8WtVFUJzfmrTDMgEccJuZLBPhFgQFxvnsoW"), ",")
51-
52-func getRateCurve (assetIdStr) = {
53- let curveRateStrLi = split(valueOrElse(getString(this, ("setup_rateCurve_" + assetIdStr)), "20000000,100000000,60000000,400000000"), ",")
54- $Tuple4(parseIntValue(curveRateStrLi[0]), parseIntValue(curveRateStrLi[1]), parseIntValue(curveRateStrLi[2]), parseIntValue(curveRateStrLi[3]))
55- }
56-
57-
58-func getRewardsSplitting (assetIdStr) = {
59- let rewardsSplittingStrLi = split(valueOrElse(getString(this, ("setup_rewardsSplitting_" + assetIdStr)), "30,50,20"), ",")
60- $Tuple3(parseIntValue(rewardsSplittingStrLi[0]), parseIntValue(rewardsSplittingStrLi[1]), parseIntValue(rewardsSplittingStrLi[2]))
61- }
62-
63-
64-let sentinels = [Address(base58'3PMcMiMEs6w56NRGacksXtFG5zS7doE9fpL'), Address(base58'3PQdNxynJy5mche2kxMVc5shXWzK8Gstq3o'), Address(base58'3P8auNWJkxxByyJtwErFXaxiXcGM45qQ1hA'), Address(base58'3P8qVX189qpoTJZQQQdKS9endHK5sxWsvrd')]
65-
66-let Scale8 = 100000000
67-
68-let Scale10 = 10000000000
69-
70-let Scale16 = (Scale8 * Scale8)
71-
72-let dayBlocks = 1440
73-
74-let withdrawalLimitBlocks = valueOrElse(getInteger(this, "setup_withdrawalLimitBlocks"), 100)
75-
76-func tryGetInteger (key) = match getInteger(this, key) {
77- case b: Int =>
78- b
4+func tryGetInt (key) = match getInteger(this, key) {
5+ case v: Int =>
6+ v
797 case _ =>
808 0
81-}
82-
83-
84-func tryGetBoolean (key) = match getBoolean(this, key) {
85- case b: Boolean =>
86- b
87- case _ =>
88- false
89-}
90-
91-
92-func tryGetString (key) = match getString(this, key) {
93- case b: String =>
94- b
95- case _ =>
96- ""
97-}
98-
99-
100-func tryGetBinary (key) = match getBinary(this, key) {
101- case b: ByteVector =>
102- b
103- case _ =>
104- base58''
1059 }
10610
10711
10812 func getAssetString (assetId) = match assetId {
10913 case b: ByteVector =>
11014 toBase58String(b)
11115 case _ =>
11216 "WAVES"
11317 }
11418
11519
11620 func getAssetBytes (assetIdStr) = if ((assetIdStr == "WAVES"))
11721 then unit
11822 else fromBase58String(assetIdStr)
11923
12024
121-func getBalance (assetIdStr) = if ((assetIdStr == "WAVES"))
122- then wavesBalance(this).available
123- else assetBalance(this, fromBase58String(assetIdStr))
124-
125-
126-func getMarketAssets () = split(tryGetString("setup_tokens"), ",")
127-
128-
129-func getOutdatedUr (assetIdStr) = {
130- let down = fraction(tryGetInteger(("total_supplied_" + assetIdStr)), tryGetInteger((assetIdStr + "_sRate")), Scale16)
131- if ((down == 0))
132- then 0
133- else fraction(Scale8, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), tryGetInteger((assetIdStr + "_bRate")), Scale16), down)
134- }
135-
136-
137-func getInterest (assetIdStr) = {
138- let ur = getOutdatedUr(assetIdStr)
139- let curve = getRateCurve(assetIdStr)
140- let rate = (curve._1 + (if ((curve._3 >= ur))
141- then fraction(ur, curve._2, curve._3)
142- else (curve._2 + fraction((ur - curve._3), curve._4, (100000000 - curve._3)))))
143- max([fraction(rate, Scale8, (dayBlocks * 365)), 1])
144- }
145-
146-
147-func tokenRatesRecalc (assetIdStr) = {
148- let interest = getInterest(assetIdStr)
149- let ur = getOutdatedUr(assetIdStr)
150- let lastRecalcHeight = tryGetInteger("lastRateHeight")
151- let lastBRate = max([tryGetInteger((assetIdStr + "_bRate")), Scale16])
152- let newBRate = (lastBRate + ((height - lastRecalcHeight) * interest))
153- let lastSRate = max([tryGetInteger((assetIdStr + "_sRate")), Scale16])
154- let newSRate = (lastSRate + fraction(((((height - lastRecalcHeight) * fraction(interest, ur, Scale8)) * (100 - reserveFund)) / 100), lastSRate, lastBRate))
155-[IntegerEntry((assetIdStr + "_sRate"), newSRate), IntegerEntry((assetIdStr + "_bRate"), newBRate), IntegerEntry("lastRateHeight", height)]
156- }
157-
158-
159-func getActualRate (assetIdStr,rateType) = {
160- func f (accum,token) = {
161- let recalc = tokenRatesRecalc(token)
162- let rawSRate = tryGetInteger((token + "_sRate"))
163- let rawBRate = tryGetInteger((token + "_bRate"))
164- let rateEntries = ((if ((recalc[0].value != rawSRate))
165- then [recalc[0]]
166- else nil) ++ (if ((recalc[1].value != rawBRate))
167- then [recalc[1]]
168- else nil))
169- let lastBRate = max([rawBRate, Scale16])
170- let feeDelta = fraction(reserveFund, fraction(tryGetInteger(("total_borrowed_" + token)), (recalc[1].value - lastBRate), Scale16), 100)
171- let feeEntries = if ((feeDelta != 0))
172- then [IntegerEntry((("fee_" + token) + "_interest"), (tryGetInteger((("fee_" + token) + "_interest")) + feeDelta))]
173- else nil
174- $Tuple3(if ((token != assetIdStr))
175- then accum._1
176- else if ((rateType == "sRate"))
177- then recalc[0].value
178- else recalc[1].value, (accum._2 ++ rateEntries), (accum._3 ++ feeEntries))
25+@Callable(i)
26+func stakeLP () = if ((size(i.payments) != 1))
27+ then throw("stakeLP: exactly 1 payment required")
28+ else {
29+ let assetIdStr = getAssetString(i.payments[0].assetId)
30+ let amount = i.payments[0].amount
31+ let current = tryGetInt(("staked_" + assetIdStr))
32+[IntegerEntry(("staked_" + assetIdStr), (current + amount))]
17933 }
180-
181- let r = {
182- let $l = getMarketAssets()
183- let $s = size($l)
184- let $acc0 = $Tuple3(0, nil, nil)
185- func $f0_1 ($a,$i) = if (($i >= $s))
186- then $a
187- else f($a, $l[$i])
188-
189- func $f0_2 ($a,$i) = if (($i >= $s))
190- then $a
191- else throw("List size exceeds 12")
192-
193- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
194- }
195- let lrhEntries = if ((tryGetInteger("lastRateHeight") != height))
196- then [IntegerEntry("lastRateHeight", height)]
197- else nil
198- $Tuple2(r._1, ((r._2 ++ r._3) ++ lrhEntries))
199- }
200-
201-
202-func getUr (assetIdStr) = {
203- let rates = tokenRatesRecalc(assetIdStr)
204- let down = fraction(tryGetInteger(("total_supplied_" + assetIdStr)), rates[0].value, Scale16)
205- fraction(Scale8, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), rates[1].value, Scale16), down)
206- }
207-
208-
209-func ratesRecalc () = {
210- func f (accum,token) = (accum ++ tokenRatesRecalc(token))
211-
212- let $l = getMarketAssets()
213- let $s = size($l)
214- let $acc0 = nil
215- func $f0_1 ($a,$i) = if (($i >= $s))
216- then $a
217- else f($a, $l[$i])
218-
219- func $f0_2 ($a,$i) = if (($i >= $s))
220- then $a
221- else throw("List size exceeds 12")
222-
223- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
224- }
225-
226-
227-func getTokenPriceWithRisk (assetIdStr,riskAversity) = if ((indexOf(stablesIdStr, assetIdStr) != unit))
228- then $Tuple2(1000000, 1000000)
229- else {
230- let price = getIntegerValue(oracleAddress, (assetIdStr + "_twap5B"))
231- let riskLevel = getIntegerValue(oracleAddress, (assetIdStr + "_riskLevel"))
232- if ((riskAversity >= riskLevel))
233- then $Tuple2(price, price)
234- else throw((("oracle prices don't match: " + toString(price)) + " is the price, but risk is too high"))
235- }
236-
237-
238-func getTokenPrice (assetIdStr) = getTokenPriceWithRisk(assetIdStr, 3)
239-
240-
241-func getTokenPriceCapped (assetIdStr) = {
242- let $t01208112144 = getTokenPriceWithRisk(assetIdStr, 3)
243- let minPrice = $t01208112144._1
244- let maxPrice = $t01208112144._2
245- let maxAllowedPrice = valueOrElse(getInteger(this, ("setup_maxPrice_" + assetIdStr)), -1)
246- let minAllowedPrice = valueOrElse(getInteger(this, ("setup_minPrice_" + assetIdStr)), -1)
247- if (if ((maxAllowedPrice != -1))
248- then (maxPrice > maxAllowedPrice)
249- else false)
250- then $Tuple2(maxAllowedPrice, maxAllowedPrice)
251- else if (if ((minAllowedPrice != -1))
252- then (minAllowedPrice > minPrice)
253- else false)
254- then $Tuple2(minAllowedPrice, minAllowedPrice)
255- else $Tuple2(minPrice, maxPrice)
256- }
257-
258-
259-func getTokenPriceForHealth (assetIdStr) = {
260- let price = getTokenPriceWithRisk(assetIdStr, 3)._1
261- let maxAllowedPrice = valueOrElse(getInteger(this, ("setup_maxPrice_" + assetIdStr)), -1)
262- let minAllowedPrice = valueOrElse(getInteger(this, ("setup_minPrice_" + assetIdStr)), -1)
263- let collatPrice = if (if ((maxAllowedPrice != -1))
264- then (price > maxAllowedPrice)
265- else false)
266- then maxAllowedPrice
267- else price
268- let debtPrice = if (if ((minAllowedPrice != -1))
269- then (minAllowedPrice > price)
270- else false)
271- then minAllowedPrice
272- else price
273- $Tuple2(collatPrice, debtPrice)
274- }
275-
276-
277-func calcAssetScale (assetIdStr) = {
278- let decimals = if ((assetIdStr == "WAVES"))
279- then 8
280- else value(assetInfo(fromBase58String(assetIdStr))).decimals
281- pow(10, 0, decimals, 0, 0, DOWN)
282- }
283-
284-
285-func calcUserCollateral (address) = {
286- let userCollateralInvoke = invoke(this, "getUserCollateral", [false, address, true, ""], nil)
287- if ((userCollateralInvoke == userCollateralInvoke))
288- then {
289- let userCollateralValue = match userCollateralInvoke {
290- case x: Int =>
291- x
292- case _ =>
293- throw("issue while doing in-dapp invocation")
294- }
295- if ((userCollateralValue == userCollateralValue))
296- then userCollateralValue
297- else throw("Strict value is not equal to itself.")
298- }
299- else throw("Strict value is not equal to itself.")
300- }
301-
302-
303-func checkWithdrawalLimit (address,assetIdStr,amountInternal,sRate) = {
304- let withdrawalLimit = valueOrElse(getInteger(this, (("setup_" + assetIdStr) + "_maxWithdrawPer100B")), -1)
305- if ((withdrawalLimit == -1))
306- then nil
307- else {
308- let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
309- let limitCap = fraction(totalSupplied, withdrawalLimit, 100)
310- let lastH = tryGetInteger(((address + "_withdrawLimitHeight_") + assetIdStr))
311- let elapsed = (height - lastH)
312- let windowExpired = (elapsed > withdrawalLimitBlocks)
313- let currentUsed = if (windowExpired)
314- then 0
315- else tryGetInteger(((address + "_withdrawLimitUsed_") + assetIdStr))
316- let blocksToReset = if (windowExpired)
317- then withdrawalLimitBlocks
318- else (withdrawalLimitBlocks - elapsed)
319- let available = (limitCap - currentUsed)
320- let availableScaled = fraction(available, sRate, Scale16, CEILING)
321- if ((amountInternal > available))
322- then throw(((((("withdrawal limit exceeded for " + assetIdStr) + ", available: ") + toString(availableScaled)) + ", blocks to reset: ") + toString(blocksToReset)))
323- else ((if (windowExpired)
324- then [IntegerEntry(((address + "_withdrawLimitHeight_") + assetIdStr), height)]
325- else nil) ++ [IntegerEntry(((address + "_withdrawLimitUsed_") + assetIdStr), (currentUsed + amountInternal))])
326- }
327- }
328-
329-
330-func checkBorrowLimit (address,assetIdStr,amountInternal,bRate,sRate) = {
331- let borrowLimit = valueOrElse(getInteger(this, (("setup_" + assetIdStr) + "_maxBorrowPer100B")), -1)
332- if ((borrowLimit == -1))
333- then nil
334- else {
335- let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
336- let limitCapSupply = fraction(totalSupplied, borrowLimit, 100)
337- let limitCap = fraction(fraction(limitCapSupply, sRate, Scale16), Scale16, bRate)
338- let lastH = tryGetInteger(((address + "_borrowLimitHeight_") + assetIdStr))
339- let elapsed = (height - lastH)
340- let windowExpired = (elapsed > withdrawalLimitBlocks)
341- let currentUsed = if (windowExpired)
342- then 0
343- else tryGetInteger(((address + "_borrowLimitUsed_") + assetIdStr))
344- let blocksToReset = if (windowExpired)
345- then withdrawalLimitBlocks
346- else (withdrawalLimitBlocks - elapsed)
347- let available = (limitCap - currentUsed)
348- let availableScaled = fraction(available, bRate, Scale16, CEILING)
349- if ((amountInternal > available))
350- then throw(((((("borrow limit exceeded for " + assetIdStr) + ", available: ") + toString(availableScaled)) + ", blocks to reset: ") + toString(blocksToReset)))
351- else ((if (windowExpired)
352- then [IntegerEntry(((address + "_borrowLimitHeight_") + assetIdStr), height)]
353- else nil) ++ [IntegerEntry(((address + "_borrowLimitUsed_") + assetIdStr), (currentUsed + amountInternal))])
354- }
355- }
356-
357-
358-@Callable(i)
359-func supply () = if (!(tryGetBoolean("setup_active")))
360- then throw("market is stopped")
361- else if (if ((size(i.payments) != 1))
362- then true
363- else (i.payments[0].amount == 0))
364- then throw("1 payment has to be attached")
365- else {
366- let assetIdStr = getAssetString(i.payments[0].assetId)
367- let assetAmount = i.payments[0].amount
368- let $t01748217549 = getActualRate(assetIdStr, "sRate")
369- let sRate = $t01748217549._1
370- let ratesRecalcResult = $t01748217549._2
371- let amount = fraction(assetAmount, Scale16, sRate, DOWN)
372- let address = toString(i.caller)
373- let maxSupply = match getString(("setup_maxSupply_" + assetIdStr)) {
374- case x: String =>
375- parseIntValue(x)
376- case _ =>
377- tryGetInteger(("setup_maxSupply_" + assetIdStr))
378- }
379- let assetPrice = getTokenPriceCapped(assetIdStr)
380- let newAddressSupplied = (tryGetInteger(((address + "_supplied_") + assetIdStr)) + amount)
381- let newTotalSupplied = (tryGetInteger(("total_supplied_" + assetIdStr)) + amount)
382- let assetScale = calcAssetScale(assetIdStr)
383- let newTotalSuppliedUsd = fraction(fraction(newTotalSupplied, sRate, Scale16), assetPrice._1, assetScale)
384- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
385- then throw("this asset is not supported by the market")
386- else if (if ((maxSupply != 0))
387- then (newTotalSuppliedUsd > maxSupply)
388- else false)
389- then throw("max total supply for this token reached in the pool")
390- else if ((tryGetInteger(("setup_paused_" + assetIdStr)) > 0))
391- then throw("this asset can't be supplied or borrowed")
392- else {
393- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
394- then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
395- else unit
396- if ((inv == inv))
397- then ([IntegerEntry(((address + "_supplied_") + assetIdStr), newAddressSupplied), IntegerEntry(("total_supplied_" + assetIdStr), newTotalSupplied)] ++ ratesRecalcResult)
398- else throw("Strict value is not equal to itself.")
399- }
400- }
40134
40235
40336
40437 @Callable(i)
405-func withdraw (assetIdStr,assetAmount) = {
406- let $t01906419131 = getActualRate(assetIdStr, "sRate")
407- let sRate = $t01906419131._1
408- let ratesRecalcResult = $t01906419131._2
409- let amount = fraction(assetAmount, Scale16, sRate, CEILING)
410- let address = toString(i.caller)
411- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
412- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
413- let userAssetSupplied = tryGetInteger(((address + "_supplied_") + assetIdStr))
414- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
415- let collateralValueInv = invoke(this, "getUserCollateral", [false, address, true, ((assetIdStr + ",supplied,") + toString(-(amount)))], nil)
416- if ((collateralValueInv == collateralValueInv))
417- then {
418- let collateralValue = match collateralValueInv {
419- case x: Int =>
420- x
421- case _ =>
422- throw("can't get user collateral value")
423- }
424- if (!(tryGetBoolean("setup_active")))
425- then throw("market is stopped")
426- else if ((0 > collateralValue))
427- then throw("you dont have enough collateral for this operation")
428- else if ((amount > (assetSupplied - assetBorrowed)))
429- then throw("this amount is not available on the market")
430- else if ((amount > (userAssetSupplied - userAssetBorrowed)))
431- then throw("this amount is not available for this user")
432- else {
433- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
434- then invoke(this, "unstakeToken", [assetIdStr, assetAmount], nil)
435- else unit
436- if ((inv == inv))
437- then {
438- let limitCheckActions = checkWithdrawalLimit(address, assetIdStr, amount, sRate)
439- if ((limitCheckActions == limitCheckActions))
440- then (([IntegerEntry(((address + "_supplied_") + assetIdStr), (tryGetInteger(((address + "_supplied_") + assetIdStr)) - amount)), IntegerEntry(("total_supplied_" + assetIdStr), (tryGetInteger(("total_supplied_" + assetIdStr)) - amount)), ScriptTransfer(i.caller, assetAmount, getAssetBytes(assetIdStr))] ++ ratesRecalcResult) ++ limitCheckActions)
441- else throw("Strict value is not equal to itself.")
442- }
443- else throw("Strict value is not equal to itself.")
444- }
445- }
446- else throw("Strict value is not equal to itself.")
38+func unstakeLP (assetIdStr,amount) = {
39+ let current = tryGetInt(("staked_" + assetIdStr))
40+ if ((amount > current))
41+ then throw("unstakeLP: insufficient staked balance")
42+ else [IntegerEntry(("staked_" + assetIdStr), (current - amount)), ScriptTransfer(i.caller, amount, getAssetBytes(assetIdStr))]
44743 }
44844
44945
45046
45147 @Callable(i)
452-func borrow (assetIdStr,assetAmount) = {
453- let address = toString(i.caller)
454- let $t02089520962 = getActualRate(assetIdStr, "bRate")
455- let bRate = $t02089520962._1
456- let ratesRecalcResult = $t02089520962._2
457- let amount = fraction(assetAmount, Scale16, bRate, CEILING)
458- let collateralValueInv = invoke(this, "getUserCollateral", [false, address, true, ((assetIdStr + ",borrowed,") + toString(amount))], nil)
459- if ((collateralValueInv == collateralValueInv))
460- then {
461- let collateralValue = match collateralValueInv {
462- case x: Int =>
463- x
464- case _ =>
465- throw("can't get user collateral value")
466- }
467- if (!(tryGetBoolean("setup_active")))
468- then throw("market is stopped")
469- else if ((0 > collateralValue))
470- then throw("you have to supply more to borrow")
471- else if ((tryGetInteger(("setup_borrowEnabled_" + assetIdStr)) == 0))
472- then throw("this asset can't be borrowed")
473- else if ((tryGetInteger(("setup_paused_" + assetIdStr)) > 0))
474- then throw("this asset can't be supplied or borrowed")
475- else {
476- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
477- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
478- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
479- if ((amount > (assetSupplied - assetBorrowed)))
480- then throw("this amount is not available")
481- else {
482- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
483- then invoke(this, "unstakeToken", [assetIdStr, assetAmount], nil)
484- else unit
485- if ((inv == inv))
486- then {
487- let sRate = tokenRatesRecalc(assetIdStr)[0].value
488- let limitCheckActions = checkBorrowLimit(address, assetIdStr, amount, bRate, sRate)
489- if ((limitCheckActions == limitCheckActions))
490- then (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed + amount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed + amount)), ScriptTransfer(i.caller, assetAmount, getAssetBytes(assetIdStr))] ++ ratesRecalcResult) ++ limitCheckActions)
491- else throw("Strict value is not equal to itself.")
492- }
493- else throw("Strict value is not equal to itself.")
494- }
495- }
496- }
497- else throw("Strict value is not equal to itself.")
498- }
499-
500-
501-
502-@Callable(i)
503-func repay () = if (!(tryGetBoolean("setup_active")))
504- then throw("market is stopped")
505- else if (if ((size(i.payments) != 1))
506- then true
507- else (i.payments[0].amount == 0))
508- then throw("1 payment has to be attached")
509- else {
510- let assetIdStr = getAssetString(i.payments[0].assetId)
511- let assetAmount = i.payments[0].amount
512- let $t02310623790 = getActualRate(assetIdStr, "bRate")
513- let bRate = $t02310623790._1
514- let ratesRecalcResult = $t02310623790._2
515- let amount = fraction(assetAmount, Scale16, bRate, CEILING)
516- let address = toString(i.caller)
517- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
518- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
519- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
520- let amountLeft = (userAssetBorrowed - amount)
521- let repayAmount = if ((amountLeft >= 0))
522- then amount
523- else userAssetBorrowed
524- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
525- then throw("this asset is not supported by the market")
526- else {
527- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
528- then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
529- else unit
530- if ((inv == inv))
531- then {
532- let excessTokens = (assetAmount - fraction(repayAmount, bRate, Scale16))
533- (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed - repayAmount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed - repayAmount))] ++ ratesRecalcResult) ++ (if ((amountLeft >= 0))
534- then nil
535- else [ScriptTransfer(i.caller, excessTokens, i.payments[0].assetId)]))
536- }
537- else throw("Strict value is not equal to itself.")
538- }
539- }
540-
541-
542-
543-@Callable(i)
544-func repayFor (address) = if (!(tryGetBoolean("setup_active")))
545- then throw("market is stopped")
546- else if ((i.caller != reserveFundAddress))
547- then throw("available only for reserve fund address")
548- else if ((address == "global"))
549- then throw("you can't repay for everyone :_)")
550- else if (if ((size(i.payments) != 1))
551- then true
552- else (i.payments[0].amount == 0))
553- then throw("1 payment has to be attached")
554- else {
555- let assetIdStr = getAssetString(i.payments[0].assetId)
556- let assetAmount = i.payments[0].amount
557- let $t02546626150 = getActualRate(assetIdStr, "bRate")
558- let bRate = $t02546626150._1
559- let ratesRecalcResult = $t02546626150._2
560- let amount = fraction(assetAmount, Scale16, bRate, CEILING)
561- let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
562- let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
563- let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
564- let amountLeft = (userAssetBorrowed - amount)
565- let repayAmount = if ((amountLeft >= 0))
566- then amount
567- else userAssetBorrowed
568- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
569- then throw("this asset is not supported by the market")
570- else {
571- let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
572- then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
573- else unit
574- if ((inv == inv))
575- then {
576- let excessTokens = (assetAmount - fraction(repayAmount, bRate, Scale16))
577- (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed - repayAmount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed - repayAmount))] ++ ratesRecalcResult) ++ (if ((amountLeft >= 0))
578- then nil
579- else [ScriptTransfer(i.caller, excessTokens, i.payments[0].assetId)]))
580- }
581- else throw("Strict value is not equal to itself.")
582- }
583- }
584-
585-
586-
587-@Callable(i)
588-func stakeToken (assetIdStr,amount) = {
589- let autostakeAddress = valueOrElse(addressFromString(tryGetString(("setup_autostake_" + assetIdStr))), Address(base58'3PDDRRS5gKyDQRpJskzWTdxREHGu1FNpdwg'))
590- let stakerSupportedAssets = getStringValue(autostakeAddress, "setup_supportedAssets")
591- if ((i.caller != this))
592- then throw("only for internal smart contract invocations")
593- else if ((indexOf(stakerSupportedAssets, assetIdStr) == unit))
594- then nil
595- else {
596- let amountStaked = tryGetInteger(("autostake_amount_" + assetIdStr))
597- let stakeInv = reentrantInvoke(autostakeAddress, "stakeLP", nil, [AttachedPayment(getAssetBytes(assetIdStr), amount)])
598- if ((stakeInv == stakeInv))
599- then [IntegerEntry(("autostake_amount_" + assetIdStr), (amountStaked + amount))]
600- else throw("Strict value is not equal to itself.")
601- }
602- }
603-
604-
605-
606-@Callable(i)
607-func stakeTokenAll (assetIdStr) = if ((i.caller != this))
608- then throw("only for internal smart contract invocations")
609- else {
610- let amount = getBalance(assetIdStr)
611- let inv = reentrantInvoke(this, "stakeToken", [assetIdStr, amount], nil)
612- if ((inv == inv))
613- then nil
614- else throw("Strict value is not equal to itself.")
615- }
616-
617-
618-
619-@Callable(i)
620-func unstakeToken (assetIdStr,amount) = {
621- let autostakeAddress = valueOrElse(addressFromString(tryGetString(("setup_autostake_" + assetIdStr))), Address(base58'3PDDRRS5gKyDQRpJskzWTdxREHGu1FNpdwg'))
622- let stakerSupportedAssets = getStringValue(autostakeAddress, "setup_supportedAssets")
623- if ((i.caller != this))
624- then throw("only for internal smart contract invocations")
625- else if ((indexOf(stakerSupportedAssets, assetIdStr) == unit))
626- then nil
627- else {
628- let amountStaked = tryGetInteger(("autostake_amount_" + assetIdStr))
629- let stakeInv = reentrantInvoke(autostakeAddress, "unstakeLP", [assetIdStr, amount], nil)
630- if ((stakeInv == stakeInv))
631- then [IntegerEntry(("autostake_amount_" + assetIdStr), (amountStaked - amount))]
632- else throw("Strict value is not equal to itself.")
633- }
634- }
635-
636-
637-
638-@Callable(i)
639-func addInterest (assetIdStr,amount) = if ((i.caller != this))
640- then throw("only for self invocation")
641- else {
642- let earned = tryGetInteger(("autostake_lastEarned_" + assetIdStr))
643- let lastHeight = tryGetInteger(("autostake_lastBlock_" + assetIdStr))
644- let cleanAmount = fraction(amount, 80, 100)
645- let stakingFee = (amount - cleanAmount)
646- let stateChanges = if (if ((lastHeight == height))
647- then true
648- else (amount == 0))
649- then nil
650- else [IntegerEntry(("autostake_preLastEarned_" + assetIdStr), earned), IntegerEntry(("autostake_preLastBlock_" + assetIdStr), lastHeight), IntegerEntry(("autostake_lastEarned_" + assetIdStr), (earned + cleanAmount)), IntegerEntry(("autostake_lastBlock_" + assetIdStr), height)]
651- (stateChanges ++ [IntegerEntry((assetIdStr + "_sRate"), (tryGetInteger((assetIdStr + "_sRate")) + fraction(Scale16, cleanAmount, tryGetInteger(("total_supplied_" + assetIdStr))))), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (tryGetInteger((("fee_" + assetIdStr) + "_staking")) + stakingFee))])
652- }
653-
654-
655-
656-@Callable(i)
657-func addInterestEXTERNAL () = if ((size(i.payments) != 1))
658- then throw("exactly 1 payment has to be attached")
659- else {
660- let assetId = i.payments[0].assetId
661- let assetIdStr = getAssetString(assetId)
662- if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
663- then throw("this asset is not supported by the market")
664- else {
665- let splitting = getRewardsSplitting(assetIdStr)
666- let amount = fraction(i.payments[0].amount, splitting._2, 100)
667- let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
668- let supplierAmount = if ((totalSupplied > 0))
669- then amount
670- else 0
671- let stakingFeeAdd = (fraction(i.payments[0].amount, splitting._3, 100) + (amount - supplierAmount))
672- let earned = tryGetInteger(("autostake_lastEarned_" + assetIdStr))
673- let lastHeight = tryGetInteger(("autostake_lastBlock_" + assetIdStr))
674- let stateChanges = if (if ((lastHeight == height))
675- then true
676- else (supplierAmount == 0))
677- then nil
678- else [IntegerEntry(("autostake_preLastEarned_" + assetIdStr), earned), IntegerEntry(("autostake_preLastBlock_" + assetIdStr), lastHeight), IntegerEntry(("autostake_lastEarned_" + assetIdStr), (earned + supplierAmount)), IntegerEntry(("autostake_lastBlock_" + assetIdStr), height)]
679- ((stateChanges ++ (if ((supplierAmount > 0))
680- then [IntegerEntry((assetIdStr + "_sRate"), (tryGetInteger((assetIdStr + "_sRate")) + fraction(Scale16, supplierAmount, totalSupplied)))]
681- else nil)) ++ [ScriptTransfer(stableFundAddress, fraction(i.payments[0].amount, splitting._1, 100), assetId), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (tryGetInteger((("fee_" + assetIdStr) + "_staking")) + stakingFeeAdd))])
682- }
683- }
684-
685-
686-
687-@Callable(i)
688-func preInit (tokens,ltvs,lts,penalties) = {
689- func f (accum,token) = (accum ++ [IntegerEntry((token + "_bRate"), Scale16), IntegerEntry((token + "_sRate"), Scale16)])
690-
691- if ((i.caller != this))
692- then throw("admin only")
693- else {
694- let rates = {
695- let $l = split(tokens, ",")
696- let $s = size($l)
697- let $acc0 = nil
698- func $f0_1 ($a,$i) = if (($i >= $s))
699- then $a
700- else f($a, $l[$i])
701-
702- func $f0_2 ($a,$i) = if (($i >= $s))
703- then $a
704- else throw("List size exceeds 12")
705-
706- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
707- }
708- ([StringEntry("setup_tokens", tokens), StringEntry("setup_ltvs", ltvs), StringEntry("setup_lts", lts), StringEntry("setup_penalties", penalties), BooleanEntry("setup_active", true)] ++ rates)
709- }
710- }
711-
712-
713-
714-@Callable(i)
715-func initNewToken (token,ltv,lt,penalty) = if ((i.caller != this))
716- then throw("admin only")
717- else [StringEntry("setup_tokens", ((tryGetString("setup_tokens") + ",") + token)), StringEntry("setup_ltvs", ((tryGetString("setup_ltvs") + ",") + ltv)), StringEntry("setup_lts", ((tryGetString("setup_lts") + ",") + lt)), StringEntry("setup_penalties", ((tryGetString("setup_penalties") + ",") + penalty)), IntegerEntry((token + "_bRate"), Scale16), IntegerEntry((token + "_sRate"), Scale16)]
718-
719-
720-
721-@Callable(i)
722-func updateParameter (key,val) = if (if ((i.caller != this))
723- then (i.caller != adminAddress)
724- else false)
725- then throw("admin only")
726- else [IntegerEntry(key, parseIntValue(val))]
727-
728-
729-
730-@Callable(i)
731-func updateString (key,val) = if (if ((i.caller != this))
732- then (i.caller != adminAddress)
733- else false)
734- then throw("admin only")
735- else [StringEntry(key, val)]
736-
737-
738-
739-@Callable(i)
740-func claimFees (assetIdStr) = if ((feeCollectorAddressStr == unit))
741- then throw("fee collector not configured")
742- else if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
743- then throw("this asset is not supported by the market")
744- else {
745- let interest = tryGetInteger((("fee_" + assetIdStr) + "_interest"))
746- let stk = tryGetInteger((("fee_" + assetIdStr) + "_staking"))
747- let liq = tryGetInteger((("fee_" + assetIdStr) + "_liquidation"))
748- let total = ((interest + stk) + liq)
749- if ((0 >= total))
750- then nil
751- else {
752- let bal = getBalance(assetIdStr)
753- let isStaked = (tryGetString(("setup_autostake_" + assetIdStr)) != "")
754- let unstakeInv = if (if (isStaked)
755- then (total > bal)
756- else false)
757- then invoke(this, "unstakeToken", [assetIdStr, (total - bal)], nil)
758- else unit
759- if ((unstakeInv == unstakeInv))
760- then {
761- let liquid = getBalance(assetIdStr)
762- let payable = min([total, liquid])
763- let payInterest = min([max([interest, 0]), payable])
764- let payStk = min([max([stk, 0]), (payable - payInterest)])
765- let payLiq = min([max([liq, 0]), ((payable - payInterest) - payStk)])
766- let pay = ((payInterest + payStk) + payLiq)
767- if ((0 >= pay))
768- then nil
769- else {
770- let recordInv = invoke(addressFromStringValue(value(feeCollectorAddressStr)), "processFees", [assetIdStr, payInterest, payStk, payLiq], [AttachedPayment(getAssetBytes(assetIdStr), pay)])
771- if ((recordInv == recordInv))
772- then [IntegerEntry((("fee_" + assetIdStr) + "_interest"), (interest - payInterest)), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (stk - payStk)), IntegerEntry((("fee_" + assetIdStr) + "_liquidation"), (liq - payLiq))]
773- else throw("Strict value is not equal to itself.")
774- }
775- }
776- else throw("Strict value is not equal to itself.")
777- }
778- }
779-
780-
781-
782-@Callable(i)
783-func claimFeesAll (tokensList) = {
784- let tokens = if ((tokensList == ""))
785- then getMarketAssets()
786- else split(tokensList, ",")
787- func f (accum,token) = {
788- let inv = invoke(this, "claimFees", [token], nil)
789- if ((inv == inv))
790- then accum
791- else throw("Strict value is not equal to itself.")
792- }
793-
794- let done = {
795- let $l = tokens
796- let $s = size($l)
797- let $acc0 = unit
798- func $f0_1 ($a,$i) = if (($i >= $s))
799- then $a
800- else f($a, $l[$i])
801-
802- func $f0_2 ($a,$i) = if (($i >= $s))
803- then $a
804- else throw("List size exceeds 12")
805-
806- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
807- }
808- if ((done == done))
48+func triggerInterest (marketAddr,assetIdStr,amount) = {
49+ let market = addressFromStringValue(marketAddr)
50+ let inv = invoke(market, "addInterest", [assetIdStr, amount], nil)
51+ if ((inv == inv))
80952 then nil
81053 else throw("Strict value is not equal to itself.")
81154 }
81255
81356
814-
815-@Callable(i)
816-func claimLiquidatorRewards (assetIdStr) = {
817- let liqProxyStr = valueOrElse(getString(this, "setup_address_liquidatorProxy"), "")
818- if ((liqProxyStr == ""))
819- then throw("liquidator proxy not configured")
820- else if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
821- then throw("this asset is not supported by the market")
822- else {
823- let reward = tryGetInteger(("liqReward_" + assetIdStr))
824- if ((0 >= reward))
825- then nil
826- else {
827- let bal = getBalance(assetIdStr)
828- let isStaked = (tryGetString(("setup_autostake_" + assetIdStr)) != "")
829- let unstakeInv = if (if (isStaked)
830- then (reward > bal)
831- else false)
832- then invoke(this, "unstakeToken", [assetIdStr, (reward - bal)], nil)
833- else unit
834- if ((unstakeInv == unstakeInv))
835- then {
836- let liquid = getBalance(assetIdStr)
837- let pay = min([reward, liquid])
838- if ((0 >= pay))
839- then nil
840- else [ScriptTransfer(addressFromStringValue(liqProxyStr), pay, getAssetBytes(assetIdStr)), IntegerEntry(("liqReward_" + assetIdStr), (reward - pay))]
841- }
842- else throw("Strict value is not equal to itself.")
843- }
844- }
845- }
846-
847-
848-
849-@Callable(i)
850-func reSetup (assetIdStr) = if (true)
851- then throw("Resetup disabled")
852- else {
853- let lastResetup = tryGetInteger("resetup_lastUpdate")
854- if ((dayBlocks > (height - lastResetup)))
855- then throw("can be updated only once per day")
856- else {
857- let lts = split(tryGetString("setup_lts"), ",")
858- let assets = getMarketAssets()
859- let ur = getUr(assetIdStr)
860- let tempLT = tryGetInteger((("setup_" + assetIdStr) + "_tempLT"))
861- let lt = parseIntValue(assets[value(indexOf(assets, assetIdStr))])
862- if ((ur > 90000000))
863- then [IntegerEntry((("setup_" + assetIdStr) + "_tempLT"), fraction(tempLT, 9975, 10000))]
864- else if (if ((lt > tempLT))
865- then (90000000 > ur)
866- else false)
867- then [IntegerEntry((("setup_" + assetIdStr) + "_tempLT"), fraction(tempLT, 10025, 10000))]
868- else nil
869- }
870- }
871-
872-
873-
874-@Callable(i)
875-func shutdown (shutdown) = if ((indexOf(shutdownWhitelist, i.caller) == unit))
876- then throw("user not in a whitelist")
877- else [BooleanEntry("setup_active", !(shutdown))]
878-
879-
880-
881-@Callable(i)
882-func liquidate (debug,address,assetAmount,sAssetIdStr,bAssetIdStr,routeStr) = if (!(verifyLiquidatorRights(i.caller)))
883- then throw("temporarily available for whitelist only")
884- else if (!(tryGetBoolean("setup_active")))
885- then throw("market is stopped")
886- else {
887- let userCollateral = calcUserCollateral(address)
888- if ((userCollateral == userCollateral))
889- then {
890- let sRate = tokenRatesRecalc(sAssetIdStr)[0].value
891- let $t04188541954 = getActualRate(bAssetIdStr, "bRate")
892- let bRate = $t04188541954._1
893- let ratesRecalcResult2 = $t04188541954._2
894- let sAssetAmount = fraction(assetAmount, Scale16, sRate)
895- let currentSPosition = tryGetInteger(((address + "_supplied_") + sAssetIdStr))
896- let currentBPositionVal = tryGetInteger(((address + "_borrowed_") + bAssetIdStr))
897- let currentBPosition = if ((currentBPositionVal > 0))
898- then currentBPositionVal
899- else throw("user has no borrow in this token")
900- if ((userCollateral > 0))
901- then throw("user can't be liquidated")
902- else if ((sAssetAmount > currentSPosition))
903- then throw("position to liquidate is bigger than user's supply")
904- else {
905- let inv = if ((tryGetString(("setup_autostake_" + sAssetIdStr)) != ""))
906- then invoke(this, "unstakeToken", [sAssetIdStr, assetAmount], nil)
907- else unit
908- if ((inv == inv))
909- then {
910- let balance0Before = getBalance(sAssetIdStr)
911- if ((balance0Before == balance0Before))
912- then {
913- let balance1Before = getBalance(bAssetIdStr)
914- if ((balance1Before == balance1Before))
915- then {
916- let exchangeInvoke = invoke(aggregatorAddress, "swap", [routeStr, 0], [AttachedPayment(getAssetBytes(sAssetIdStr), assetAmount)])
917- if ((exchangeInvoke == exchangeInvoke))
918- then {
919- let asset0Sold = (balance0Before - getBalance(sAssetIdStr))
920- if ((asset0Sold == asset0Sold))
921- then {
922- let asset1Bought = (getBalance(bAssetIdStr) - balance1Before)
923- if ((asset1Bought == asset1Bought))
924- then {
925- let asset0Price = getTokenPriceCapped(sAssetIdStr)._1
926- let asset0Scale = calcAssetScale(sAssetIdStr)
927- let asset0Usd = fraction(asset0Sold, asset0Price, asset0Scale)
928- let asset1Price = getTokenPriceCapped(bAssetIdStr)._2
929- let asset1Scale = calcAssetScale(bAssetIdStr)
930- let asset1Usd = fraction(asset1Bought, asset1Price, asset1Scale)
931- let penalty = parseIntValue(split(tryGetString("setup_penalties"), ",")[value(indexOf(getMarketAssets(), bAssetIdStr))])
932- let liquidationProfit = (asset1Usd - fraction(asset0Usd, (Scale8 - penalty), Scale8))
933- let sAssetChange = fraction(asset0Sold, Scale16, sRate)
934- let bAssetChange = fraction(fraction(asset1Bought, Scale16, bRate), (Scale8 - fraction(liquidationProfit, Scale8, asset1Usd)), Scale8)
935- let penaltyTokens = (asset1Bought - fraction(bAssetChange, bRate, Scale16))
936- let liqProxyStr = valueOrElse(getString(this, "setup_address_liquidatorProxy"), "")
937- let liquidatorShare = if (if ((liqProxyStr != ""))
938- then (toString(i.caller) == liqProxyStr)
939- else false)
940- then min([max([valueOrElse(getInteger(addressFromStringValue(liqProxyStr), "setup_penaltyShare"), 0), 0]), 10000])
941- else 0
942- let liquidatorPart = fraction(penaltyTokens, liquidatorShare, 10000)
943- if ((asset0Sold > assetAmount))
944- then throw("more assets exchanged than expected")
945- else if ((0 > liquidationProfit))
946- then throw("price impact is bigger than liquidation penalty")
947- else if ((bAssetChange > currentBPosition))
948- then throw("debt reduction exceeds user's borrow")
949- else $Tuple2((([IntegerEntry(((address + "_supplied_") + sAssetIdStr), (currentSPosition - sAssetChange)), IntegerEntry(((address + "_borrowed_") + bAssetIdStr), (currentBPosition - bAssetChange)), IntegerEntry(("total_supplied_" + sAssetIdStr), (tryGetInteger(("total_supplied_" + sAssetIdStr)) - sAssetChange)), IntegerEntry(("total_borrowed_" + bAssetIdStr), (tryGetInteger(("total_borrowed_" + bAssetIdStr)) - bAssetChange)), IntegerEntry((("fee_" + bAssetIdStr) + "_liquidation"), (tryGetInteger((("fee_" + bAssetIdStr) + "_liquidation")) + (penaltyTokens - liquidatorPart)))] ++ (if ((liquidatorPart > 0))
950- then [IntegerEntry(("liqReward_" + bAssetIdStr), (tryGetInteger(("liqReward_" + bAssetIdStr)) + liquidatorPart))]
951- else nil)) ++ ratesRecalcResult2), liquidatorPart)
952- }
953- else throw("Strict value is not equal to itself.")
954- }
955- else throw("Strict value is not equal to itself.")
956- }
957- else throw("Strict value is not equal to itself.")
958- }
959- else throw("Strict value is not equal to itself.")
960- }
961- else throw("Strict value is not equal to itself.")
962- }
963- else throw("Strict value is not equal to itself.")
964- }
965- }
966- else throw("Strict value is not equal to itself.")
967- }
968-
969-
970-
971-@Callable(i)
972-func liquidateV2 (debug,address,sAssetIdStr) = if (!(verifyLiquidatorRights(i.caller)))
973- then throw("temporarily available for whitelist only")
974- else if (!(tryGetBoolean("setup_active")))
975- then throw("market is stopped")
976- else if ((size(i.payments) != 1))
977- then throw("exactly 1 payment has to be attached")
978- else {
979- let bAssetId = i.payments[0].assetId
980- let bAssetIdStr = getAssetString(bAssetId)
981- let bAssetAmount = i.payments[0].amount
982- let userCollateral = calcUserCollateral(address)
983- if ((userCollateral == userCollateral))
984- then if ((userCollateral > 0))
985- then throw("user can't be liquidated")
986- else {
987- let marketAssets = getMarketAssets()
988- let asset1Num = value(indexOf(marketAssets, bAssetIdStr))
989- let $t04835548417 = getActualRate(bAssetIdStr, "bRate")
990- let bRate = $t04835548417._1
991- let ratesResult = $t04835548417._2
992- let currentSPosition = tryGetInteger(((address + "_supplied_") + sAssetIdStr))
993- let currentBPositionVal = tryGetInteger(((address + "_borrowed_") + bAssetIdStr))
994- let currentBPosition = if ((currentBPositionVal > 0))
995- then currentBPositionVal
996- else throw("user has no borrow in this token")
997- let bAmountRaw = fraction(bAssetAmount, Scale16, bRate)
998- let bAmount = min([bAmountRaw, currentBPosition])
999- let bAssetAmountEff = if ((currentBPosition >= bAmountRaw))
1000- then bAssetAmount
1001- else fraction(bAmount, bRate, Scale16, CEILING)
1002- let refund = (bAssetAmount - bAssetAmountEff)
1003- let asset1Price = getTokenPriceCapped(bAssetIdStr)._2
1004- let asset1Scale = calcAssetScale(bAssetIdStr)
1005- let bAmountUsd = fraction(bAssetAmountEff, asset1Price, asset1Scale)
1006- let penalty = parseIntValue(value(split(tryGetString("setup_penalties"), ",")[asset1Num]))
1007- let asset0Price = getTokenPriceCapped(sAssetIdStr)._1
1008- let asset0Scale = calcAssetScale(sAssetIdStr)
1009- let sAmountUsd = fraction(bAmountUsd, (Scale8 + penalty), Scale8)
1010- let sAssetAmount = fraction(sAmountUsd, asset0Scale, asset0Price)
1011- let sAmount = fraction(sAssetAmount, Scale16, tokenRatesRecalc(sAssetIdStr)[0].value)
1012- if ((sAmount > currentSPosition))
1013- then throw("position to liquidate is bigger than user's supply")
1014- else {
1015- let inv = if ((tryGetString(("setup_autostake_" + sAssetIdStr)) != ""))
1016- then invoke(this, "unstakeToken", [sAssetIdStr, sAssetAmount], nil)
1017- else unit
1018- if ((inv == inv))
1019- then if (debug)
1020- then throw("liquidation will pass")
1021- else (([ScriptTransfer(i.caller, sAssetAmount, getAssetBytes(sAssetIdStr)), IntegerEntry(((address + "_supplied_") + sAssetIdStr), (currentSPosition - sAmount)), IntegerEntry(((address + "_borrowed_") + bAssetIdStr), (currentBPosition - bAmount)), IntegerEntry(("total_supplied_" + sAssetIdStr), (tryGetInteger(("total_supplied_" + sAssetIdStr)) - sAmount)), IntegerEntry(("total_borrowed_" + bAssetIdStr), (tryGetInteger(("total_borrowed_" + bAssetIdStr)) - bAmount))] ++ ratesResult) ++ (if ((refund > 0))
1022- then [ScriptTransfer(i.caller, refund, bAssetId)]
1023- else nil))
1024- else throw("Strict value is not equal to itself.")
1025- }
1026- }
1027- else throw("Strict value is not equal to itself.")
1028- }
1029-
1030-
1031-
1032-@Callable(i)
1033-func getUserCollateral (debug,address,minusBorrowed,afterChange) = {
1034- let assets = getMarketAssets()
1035- let ltvs = split(tryGetString("setup_ltvs"), ",")
1036- let lts = split(tryGetString("setup_lts"), ",")
1037- let changeHandler = split(afterChange, ",")
1038- func f (accum,next) = if ((next >= size(assets)))
1039- then accum
1040- else {
1041- let userSupplied = tryGetInteger(((address + "_supplied_") + assets[next]))
1042- let userBorrowed = tryGetInteger(((address + "_borrowed_") + assets[next]))
1043- let needTokenAccounting = if ((afterChange == ""))
1044- then if (if ((userBorrowed != 0))
1045- then true
1046- else (userSupplied != 0))
1047- then true
1048- else false
1049- else true
1050- if (needTokenAccounting)
1051- then {
1052- let assetScale = calcAssetScale(assets[next])
1053- let assetPrice = getTokenPriceForHealth(assets[next])
1054- let assetRates = tokenRatesRecalc(assets[next])
1055- ((accum + fraction(fraction(fraction((userSupplied + (if (if (if ((afterChange != ""))
1056- then (changeHandler[0] == assets[next])
1057- else false)
1058- then (changeHandler[1] == "supplied")
1059- else false)
1060- then parseIntValue(changeHandler[2])
1061- else 0)), assetRates[0].value, Scale16), parseIntValue(ltvs[next]), Scale8), assetPrice._1, assetScale)) - (if (minusBorrowed)
1062- then fraction(fraction(fraction((userBorrowed + (if (if (if ((afterChange != ""))
1063- then (changeHandler[0] == assets[next])
1064- else false)
1065- then (changeHandler[1] == "borrowed")
1066- else false)
1067- then parseIntValue(changeHandler[2])
1068- else 0)), assetRates[1].value, Scale16), Scale8, parseIntValue(lts[next])), assetPrice._2, assetScale)
1069- else 0))
1070- }
1071- else accum
1072- }
1073-
1074- let result = {
1075- let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
1076- let $s = size($l)
1077- let $acc0 = 0
1078- func $f0_1 ($a,$i) = if (($i >= $s))
1079- then $a
1080- else f($a, $l[$i])
1081-
1082- func $f0_2 ($a,$i) = if (($i >= $s))
1083- then $a
1084- else throw("List size exceeds 12")
1085-
1086- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1087- }
1088- if (debug)
1089- then throw(toString(result))
1090- else $Tuple2(nil, result)
1091- }
1092-
1093-
1094-
1095-@Callable(i)
1096-func getPrices (debug) = {
1097- let assets = getMarketAssets()
1098- func f (accum,next) = if ((next >= size(assets)))
1099- then accum
1100- else {
1101- let assetPrice = getTokenPriceWithRisk(assets[next], 3)
1102- ((((accum + toString(assetPrice._1)) + ",") + toString(assetPrice._2)) + "|")
1103- }
1104-
1105- let result = {
1106- let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
1107- let $s = size($l)
1108- let $acc0 = ""
1109- func $f0_1 ($a,$i) = if (($i >= $s))
1110- then $a
1111- else f($a, $l[$i])
1112-
1113- func $f0_2 ($a,$i) = if (($i >= $s))
1114- then $a
1115- else throw("List size exceeds 12")
1116-
1117- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1118- }
1119- if (debug)
1120- then throw(result)
1121- else $Tuple2(nil, result)
1122- }
1123-
1124-
1125-
1126-@Callable(i)
1127-func calculateUtilizationRatio (assetIdStr,debug) = if (debug)
1128- then throw(toString(getUr(assetIdStr)))
1129- else $Tuple2(nil, getUr(assetIdStr))
1130-
1131-
1132-
1133-@Callable(i)
1134-func calculateOutdatedUR (assetIdStr,debug) = if (debug)
1135- then throw(toString(getOutdatedUr(assetIdStr)))
1136- else $Tuple2(nil, getOutdatedUr(assetIdStr))
1137-
1138-
1139-
1140-@Callable(i)
1141-func calculateTokenRates (debug) = {
1142- func f (accum,assetIdStr) = {
1143- let rates = tokenRatesRecalc(assetIdStr)
1144- let rawSRate = tryGetInteger((assetIdStr + "_sRate"))
1145- let rawBRate = tryGetInteger((assetIdStr + "_bRate"))
1146- let rateEntries = ((if ((rates[0].value != rawSRate))
1147- then [rates[0]]
1148- else nil) ++ (if ((rates[1].value != rawBRate))
1149- then [rates[1]]
1150- else nil))
1151- let lastBRate = max([rawBRate, Scale16])
1152- let feeDelta = fraction(reserveFund, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), (rates[1].value - lastBRate), Scale16), 100)
1153- let feeEntries = if ((feeDelta != 0))
1154- then [IntegerEntry((("fee_" + assetIdStr) + "_interest"), (tryGetInteger((("fee_" + assetIdStr) + "_interest")) + feeDelta))]
1155- else nil
1156- $Tuple3(((((accum._1 + toString(rates[1].value)) + "|") + toString(rates[0].value)) + ","), (accum._2 ++ rateEntries), (accum._3 ++ feeEntries))
1157- }
1158-
1159- let parameter = {
1160- let $l = getMarketAssets()
1161- let $s = size($l)
1162- let $acc0 = $Tuple3("", nil, nil)
1163- func $f0_1 ($a,$i) = if (($i >= $s))
1164- then $a
1165- else f($a, $l[$i])
1166-
1167- func $f0_2 ($a,$i) = if (($i >= $s))
1168- then $a
1169- else throw("List size exceeds 12")
1170-
1171- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1172- }
1173- let lrhEntries = if ((tryGetInteger("lastRateHeight") != height))
1174- then [IntegerEntry("lastRateHeight", height)]
1175- else nil
1176- if (debug)
1177- then throw(parameter._1)
1178- else $Tuple2(((parameter._2 ++ parameter._3) ++ lrhEntries), parameter._1)
1179- }
1180-
1181-
1182-
1183-@Callable(i)
1184-func calculateTokensInterest (debug) = {
1185- func f (accum,assetIdStr) = {
1186- let rate = fraction(getInterest(assetIdStr), dayBlocks, Scale8)
1187- ((accum + toString(rate)) + ",")
1188- }
1189-
1190- let parameter = {
1191- let $l = getMarketAssets()
1192- let $s = size($l)
1193- let $acc0 = ""
1194- func $f0_1 ($a,$i) = if (($i >= $s))
1195- then $a
1196- else f($a, $l[$i])
1197-
1198- func $f0_2 ($a,$i) = if (($i >= $s))
1199- then $a
1200- else throw("List size exceeds 12")
1201-
1202- $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1203- }
1204- if (debug)
1205- then throw(parameter)
1206- else $Tuple2(nil, parameter)
1207- }
1208-
1209-
1210-
1211-@Callable(i)
1212-func setApproverAddress (approverAddress) = {
1213- let isSelf = if ((i.caller == this))
1214- then true
1215- else throw("Only self invoke")
1216- if ((isSelf == isSelf))
1217- then {
1218- let _approverAddress = addressFromString(approverAddress)
1219- let approverOk = match _approverAddress {
1220- case t: Address =>
1221- true
1222- case _ =>
1223- false
1224- }
1225- let canSetApprover = if (if (approverOk)
1226- then true
1227- else (approverAddress == ""))
1228- then true
1229- else throw("Wrong approver address")
1230- if ((canSetApprover == canSetApprover))
1231- then {
1232- let isInited = valueOrElse(getBoolean(value(_approverAddress), "INITED"), false)
1233- let hasAdmins = (valueOrElse(getString(value(_approverAddress), "ADMINS_PBKS"), "") != "")
1234- let isApproverContract = if (if ((approverAddress == ""))
1235- then true
1236- else if (isInited)
1237- then hasAdmins
1238- else false)
1239- then true
1240- else throw("Address is not approver contract")
1241- if ((isApproverContract == isApproverContract))
1242- then [StringEntry("APPROVER_ADDRESS", approverAddress)]
1243- else throw("Strict value is not equal to itself.")
1244- }
1245- else throw("Strict value is not equal to itself.")
1246- }
1247- else throw("Strict value is not equal to itself.")
1248- }
1249-
1250-
1251-
1252-@Callable(i)
1253-func initNewMaster (master) = {
1254- let addressOK = match addressFromString(master) {
1255- case a: Address =>
1256- true
1257- case _ =>
1258- false
1259- }
1260- if (!(addressOK))
1261- then throw(("incorrect address " + master))
1262- else if ((i.caller != this))
1263- then throw("available for self call only")
1264- else [StringEntry("verifier_master", master)]
1265- }
1266-
1267-
1268-
1269-@Callable(i)
1270-func requestNewMaster (newMaster) = {
1271- let addressOK = match addressFromString(newMaster) {
1272- case a: Address =>
1273- true
1274- case _ =>
1275- false
1276- }
1277- if (!(addressOK))
1278- then throw(("incorrect address " + newMaster))
1279- else if ((indexOf(sentinels, i.caller) == unit))
1280- then throw("whitelist only")
1281- else [StringEntry("verifier_newMaster", newMaster), IntegerEntry("verifier_newMasterEligibleAfter", (height + 10000))]
1282- }
1283-
1284-
1285-
1286-@Callable(i)
1287-func activateNewMaster () = {
1288- let eligibleHeight = getIntegerValue(this, "verifier_newMasterEligibleAfter")
1289- let newMaster = getStringValue(this, "verifier_newMaster")
1290- if ((indexOf(sentinels, i.caller) == unit))
1291- then throw("whitelist only")
1292- else if ((eligibleHeight > height))
1293- then throw("new master cannot be activated yet")
1294- else [DeleteEntry("verifier_newMaster"), DeleteEntry("verifier_newMasterEligibleAfter"), StringEntry("verifier_master", newMaster)]
1295- }
1296-
1297-
1298-@Verifier(tx)
1299-func verify () = {
1300- let multisigStr = valueOrElse(getString("APPROVER_ADDRESS"), "")
1301- let multisigAddress = addressFromString(multisigStr)
1302- let multisigOk = match multisigAddress {
1303- case t: Address =>
1304- true
1305- case _ =>
1306- false
1307- }
1308- let isInited = if (multisigOk)
1309- then valueOrElse(getBoolean(value(multisigAddress), "INITED"), false)
1310- else false
1311- let hasAdmins = if (multisigOk)
1312- then (valueOrElse(getString(value(multisigAddress), "ADMINS_PBKS"), "") != "")
1313- else false
1314- if (if (if (multisigOk)
1315- then isInited
1316- else false)
1317- then hasAdmins
1318- else false)
1319- then match tx {
1320- case ttx: SetScriptTransaction =>
1321- match ttx.script {
1322- case script: ByteVector =>
1323- let scriptHasha = toBase58String(blake2b256(script))
1324- let validFrom = valueOrErrorMessage(getInteger(value(multisigAddress), (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validFrom")), "validFrom not set")
1325- let validTo = valueOrErrorMessage(getInteger(value(multisigAddress), (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validTo")), "validTo not set")
1326- if (if (if ((height >= validFrom))
1327- then (validTo >= height)
1328- else false)
1329- then (12000000 >= ttx.fee)
1330- else false)
1331- then (scriptHash(this) != blake2b256(script))
1332- else false
1333- case _ =>
1334- false
1335- }
1336- case otx =>
1337- let taskId = ((("tx_" + toString(this)) + "_") + toBase58String(otx.id))
1338- let isApproved = valueOrElse(getBoolean(value(multisigAddress), (((toString(this) + "_") + toBase58String(otx.id)) + "__approved")), false)
1339- let approvedFrom = valueOrElse(getInteger(value(multisigAddress), (taskId + "__approvedFrom")), 0)
1340- if (isApproved)
1341- then (height >= approvedFrom)
1342- else false
1343- }
1344- else {
1345- let masterAddress = getString("verifier_master")
1346- let approvedByMaster = match masterAddress {
1347- case x: String =>
1348- match getInteger(addressFromStringValue(x), ("approvedTx_" + toBase58String(tx.id))) {
1349- case y: Int =>
1350- y
1351- case _ =>
1352- 0
1353- }
1354- case _ =>
1355- 1
1356- }
1357- if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
1358- then (approvedByMaster > 0)
1359- else false
1360- }
1361- }
1362-

github/deemru/w8io
124.29 ms