1 | | - | {-# STDLIB_VERSION 6 #-} |
---|
2 | | - | {-# SCRIPT_TYPE ACCOUNT #-} |
---|
3 | | - | {-# CONTENT_TYPE DAPP #-} |
---|
4 | | - | let k_ora_key = "k_ora_key" |
---|
5 | | - | |
---|
6 | | - | let k_ora_block_key = "k_ora_block_key" |
---|
7 | | - | |
---|
8 | | - | let k_ora = "k_ora" |
---|
9 | | - | |
---|
10 | | - | let k_balance = "k_balance" |
---|
11 | | - | |
---|
12 | | - | let k_positionSize = "k_positionSize" |
---|
13 | | - | |
---|
14 | | - | let k_positionMargin = "k_positionMargin" |
---|
15 | | - | |
---|
16 | | - | let k_positionOpenNotional = "k_positionOpenNotional" |
---|
17 | | - | |
---|
18 | | - | let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction" |
---|
19 | | - | |
---|
20 | | - | let k_initialized = "k_initialized" |
---|
21 | | - | |
---|
22 | | - | let k_paused = "k_paused" |
---|
23 | | - | |
---|
24 | | - | let k_fee = "k_fee" |
---|
25 | | - | |
---|
26 | | - | let k_fundingPeriod = "k_fundingPeriod" |
---|
27 | | - | |
---|
28 | | - | let k_initMarginRatio = "k_initMarginRatio" |
---|
29 | | - | |
---|
30 | | - | let k_maintenanceMarginRatio = "k_mmr" |
---|
31 | | - | |
---|
32 | | - | let k_liquidationFeeRatio = "k_liquidationFeeRatio" |
---|
33 | | - | |
---|
34 | | - | let k_partialLiquidationRatio = "k_partLiquidationRatio" |
---|
35 | | - | |
---|
36 | | - | let k_spreadLimit = "k_spreadLimit" |
---|
37 | | - | |
---|
38 | | - | let k_maxPriceImpact = "k_maxPriceImpact" |
---|
39 | | - | |
---|
40 | | - | let k_maxPriceSpread = "k_maxPriceSpread" |
---|
41 | | - | |
---|
42 | | - | let k_lastDataStr = "k_lastDataStr" |
---|
43 | | - | |
---|
44 | | - | let k_lastMinuteId = "k_lastMinuteId" |
---|
45 | | - | |
---|
46 | | - | let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice" |
---|
47 | | - | |
---|
48 | | - | let k_twapDataLastPrice = "k_twapDataLastPrice" |
---|
49 | | - | |
---|
50 | | - | let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId" |
---|
51 | | - | |
---|
52 | | - | let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction" |
---|
53 | | - | |
---|
54 | | - | let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction" |
---|
55 | | - | |
---|
56 | | - | let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp" |
---|
57 | | - | |
---|
58 | | - | let k_longFundingRate = "k_longFundingRate" |
---|
59 | | - | |
---|
60 | | - | let k_shortFundingRate = "k_shortFundingRate" |
---|
61 | | - | |
---|
62 | | - | let k_quoteAssetReserve = "k_qtAstR" |
---|
63 | | - | |
---|
64 | | - | let k_baseAssetReserve = "k_bsAstR" |
---|
65 | | - | |
---|
66 | | - | let k_totalPositionSize = "k_totalPositionSize" |
---|
67 | | - | |
---|
68 | | - | let k_totalLongPositionSize = "k_totalLongPositionSize" |
---|
69 | | - | |
---|
70 | | - | let k_totalShortPositionSize = "k_totalShortPositionSize" |
---|
71 | | - | |
---|
72 | | - | let k_cumulativeNotional = "k_cumulativeNotional" |
---|
73 | | - | |
---|
74 | | - | let k_openInterestNotional = "k_openInterestNotional" |
---|
75 | | - | |
---|
76 | | - | let k_coordinatorAddress = "k_coordinatorAddress" |
---|
77 | | - | |
---|
78 | | - | let k_insurance_address = "k_insurance_address" |
---|
79 | | - | |
---|
80 | | - | let k_admin_address = "k_admin_address" |
---|
81 | | - | |
---|
82 | | - | let k_admin_public_key = "k_admin_public_key" |
---|
83 | | - | |
---|
84 | | - | let k_quote_asset = "k_quote_asset" |
---|
85 | | - | |
---|
86 | | - | let k_quote_staking = "k_quote_staking" |
---|
87 | | - | |
---|
88 | | - | let k_staking_address = "k_staking_address" |
---|
89 | | - | |
---|
90 | | - | let k_miner_address = "k_miner_address" |
---|
91 | | - | |
---|
92 | | - | func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set") |
---|
93 | | - | |
---|
94 | | - | |
---|
95 | | - | func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address)) |
---|
96 | | - | |
---|
97 | | - | |
---|
98 | | - | func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key)) |
---|
99 | | - | |
---|
100 | | - | |
---|
101 | | - | func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset)) |
---|
102 | | - | |
---|
103 | | - | |
---|
104 | | - | func quoteAssetStaking () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_quote_staking)), "Quote asset staking not set") |
---|
105 | | - | |
---|
106 | | - | |
---|
107 | | - | func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Insurance not set") |
---|
108 | | - | |
---|
109 | | - | |
---|
110 | | - | func insuranceAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_insurance_address)), "Insurance not set") |
---|
111 | | - | |
---|
112 | | - | |
---|
113 | | - | func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Insurance not set") |
---|
114 | | - | |
---|
115 | | - | |
---|
116 | | - | let DIR_LONG = 1 |
---|
117 | | - | |
---|
118 | | - | let DIR_SHORT = 2 |
---|
119 | | - | |
---|
120 | | - | let TWAP_INTERVAL = 15 |
---|
121 | | - | |
---|
122 | | - | let ORACLE_INTERVAL = 15 |
---|
123 | | - | |
---|
124 | | - | let SECONDS = 1000 |
---|
125 | | - | |
---|
126 | | - | let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10)) |
---|
127 | | - | |
---|
128 | | - | let ONE_DAY = (86400 * DECIMAL_UNIT) |
---|
129 | | - | |
---|
130 | | - | let ALL_FEES = 100 |
---|
131 | | - | |
---|
132 | | - | let PNL_OPTION_SPOT = 1 |
---|
133 | | - | |
---|
134 | | - | let PNL_OPTION_ORACLE = 2 |
---|
135 | | - | |
---|
136 | | - | func s (_x) = (toString(_x) + ",") |
---|
137 | | - | |
---|
138 | | - | |
---|
139 | | - | func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN) |
---|
140 | | - | |
---|
141 | | - | |
---|
142 | | - | func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN) |
---|
143 | | - | |
---|
144 | | - | |
---|
145 | | - | func abs (_x) = if ((_x > 0)) |
---|
146 | | - | then _x |
---|
147 | | - | else -(_x) |
---|
148 | | - | |
---|
149 | | - | |
---|
150 | | - | func vmax (_x,_y) = if ((_x >= _y)) |
---|
151 | | - | then _x |
---|
152 | | - | else _y |
---|
153 | | - | |
---|
154 | | - | |
---|
155 | | - | func toCompositeKey (_key,_address) = ((_key + "_") + _address) |
---|
156 | | - | |
---|
157 | | - | |
---|
158 | | - | func listToStr (_list) = { |
---|
159 | | - | func _join (accumulator,val) = ((accumulator + val) + ",") |
---|
160 | | - | |
---|
161 | | - | let newListStr = { |
---|
162 | | - | let $l = _list |
---|
163 | | - | let $s = size($l) |
---|
164 | | - | let $acc0 = "" |
---|
165 | | - | func $f0_1 ($a,$i) = if (($i >= $s)) |
---|
166 | | - | then $a |
---|
167 | | - | else _join($a, $l[$i]) |
---|
168 | | - | |
---|
169 | | - | func $f0_2 ($a,$i) = if (($i >= $s)) |
---|
170 | | - | then $a |
---|
171 | | - | else throw("List size exceeds 20") |
---|
172 | | - | |
---|
173 | | - | $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($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), 16), 17), 18), 19), 20) |
---|
174 | | - | } |
---|
175 | | - | let newListStrU = dropRight(newListStr, 1) |
---|
176 | | - | let newListStrR = if ((take(newListStrU, 1) == ",")) |
---|
177 | | - | then drop(newListStrU, 1) |
---|
178 | | - | else newListStrU |
---|
179 | | - | newListStrR |
---|
180 | | - | } |
---|
181 | | - | |
---|
182 | | - | |
---|
183 | | - | func strToList (_str) = split(_str, ",") |
---|
184 | | - | |
---|
185 | | - | |
---|
186 | | - | func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize)) |
---|
187 | | - | then (removeByIndex(_list, 0) :+ _value) |
---|
188 | | - | else (_list :+ _value) |
---|
189 | | - | |
---|
190 | | - | |
---|
191 | | - | func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k)) |
---|
192 | | - | |
---|
193 | | - | |
---|
194 | | - | func cbalance () = int(k_balance) |
---|
195 | | - | |
---|
196 | | - | |
---|
197 | | - | func fee () = int(k_fee) |
---|
198 | | - | |
---|
199 | | - | |
---|
200 | | - | func initMarginRatio () = int(k_initMarginRatio) |
---|
201 | | - | |
---|
202 | | - | |
---|
203 | | - | func qtAstR () = int(k_quoteAssetReserve) |
---|
204 | | - | |
---|
205 | | - | |
---|
206 | | - | func bsAstR () = int(k_baseAssetReserve) |
---|
207 | | - | |
---|
208 | | - | |
---|
209 | | - | func totalPositionSize () = int(k_totalPositionSize) |
---|
210 | | - | |
---|
211 | | - | |
---|
212 | | - | func cumulativeNotional () = int(k_cumulativeNotional) |
---|
213 | | - | |
---|
214 | | - | |
---|
215 | | - | func openInterestNotional () = int(k_openInterestNotional) |
---|
216 | | - | |
---|
217 | | - | |
---|
218 | | - | func nextFundingBlockTimestamp () = int(k_nextFundingBlock) |
---|
219 | | - | |
---|
220 | | - | |
---|
221 | | - | func fundingPeriodRaw () = int(k_fundingPeriod) |
---|
222 | | - | |
---|
223 | | - | |
---|
224 | | - | func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT) |
---|
225 | | - | |
---|
226 | | - | |
---|
227 | | - | func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS) |
---|
228 | | - | |
---|
229 | | - | |
---|
230 | | - | func maintenanceMarginRatio () = int(k_maintenanceMarginRatio) |
---|
231 | | - | |
---|
232 | | - | |
---|
233 | | - | func liquidationFeeRatio () = int(k_liquidationFeeRatio) |
---|
234 | | - | |
---|
235 | | - | |
---|
236 | | - | func partialLiquidationRatio () = int(k_partialLiquidationRatio) |
---|
237 | | - | |
---|
238 | | - | |
---|
239 | | - | func spreadLimit () = int(k_spreadLimit) |
---|
240 | | - | |
---|
241 | | - | |
---|
242 | | - | func maxPriceImpact () = int(k_maxPriceImpact) |
---|
243 | | - | |
---|
244 | | - | |
---|
245 | | - | func maxPriceSpread () = int(k_maxPriceSpread) |
---|
246 | | - | |
---|
247 | | - | |
---|
248 | | - | func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction) |
---|
249 | | - | |
---|
250 | | - | |
---|
251 | | - | func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction) |
---|
252 | | - | |
---|
253 | | - | |
---|
254 | | - | func totalShortPositionSize () = int(k_totalShortPositionSize) |
---|
255 | | - | |
---|
256 | | - | |
---|
257 | | - | func totalLongPositionSize () = int(k_totalLongPositionSize) |
---|
258 | | - | |
---|
259 | | - | |
---|
260 | | - | func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = { |
---|
261 | | - | let remainingMarginRatio = (_marginRatio - _baseMarginRatio) |
---|
262 | | - | if (if (_largerThanOrEqualTo) |
---|
263 | | - | then (0 > remainingMarginRatio) |
---|
264 | | - | else false) |
---|
265 | | - | then throw("Invalid margin") |
---|
266 | | - | else if (if (!(_largerThanOrEqualTo)) |
---|
267 | | - | then (remainingMarginRatio >= 0) |
---|
268 | | - | else false) |
---|
269 | | - | then throw("Invalid margin") |
---|
270 | | - | else true |
---|
271 | | - | } |
---|
272 | | - | |
---|
273 | | - | |
---|
274 | | - | func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0)) |
---|
275 | | - | then throw("Should not be called with _positionSize == 0") |
---|
276 | | - | else if ((_positionSize > 0)) |
---|
277 | | - | then latestLongCumulativePremiumFraction() |
---|
278 | | - | else latestShortCumulativePremiumFraction() |
---|
279 | | - | |
---|
280 | | - | |
---|
281 | | - | func getPosition (_trader) = { |
---|
282 | | - | let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader)) |
---|
283 | | - | match positionSizeOpt { |
---|
284 | | - | case positionSize: Int => |
---|
285 | | - | $Tuple4(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader))) |
---|
286 | | - | case _ => |
---|
287 | | - | $Tuple4(0, 0, 0, 0) |
---|
288 | | - | } |
---|
289 | | - | } |
---|
290 | | - | |
---|
291 | | - | |
---|
292 | | - | func requireOpenPosition (_trader) = if ((getPosition(_trader)._1 == 0)) |
---|
293 | | - | then throw("No open position") |
---|
294 | | - | else true |
---|
295 | | - | |
---|
296 | | - | |
---|
297 | | - | func initialized () = valueOrElse(getBoolean(this, k_initialized), false) |
---|
298 | | - | |
---|
299 | | - | |
---|
300 | | - | func paused () = valueOrElse(getBoolean(this, k_paused), false) |
---|
301 | | - | |
---|
302 | | - | |
---|
303 | | - | func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd) |
---|
304 | | - | then { |
---|
305 | | - | let newBase = (bsAstR() - _baseAssetAmount) |
---|
306 | | - | if ((0 >= newBase)) |
---|
307 | | - | then throw("Tx lead to base asset reserve <= 0, revert") |
---|
308 | | - | else $Tuple4((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount), (cumulativeNotional() + _quoteAssetAmount)) |
---|
309 | | - | } |
---|
310 | | - | else { |
---|
311 | | - | let newQuote = (qtAstR() - _quoteAssetAmount) |
---|
312 | | - | if ((0 >= newQuote)) |
---|
313 | | - | then throw("Tx lead to base quote reserve <= 0, revert") |
---|
314 | | - | else $Tuple4(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount), (cumulativeNotional() - _quoteAssetAmount)) |
---|
315 | | - | } |
---|
316 | | - | |
---|
317 | | - | |
---|
318 | | - | func swapInput (_isAdd,_quoteAssetAmount) = { |
---|
319 | | - | let _qtAstR = qtAstR() |
---|
320 | | - | let _bsAstR = bsAstR() |
---|
321 | | - | let k = muld(_qtAstR, _bsAstR) |
---|
322 | | - | let quoteAssetReserveAfter = if (_isAdd) |
---|
323 | | - | then (_qtAstR + _quoteAssetAmount) |
---|
324 | | - | else (_qtAstR - _quoteAssetAmount) |
---|
325 | | - | let baseAssetReserveAfter = divd(k, quoteAssetReserveAfter) |
---|
326 | | - | let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR)) |
---|
327 | | - | let amountBaseAssetBought = if (_isAdd) |
---|
328 | | - | then amountBaseAssetBoughtAbs |
---|
329 | | - | else -(amountBaseAssetBoughtAbs) |
---|
330 | | - | let $t01217712370 = updateReserve(_isAdd, _quoteAssetAmount, amountBaseAssetBoughtAbs) |
---|
331 | | - | let quoteAssetReserveAfter1 = $t01217712370._1 |
---|
332 | | - | let baseAssetReserveAfter1 = $t01217712370._2 |
---|
333 | | - | let totalPositionSizeAfter1 = $t01217712370._3 |
---|
334 | | - | let cumulativeNotionalAfter1 = $t01217712370._4 |
---|
335 | | - | let priceBefore = divd(_qtAstR, _bsAstR) |
---|
336 | | - | let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs) |
---|
337 | | - | let priceDiff = abs((priceBefore - marketPrice)) |
---|
338 | | - | let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff))) |
---|
339 | | - | let maxPriceImpactValue = maxPriceImpact() |
---|
340 | | - | if ((priceImpact > maxPriceImpactValue)) |
---|
341 | | - | then throw(((((((((((((("Price impact " + toString(priceImpact)) + " > max price impact ") + toString(maxPriceImpactValue)) + " before quote asset: ") + toString(_qtAstR)) + " before base asset: ") + toString(_bsAstR)) + " quote asset amount to exchange: ") + toString(_quoteAssetAmount)) + " price before: ") + toString(priceBefore)) + " marketPrice: ") + toString(marketPrice))) |
---|
342 | | - | else $Tuple5(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, cumulativeNotionalAfter1) |
---|
343 | | - | } |
---|
344 | | - | |
---|
345 | | - | |
---|
346 | | - | func calcRemainMarginWithFundingPayment (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_marginDelta) = { |
---|
347 | | - | let fundingPayment = if ((_oldPositionSize != 0)) |
---|
348 | | - | then { |
---|
349 | | - | let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize) |
---|
350 | | - | muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize) |
---|
351 | | - | } |
---|
352 | | - | else 0 |
---|
353 | | - | let signedMargin = ((_marginDelta - fundingPayment) + _oldPositionMargin) |
---|
354 | | - | let $t01386113988 = if ((0 > signedMargin)) |
---|
355 | | - | then $Tuple2(0, abs(signedMargin)) |
---|
356 | | - | else $Tuple2(abs(signedMargin), 0) |
---|
357 | | - | let remainMargin = $t01386113988._1 |
---|
358 | | - | let badDebt = $t01386113988._2 |
---|
359 | | - | $Tuple3(remainMargin, badDebt, fundingPayment) |
---|
360 | | - | } |
---|
361 | | - | |
---|
362 | | - | |
---|
363 | | - | func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_baseAssetReserve) = { |
---|
364 | | - | let priceBefore = divd(_quoteAssetReserve, _baseAssetReserve) |
---|
365 | | - | if ((_baseAssetAmount == 0)) |
---|
366 | | - | then throw("Invalid base asset amount") |
---|
367 | | - | else { |
---|
368 | | - | let k = muld(_quoteAssetReserve, _baseAssetReserve) |
---|
369 | | - | let baseAssetPoolAmountAfter = if (_isAdd) |
---|
370 | | - | then (_baseAssetReserve + _baseAssetAmount) |
---|
371 | | - | else (_baseAssetReserve - _baseAssetAmount) |
---|
372 | | - | let quoteAssetAfter = divd(k, baseAssetPoolAmountAfter) |
---|
373 | | - | let quoteAssetSold = abs((quoteAssetAfter - _quoteAssetReserve)) |
---|
374 | | - | let maxPriceImpactValue = maxPriceImpact() |
---|
375 | | - | let $t01496515158 = updateReserve(!(_isAdd), quoteAssetSold, _baseAssetAmount) |
---|
376 | | - | let quoteAssetReserveAfter1 = $t01496515158._1 |
---|
377 | | - | let baseAssetReserveAfter1 = $t01496515158._2 |
---|
378 | | - | let totalPositionSizeAfter1 = $t01496515158._3 |
---|
379 | | - | let cumulativeNotionalAfter1 = $t01496515158._4 |
---|
380 | | - | let marketPrice = divd(quoteAssetSold, _baseAssetAmount) |
---|
381 | | - | let priceDiff = abs((priceBefore - marketPrice)) |
---|
382 | | - | let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff))) |
---|
383 | | - | if (if ((priceImpact > maxPriceImpactValue)) |
---|
384 | | - | then _checkMaxPriceImpact |
---|
385 | | - | else false) |
---|
386 | | - | then throw(((((((((((((("Price impact " + toString(priceImpact)) + " > max price impact ") + toString(maxPriceImpactValue)) + " before quote asset: ") + toString(_quoteAssetReserve)) + " before base asset: ") + toString(_baseAssetReserve)) + " base asset amount to exchange: ") + toString(_baseAssetAmount)) + " price before: ") + toString(priceBefore)) + " market price: ") + toString(marketPrice))) |
---|
387 | | - | else $Tuple8(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, cumulativeNotionalAfter1, (totalLongPositionSize() - (if (_isAdd) |
---|
388 | | - | then abs(_baseAssetAmount) |
---|
389 | | - | else 0)), (totalShortPositionSize() - (if (!(_isAdd)) |
---|
390 | | - | then abs(_baseAssetAmount) |
---|
391 | | - | else 0)), priceImpact) |
---|
392 | | - | } |
---|
393 | | - | } |
---|
394 | | - | |
---|
395 | | - | |
---|
396 | | - | func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), bsAstR()) |
---|
397 | | - | |
---|
398 | | - | |
---|
399 | | - | func getOracleTwapPrice () = { |
---|
400 | | - | let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "") |
---|
401 | | - | let priceKey = getStringValue(this, k_ora_key) |
---|
402 | | - | let blockKey = getStringValue(this, k_ora_block_key) |
---|
403 | | - | let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey)) |
---|
404 | | - | lastValue |
---|
405 | | - | } |
---|
406 | | - | |
---|
407 | | - | |
---|
408 | | - | func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = { |
---|
409 | | - | let oraclePrice = getOracleTwapPrice() |
---|
410 | | - | let priceAfter = divd(_quoteAssetReserve, _baseAssetReserve) |
---|
411 | | - | let averagePrice = divd((oraclePrice + priceAfter), (2 * DECIMAL_UNIT)) |
---|
412 | | - | let absPriceDiff = divd(abs((oraclePrice - priceAfter)), averagePrice) |
---|
413 | | - | if ((absPriceDiff > maxPriceSpread())) |
---|
414 | | - | then throw(((("Price spread " + toString(absPriceDiff)) + " > max price spread ") + toString(maxPriceSpread()))) |
---|
415 | | - | else true |
---|
416 | | - | } |
---|
417 | | - | |
---|
418 | | - | |
---|
419 | | - | func getSpotPrice () = { |
---|
420 | | - | let _quoteAssetReserve = qtAstR() |
---|
421 | | - | let _baseAssetReserve = bsAstR() |
---|
422 | | - | divd(_quoteAssetReserve, _baseAssetReserve) |
---|
423 | | - | } |
---|
424 | | - | |
---|
425 | | - | |
---|
426 | | - | func isOverFluctuationLimit () = { |
---|
427 | | - | let oraclePrice = getOracleTwapPrice() |
---|
428 | | - | let currentPrice = getSpotPrice() |
---|
429 | | - | (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit()) |
---|
430 | | - | } |
---|
431 | | - | |
---|
432 | | - | |
---|
433 | | - | func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_baseAssetReserve) = { |
---|
434 | | - | let positionSizeAbs = abs(_positionSize) |
---|
435 | | - | let isShort = (0 > _positionSize) |
---|
436 | | - | let positionNotional = if ((_option == PNL_OPTION_SPOT)) |
---|
437 | | - | then { |
---|
438 | | - | let $t01837618547 = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _baseAssetReserve) |
---|
439 | | - | let outPositionNotional = $t01837618547._1 |
---|
440 | | - | let x1 = $t01837618547._2 |
---|
441 | | - | let x2 = $t01837618547._3 |
---|
442 | | - | let x3 = $t01837618547._4 |
---|
443 | | - | outPositionNotional |
---|
444 | | - | } |
---|
445 | | - | else muld(positionSizeAbs, getOracleTwapPrice()) |
---|
446 | | - | positionNotional |
---|
447 | | - | } |
---|
448 | | - | |
---|
449 | | - | |
---|
450 | | - | func getPositionNotionalAndUnrealizedPnl (_trader,_option) = { |
---|
451 | | - | let $t01894119069 = getPosition(_trader) |
---|
452 | | - | let positionSize = $t01894119069._1 |
---|
453 | | - | let positionMargin = $t01894119069._2 |
---|
454 | | - | let positionOpenNotional = $t01894119069._3 |
---|
455 | | - | let positionLstUpdCPF = $t01894119069._4 |
---|
456 | | - | if ((positionSize == 0)) |
---|
457 | | - | then throw("Invalid position size") |
---|
458 | | - | else { |
---|
459 | | - | let isShort = (0 > positionSize) |
---|
460 | | - | let positionNotional = getPositionAdjustedOpenNotional(positionSize, _option, qtAstR(), bsAstR()) |
---|
461 | | - | let unrealizedPnl = if (isShort) |
---|
462 | | - | then (positionOpenNotional - positionNotional) |
---|
463 | | - | else (positionNotional - positionOpenNotional) |
---|
464 | | - | $Tuple2(positionNotional, unrealizedPnl) |
---|
465 | | - | } |
---|
466 | | - | } |
---|
467 | | - | |
---|
468 | | - | |
---|
469 | | - | func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional) |
---|
470 | | - | |
---|
471 | | - | |
---|
472 | | - | func getMarginRatioByOption (_trader,_option) = { |
---|
473 | | - | let $t01990220013 = getPosition(_trader) |
---|
474 | | - | let positionSize = $t01990220013._1 |
---|
475 | | - | let positionMargin = $t01990220013._2 |
---|
476 | | - | let pon = $t01990220013._3 |
---|
477 | | - | let positionLstUpdCPF = $t01990220013._4 |
---|
478 | | - | let $t02001920112 = getPositionNotionalAndUnrealizedPnl(_trader, _option) |
---|
479 | | - | let positionNotional = $t02001920112._1 |
---|
480 | | - | let unrealizedPnl = $t02001920112._2 |
---|
481 | | - | let $t02011720283 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl) |
---|
482 | | - | let remainMargin = $t02011720283._1 |
---|
483 | | - | let badDebt = $t02011720283._2 |
---|
484 | | - | calcMarginRatio(remainMargin, badDebt, positionNotional) |
---|
485 | | - | } |
---|
486 | | - | |
---|
487 | | - | |
---|
488 | | - | func getMarginRatio (_trader) = getMarginRatioByOption(_trader, PNL_OPTION_SPOT) |
---|
489 | | - | |
---|
490 | | - | |
---|
491 | | - | func getPartialLiquidationAmount (_trader,_positionSize) = { |
---|
492 | | - | let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader), maintenanceMarginRatio()))) |
---|
493 | | - | let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio) |
---|
494 | | - | let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false) |
---|
495 | | - | let maxExchangedQuoteAssetAmount = swapResult._1 |
---|
496 | | - | let priceImpact = swapResult._8 |
---|
497 | | - | if ((maxPriceImpact() > priceImpact)) |
---|
498 | | - | then maxExchangedQuoteAssetAmount |
---|
499 | | - | else { |
---|
500 | | - | let exchangedPositionSize = muld(abs(_positionSize), partialLiquidationRatio()) |
---|
501 | | - | let exchangedQuoteAssetAmount = swapOutput((_positionSize > 0), exchangedPositionSize, false)._1 |
---|
502 | | - | exchangedQuoteAssetAmount |
---|
503 | | - | } |
---|
504 | | - | } |
---|
505 | | - | |
---|
506 | | - | |
---|
507 | | - | func internalClosePosition (_trader,_checkMaxPriceImpact) = { |
---|
508 | | - | let $t02146521593 = getPosition(_trader) |
---|
509 | | - | let positionSize = $t02146521593._1 |
---|
510 | | - | let positionMargin = $t02146521593._2 |
---|
511 | | - | let positionOpenNotional = $t02146521593._3 |
---|
512 | | - | let positionLstUpdCPF = $t02146521593._4 |
---|
513 | | - | let unrealizedPnl = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)._2 |
---|
514 | | - | let $t02168821856 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl) |
---|
515 | | - | let remainMargin = $t02168821856._1 |
---|
516 | | - | let badDebt = $t02168821856._2 |
---|
517 | | - | let exchangedPositionSize = -(positionSize) |
---|
518 | | - | let realizedPnl = unrealizedPnl |
---|
519 | | - | let marginToVault = -(remainMargin) |
---|
520 | | - | let $t02198322294 = swapOutput((positionSize > 0), abs(positionSize), _checkMaxPriceImpact) |
---|
521 | | - | let exchangedQuoteAssetAmount = $t02198322294._1 |
---|
522 | | - | let quoteAssetReserveAfter = $t02198322294._2 |
---|
523 | | - | let baseAssetReserveAfter = $t02198322294._3 |
---|
524 | | - | let totalPositionSizeAfter = $t02198322294._4 |
---|
525 | | - | let cumulativeNotionalAfter = $t02198322294._5 |
---|
526 | | - | let totalLongAfter = $t02198322294._6 |
---|
527 | | - | let totalShortAfter = $t02198322294._7 |
---|
528 | | - | let openInterestNotionalAfter = (openInterestNotional() - positionOpenNotional) |
---|
529 | | - | $Tuple12(exchangedPositionSize, badDebt, realizedPnl, marginToVault, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, exchangedQuoteAssetAmount, totalLongAfter, totalShortAfter) |
---|
530 | | - | } |
---|
531 | | - | |
---|
532 | | - | |
---|
533 | | - | func getTwapSpotPrice () = { |
---|
534 | | - | let minuteId = ((lastBlock.timestamp / 1000) / 60) |
---|
535 | | - | let startMinuteId = (minuteId - TWAP_INTERVAL) |
---|
536 | | - | let listStr = valueOrElse(getString(this, k_lastDataStr), "") |
---|
537 | | - | let list = split(listStr, ",") |
---|
538 | | - | func filterFn (accumulator,next) = if ((startMinuteId >= parseIntValue(next))) |
---|
539 | | - | then (accumulator :+ parseIntValue(next)) |
---|
540 | | - | else accumulator |
---|
541 | | - | |
---|
542 | | - | let listF = { |
---|
543 | | - | let $l = list |
---|
544 | | - | let $s = size($l) |
---|
545 | | - | let $acc0 = nil |
---|
546 | | - | func $f0_1 ($a,$i) = if (($i >= $s)) |
---|
547 | | - | then $a |
---|
548 | | - | else filterFn($a, $l[$i]) |
---|
549 | | - | |
---|
550 | | - | func $f0_2 ($a,$i) = if (($i >= $s)) |
---|
551 | | - | then $a |
---|
552 | | - | else throw("List size exceeds 20") |
---|
553 | | - | |
---|
554 | | - | $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($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), 16), 17), 18), 19), 20) |
---|
555 | | - | } |
---|
556 | | - | let maxIndex = if ((size(listF) > 0)) |
---|
557 | | - | then max(listF) |
---|
558 | | - | else parseIntValue(list[0]) |
---|
559 | | - | let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0) |
---|
560 | | - | let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0) |
---|
561 | | - | let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0) |
---|
562 | | - | let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice)) |
---|
563 | | - | let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0) |
---|
564 | | - | let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0) |
---|
565 | | - | let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice)) |
---|
566 | | - | ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL) |
---|
567 | | - | } |
---|
568 | | - | |
---|
569 | | - | |
---|
570 | | - | func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread) = [IntegerEntry(k_initMarginRatio, _initMarginRatio), IntegerEntry(k_maintenanceMarginRatio, _mmr), IntegerEntry(k_liquidationFeeRatio, _liquidationFeeRatio), IntegerEntry(k_fundingPeriod, _fundingPeriod), IntegerEntry(k_fee, _fee), IntegerEntry(k_spreadLimit, _spreadLimit), IntegerEntry(k_maxPriceImpact, _maxPriceImpact), IntegerEntry(k_partialLiquidationRatio, _partialLiquidationRatio), IntegerEntry(k_maxPriceSpread, _maxPriceSpread)] |
---|
571 | | - | |
---|
572 | | - | |
---|
573 | | - | func updateFunding (_nextFundingBlock,_latestLongCumulativePremiumFraction,_latestShortCumulativePremiumFraction,_longFundingRate,_shortFundingRate) = [IntegerEntry(k_nextFundingBlock, _nextFundingBlock), IntegerEntry(k_latestLongCumulativePremiumFraction, _latestLongCumulativePremiumFraction), IntegerEntry(k_latestShortCumulativePremiumFraction, _latestShortCumulativePremiumFraction), IntegerEntry(k_longFundingRate, _longFundingRate), IntegerEntry(k_shortFundingRate, _shortFundingRate)] |
---|
574 | | - | |
---|
575 | | - | |
---|
576 | | - | func updatePosition (_address,_size,_margin,_openNotional,_latestCumulativePremiumFraction) = [IntegerEntry(toCompositeKey(k_positionSize, _address), _size), IntegerEntry(toCompositeKey(k_positionMargin, _address), _margin), IntegerEntry(toCompositeKey(k_positionOpenNotional, _address), _openNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address), _latestCumulativePremiumFraction)] |
---|
577 | | - | |
---|
578 | | - | |
---|
579 | | - | func appendTwap (price) = { |
---|
580 | | - | let minuteId = ((lastBlock.timestamp / 1000) / 60) |
---|
581 | | - | let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0) |
---|
582 | | - | if ((previousMinuteId > minuteId)) |
---|
583 | | - | then throw("TWAP out-of-order") |
---|
584 | | - | else { |
---|
585 | | - | let lastMinuteId = if ((previousMinuteId == 0)) |
---|
586 | | - | then minuteId |
---|
587 | | - | else previousMinuteId |
---|
588 | | - | if ((minuteId > previousMinuteId)) |
---|
589 | | - | then { |
---|
590 | | - | let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0) |
---|
591 | | - | let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), price) |
---|
592 | | - | let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice)) |
---|
593 | | - | let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId)) |
---|
594 | | - | [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), price), IntegerEntry(toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId)), previousMinuteId), IntegerEntry(k_lastMinuteId, minuteId), StringEntry(k_lastDataStr, listToStr(list))] |
---|
595 | | - | } |
---|
596 | | - | else { |
---|
597 | | - | let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0) |
---|
598 | | - | let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0) |
---|
599 | | - | let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), price) |
---|
600 | | - | let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice)) |
---|
601 | | - | [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), price)] |
---|
602 | | - | } |
---|
603 | | - | } |
---|
604 | | - | } |
---|
605 | | - | |
---|
606 | | - | |
---|
607 | | - | func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)] |
---|
608 | | - | |
---|
609 | | - | |
---|
610 | | - | func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_cumulativeNotionalAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize) = if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter)) |
---|
611 | | - | then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter))) |
---|
612 | | - | else ((updateAmmReserves(_qtAstR, _bsAstR) ++ [IntegerEntry(k_totalPositionSize, _totalPositionSizeAfter), IntegerEntry(k_cumulativeNotional, _cumulativeNotionalAfter), IntegerEntry(k_openInterestNotional, _openInterestNotional), IntegerEntry(k_totalLongPositionSize, _totalLongPositionSize), IntegerEntry(k_totalShortPositionSize, _totalShortPositionSize)]) ++ appendTwap(divd(_qtAstR, _bsAstR))) |
---|
613 | | - | |
---|
614 | | - | |
---|
615 | | - | func deletePosition (_address) = [DeleteEntry(toCompositeKey(k_positionSize, _address)), DeleteEntry(toCompositeKey(k_positionMargin, _address)), DeleteEntry(toCompositeKey(k_positionOpenNotional, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address))] |
---|
616 | | - | |
---|
617 | | - | |
---|
618 | | - | func withdraw (_address,_amount) = { |
---|
619 | | - | let balance = assetBalance(this, quoteAsset()) |
---|
620 | | - | if ((_amount > balance)) |
---|
621 | | - | then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance))) |
---|
622 | | - | else [ScriptTransfer(_address, _amount, quoteAsset())] |
---|
623 | | - | } |
---|
624 | | - | |
---|
625 | | - | |
---|
626 | | - | func updateBalance (i) = if ((0 > i)) |
---|
627 | | - | then throw("Balance") |
---|
628 | | - | else [IntegerEntry(k_balance, i)] |
---|
629 | | - | |
---|
630 | | - | |
---|
631 | | - | func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())] |
---|
632 | | - | |
---|
633 | | - | |
---|
634 | | - | @Callable(i) |
---|
635 | | - | func pause () = if ((i.caller != adminAddress())) |
---|
636 | | - | then throw("Invalid togglePause params") |
---|
637 | | - | else [BooleanEntry(k_paused, true)] |
---|
638 | | - | |
---|
639 | | - | |
---|
640 | | - | |
---|
641 | | - | @Callable(i) |
---|
642 | | - | func unpause () = if ((i.caller != adminAddress())) |
---|
643 | | - | then throw("Invalid togglePause params") |
---|
644 | | - | else [BooleanEntry(k_paused, false)] |
---|
645 | | - | |
---|
646 | | - | |
---|
647 | | - | |
---|
648 | | - | @Callable(i) |
---|
649 | | - | func addLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress())) |
---|
650 | | - | then true |
---|
651 | | - | else (0 >= _quoteAssetAmount)) |
---|
652 | | - | then throw("Invalid addLiquidity params") |
---|
653 | | - | else { |
---|
654 | | - | let _qtAstR = qtAstR() |
---|
655 | | - | let _bsAstR = bsAstR() |
---|
656 | | - | let price = divd(_qtAstR, _bsAstR) |
---|
657 | | - | let baseAssetAmountToAdd = divd(_quoteAssetAmount, price) |
---|
658 | | - | let qtAstRAfter = (_qtAstR + _quoteAssetAmount) |
---|
659 | | - | let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd) |
---|
660 | | - | updateAmmReserves(qtAstRAfter, bsAstRAfter) |
---|
661 | | - | } |
---|
662 | | - | |
---|
663 | | - | |
---|
664 | | - | |
---|
665 | | - | @Callable(i) |
---|
666 | | - | func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress())) |
---|
667 | | - | then true |
---|
668 | | - | else (0 >= _quoteAssetAmount)) |
---|
669 | | - | then throw("Invalid removeLiquidity params") |
---|
670 | | - | else { |
---|
671 | | - | let _qtAstR = qtAstR() |
---|
672 | | - | let _bsAstR = bsAstR() |
---|
673 | | - | let price = divd(_qtAstR, _bsAstR) |
---|
674 | | - | let baseAssetAmountToRemove = divd(_quoteAssetAmount, price) |
---|
675 | | - | let qtAstRAfter = (_qtAstR - _quoteAssetAmount) |
---|
676 | | - | let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove) |
---|
677 | | - | updateAmmReserves(qtAstRAfter, bsAstRAfter) |
---|
678 | | - | } |
---|
679 | | - | |
---|
680 | | - | |
---|
681 | | - | |
---|
682 | | - | @Callable(i) |
---|
683 | | - | func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread) = if ((i.caller != adminAddress())) |
---|
684 | | - | then throw("Invalid changeSettings params") |
---|
685 | | - | else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread) |
---|
686 | | - | |
---|
687 | | - | |
---|
688 | | - | |
---|
689 | | - | @Callable(i) |
---|
690 | | - | func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_oracle,_oracleKey,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread) = if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR)) |
---|
691 | | - | then true |
---|
692 | | - | else (0 >= _bsAstR)) |
---|
693 | | - | then true |
---|
694 | | - | else (0 >= _fundingPeriod)) |
---|
695 | | - | then true |
---|
696 | | - | else (0 >= _initMarginRatio)) |
---|
697 | | - | then true |
---|
698 | | - | else (0 >= _mmr)) |
---|
699 | | - | then true |
---|
700 | | - | else (0 >= _liquidationFeeRatio)) |
---|
701 | | - | then true |
---|
702 | | - | else (0 >= _fee)) |
---|
703 | | - | then true |
---|
704 | | - | else (0 >= _spreadLimit)) |
---|
705 | | - | then true |
---|
706 | | - | else (0 >= _maxPriceImpact)) |
---|
707 | | - | then true |
---|
708 | | - | else (0 >= _partialLiquidationRatio)) |
---|
709 | | - | then true |
---|
710 | | - | else (0 >= _maxPriceSpread)) |
---|
711 | | - | then true |
---|
712 | | - | else initialized()) |
---|
713 | | - | then throw("Invalid initialize parameters") |
---|
714 | | - | else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread)) ++ updateFunding((lastBlock.timestamp + _fundingPeriod), 0, 0, 0, 0)) ++ updateBalance(0)) ++ [BooleanEntry(k_initialized, true), StringEntry(k_ora, _oracle), StringEntry(k_ora_key, _oracleKey), StringEntry(k_coordinatorAddress, _coordinator)]) |
---|
715 | | - | |
---|
716 | | - | |
---|
717 | | - | |
---|
718 | | - | @Callable(i) |
---|
719 | | - | func setInitMarginRatio (_initMarginRatio) = if (if ((0 >= _initMarginRatio)) |
---|
720 | | - | then true |
---|
721 | | - | else !(initialized())) |
---|
722 | | - | then throw("Invalid setInitMarginRatio parameters") |
---|
723 | | - | else updateSettings(_initMarginRatio, maintenanceMarginRatio(), liquidationFeeRatio(), fundingPeriodRaw(), fee(), spreadLimit(), maxPriceImpact(), partialLiquidationRatio(), maxPriceSpread()) |
---|
724 | | - | |
---|
725 | | - | |
---|
726 | | - | |
---|
727 | | - | @Callable(i) |
---|
728 | | - | func decreasePosition (_amount,_leverage,_minBaseAssetAmount) = if (if (if (if (if ((0 >= _amount)) |
---|
729 | | - | then true |
---|
730 | | - | else !(initialized())) |
---|
731 | | - | then true |
---|
732 | | - | else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true))) |
---|
733 | | - | then true |
---|
734 | | - | else !(requireOpenPosition(toString(i.caller)))) |
---|
735 | | - | then true |
---|
736 | | - | else paused()) |
---|
737 | | - | then throw("Invalid decreasePosition parameters") |
---|
738 | | - | else { |
---|
739 | | - | let $t03418734339 = getPosition(toString(i.caller)) |
---|
740 | | - | let oldPositionSize = $t03418734339._1 |
---|
741 | | - | let oldPositionMargin = $t03418734339._2 |
---|
742 | | - | let oldPositionOpenNotional = $t03418734339._3 |
---|
743 | | - | let oldPositionLstUpdCPF = $t03418734339._4 |
---|
744 | | - | let _direction = if ((oldPositionSize > 0)) |
---|
745 | | - | then DIR_SHORT |
---|
746 | | - | else DIR_LONG |
---|
747 | | - | let isAdd = (_direction == DIR_LONG) |
---|
748 | | - | let openNotional = muld(_amount, _leverage) |
---|
749 | | - | let $t03451234628 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT) |
---|
750 | | - | let oldPositionNotional = $t03451234628._1 |
---|
751 | | - | let unrealizedPnl = $t03451234628._2 |
---|
752 | | - | let $t03463437183 = if ((oldPositionNotional > openNotional)) |
---|
753 | | - | then { |
---|
754 | | - | let $t03501135230 = swapInput(isAdd, openNotional) |
---|
755 | | - | let exchangedPositionSize = $t03501135230._1 |
---|
756 | | - | let quoteAssetReserveAfter = $t03501135230._2 |
---|
757 | | - | let baseAssetReserveAfter = $t03501135230._3 |
---|
758 | | - | let totalPositionSizeAfter = $t03501135230._4 |
---|
759 | | - | let cumulativeNotionalAfter = $t03501135230._5 |
---|
760 | | - | let exchangedPositionSizeAbs = abs(exchangedPositionSize) |
---|
761 | | - | if (if ((_minBaseAssetAmount != 0)) |
---|
762 | | - | then (_minBaseAssetAmount > exchangedPositionSizeAbs) |
---|
763 | | - | else false) |
---|
764 | | - | then throw(((("Too little base asset exchanged, got " + toString(exchangedPositionSizeAbs)) + " expected ") + toString(_minBaseAssetAmount))) |
---|
765 | | - | else { |
---|
766 | | - | let realizedPnl = divd(muld(unrealizedPnl, exchangedPositionSizeAbs), abs(oldPositionSize)) |
---|
767 | | - | let $t03566735912 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl) |
---|
768 | | - | let remainMargin = $t03566735912._1 |
---|
769 | | - | let badDebt = $t03566735912._2 |
---|
770 | | - | let fundingPayment = $t03566735912._3 |
---|
771 | | - | let exchangedQuoteAssetAmount = openNotional |
---|
772 | | - | let unrealizedPnlAfter = (unrealizedPnl - realizedPnl) |
---|
773 | | - | let remainOpenNotional = if ((oldPositionSize > 0)) |
---|
774 | | - | then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter) |
---|
775 | | - | else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount) |
---|
776 | | - | let newPositionSize = (oldPositionSize + exchangedPositionSize) |
---|
777 | | - | $Tuple11(newPositionSize, remainMargin, abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, (openInterestNotional() - openNotional), (totalLongPositionSize() - (if ((newPositionSize > 0)) |
---|
778 | | - | then abs(exchangedPositionSize) |
---|
779 | | - | else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize)) |
---|
780 | | - | then abs(exchangedPositionSize) |
---|
781 | | - | else 0))) |
---|
782 | | - | } |
---|
783 | | - | } |
---|
784 | | - | else throw("Close position first") |
---|
785 | | - | let newPositionSize = $t03463437183._1 |
---|
786 | | - | let newPositionRemainMargin = $t03463437183._2 |
---|
787 | | - | let newPositionOpenNotional = $t03463437183._3 |
---|
788 | | - | let newPositionLatestCPF = $t03463437183._4 |
---|
789 | | - | let baseAssetReserveAfter = $t03463437183._5 |
---|
790 | | - | let quoteAssetReserveAfter = $t03463437183._6 |
---|
791 | | - | let totalPositionSizeAfter = $t03463437183._7 |
---|
792 | | - | let cumulativeNotionalAfter = $t03463437183._8 |
---|
793 | | - | let openInterestNotionalAfter = $t03463437183._9 |
---|
794 | | - | let totalLongAfter = $t03463437183._10 |
---|
795 | | - | let totalShortAfter = $t03463437183._11 |
---|
796 | | - | let notifyNotional = invoke(minerAddress(), "notifyNotional", [toString(i.caller), newPositionOpenNotional], nil) |
---|
797 | | - | if ((notifyNotional == notifyNotional)) |
---|
798 | | - | then (updatePosition(toString(i.caller), newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) |
---|
799 | | - | else throw("Strict value is not equal to itself.") |
---|
800 | | - | } |
---|
801 | | - | |
---|
802 | | - | |
---|
803 | | - | |
---|
804 | | - | @Callable(i) |
---|
805 | | - | func increasePosition (_direction,_leverage,_minBaseAssetAmount) = { |
---|
806 | | - | let _rawAmount = i.payments[0].amount |
---|
807 | | - | if (if (if (if (if (if (if ((_direction != DIR_LONG)) |
---|
808 | | - | then (_direction != DIR_SHORT) |
---|
809 | | - | else false) |
---|
810 | | - | then true |
---|
811 | | - | else (0 >= _rawAmount)) |
---|
812 | | - | then true |
---|
813 | | - | else !(initialized())) |
---|
814 | | - | then true |
---|
815 | | - | else (i.payments[0].assetId != quoteAsset())) |
---|
816 | | - | then true |
---|
817 | | - | else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true))) |
---|
818 | | - | then true |
---|
819 | | - | else paused()) |
---|
820 | | - | then throw("Invalid increasePosition parameters") |
---|
821 | | - | else { |
---|
822 | | - | let feeAmount = muld(_rawAmount, fee()) |
---|
823 | | - | let _amount = (_rawAmount - feeAmount) |
---|
824 | | - | let $t03830138453 = getPosition(toString(i.caller)) |
---|
825 | | - | let oldPositionSize = $t03830138453._1 |
---|
826 | | - | let oldPositionMargin = $t03830138453._2 |
---|
827 | | - | let oldPositionOpenNotional = $t03830138453._3 |
---|
828 | | - | let oldPositionLstUpdCPF = $t03830138453._4 |
---|
829 | | - | let isNewPosition = (oldPositionSize == 0) |
---|
830 | | - | let isSameDirection = if ((oldPositionSize > 0)) |
---|
831 | | - | then (_direction == DIR_LONG) |
---|
832 | | - | else (_direction == DIR_SHORT) |
---|
833 | | - | let expandExisting = if (!(isNewPosition)) |
---|
834 | | - | then isSameDirection |
---|
835 | | - | else false |
---|
836 | | - | let isAdd = (_direction == DIR_LONG) |
---|
837 | | - | let $t03874241310 = if (if (isNewPosition) |
---|
838 | | - | then true |
---|
839 | | - | else expandExisting) |
---|
840 | | - | then { |
---|
841 | | - | let openNotional = muld(_amount, _leverage) |
---|
842 | | - | let $t03916639372 = swapInput(isAdd, openNotional) |
---|
843 | | - | let amountBaseAssetBought = $t03916639372._1 |
---|
844 | | - | let quoteAssetReserveAfter = $t03916639372._2 |
---|
845 | | - | let baseAssetReserveAfter = $t03916639372._3 |
---|
846 | | - | let totalPositionSizeAfter = $t03916639372._4 |
---|
847 | | - | let cumulativeNotionalAfter = $t03916639372._5 |
---|
848 | | - | if (if ((_minBaseAssetAmount != 0)) |
---|
849 | | - | then (_minBaseAssetAmount > abs(amountBaseAssetBought)) |
---|
850 | | - | else false) |
---|
851 | | - | then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount))) |
---|
852 | | - | else { |
---|
853 | | - | let newPositionSize = (oldPositionSize + amountBaseAssetBought) |
---|
854 | | - | let increaseMarginRequirement = divd(openNotional, _leverage) |
---|
855 | | - | let $t03975339992 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, increaseMarginRequirement) |
---|
856 | | - | let remainMargin = $t03975339992._1 |
---|
857 | | - | let x1 = $t03975339992._2 |
---|
858 | | - | let x2 = $t03975339992._3 |
---|
859 | | - | if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter))) |
---|
860 | | - | then throw("Over max spread limit") |
---|
861 | | - | else $Tuple11(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0)) |
---|
862 | | - | then abs(amountBaseAssetBought) |
---|
863 | | - | else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize)) |
---|
864 | | - | then abs(amountBaseAssetBought) |
---|
865 | | - | else 0))) |
---|
866 | | - | } |
---|
867 | | - | } |
---|
868 | | - | else { |
---|
869 | | - | let openNotional = muld(_amount, _leverage) |
---|
870 | | - | let $t04100341119 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT) |
---|
871 | | - | let oldPositionNotional = $t04100341119._1 |
---|
872 | | - | let unrealizedPnl = $t04100341119._2 |
---|
873 | | - | if ((oldPositionNotional > openNotional)) |
---|
874 | | - | then throw("Use decreasePosition to decrease position size") |
---|
875 | | - | else throw("Close position first") |
---|
876 | | - | } |
---|
877 | | - | let newPositionSize = $t03874241310._1 |
---|
878 | | - | let newPositionRemainMargin = $t03874241310._2 |
---|
879 | | - | let newPositionOpenNotional = $t03874241310._3 |
---|
880 | | - | let newPositionLatestCPF = $t03874241310._4 |
---|
881 | | - | let baseAssetReserveAfter = $t03874241310._5 |
---|
882 | | - | let quoteAssetReserveAfter = $t03874241310._6 |
---|
883 | | - | let totalPositionSizeAfter = $t03874241310._7 |
---|
884 | | - | let cumulativeNotionalAfter = $t03874241310._8 |
---|
885 | | - | let openInterestNotionalAfter = $t03874241310._9 |
---|
886 | | - | let totalLongAfter = $t03874241310._10 |
---|
887 | | - | let totalShortAfter = $t03874241310._11 |
---|
888 | | - | let feeToStakers = (feeAmount / 2) |
---|
889 | | - | let feeToInsurance = (feeAmount - feeToStakers) |
---|
890 | | - | let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)]) |
---|
891 | | - | if ((stake == stake)) |
---|
892 | | - | then { |
---|
893 | | - | let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)]) |
---|
894 | | - | if ((depositInsurance == depositInsurance)) |
---|
895 | | - | then { |
---|
896 | | - | let notifyFee = invoke(minerAddress(), "notifyFees", [toString(i.caller), feeAmount], nil) |
---|
897 | | - | if ((notifyFee == notifyFee)) |
---|
898 | | - | then { |
---|
899 | | - | let notifyNotional = invoke(minerAddress(), "notifyNotional", [toString(i.caller), newPositionOpenNotional], nil) |
---|
900 | | - | if ((notifyNotional == notifyNotional)) |
---|
901 | | - | then (((updatePosition(toString(i.caller), newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) |
---|
902 | | - | else throw("Strict value is not equal to itself.") |
---|
903 | | - | } |
---|
904 | | - | else throw("Strict value is not equal to itself.") |
---|
905 | | - | } |
---|
906 | | - | else throw("Strict value is not equal to itself.") |
---|
907 | | - | } |
---|
908 | | - | else throw("Strict value is not equal to itself.") |
---|
909 | | - | } |
---|
910 | | - | } |
---|
911 | | - | |
---|
912 | | - | |
---|
913 | | - | |
---|
914 | | - | @Callable(i) |
---|
915 | | - | func addMargin () = { |
---|
916 | | - | let _rawAmount = i.payments[0].amount |
---|
917 | | - | if (if (if (if ((i.payments[0].assetId != quoteAsset())) |
---|
918 | | - | then true |
---|
919 | | - | else !(requireOpenPosition(toString(i.caller)))) |
---|
920 | | - | then true |
---|
921 | | - | else !(initialized())) |
---|
922 | | - | then true |
---|
923 | | - | else paused()) |
---|
924 | | - | then throw("Invalid addMargin parameters") |
---|
925 | | - | else { |
---|
926 | | - | let feeAmount = muld(_rawAmount, fee()) |
---|
927 | | - | let _amount = (_rawAmount - feeAmount) |
---|
928 | | - | let $t04286643018 = getPosition(toString(i.caller)) |
---|
929 | | - | let oldPositionSize = $t04286643018._1 |
---|
930 | | - | let oldPositionMargin = $t04286643018._2 |
---|
931 | | - | let oldPositionOpenNotional = $t04286643018._3 |
---|
932 | | - | let oldPositionLstUpdCPF = $t04286643018._4 |
---|
933 | | - | let feeToStakers = (feeAmount / 2) |
---|
934 | | - | let feeToInsurance = (feeAmount - feeToStakers) |
---|
935 | | - | let stake = invoke(quoteAssetStaking(), "lockNeutrinoSP", [toString(stakingAddress()), ALL_FEES], [AttachedPayment(quoteAsset(), _amount)]) |
---|
936 | | - | if ((stake == stake)) |
---|
937 | | - | then { |
---|
938 | | - | let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)]) |
---|
939 | | - | if ((depositInsurance == depositInsurance)) |
---|
940 | | - | then { |
---|
941 | | - | let notifyFee = invoke(minerAddress(), "notifyFees", [toString(i.caller), feeAmount], nil) |
---|
942 | | - | if ((notifyFee == notifyFee)) |
---|
943 | | - | then ((updatePosition(toString(i.caller), oldPositionSize, (oldPositionMargin + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF) ++ transferFee(feeToStakers)) ++ updateBalance((cbalance() + _amount))) |
---|
944 | | - | else throw("Strict value is not equal to itself.") |
---|
945 | | - | } |
---|
946 | | - | else throw("Strict value is not equal to itself.") |
---|
947 | | - | } |
---|
948 | | - | else throw("Strict value is not equal to itself.") |
---|
949 | | - | } |
---|
950 | | - | } |
---|
951 | | - | |
---|
952 | | - | |
---|
953 | | - | |
---|
954 | | - | @Callable(i) |
---|
955 | | - | func removeMargin (_amount) = if (if (if (if ((0 >= _amount)) |
---|
956 | | - | then true |
---|
957 | | - | else !(requireOpenPosition(toString(i.caller)))) |
---|
958 | | - | then true |
---|
959 | | - | else !(initialized())) |
---|
960 | | - | then true |
---|
961 | | - | else paused()) |
---|
962 | | - | then throw("Invalid removeMargin parameters") |
---|
963 | | - | else { |
---|
964 | | - | let $t04406744219 = getPosition(toString(i.caller)) |
---|
965 | | - | let oldPositionSize = $t04406744219._1 |
---|
966 | | - | let oldPositionMargin = $t04406744219._2 |
---|
967 | | - | let oldPositionOpenNotional = $t04406744219._3 |
---|
968 | | - | let oldPositionLstUpdCPF = $t04406744219._4 |
---|
969 | | - | let marginDelta = -(_amount) |
---|
970 | | - | let $t04425644435 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, marginDelta) |
---|
971 | | - | let remainMargin = $t04425644435._1 |
---|
972 | | - | let badDebt = $t04425644435._2 |
---|
973 | | - | if ((badDebt != 0)) |
---|
974 | | - | then throw("Invalid removed margin amount") |
---|
975 | | - | else { |
---|
976 | | - | let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional) |
---|
977 | | - | if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true))) |
---|
978 | | - | then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio()))) |
---|
979 | | - | else { |
---|
980 | | - | let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [_amount, toBase58String(quoteAsset())], nil) |
---|
981 | | - | if ((unstake == unstake)) |
---|
982 | | - | then ((updatePosition(toString(i.caller), oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize)) ++ withdraw(i.caller, _amount)) ++ updateBalance((cbalance() - _amount))) |
---|
983 | | - | else throw("Strict value is not equal to itself.") |
---|
984 | | - | } |
---|
985 | | - | } |
---|
986 | | - | } |
---|
987 | | - | |
---|
988 | | - | |
---|
989 | | - | |
---|
990 | | - | @Callable(i) |
---|
991 | | - | func closePosition () = if (if (if (!(requireOpenPosition(toString(i.caller)))) |
---|
992 | | - | then true |
---|
993 | | - | else !(initialized())) |
---|
994 | | - | then true |
---|
995 | | - | else paused()) |
---|
996 | | - | then throw("Invalid closePosition parameters") |
---|
997 | | - | else { |
---|
998 | | - | let $t04553145921 = internalClosePosition(toString(i.caller), true) |
---|
999 | | - | let x1 = $t04553145921._1 |
---|
1000 | | - | let positionBadDebt = $t04553145921._2 |
---|
1001 | | - | let realizedPnl = $t04553145921._3 |
---|
1002 | | - | let marginToVault = $t04553145921._4 |
---|
1003 | | - | let quoteAssetReserveAfter = $t04553145921._5 |
---|
1004 | | - | let baseAssetReserveAfter = $t04553145921._6 |
---|
1005 | | - | let totalPositionSizeAfter = $t04553145921._7 |
---|
1006 | | - | let cumulativeNotionalAfter = $t04553145921._8 |
---|
1007 | | - | let openInterestNotionalAfter = $t04553145921._9 |
---|
1008 | | - | let x2 = $t04553145921._10 |
---|
1009 | | - | let totalLongAfter = $t04553145921._11 |
---|
1010 | | - | let totalShortAfter = $t04553145921._12 |
---|
1011 | | - | if ((positionBadDebt > 0)) |
---|
1012 | | - | then throw("Unable to close position with bad debt") |
---|
1013 | | - | else { |
---|
1014 | | - | let withdrawAmount = abs(marginToVault) |
---|
1015 | | - | let ammBalance = (cbalance() - withdrawAmount) |
---|
1016 | | - | let $t04613046272 = if ((0 > ammBalance)) |
---|
1017 | | - | then $Tuple2(0, abs(ammBalance)) |
---|
1018 | | - | else $Tuple2(ammBalance, 0) |
---|
1019 | | - | let ammNewBalance = $t04613046272._1 |
---|
1020 | | - | let getFromInsurance = $t04613046272._2 |
---|
1021 | | - | let x = if ((getFromInsurance > 0)) |
---|
1022 | | - | then { |
---|
1023 | | - | let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [getFromInsurance], nil) |
---|
1024 | | - | if ((withdrawInsurance == withdrawInsurance)) |
---|
1025 | | - | then nil |
---|
1026 | | - | else throw("Strict value is not equal to itself.") |
---|
1027 | | - | } |
---|
1028 | | - | else nil |
---|
1029 | | - | if ((x == x)) |
---|
1030 | | - | then { |
---|
1031 | | - | let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [(withdrawAmount - getFromInsurance), toBase58String(quoteAsset())], nil) |
---|
1032 | | - | if ((unstake == unstake)) |
---|
1033 | | - | then { |
---|
1034 | | - | let notifyNotional = invoke(minerAddress(), "notifyNotional", [toString(i.caller), 0], nil) |
---|
1035 | | - | if ((notifyNotional == notifyNotional)) |
---|
1036 | | - | then (((deletePosition(toString(i.caller)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ withdraw(i.caller, withdrawAmount)) ++ updateBalance(ammNewBalance)) |
---|
1037 | | - | else throw("Strict value is not equal to itself.") |
---|
1038 | | - | } |
---|
1039 | | - | else throw("Strict value is not equal to itself.") |
---|
1040 | | - | } |
---|
1041 | | - | else throw("Strict value is not equal to itself.") |
---|
1042 | | - | } |
---|
1043 | | - | } |
---|
1044 | | - | |
---|
1045 | | - | |
---|
1046 | | - | |
---|
1047 | | - | @Callable(i) |
---|
1048 | | - | func liquidate (_trader) = { |
---|
1049 | | - | let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT) |
---|
1050 | | - | let marginRatio = if (isOverFluctuationLimit()) |
---|
1051 | | - | then { |
---|
1052 | | - | let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE) |
---|
1053 | | - | vmax(spotMarginRatio, oracleMarginRatio) |
---|
1054 | | - | } |
---|
1055 | | - | else spotMarginRatio |
---|
1056 | | - | if (if (if (if (!(requireMoreMarginRatio(marginRatio, maintenanceMarginRatio(), false))) |
---|
1057 | | - | then true |
---|
1058 | | - | else !(requireOpenPosition(_trader))) |
---|
1059 | | - | then true |
---|
1060 | | - | else !(initialized())) |
---|
1061 | | - | then true |
---|
1062 | | - | else paused()) |
---|
1063 | | - | then throw("Unable to liquidate") |
---|
1064 | | - | else if (if (if ((spotMarginRatio > liquidationFeeRatio())) |
---|
1065 | | - | then (partialLiquidationRatio() > 0) |
---|
1066 | | - | else false) |
---|
1067 | | - | then (DECIMAL_UNIT > partialLiquidationRatio()) |
---|
1068 | | - | else false) |
---|
1069 | | - | then { |
---|
1070 | | - | let $t04837348523 = getPosition(_trader) |
---|
1071 | | - | let oldPositionSize = $t04837348523._1 |
---|
1072 | | - | let oldPositionMargin = $t04837348523._2 |
---|
1073 | | - | let oldPositionOpenNotional = $t04837348523._3 |
---|
1074 | | - | let oldPositionLstUpdCPF = $t04837348523._4 |
---|
1075 | | - | let _direction = if ((oldPositionSize > 0)) |
---|
1076 | | - | then DIR_SHORT |
---|
1077 | | - | else DIR_LONG |
---|
1078 | | - | let isAdd = (_direction == DIR_LONG) |
---|
1079 | | - | let exchangedQuoteAssetAmount = getPartialLiquidationAmount(_trader, oldPositionSize) |
---|
1080 | | - | let $t04874848852 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT) |
---|
1081 | | - | let oldPositionNotional = $t04874848852._1 |
---|
1082 | | - | let unrealizedPnl = $t04874848852._2 |
---|
1083 | | - | let $t04886049150 = swapInput(isAdd, exchangedQuoteAssetAmount) |
---|
1084 | | - | let exchangedPositionSize = $t04886049150._1 |
---|
1085 | | - | let quoteAssetReserveAfter = $t04886049150._2 |
---|
1086 | | - | let baseAssetReserveAfter = $t04886049150._3 |
---|
1087 | | - | let totalPositionSizeAfter = $t04886049150._4 |
---|
1088 | | - | let cumulativeNotionalAfter = $t04886049150._5 |
---|
1089 | | - | let realizedPnl = divd(muld(unrealizedPnl, abs(exchangedPositionSize)), abs(oldPositionSize)) |
---|
1090 | | - | let $t04925749490 = calcRemainMarginWithFundingPayment(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, realizedPnl) |
---|
1091 | | - | let remainMargin = $t04925749490._1 |
---|
1092 | | - | let badDebt = $t04925749490._2 |
---|
1093 | | - | let fundingPayment = $t04925749490._3 |
---|
1094 | | - | let unrealizedPnlAfter = (unrealizedPnl - realizedPnl) |
---|
1095 | | - | let remainOpenNotional = if ((oldPositionSize > 0)) |
---|
1096 | | - | then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter) |
---|
1097 | | - | else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount) |
---|
1098 | | - | let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio()) |
---|
1099 | | - | let feeToLiquidator = (liquidationPenalty / 2) |
---|
1100 | | - | let feeToInsurance = (liquidationPenalty - feeToLiquidator) |
---|
1101 | | - | let newPositionMargin = (remainMargin - liquidationPenalty) |
---|
1102 | | - | let newPositionSize = (oldPositionSize + exchangedPositionSize) |
---|
1103 | | - | let newPositionOpenNotional = abs(remainOpenNotional) |
---|
1104 | | - | let newPositionLstUpdCPF = latestCumulativePremiumFraction(newPositionSize) |
---|
1105 | | - | let openInterestNotionalAfter = (openInterestNotional() - exchangedQuoteAssetAmount) |
---|
1106 | | - | let ammBalance = (cbalance() - liquidationPenalty) |
---|
1107 | | - | let $t05066350806 = if ((0 > ammBalance)) |
---|
1108 | | - | then $Tuple2(0, abs(ammBalance)) |
---|
1109 | | - | else $Tuple2(ammBalance, 0) |
---|
1110 | | - | let newAmmBalance = $t05066350806._1 |
---|
1111 | | - | let takeFromInsurance = $t05066350806._2 |
---|
1112 | | - | let x = if ((takeFromInsurance > 0)) |
---|
1113 | | - | then { |
---|
1114 | | - | let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [takeFromInsurance], nil) |
---|
1115 | | - | if ((withdrawInsurance == withdrawInsurance)) |
---|
1116 | | - | then nil |
---|
1117 | | - | else throw("Strict value is not equal to itself.") |
---|
1118 | | - | } |
---|
1119 | | - | else nil |
---|
1120 | | - | if ((x == x)) |
---|
1121 | | - | then { |
---|
1122 | | - | let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [(liquidationPenalty - takeFromInsurance), toBase58String(quoteAsset())], nil) |
---|
1123 | | - | if ((unstake == unstake)) |
---|
1124 | | - | then { |
---|
1125 | | - | let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)]) |
---|
1126 | | - | if ((depositInsurance == depositInsurance)) |
---|
1127 | | - | then { |
---|
1128 | | - | let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil) |
---|
1129 | | - | if ((notifyNotional == notifyNotional)) |
---|
1130 | | - | then (((updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, (totalLongPositionSize() - (if ((newPositionSize > 0)) |
---|
1131 | | - | then abs(exchangedPositionSize) |
---|
1132 | | - | else 0)), (totalShortPositionSize() - (if ((0 > newPositionSize)) |
---|
1133 | | - | then abs(exchangedPositionSize) |
---|
1134 | | - | else 0)))) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance)) |
---|
1135 | | - | else throw("Strict value is not equal to itself.") |
---|
1136 | | - | } |
---|
1137 | | - | else throw("Strict value is not equal to itself.") |
---|
1138 | | - | } |
---|
1139 | | - | else throw("Strict value is not equal to itself.") |
---|
1140 | | - | } |
---|
1141 | | - | else throw("Strict value is not equal to itself.") |
---|
1142 | | - | } |
---|
1143 | | - | else { |
---|
1144 | | - | let $t05226252717 = internalClosePosition(_trader, false) |
---|
1145 | | - | let x1 = $t05226252717._1 |
---|
1146 | | - | let badDebt = $t05226252717._2 |
---|
1147 | | - | let x2 = $t05226252717._3 |
---|
1148 | | - | let x3 = $t05226252717._4 |
---|
1149 | | - | let quoteAssetReserveAfter = $t05226252717._5 |
---|
1150 | | - | let baseAssetReserveAfter = $t05226252717._6 |
---|
1151 | | - | let totalPositionSizeAfter = $t05226252717._7 |
---|
1152 | | - | let cumulativeNotionalAfter = $t05226252717._8 |
---|
1153 | | - | let openInterestNotionalAfter = $t05226252717._9 |
---|
1154 | | - | let exchangedQuoteAssetAmount = $t05226252717._10 |
---|
1155 | | - | let totalLongAfter = $t05226252717._11 |
---|
1156 | | - | let totalShortAfter = $t05226252717._12 |
---|
1157 | | - | let liquidationPenalty = muld(exchangedQuoteAssetAmount, liquidationFeeRatio()) |
---|
1158 | | - | let feeToLiquidator = (liquidationPenalty / 2) |
---|
1159 | | - | let feeToInsurance = (liquidationPenalty - feeToLiquidator) |
---|
1160 | | - | let ammBalance = (cbalance() - liquidationPenalty) |
---|
1161 | | - | let $t05312953272 = if ((0 > ammBalance)) |
---|
1162 | | - | then $Tuple2(0, abs(ammBalance)) |
---|
1163 | | - | else $Tuple2(ammBalance, 0) |
---|
1164 | | - | let newAmmBalance = $t05312953272._1 |
---|
1165 | | - | let takeFromInsurance = $t05312953272._2 |
---|
1166 | | - | let x = if ((takeFromInsurance > 0)) |
---|
1167 | | - | then { |
---|
1168 | | - | let withdrawInsurance = invoke(insuranceAddress(), "withdraw", [takeFromInsurance], nil) |
---|
1169 | | - | if ((withdrawInsurance == withdrawInsurance)) |
---|
1170 | | - | then nil |
---|
1171 | | - | else throw("Strict value is not equal to itself.") |
---|
1172 | | - | } |
---|
1173 | | - | else nil |
---|
1174 | | - | if ((x == x)) |
---|
1175 | | - | then { |
---|
1176 | | - | let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [(liquidationPenalty - takeFromInsurance), toBase58String(quoteAsset())], nil) |
---|
1177 | | - | if ((unstake == unstake)) |
---|
1178 | | - | then { |
---|
1179 | | - | let depositInsurance = invoke(insuranceAddress(), "deposit", nil, [AttachedPayment(quoteAsset(), feeToInsurance)]) |
---|
1180 | | - | if ((depositInsurance == depositInsurance)) |
---|
1181 | | - | then { |
---|
1182 | | - | let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, 0], nil) |
---|
1183 | | - | if ((notifyNotional == notifyNotional)) |
---|
1184 | | - | then (((deletePosition(_trader) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, cumulativeNotionalAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance)) |
---|
1185 | | - | else throw("Strict value is not equal to itself.") |
---|
1186 | | - | } |
---|
1187 | | - | else throw("Strict value is not equal to itself.") |
---|
1188 | | - | } |
---|
1189 | | - | else throw("Strict value is not equal to itself.") |
---|
1190 | | - | } |
---|
1191 | | - | else throw("Strict value is not equal to itself.") |
---|
1192 | | - | } |
---|
1193 | | - | } |
---|
1194 | | - | |
---|
1195 | | - | |
---|
1196 | | - | |
---|
1197 | | - | @Callable(i) |
---|
1198 | | - | func payFunding () = { |
---|
1199 | | - | let fundingBlockTimestamp = nextFundingBlockTimestamp() |
---|
1200 | | - | if (if (if ((fundingBlockTimestamp > lastBlock.timestamp)) |
---|
1201 | | - | then true |
---|
1202 | | - | else !(initialized())) |
---|
1203 | | - | then true |
---|
1204 | | - | else paused()) |
---|
1205 | | - | then throw(((("Invalid funding block timestamp: " + toString(lastBlock.timestamp)) + " < ") + toString(fundingBlockTimestamp))) |
---|
1206 | | - | else { |
---|
1207 | | - | let underlyingPrice = getOracleTwapPrice() |
---|
1208 | | - | let spotTwapPrice = getTwapSpotPrice() |
---|
1209 | | - | let premium = (spotTwapPrice - underlyingPrice) |
---|
1210 | | - | let $t05486056195 = if (if ((totalShortPositionSize() == 0)) |
---|
1211 | | - | then true |
---|
1212 | | - | else (totalLongPositionSize() == 0)) |
---|
1213 | | - | then $Tuple2(0, 0) |
---|
1214 | | - | else if ((0 > premium)) |
---|
1215 | | - | then { |
---|
1216 | | - | let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY) |
---|
1217 | | - | let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize()) |
---|
1218 | | - | $Tuple2(shortPremiumFraction, longPremiumFraction) |
---|
1219 | | - | } |
---|
1220 | | - | else { |
---|
1221 | | - | let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY) |
---|
1222 | | - | let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize()) |
---|
1223 | | - | $Tuple2(shortPremiumFraction, longPremiumFraction) |
---|
1224 | | - | } |
---|
1225 | | - | let shortPremiumFraction = $t05486056195._1 |
---|
1226 | | - | let longPremiumFraction = $t05486056195._2 |
---|
1227 | | - | updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice)) |
---|
1228 | | - | } |
---|
1229 | | - | } |
---|
1230 | | - | |
---|
1231 | | - | |
---|
1232 | | - | |
---|
1233 | | - | @Callable(i) |
---|
1234 | | - | func v_get (_trader) = { |
---|
1235 | | - | let $t05657056630 = internalClosePosition(_trader, false) |
---|
1236 | | - | let x1 = $t05657056630._1 |
---|
1237 | | - | let x2 = $t05657056630._2 |
---|
1238 | | - | let x3 = $t05657056630._3 |
---|
1239 | | - | let x4 = $t05657056630._4 |
---|
1240 | | - | throw((((s(x2) + s(x3)) + s(x4)) + s(getMarginRatio(_trader)))) |
---|
1241 | | - | } |
---|
1242 | | - | |
---|
1243 | | - | |
---|
1244 | | - | |
---|
1245 | | - | @Callable(i) |
---|
1246 | | - | func view_calcRemainMarginWithFundingPayment (_trader) = { |
---|
1247 | | - | let $t05677756888 = getPosition(_trader) |
---|
1248 | | - | let positionSize = $t05677756888._1 |
---|
1249 | | - | let positionMargin = $t05677756888._2 |
---|
1250 | | - | let pon = $t05677756888._3 |
---|
1251 | | - | let positionLstUpdCPF = $t05677756888._4 |
---|
1252 | | - | let $t05689356994 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT) |
---|
1253 | | - | let positionNotional = $t05689356994._1 |
---|
1254 | | - | let unrealizedPnl = $t05689356994._2 |
---|
1255 | | - | let $t05699957181 = calcRemainMarginWithFundingPayment(positionSize, positionMargin, positionLstUpdCPF, unrealizedPnl) |
---|
1256 | | - | let remainMargin = $t05699957181._1 |
---|
1257 | | - | let badDebt = $t05699957181._2 |
---|
1258 | | - | let fundingPayment = $t05699957181._3 |
---|
1259 | | - | throw((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional))) |
---|
1260 | | - | } |
---|
1261 | | - | |
---|
1262 | | - | |
---|
1263 | | - | |
---|
1264 | | - | @Callable(i) |
---|
1265 | | - | func forceMoveAsset (_trader,_amount) = if (if ((addressFromPublicKey(adminPublicKey()) != i.caller)) |
---|
1266 | | - | then true |
---|
1267 | | - | else (0 > _amount)) |
---|
1268 | | - | then throw("Invalid forceMoveAsset parameters") |
---|
1269 | | - | else { |
---|
1270 | | - | let unstake = invoke(quoteAssetStaking(), "unlockNeutrino", [_amount, toBase58String(quoteAsset())], nil) |
---|
1271 | | - | if ((unstake == unstake)) |
---|
1272 | | - | then (withdraw(addressFromStringValue(_trader), _amount) ++ updateBalance((cbalance() - _amount))) |
---|
1273 | | - | else throw("Strict value is not equal to itself.") |
---|
1274 | | - | } |
---|
1275 | | - | |
---|
1276 | | - | |
---|
1277 | | - | @Verifier(tx) |
---|
1278 | | - | func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey()) |
---|
1279 | | - | |
---|
| 1 | + | # no script |
---|