2020.11.25 22:25 [2345070] smart account 3P3b9ZcfQmAyE9MVoRKE5tfRJSHR4BDXMEo > SELF 0.00000000 Waves

{ "type": 13, "id": "4fVyskYdkp7BWuDeN18a22Jkeouy1LJTWwsYRHJVDQqX", "fee": 1400000, "feeAssetId": null, "timestamp": 1606332310092, "version": 1, "sender": "3P3b9ZcfQmAyE9MVoRKE5tfRJSHR4BDXMEo", "senderPublicKey": "BvoMQVENxUeFiSzGs66VPKRbddcurTqSSuQhBEKHmXiv", "proofs": [ "3CwyyoE5VjGJA8Yyb5z854adc9nBQGSj7RdWdL84VF5jmxSkWU1d1RNPUDMa9V5ZC2Qdq5nh6Nzihd5Jt6RD4nMp", "qJqcu5VBvVGc4B6HvRmYdnRqz5WHbssw6Ufr2Byzd4c8zLAWptfCo1khBPjW2UdZWmUFVLXuQJo1C6TvmB1YAtQ" ], "script": "base64:AAIEAAAAAAAAADgIAhINCgsICAgICAgICAgBARIDCgEBEgASAwoBARIDCgEIEgQKAggBEgASAwoBARIAEgMKAQESAAAAAG0BAAAAAlNFAAAAAgAAAAFrAAAAAXYJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAAWsFAAAAAXYBAAAAAklFAAAAAgAAAAFrAAAAAXYJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAAFrBQAAAAF2AQAAAAJTVAAAAAMAAAABYQAAAANhbXQAAAABdAkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAABYQUAAAADYW10BQAAAAF0AQAAAAVkZWJ1ZwAAAAIAAAABawAAAAF2CQEAAAACU0UAAAACCQABLAAAAAICAAAAB19fZGJnX18FAAAAAWsFAAAAAXYAAAAABHRlbjYAAAAAAAAPQkAAAAAABHRlbjgAAAAAAAX14QAAAAAAA01BWAB//////////wAAAAARY29uZmlnUHJvdmlkZXJLZXkCAAAADmNvbmZpZ1Byb3ZpZGVyAAAAAA5jb25maWdQcm92aWRlcgQAAAAHJG1hdGNoMAkABB0AAAACBQAAAAR0aGlzBQAAABFjb25maWdQcm92aWRlcktleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAGU3RyaW5nBAAAAAFzBQAAAAckbWF0Y2gwCQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABBQAAAAFzBQAAAAR0aGlzAQAAAAZsb2NhbEkAAAACAAAAAWsAAAABZQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAAWsFAAAAAWUBAAAABmxvY2FsUwAAAAIAAAABawAAAAFlCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQdAAAAAgUAAAAEdGhpcwUAAAABawUAAAABZQEAAAAFY29uZkkAAAACAAAAAWsAAAABZQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAADmNvbmZpZ1Byb3ZpZGVyBQAAAAFrBQAAAAFlAQAAAAVjb25mUwAAAAIAAAABawAAAAFlCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQdAAAAAgUAAAAOY29uZmlnUHJvdmlkZXIFAAAAAWsFAAAAAWUAAAAABUJVTExLAgAAAAZCVUxMSWQAAAAABUJFQVJLAgAAAAZCRUFSSWQAAAAABVVTRE5LAgAAAAttYWluVG9rZW5JZAAAAAAIQlVMTENPTEsCAAAADmJ1bGxDb2xsYXRlcmFsAAAAAAhCRUFSQ09MSwIAAAAOYmVhckNvbGxhdGVyYWwAAAAACUJVTExDSVJDSwIAAAAPYnVsbENpcmN1bGF0aW9uAAAAAAlCRUFSQ0lSQ0sCAAAAD2JlYXJDaXJjdWxhdGlvbgAAAAAISVNTUEVSQ0sCAAAAD2lzc3VlUGVyY2VudGlsZQAAAAAIUkVEUEVSQ0sCAAAAEHJlZGVlbVBlcmNlbnRpbGUAAAAAB01JTklTU0sCAAAACG1pbklzc3VlAAAAAAdNSU5SRURLAgAAAAltaW5SZWRlZW0AAAAACE1JTlBPT0xLAgAAAAdtaW5Qb29sAAAAAAdGRUVBQ0NLAgAAAA9mZWVzQWNjdW11bGF0ZWQAAAAABldMSVNUSwIAAAAOaXNzdWVXaGl0ZUxpc3QAAAAACFJFQlBFUkNLAgAAABNyZWJhbGFuY2VQZXJjZW50aWxlAAAAAAdSRUJJRFhLAgAAABVsYXN0U2V0dGxlbWVudFByaWNlSWQAAAAABUhFQURLAgAAAAtoZWFkUG9pbnRlcgAAAAAFVEFJTEsCAAAAC3RhaWxQb2ludGVyAAAAAAZRU0laRUsCAAAACXF1ZXVlU2l6ZQAAAAAJUE9PTFVTRE5LAgAAABJwb29sTWFpblRva2VuVmFsdWUAAAAAB1BPT0xVUEsCAAAABnBvb2xVcAAAAAAIUE9PTERXTksCAAAAB3Bvb2xEd24AAAAACVBPT0xDSVJDSwIAAAAUcG9vbFRva2VuQ2lyY3VsYXRpb24AAAAABVBPT0xLAgAAAAlwb29sVG9rZW4AAAAACEFTU05BTUVLAgAAAA1kZWZvQXNzZXROYW1lAAAAAARMRVZLAgAAAAhsZXZlcmFnZQAAAAAJV0FWRVNGRUVLAgAAABF3YXZlc1BhY2VtYWtlckZlZQAAAAAIVVNETkZFRUsCAAAAEHVzZG5QYWNlbWFrZXJGZWUAAAAAC29yYWNsZVBLS2V5AgAAAAZvcmFjbGUBAAAAEWxhc3RQcmljZUluZGV4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ZQkAAGsAAAADBQAAAAdidWxsQ29sBQAAAAZwb29sVXAFAAAACGJ1bGxDaXJjAAAAABBwb29sQmVhckV4cG9zdXJlCQAAawAAAAMFAAAAB2JlYXJDb2wFAAAAB3Bvb2xEd24FAAAACGJlYXJDaXJjAAAAAAlwb29sVmFsdWUJAABkAAAAAgkAAGQAAAACBQAAAAhwb29sTWFpbgUAAAAQcG9vbEJ1bGxFeHBvc3VyZQUAAAAQcG9vbEJlYXJFeHBvc3VyZQAAAAAGb3JhY2xlCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAQAAABRhZGRyZXNzRnJvbVB1YmxpY0tleQAAAAEJAAJZAAAAAQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAABHRoaXMFAAAAC29yYWNsZVBLS2V5AgAAAA5ubyBvcmFjbGVQS0tleQIAAAASYmFkIG9yYWNsZSBhZGRyZXNzAAAAABRyZWJhbGFuY2VkUHJpY2VJbmRleAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAAB1JFQklEWEsCAAAAF25vIGxhc3QgcmViYWxhbmNlIHByaWNlAAAAABBvcmFjbGVQcmljZUluZGV4CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAGb3JhY2xlCQEAAAARbGFzdFByaWNlSW5kZXhLZXkAAAABBQAAAAlhc3NldE5hbWUJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAE2JhZCBvcmFjbGUgZGF0YSBhdCAJAAQlAAAAAQUAAAAGb3JhY2xlAgAAABA6IG5vIGludGVnZXIgYXQgCQEAAAARbGFzdFByaWNlSW5kZXhLZXkAAAABBQAAAAlhc3NldE5hbWUAAAAACGxldmVyYWdlCQEAAAALdmFsdWVPckVsc2UAAAACCQAEGgAAAAIFAAAABHRoaXMFAAAABExFVksAAAAAAAAAAAMBAAAADWhlaWdodEJ5SW5kZXgAAAACAAAACWFzc2V0TmFtZQAAAApwcmljZUluZGV4CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAGb3JhY2xlCQABLAAAAAIJAQAAABBwcmljZUluZGV4UHJlZml4AAAAAQUAAAAJYXNzZXROYW1lCQABpAAAAAEFAAAACnByaWNlSW5kZXgJAAEsAAAAAgIAAAARbm8gZGF0YSBhdCBpbmRleCAJAAGkAAAAAQUAAAAKcHJpY2VJbmRleAEAAAANcHJpY2VCeUhlaWdodAAAAAIAAAAJYXNzZXROYW1lAAAAC3ByaWNlSGVpZ2h0CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQaAAAAAgUAAAAGb3JhY2xlCQABLAAAAAIJAQAAABFwcmljZUhlaWdodFByZWZpeAAAAAEFAAAACWFzc2V0TmFtZQkAAaQAAAABBQAAAAtwcmljZUhlaWdodAkAASwAAAACAgAAABNubyBkYXRhIGZvciBoZWlnaHQgCQABpAAAAAEFAAAAC3ByaWNlSGVpZ2h0AQAAAAxwcmljZUJ5SW5kZXgAAAACAAAACWFzc2V0TmFtZQAAAApwcmljZUluZGV4CQEAAAANcHJpY2VCeUhlaWdodAAAAAIFAAAACWFzc2V0TmFtZQkBAAAADWhlaWdodEJ5SW5kZXgAAAACBQAAAAlhc3NldE5hbWUFAAAACnByaWNlSW5kZXgAAAAACXF1ZXVlU2l6ZQkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAAAZRU0laRUsAAAAAAAAAAAAAAAAAC2hlYWRQb2ludGVyCQEAAAALdmFsdWVPckVsc2UAAAACCQAEHQAAAAIFAAAABHRoaXMFAAAABUhFQURLAgAAAAAAAAAAC3RhaWxQb2ludGVyCQEAAAALdmFsdWVPckVsc2UAAAACCQAEHQAAAAIFAAAABHRoaXMFAAAABVRBSUxLAgAAAAAAAAAAD2ZlZXNBY2N1bXVsYXRlZAkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABBoAAAACBQAAAAR0aGlzBQAAAAdGRUVBQ0NLAAAAAAAAAAAAAAAAAAVJU1NVRQIAAAAFSVNTVUUAAAAABlJFREVFTQIAAAAGUkVERUVNAAAAAARQT09MAgAAAARQT09MAAAAAAZVTlBPT0wCAAAABlVOUE9PTAAAAAAKZmVlQWRkcktleQIAAAAKZmVlQWRkcmVzcwAAAAAOc3Rha2luZ0FkZHJLZXkCAAAADnN0YWtpbmdBZGRyZXNzAAAAAA9kYWVtb25QdWJLZXlLZXkCAAAAD2RhZW1vblB1YmxpY0tleQAAAAAKZmVlQWRkcmVzcwkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEJgAAAAEJAQAAAAVjb25mUwAAAAIFAAAACmZlZUFkZHJLZXkCAAAADW5vIGZlZUFkZHJlc3MCAAAADmJhZCBmZWVBZGRyZXNzAAAAAA5zdGFraW5nQWRkcmVzcwkBAAAABWNvbmZTAAAAAgUAAAAOc3Rha2luZ0FkZHJLZXkCAAAAEW5vIHN0YWtpbmdBZGRyZXNzAAAAAA9kYWVtb25QdWJsaWNLZXkJAAJZAAAAAQkBAAAABWNvbmZTAAAAAgUAAAAPZGFlbW9uUHViS2V5S2V5AgAAABJubyBkYWVtb25QdWJsaWNLZXkAAAAACnJwZEFkZHJlc3MJAAQmAAAAAQIAAAAjM1BOaWtNNnlwNE5xY1NVOGd1eFF0bVI1b25yMkQ0ZTh5VEoAAAAABmFkbWlucwkABEwAAAACAgAAACwySEhxVjhXOURKYXlWNVI2dEJEMlNiOHNycGhwb2JvRGk3cjF0MWFQaXVtQwkABEwAAAACAgAAACw1WlhlODJSUkFTVTdxc2hYTTJKOUpOWWhxSjlHV1lqalZxMmd3VVY1TmF6OQkABEwAAAACAgAAACw1V1JYRlNqd2NUYk5mS2NKczhacVhtU1NXWXNTVkpVdE12TXFaajVoSDROYwUAAAADbmlsAQAAAAxidWlsZE5ld0l0ZW0AAAAHAAAABmFjdGlvbgAAAANhbXQAAAAFdG9rZW4AAAAKcHJpY2VJbmRleAAAAAdpbnZva2VyAAAACW1pblBheW91dAAAAAltYXhQYXlvdXQJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgUAAAAGYWN0aW9uAgAAAAF8CQABpAAAAAEFAAAAA2FtdAIAAAABfAUAAAAFdG9rZW4CAAAAAXwJAAGkAAAAAQUAAAAKcHJpY2VJbmRleAIAAAABfAUAAAAHaW52b2tlcgIAAAABfAkA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AAIJAAQaAAAAAgUAAAAEdGhpcwUAAAAHUkVCSURYSwIAAAARaW5jb25zaXN0ZW50IGRhdGEEAAAAE3Vuc2V0dGxlZFByaWNlSW5kZXgJAABkAAAAAgUAAAARc2V0dGxlZFByaWNlSW5kZXgAAAAAAAAAAAEEAAAADHNldHRsZWRQcmljZQkBAAAADHByaWNlQnlJbmRleAAAAAIFAAAACWFzc2V0TmFtZQUAAAARc2V0dGxlZFByaWNlSW5kZXgEAAAACW5leHRQcmljZQkBAAAADHByaWNlQnlJbmRleAAAAAIFAAAACWFzc2V0TmFtZQUAAAATdW5zZXR0bGVkUHJpY2VJbmRleAQAAAAGbWluVm9sAwkAAGYAAAACBQAAAAdiZWFyQ29sBQAAAAdidWxsQ29sBQAAAAdidWxsQ29sBQAAAAdiZWFyQ29sBAAAAAZyZWRpc3QJAQAAAAJMVgAAAAQFAAAABm1pblZvbAUAAAAMc2V0dGxlZFByaWNlBQAAAAluZXh0UHJpY2UFAAAACGxldmVyYWdlBAAAABNwcmljZVVwR29vZEZvckJ1bGxzCQAAAAAAAAIFAAAACWFzc2V0TmFtZQIAAAAABAAAAAtwcmljZUdvZXNVcAkAAGYAAAACBQAAAAluZXh0UHJpY2UFAAAADHNldHRsZWRQcmljZQQAAAAJYnVsbHNFYXJuCQAAAAAAAAIFAAAAE3ByaWNlVXBHb29kRm9yQnVsbHMFAAAAC3ByaWNlR29lc1VwBAAAAApuZXdCdWxsQ29sAwUAAAAJYnVsbHNFYXJuCQAAZAAAAAIFAAAAB2J1bGxDb2wFAAAABnJlZGlzdAkAAGUAAAACBQAAAAdidWxsQ29sBQAAAAZyZWRpc3QEAAAACm5ld0JlYXJDb2wDBQAAAAlidWxsc0Vhcm4JAABlAAAAAgUAAAAHYmVhckNvbAUAAAAGcmVkaXN0CQAAZAAAAAIFAAAAB2JlYXJDb2wFAAAABnJlZGlzdAQAAAANJHQwMTk2MDgxOTc5NAkBAAAAC3Bvb2xTdXBwb3J0AAAABwUAAAAKbmV3QnVsbENvbAUAAAAKbmV3QmVhckNvbAUAAAAIYnVsbENpcmMFAAAACGJlYXJDaXJjBQAAAAhwb29sTWFpbgUAAAAGcG9vbFVwBQAAAAdwb29sRHduBAAAAAp1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", "chainId": 87, "height": 2345070, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 6kP7tai1G9vcndu8iwd1JtxsHKvAiYjmBAQ6E7McpGBG Next: 2ypViX1NCEGfutiN37STs72qNWqcj4rm5Aq5gh9EkFCQ Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 4 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4+func SE (k,v) = StringEntry(k, v)
5+
6+
7+func IE (k,v) = IntegerEntry(k, v)
8+
9+
10+func ST (a,amt,t) = ScriptTransfer(a, amt, t)
11+
12+
13+func debug (k,v) = SE(("__dbg__" + k), v)
14+
15+
416 let ten6 = 1000000
517
618 let ten8 = 100000000
19+
20+let MAX = 9223372036854775807
721
822 let configProviderKey = "configProvider"
923
1428 this
1529 }
1630
17-let BULLKey = "BULLId"
31+func localI (k,e) = valueOrErrorMessage(getInteger(this, k), e)
1832
19-let BEARKey = "BEARId"
2033
21-let mainTokenKey = "mainTokenId"
34+func localS (k,e) = valueOrErrorMessage(getString(this, k), e)
2235
23-let bullCollateralKey = "bullCollateral"
2436
25-let bearCollateralKey = "bearCollateral"
37+func confI (k,e) = valueOrErrorMessage(getInteger(configProvider, k), e)
2638
27-let bullCirculationKey = "bullCirculation"
2839
29-let bearCirculationKey = "bearCirculation"
40+func confS (k,e) = valueOrErrorMessage(getString(configProvider, k), e)
3041
31-let issuePercentileKey = "issuePercentile"
3242
33-let redeemPercentileKey = "redeemPercentile"
43+let BULLK = "BULLId"
3444
35-let minIssueKey = "minIssue"
45+let BEARK = "BEARId"
3646
37-let minRedeemKey = "minRedeem"
47+let USDNK = "mainTokenId"
3848
39-let minPoolKey = "minPool"
49+let BULLCOLK = "bullCollateral"
4050
41-let feesAccumulatedKey = "feesAccumulated"
51+let BEARCOLK = "bearCollateral"
4252
43-let whitelistKey = "issueWhiteList"
53+let BULLCIRCK = "bullCirculation"
54+
55+let BEARCIRCK = "bearCirculation"
56+
57+let ISSPERCK = "issuePercentile"
58+
59+let REDPERCK = "redeemPercentile"
60+
61+let MINISSK = "minIssue"
62+
63+let MINREDK = "minRedeem"
64+
65+let MINPOOLK = "minPool"
66+
67+let FEEACCK = "feesAccumulated"
68+
69+let WLISTK = "issueWhiteList"
70+
71+let REBPERCK = "rebalancePercentile"
72+
73+let REBIDXK = "lastSettlementPriceId"
74+
75+let HEADK = "headPointer"
76+
77+let TAILK = "tailPointer"
78+
79+let QSIZEK = "queueSize"
80+
81+let POOLUSDNK = "poolMainTokenValue"
82+
83+let POOLUPK = "poolUp"
84+
85+let POOLDWNK = "poolDwn"
86+
87+let POOLCIRCK = "poolTokenCirculation"
88+
89+let POOLK = "poolToken"
90+
91+let ASSNAMEK = "defoAssetName"
92+
93+let LEVK = "leverage"
94+
95+let WAVESFEEK = "wavesPacemakerFee"
96+
97+let USDNFEEK = "usdnPacemakerFee"
4498
4599 let oraclePKKey = "oracle"
46100
47-let lastPriceIndexKey = "price_index"
101+func lastPriceIndexKey (assetId) = if ((assetId == ""))
102+ then "price_index"
103+ else ("%s%s__idxCurrent__" + assetId)
48104
49-let priceIndexPrefix = "price_index_"
50105
51-let priceHeightPrefix = "price_"
106+func priceIndexPrefix (assetId) = if ((assetId == ""))
107+ then "price_index_"
108+ else (("%s%s%d__idx2Height__" + assetId) + "__")
52109
53-let oracleCurrentPriceIndexKey = "price_index"
54110
55-let lastRebalancePriceIndexKey = "lastSettlementPriceId"
111+func priceHeightPrefix (assetId) = if ((assetId == ""))
112+ then "price_"
113+ else (("%s%s%d__priceByHeight__" + assetId) + "__")
56114
57-let headPointerKey = "headPointer"
58115
59-let tailPointerKey = "tailPointer"
116+let minUsdnFee = valueOrElse(getInteger(configProvider, USDNFEEK), 0)
60117
61-let queueSizeKey = "queueSize"
118+let minWavesFee = valueOrElse(getInteger(configProvider, WAVESFEEK), 0)
62119
63-let poolMainTokenValueKey = "poolMainTokenValue"
120+let assetName = valueOrElse(getString(this, ASSNAMEK), "")
64121
65-let poolUpKey = "poolUp"
122+let bullCol = localI(BULLCOLK, "no 0")
66123
67-let poolDwnKey = "poolDwn"
124+let bearCol = localI(BEARCOLK, "no 1")
68125
69-let poolTokenCirculationKey = "poolTokenCirculation"
126+let bullCirc = localI(BULLCIRCK, "no 2")
70127
71-let poolTokenKey = "poolToken"
128+let bearCirc = localI(BEARCIRCK, "no 3")
72129
73-let bullCol = valueOrErrorMessage(getInteger(this, bullCollateralKey), "no bullCollateralKey")
130+let BULL = localS(BULLK, "no 14")
74131
75-let bearCol = valueOrErrorMessage(getInteger(this, bearCollateralKey), "no bearCollateralKey")
132+let BEAR = localS(BEARK, "no 15")
76133
77-let bullCirc = valueOrErrorMessage(getInteger(this, bullCirculationKey), "no bullCirculationKey")
134+let mainToken = localS(USDNK, "no 16")
78135
79-let bearCirc = valueOrErrorMessage(getInteger(this, bearCirculationKey), "no bearCirculationKey")
136+let issuePercentile = confI(ISSPERCK, "no 4")
80137
81-let BULL = valueOrErrorMessage(getString(this, BULLKey), "no BULLKey")
138+let redeemPercentile = confI(REDPERCK, "no 5")
82139
83-let BEAR = valueOrErrorMessage(getString(this, BEARKey), "no BEARKey")
140+let minIssue = confI(MINISSK, "no 6")
84141
85-let mainToken = valueOrErrorMessage(getString(this, mainTokenKey), "no mainTokenKey")
142+let minRedeem = confI(MINREDK, "no 7")
86143
87-let issuePercentile = valueOrErrorMessage(getInteger(configProvider, issuePercentileKey), "no issuePercentileKey")
144+let minPool = confI(MINPOOLK, "no 8")
88145
89-let redeemPercentile = valueOrErrorMessage(getInteger(configProvider, redeemPercentileKey), "no redeemPercentileKey")
146+let rebalancePercentile = valueOrElse(getInteger(configProvider, ((toString(this) + "_") + REBPERCK)), 0)
90147
91-let minIssue = valueOrErrorMessage(getInteger(configProvider, minIssueKey), "no minIssueKey")
92-
93-let minRedeem = valueOrErrorMessage(getInteger(configProvider, minRedeemKey), "no minRedeemKey")
94-
95-let minPool = valueOrErrorMessage(getInteger(configProvider, minPoolKey), "no minPoolKey")
96-
97-let whitelist = valueOrErrorMessage(getString(configProvider, whitelistKey), "no whitelistKey")
148+let whitelist = confS(WLISTK, "no 9")
98149
99150 func allowed (a) = if ((whitelist == ""))
100151 then true
101152 else isDefined(indexOf(whitelist, toString(a)))
102153
103154
104-let poolMain = valueOrErrorMessage(getInteger(this, poolMainTokenValueKey), "no poolMainTokenValueKey")
155+let poolMain = localI(POOLUSDNK, "no")
105156
106-let poolUp = valueOrErrorMessage(getInteger(this, poolUpKey), "no poolUpKey")
157+let poolUp = localI(POOLUPK, "no 10")
107158
108-let poolDwn = valueOrErrorMessage(getInteger(this, poolDwnKey), "no poolDwnKey")
159+let poolDwn = localI(POOLDWNK, "no 11")
109160
110-let poolToken = valueOrErrorMessage(getString(this, poolTokenKey), "no poolTokenKey")
161+let poolToken = localS(POOLK, "no 12")
111162
112-let poolTokenCirculation = valueOrErrorMessage(getInteger(this, poolTokenCirculationKey), "no poolTokenCirculationKey")
163+let poolTokenCirculation = localI(POOLCIRCK, "no 13")
113164
114165 let poolBullExposure = fraction(bullCol, poolUp, bullCirc)
115166
119170
120171 let oracle = valueOrErrorMessage(addressFromPublicKey(fromBase58String(valueOrErrorMessage(getString(this, oraclePKKey), "no oraclePKKey"))), "bad oracle address")
121172
122-let rebalancedPriceIndex = valueOrErrorMessage(getInteger(this, lastRebalancePriceIndexKey), "no last rebalance price")
173+let rebalancedPriceIndex = valueOrErrorMessage(getInteger(this, REBIDXK), "no last rebalance price")
123174
124-let oraclePriceIndex = valueOrErrorMessage(getInteger(oracle, lastPriceIndexKey), ((("bad oracle data at " + toString(oracle)) + ": no integer at ") + lastPriceIndexKey))
175+let oraclePriceIndex = valueOrErrorMessage(getInteger(oracle, lastPriceIndexKey(assetName)), ((("bad oracle data at " + toString(oracle)) + ": no integer at ") + lastPriceIndexKey(assetName)))
125176
126-let queueSize = valueOrElse(getInteger(this, queueSizeKey), 0)
177+let leverage = valueOrElse(getInteger(this, LEVK), 3)
127178
128-let headPointer = valueOrElse(getString(this, headPointerKey), "")
179+func heightByIndex (assetName,priceIndex) = valueOrErrorMessage(getInteger(oracle, (priceIndexPrefix(assetName) + toString(priceIndex))), ("no data at index " + toString(priceIndex)))
129180
130-let tailPointer = valueOrElse(getString(this, tailPointerKey), "")
131181
132-let feesAccumulated = valueOrElse(getInteger(this, feesAccumulatedKey), 0)
182+func priceByHeight (assetName,priceHeight) = valueOrErrorMessage(getInteger(oracle, (priceHeightPrefix(assetName) + toString(priceHeight))), ("no data for height " + toString(priceHeight)))
183+
184+
185+func priceByIndex (assetName,priceIndex) = priceByHeight(assetName, heightByIndex(assetName, priceIndex))
186+
187+
188+let queueSize = valueOrElse(getInteger(this, QSIZEK), 0)
189+
190+let headPointer = valueOrElse(getString(this, HEADK), "")
191+
192+let tailPointer = valueOrElse(getString(this, TAILK), "")
193+
194+let feesAccumulated = valueOrElse(getInteger(this, FEEACCK), 0)
133195
134196 let ISSUE = "ISSUE"
135197
145207
146208 let daemonPubKeyKey = "daemonPublicKey"
147209
148-let feeAddress = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(configProvider, feeAddrKey), "no feeAddress")), "bad feeAddress")
210+let feeAddress = valueOrErrorMessage(addressFromString(confS(feeAddrKey, "no feeAddress")), "bad feeAddress")
149211
150-let stakingAddress = valueOrErrorMessage(getString(configProvider, stakingAddrKey), "no stakingAddress")
212+let stakingAddress = confS(stakingAddrKey, "no stakingAddress")
151213
152-let daemonPublicKey = fromBase58String(valueOrErrorMessage(getString(configProvider, daemonPubKeyKey), "no daemonPublicKey"))
214+let daemonPublicKey = fromBase58String(confS(daemonPubKeyKey, "no daemonPublicKey"))
153215
154216 let rpdAddress = addressFromString("3PNikM6yp4NqcSU8guxQtmR5onr2D4e8yTJ")
155217
156-let pubKeyAdminsList = ["2HHqV8W9DJayV5R6tBD2Sb8srphpoboDi7r1t1aPiumC", "5ZXe82RRASU7qshXM2J9JNYhqJ9GWYjjVq2gwUV5Naz9", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"]
218+let admins = ["2HHqV8W9DJayV5R6tBD2Sb8srphpoboDi7r1t1aPiumC", "5ZXe82RRASU7qshXM2J9JNYhqJ9GWYjjVq2gwUV5Naz9", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"]
157219
158-func safeFraction (a,b,c) = if (if ((a == 0))
159- then true
160- else (b == 0))
161- then 0
162- else fraction(a, b, c)
220+func buildNewItem (action,amt,token,priceIndex,invoker,minPayout,maxPayout) = (((((((((((((action + "|") + toString(amt)) + "|") + token) + "|") + toString(priceIndex)) + "|") + invoker) + "|") + toString(minPayout)) + "|") + toString(maxPayout)) + "|")
163221
164222
165-func buildNewItem (action,amt,token,priceIndex,invoker) = (((((((((action + "|") + toString(amt)) + "|") + token) + "|") + toString(priceIndex)) + "|") + invoker) + "|")
223+func userDiffAbs () = {
224+ let $t057975886 = $Tuple2((bullCol - poolBullExposure), (bearCol - poolBearExposure))
225+ let userBullCol = $t057975886._1
226+ let userBearCol = $t057975886._2
227+ let diff = (userBullCol - userBearCol)
228+ if ((diff > 0))
229+ then diff
230+ else (0 - diff)
231+ }
166232
167233
168234 func maxIssue (tokenId) = {
171237 else BEAR
172238 if ((tokenId != poolInvestment))
173239 then poolMain
174- else {
175- let $t053745463 = $Tuple2((bullCol - poolBullExposure), (bearCol - poolBearExposure))
176- let userBullCol = $t053745463._1
177- let userBearCol = $t053745463._2
178- let diff = (userBullCol - userBearCol)
179- let diffAbs = if ((diff > 0))
180- then diff
181- else (0 - diff)
182- (diffAbs + poolValue)
183- }
240+ else (userDiffAbs() + poolValue)
184241 }
242+
243+
244+func validatePMFee (i,minPayout) = if ((0 > minPayout))
245+ then throw("negative min payout")
246+ else {
247+ let p = i.payments[1]
248+ let ok = match p.assetId {
249+ case bv: ByteVector =>
250+ if ((toBase58String(bv) == mainToken))
251+ then (p.amount >= minUsdnFee)
252+ else false
253+ case waves: Unit =>
254+ (p.amount >= minWavesFee)
255+ case _ =>
256+ throw("Match error")
257+ }
258+ if (!(ok))
259+ then throw("incorrect pacemaker fee")
260+ else true
261+ }
185262
186263
187264 func validateRequestRedeem (inv) = if ((inv.caller == this))
188265 then throw("can't do")
189266 else {
190- func errorMessage (got) = throw(((((("only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are accepted, received: ") + got))
267+ func errorMessage (got) = throw(((((("bad token att: only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are accepted, received: ") + got))
191268
192- let assetId = toBase58String(valueOrErrorMessage(value(inv.payments[0]).assetId, "waves are not accepted here"))
269+ let assetId = toBase58String(valueOrErrorMessage(value(inv.payments[0]).assetId, "bad token att"))
193270 if (if ((assetId != BEAR))
194271 then (assetId != BULL)
195272 else false)
210287 }
211288
212289
213-func enqueue (id,action,amt,token,priceIndex,invoker) = {
214- let increaseQueueSize = IntegerEntry(queueSizeKey, (queueSize + 1))
215- let itm = buildNewItem(action, amt, token, priceIndex, invoker)
290+func enqueue (id,action,amt,token,priceIndex,invoker,minPayout,maxPayout) = {
291+ let increaseQueueSize = IE(QSIZEK, (queueSize + 1))
292+ let itm = buildNewItem(action, amt, token, priceIndex, invoker, minPayout, maxPayout)
216293 if ((queueSize == 0))
217- then [StringEntry(headPointerKey, id), StringEntry(tailPointerKey, id), StringEntry(id, itm), increaseQueueSize]
294+ then [SE(HEADK, id), SE(TAILK, id), SE(id, itm), increaseQueueSize]
218295 else {
219- let prevId = valueOrErrorMessage(getString(this, tailPointerKey), "can't get tail pointer")
220- let prevItm = split(valueOrErrorMessage(getString(this, prevId), "can't resolve pointer"), "|")
221- let updatedPrevItm = ((((((((((prevItm[0] + "|") + prevItm[1]) + "|") + prevItm[2]) + "|") + prevItm[3]) + "|") + prevItm[4]) + "|") + id)
222-[StringEntry(prevId, updatedPrevItm), StringEntry(id, itm), StringEntry(tailPointerKey, id), increaseQueueSize]
296+ let prevId = localS(TAILK, "can't get tail pointer")
297+ let prevItm = localS(prevId, "can't resolve pointer")
298+ let updatedPrevItm = (prevItm + id)
299+[SE(prevId, updatedPrevItm), SE(id, itm), SE(TAILK, id), increaseQueueSize]
223300 }
224301 }
225302
226303
227304 func poolSupport (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0,curPoolMain0,curPoolUp0,curPoolDwn0) = {
228- func closeUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
229- let diff = (curBullCol - curBearCol)
230- let exposure = fraction(curBullCol, curPoolUp, curBullCirc)
231- let liquidatedTokens = if ((diff > exposure))
232- then curPoolUp
233- else fraction(diff, curBullCirc, curBullCol)
234- let liquidatedValue = if ((diff > exposure))
235- then exposure
236- else fraction(liquidatedTokens, curBullCol, curBullCirc)
237- $Tuple7((curBullCol - liquidatedValue), curBearCol, (curBullCirc - liquidatedTokens), curBearCirc, (curPoolMain + liquidatedValue), (curPoolUp - liquidatedTokens), curPoolDwn)
305+ func closeUp (c1,c2,a0,a1,c0,pu,pd) = {
306+ let diff = (c1 - c2)
307+ let exp = fraction(c1, pu, a0)
308+ let liquidatedTokens = if ((diff > exp))
309+ then pu
310+ else fraction(diff, a0, c1)
311+ let liquidatedValue = if ((diff > exp))
312+ then exp
313+ else fraction(liquidatedTokens, c1, a0)
314+ $Tuple7((c1 - liquidatedValue), c2, (a0 - liquidatedTokens), a1, (c0 + liquidatedValue), (pu - liquidatedTokens), pd)
238315 }
239316
240- func closeDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
241- let diff = (curBearCol - curBullCol)
242- let exposure = fraction(curBearCol, curPoolDwn, curBearCirc)
243- let liquidatedTokens = if ((diff > exposure))
244- then curPoolDwn
245- else fraction(diff, curBearCirc, curBearCol)
246- let liquidatedValue = if ((diff > exposure))
247- then exposure
248- else fraction(liquidatedTokens, curBearCol, curBearCirc)
249- $Tuple7(curBullCol, (curBearCol - liquidatedValue), curBullCirc, (curBearCirc - liquidatedTokens), (curPoolMain + liquidatedValue), curPoolUp, (curPoolDwn - liquidatedTokens))
317+ func closeDwn (c1,c2,a0,a1,c0,pu,pd) = {
318+ let diff = (c2 - c1)
319+ let exp = fraction(c2, pd, a1)
320+ let liquidatedTokens = if ((diff > exp))
321+ then pd
322+ else fraction(diff, a1, c2)
323+ let liquidatedValue = if ((diff > exp))
324+ then exp
325+ else fraction(liquidatedTokens, c2, a1)
326+ $Tuple7(c1, (c2 - liquidatedValue), a0, (a1 - liquidatedTokens), (c0 + liquidatedValue), pu, (pd - liquidatedTokens))
250327 }
251328
252- func openDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
253- let diff = (curBullCol - curBearCol)
254- let spentPoolValue = if ((curPoolMain > diff))
329+ func openDwn (c1,c2,a0,a1,c0,pu,pd) = {
330+ let diff = (c1 - c2)
331+ let spentPoolValue = if ((c0 > diff))
255332 then diff
256- else curPoolMain
257- let acquiredTokens = fraction(spentPoolValue, curBearCirc, curBearCol)
258- $Tuple7(curBullCol, (curBearCol + spentPoolValue), curBullCirc, (curBearCirc + acquiredTokens), (curPoolMain - spentPoolValue), curPoolUp, (curPoolDwn + acquiredTokens))
333+ else c0
334+ let acquiredTokens = fraction(spentPoolValue, a1, c2)
335+ $Tuple7(c1, (c2 + spentPoolValue), a0, (a1 + acquiredTokens), (c0 - spentPoolValue), pu, (pd + acquiredTokens))
259336 }
260337
261- func openUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
262- let diff = (curBearCol - curBullCol)
263- let spentPoolValue = if ((curPoolMain > diff))
338+ func openUp (c1,c2,a0,a1,c0,pu,pd) = {
339+ let diff = (c2 - c1)
340+ let spentPoolValue = if ((c0 > diff))
264341 then diff
265- else curPoolMain
266- let acquiredTokens = fraction(spentPoolValue, curBullCirc, curBullCol)
267- $Tuple7((curBullCol + spentPoolValue), curBearCol, (curBullCirc + acquiredTokens), curBearCirc, (curPoolMain - spentPoolValue), (curPoolUp + acquiredTokens), curPoolDwn)
342+ else c0
343+ let acquiredTokens = fraction(spentPoolValue, a0, c1)
344+ $Tuple7((c1 + spentPoolValue), c2, (a0 + acquiredTokens), a1, (c0 - spentPoolValue), (pu + acquiredTokens), pd)
268345 }
269346
270- if ((curBullCol0 > curBearCol0))
347+ let $t01025511290 = if ((curBullCol0 > curBearCol0))
271348 then {
272349 let afterCloseUp = closeUp(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0)
273- let $t01047210609 = afterCloseUp
274- let a = $t01047210609._1
275- let b = $t01047210609._2
276- let c = $t01047210609._3
277- let d = $t01047210609._4
278- let e = $t01047210609._5
279- let f = $t01047210609._6
280- let g = $t01047210609._7
350+ let $t01048110618 = afterCloseUp
351+ let a = $t01048110618._1
352+ let b = $t01048110618._2
353+ let c = $t01048110618._3
354+ let d = $t01048110618._4
355+ let e = $t01048110618._5
356+ let f = $t01048110618._6
357+ let g = $t01048110618._7
281358 if ((f > 0))
282359 then afterCloseUp
283360 else if ((f == 0))
286363 }
287364 else {
288365 let afterCloseDwn = closeDwn(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0)
289- let $t01096011100 = afterCloseDwn
290- let a = $t01096011100._1
291- let b = $t01096011100._2
292- let c = $t01096011100._3
293- let d = $t01096011100._4
294- let e = $t01096011100._5
295- let f = $t01096011100._6
296- let g = $t01096011100._7
366+ let $t01096911109 = afterCloseDwn
367+ let a = $t01096911109._1
368+ let b = $t01096911109._2
369+ let c = $t01096911109._3
370+ let d = $t01096911109._4
371+ let e = $t01096911109._5
372+ let f = $t01096911109._6
373+ let g = $t01096911109._7
297374 if ((g > 0))
298375 then afterCloseDwn
299376 else if ((g == 0))
300377 then openUp(a, b, c, d, e, f, g)
301378 else throw("poolDwn < 0")
302379 }
380+ let c1 = $t01025511290._1
381+ let c2 = $t01025511290._2
382+ let a0 = $t01025511290._3
383+ let a1 = $t01025511290._4
384+ let c0 = $t01025511290._5
385+ let pu = $t01025511290._6
386+ let pd = $t01025511290._7
387+ let charge = fraction(userDiffAbs(), rebalancePercentile, ((1440 * 100) * 100))
388+ let percentileActivated = (height >= valueOrElse(getInteger(configProvider, "percentileActivationHeight"), 10000000))
389+ let c1SplitP = if (if (percentileActivated)
390+ then (pd > 0)
391+ else false)
392+ then charge
393+ else 0
394+ let c2SplitP = if (if (percentileActivated)
395+ then (pu > 0)
396+ else false)
397+ then charge
398+ else 0
399+ $Tuple7((c1 - c1SplitP), (c2 - c2SplitP), a0, a1, ((c0 + c1SplitP) + c2SplitP), pu, pd)
303400 }
304401
305402
306-func actionsWithMaybePool (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0) = {
307- let $t01139711580 = poolSupport(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, poolMain, poolUp, poolDwn)
308- let bullCol1 = $t01139711580._1
309- let bearCol1 = $t01139711580._2
310- let bullCic1 = $t01139711580._3
311- let bearCirc1 = $t01139711580._4
312- let poolMain1 = $t01139711580._5
313- let poolUp1 = $t01139711580._6
314- let poolDwn1 = $t01139711580._7
315-[IntegerEntry(bullCollateralKey, bullCol1), IntegerEntry(bullCirculationKey, bullCic1), IntegerEntry(bearCollateralKey, bearCol1), IntegerEntry(bearCirculationKey, bearCirc1), IntegerEntry(poolMainTokenValueKey, poolMain1), IntegerEntry(poolUpKey, poolUp1), IntegerEntry(poolDwnKey, poolDwn1)]
403+func poolSup (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0) = {
404+ let $t01187112053 = poolSupport(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, poolMain, poolUp, poolDwn)
405+ let bullCol1 = $t01187112053._1
406+ let bearCol1 = $t01187112053._2
407+ let bullCic1 = $t01187112053._3
408+ let bearCirc1 = $t01187112053._4
409+ let poolMain1 = $t01187112053._5
410+ let poolUp1 = $t01187112053._6
411+ let poolDwn1 = $t01187112053._7
412+[IE(BULLCOLK, bullCol1), IE(BULLCIRCK, bullCic1), IE(BEARCOLK, bearCol1), IE(BEARCIRCK, bearCirc1), IE(POOLUSDNK, poolMain1), IE(POOLUPK, poolUp1), IE(POOLDWNK, poolDwn1)]
316413 }
317414
318415
319-func dequeue () = if ((queueSize == 0))
320- then throw("nothing to settle")
321- else {
322- func collectFee (fees) = IntegerEntry(feesAccumulatedKey, (feesAccumulated + fees))
416+func dequeue () = {
417+ func sp (a,mx) = if ((mx >= a))
418+ then $Tuple2(a, 0)
419+ else $Tuple2(mx, (a - mx))
323420
324- let decreaseQueueSize = IntegerEntry(queueSizeKey, (queueSize - 1))
325- let isLastElement = (headPointer == tailPointer)
326- let overwriteTail = StringEntry(tailPointerKey, "")
327- let data = split(valueOrErrorMessage(getString(this, headPointer), "bad head pointer"), "|")
328- let action = data[0]
329- let amt = parseIntValue(data[1])
330- let token = data[2]
331- let priceIndex = parseIntValue(data[3])
332- let invoker = addressFromStringValue(data[4])
333- let next = data[5]
334- let items = if ((rebalancedPriceIndex > priceIndex))
335- then throw(((("corrupt state, rebalancedPriceIndex=" + toString(rebalancedPriceIndex)) + ", request price id=") + toString(priceIndex)))
336- else if ((priceIndex > rebalancedPriceIndex))
337- then throw("can't dequeue, too early, rebalance first")
338- else if ((action == ISSUE))
339- then {
340- let feeSize = fraction(amt, issuePercentile, 10000)
341- let addedCollateral = (amt - feeSize)
342- if ((token == BULL))
421+ if ((queueSize == 0))
422+ then throw("nothing to settle")
423+ else {
424+ func collectFee (fees) = IE(FEEACCK, (feesAccumulated + fees))
425+
426+ let decreaseQueueSize = IE(QSIZEK, (queueSize - 1))
427+ let isLastElement = (headPointer == tailPointer)
428+ let overwriteTail = SE(TAILK, "")
429+ let dataStr = localS(headPointer, "bad head pointer(dequeue)")
430+ let data = split(dataStr, "|")
431+ let action = data[0]
432+ let amt = parseIntValue(data[1])
433+ let token = data[2]
434+ let priceIndex = parseIntValue(data[3])
435+ let invoker = addressFromStringValue(data[4])
436+ let minPayout = if ((8 > size(data)))
437+ then 0
438+ else parseIntValue(data[5])
439+ let maxPayout = if ((8 > size(data)))
440+ then MAX
441+ else parseIntValue(data[6])
442+ let next = data[(size(data) - 1)]
443+ func payback (tkn) = [SE(HEADK, next), decreaseQueueSize, ST(invoker, amt, fromBase58String(tkn))]
444+
445+ let items = if ((rebalancedPriceIndex > priceIndex))
446+ then throw(((("corrupt state, rebalancedPriceIndex=" + toString(rebalancedPriceIndex)) + ", request price id=") + toString(priceIndex)))
447+ else if ((priceIndex > rebalancedPriceIndex))
448+ then throw("can't dequeue, too early, rebalance first")
449+ else if ((action == ISSUE))
450+ then {
451+ let feeSize = fraction(amt, issuePercentile, 10000)
452+ let addedCollateral = (amt - feeSize)
453+ let a = if ((token == BULL))
454+ then fraction(bullCirc, addedCollateral, bullCol)
455+ else if ((token == BEAR))
456+ then fraction(bearCirc, addedCollateral, bearCol)
457+ else throw("bad token id")
458+ let $t01416714223 = sp(a, maxPayout)
459+ let addedToCirculation = $t01416714223._1
460+ let extraTokens = $t01416714223._2
461+ let $t01424014411 = if ((token == BULL))
462+ then $Tuple4(addedToCirculation, addedCollateral, 0, 0)
463+ else $Tuple4(0, 0, addedToCirculation, addedCollateral)
464+ let plusBulls = $t01424014411._1
465+ let plusBullCol = $t01424014411._2
466+ let plusBears = $t01424014411._3
467+ let plusBearCol = $t01424014411._4
468+ if ((minPayout > addedToCirculation))
469+ then payback(mainToken)
470+ else (poolSup((bullCol + plusBullCol), (bearCol + plusBearCol), (bullCirc + plusBulls), (bearCirc + plusBears)) ++ [SE(HEADK, next), collectFee(feeSize), decreaseQueueSize, ST(invoker, addedToCirculation, fromBase58String(token)), ST(feeAddress, extraTokens, fromBase58String(token))])
471+ }
472+ else if ((action == REDEEM))
343473 then {
344- let addedToCirculation = fraction(bullCirc, addedCollateral, bullCol)
345- (actionsWithMaybePool((bullCol + addedCollateral), bearCol, (bullCirc + addedToCirculation), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BULL))])
474+ let removedTokens = amt
475+ let calcPo = if ((token == BULL))
476+ then fraction(bullCol, removedTokens, bullCirc)
477+ else if ((token == BEAR))
478+ then fraction(bearCol, removedTokens, bearCirc)
479+ else throw("bad token id")
480+ let $t01532615375 = sp(calcPo, maxPayout)
481+ let payoutCapped = $t01532615375._1
482+ let extra = $t01532615375._2
483+ let feeSize = fraction(payoutCapped, redeemPercentile, 10000)
484+ let payout = if ((payoutCapped > feeSize))
485+ then (payoutCapped - feeSize)
486+ else 0
487+ let $t01556115720 = if ((token == BULL))
488+ then $Tuple4(removedTokens, payoutCapped, 0, 0)
489+ else $Tuple4(0, 0, removedTokens, payoutCapped)
490+ let minusBulls = $t01556115720._1
491+ let minusBullCol = $t01556115720._2
492+ let minusBears = $t01556115720._3
493+ let minusBearCol = $t01556115720._4
494+ if ((minPayout > payout))
495+ then payback(token)
496+ else (poolSup((bullCol - minusBullCol), (bearCol - minusBearCol), (bullCirc - minusBulls), (bearCirc - minusBears)) ++ [SE(HEADK, next), collectFee(feeSize), decreaseQueueSize, ST(invoker, payout, fromBase58String(mainToken)), ST(feeAddress, extra, fromBase58String(mainToken))])
346497 }
347- else if ((token == BEAR))
498+ else if ((action == POOL))
348499 then {
349- let addedToCirculation = fraction(bearCirc, addedCollateral, bearCol)
350- (actionsWithMaybePool(bullCol, (bearCol + addedCollateral), bullCirc, (bearCirc + addedToCirculation)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BEAR))])
500+ let issueTokens = fraction(poolTokenCirculation, amt, poolValue)
501+ if ((minPayout > issueTokens))
502+ then payback(mainToken)
503+ else [IE(POOLUSDNK, (poolMain + amt)), IE(POOLCIRCK, (poolTokenCirculation + issueTokens)), SE(HEADK, next), decreaseQueueSize, ST(invoker, issueTokens, fromBase58String(poolToken))]
351504 }
352- else throw("bad token id")
353- }
354- else if ((action == REDEEM))
355- then {
356- let removedTokens = amt
357- if ((token == BULL))
358- then {
359- let removedCollateral = fraction(bullCol, removedTokens, bullCirc)
360- let feeSize = fraction(removedCollateral, redeemPercentile, 10000)
361- let payout = if ((removedCollateral > feeSize))
362- then (removedCollateral - feeSize)
363- else 0
364- (actionsWithMaybePool((bullCol - removedCollateral), bearCol, (bullCirc - removedTokens), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))])
365- }
366- else if ((token == BEAR))
505+ else if ((action == UNPOOL))
367506 then {
368- let removedCollateral = fraction(bearCol, removedTokens, bearCirc)
369- let feeSize = fraction(removedCollateral, redeemPercentile, 10000)
370- let payout = if ((removedCollateral > feeSize))
371- then (removedCollateral - feeSize)
372- else 0
373- (actionsWithMaybePool(bullCol, (bearCol - removedCollateral), bullCirc, (bearCirc - removedTokens)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))])
507+ func share (a) = fraction(a, amt, poolTokenCirculation)
508+
509+ let unpooledMain = share(poolMain)
510+ let unpooledUp = share(poolUp)
511+ let unpooledDwn = share(poolDwn)
512+ let unpooledUpValue = fraction(unpooledUp, bullCol, bullCirc)
513+ let unpooledDwnValue = fraction(unpooledDwn, bearCol, bearCirc)
514+ let totalUnpooledValue = ((unpooledMain + unpooledUpValue) + unpooledDwnValue)
515+ if ((minPayout > totalUnpooledValue))
516+ then payback(poolToken)
517+ else [IE(POOLUSDNK, (poolMain - unpooledMain)), IE(POOLCIRCK, (poolTokenCirculation - amt)), IE(POOLUPK, (poolUp - unpooledUp)), IE(POOLDWNK, (poolDwn - unpooledDwn)), IE(BULLCIRCK, (bullCirc - unpooledUp)), IE(BEARCIRCK, (bearCirc - unpooledDwn)), IE(BULLCOLK, (bullCol - unpooledUpValue)), IE(BEARCOLK, (bearCol - unpooledDwnValue)), SE(HEADK, next), decreaseQueueSize, ST(invoker, totalUnpooledValue, fromBase58String(mainToken))]
374518 }
375- else throw("bad token id")
376- }
377- else if ((action == POOL))
378- then {
379- let issueTokens = fraction(poolTokenCirculation, amt, poolValue)
380-[IntegerEntry(poolMainTokenValueKey, (poolMain + amt)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation + issueTokens)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, issueTokens, fromBase58String(poolToken))]
381- }
382- else if ((action == UNPOOL))
383- then {
384- func share (a) = fraction(a, amt, poolTokenCirculation)
385-
386- let unpooledMain = share(poolMain)
387- let unpooledUp = share(poolUp)
388- let unpooledDwn = share(poolDwn)
389- let unpooledUpValue = fraction(unpooledUp, bullCol, bullCirc)
390- let unpooledDwnValue = fraction(unpooledDwn, bearCol, bearCirc)
391-[IntegerEntry(poolMainTokenValueKey, (poolMain - unpooledMain)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation - amt)), IntegerEntry(poolUpKey, (poolUp - unpooledUp)), IntegerEntry(poolDwnKey, (poolDwn - unpooledDwn)), IntegerEntry(bullCirculationKey, (bullCirc - unpooledUp)), IntegerEntry(bearCirculationKey, (bearCirc - unpooledDwn)), IntegerEntry(bullCollateralKey, (bullCol - unpooledUpValue)), IntegerEntry(bearCollateralKey, (bearCol - unpooledDwnValue)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, ((unpooledMain + unpooledUpValue) + unpooledDwnValue), fromBase58String(mainToken))]
392- }
393- else throw(("bad action: " + action))
394- if (isLastElement)
395- then overwriteTail :: items
396- else items
397- }
519+ else throw(("bad action: " + action))
520+ if (isLastElement)
521+ then overwriteTail :: items
522+ else items
523+ }
524+ }
398525
399526
400527 func rebalance () = {
401- func LV (v,p0,p1) = {
402- let denom = 100
528+ func LV (v,p0,p1,m) = {
529+ let denom = {
530+ let md = (((2 * (if ((p1 > p0))
531+ then p1
532+ else p0)) * m) / 3037000499)
533+ if ((10 > md))
534+ then 10
535+ else if ((100 > md))
536+ then 100
537+ else 1000
538+ }
403539 let pmax = ((if ((p1 > p0))
404540 then p1
405541 else p0) / denom)
407543 then p1
408544 else p0) / denom)
409545 let a = (pmin * pmin)
410- let b = (((9 * pmax) * pmax) - ((15 * pmax) * pmin))
411- fraction(v, ((6 * a) + b), ((7 * a) + b))
546+ let b = ((((m * m) * pmax) * pmax) - (((((2 * m) * m) - m) * pmax) * pmin))
547+ let ma = ((m * m) - m)
548+ fraction(v, ((ma * a) + b), (((ma + 1) * a) + b))
412549 }
413550
414- let settledPriceIndex = valueOrErrorMessage(getInteger(this, lastRebalancePriceIndexKey), "inconsistent data")
551+ let settledPriceIndex = valueOrErrorMessage(getInteger(this, REBIDXK), "inconsistent data")
415552 let unsettledPriceIndex = (settledPriceIndex + 1)
416- let settledPriceHeight = valueOrErrorMessage(getInteger(oracle, ("price_index_" + toString(settledPriceIndex))), "bad oracle data for settled price height")
417- let settledPrice = valueOrErrorMessage(getInteger(oracle, ("price_" + toString(settledPriceHeight))), "bad oracle data for price")
418- let nextPriceHeight = valueOrErrorMessage(getInteger(oracle, ("price_index_" + toString(unsettledPriceIndex))), "no next price height")
419- let nextPrice = valueOrErrorMessage(getInteger(oracle, ("price_" + toString(nextPriceHeight))), "no next price")
553+ let settledPrice = priceByIndex(assetName, settledPriceIndex)
554+ let nextPrice = priceByIndex(assetName, unsettledPriceIndex)
420555 let minVol = if ((bearCol > bullCol))
421556 then bullCol
422557 else bearCol
423- let redist = LV(minVol, settledPrice, nextPrice)
424- let newBullCol = if ((nextPrice > settledPrice))
558+ let redist = LV(minVol, settledPrice, nextPrice, leverage)
559+ let priceUpGoodForBulls = (assetName == "")
560+ let priceGoesUp = (nextPrice > settledPrice)
561+ let bullsEarn = (priceUpGoodForBulls == priceGoesUp)
562+ let newBullCol = if (bullsEarn)
425563 then (bullCol + redist)
426564 else (bullCol - redist)
427- let newBearCol = if ((nextPrice > settledPrice))
565+ let newBearCol = if (bullsEarn)
428566 then (bearCol - redist)
429567 else (bearCol + redist)
430- let $t01944619633 = poolSupport(newBullCol, newBearCol, bullCirc, bearCirc, poolMain, poolUp, poolDwn)
431- let updBullCol = $t01944619633._1
432- let updBearCol = $t01944619633._2
433- let updBullCirc = $t01944619633._3
434- let updBearCirc = $t01944619633._4
435- let updPoolMain = $t01944619633._5
436- let updPoolUp = $t01944619633._6
437- let updPoolDwn = $t01944619633._7
438-[IntegerEntry(bullCollateralKey, updBullCol), IntegerEntry(bearCollateralKey, updBearCol), IntegerEntry(bullCirculationKey, updBullCirc), IntegerEntry(bearCirculationKey, updBearCirc), IntegerEntry(poolMainTokenValueKey, updPoolMain), IntegerEntry(poolUpKey, updPoolUp), IntegerEntry(poolDwnKey, updPoolDwn), IntegerEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]
568+ let $t01960819794 = poolSupport(newBullCol, newBearCol, bullCirc, bearCirc, poolMain, poolUp, poolDwn)
569+ let updBullCol = $t01960819794._1
570+ let updBearCol = $t01960819794._2
571+ let updBullCirc = $t01960819794._3
572+ let updBearCirc = $t01960819794._4
573+ let updPoolMain = $t01960819794._5
574+ let updPoolUp = $t01960819794._6
575+ let updPoolDwn = $t01960819794._7
576+[IE(BULLCOLK, updBullCol), IE(BEARCOLK, updBearCol), IE(BULLCIRCK, updBullCirc), IE(BEARCIRCK, updBearCirc), IE(POOLUSDNK, updPoolMain), IE(POOLUPK, updPoolUp), IE(POOLDWNK, updPoolDwn), IE(REBIDXK, unsettledPriceIndex)]
577+ }
578+
579+
580+func calcMax (min,avg) = if ((min > avg))
581+ then throw(((("price too old: minPayout " + toString(min)) + " > avg = ") + toString(avg)))
582+ else ((avg + avg) - min)
583+
584+
585+func requestIssueInternal (inv,tokenId,minPayout) = if (if ((tokenId != BULL))
586+ then (tokenId != BEAR)
587+ else false)
588+ then throw("bad token req")
589+ else if ((inv.caller == this))
590+ then throw("can't do")
591+ else if (!(allowed(inv.caller)))
592+ then throw("only whitelisted can do")
593+ else {
594+ let errorMessage = (((("bad token req, only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") allowed")
595+ if ((inv.payments[0].assetId != fromBase58String(mainToken)))
596+ then throw("bad token att")
597+ else {
598+ let amt = inv.payments[0].amount
599+ let $t02080020978 = if ((tokenId == BULL))
600+ then $Tuple2(bullCol, bullCirc)
601+ else if ((tokenId == BEAR))
602+ then $Tuple2(bearCol, bearCirc)
603+ else throw(errorMessage)
604+ let col = $t02080020978._1
605+ let circ = $t02080020978._2
606+ let est = fraction(amt, circ, col)
607+ let $t02102021114 = if ((minPayout == 0))
608+ then $Tuple2(0, MAX)
609+ else $Tuple2(minPayout, calcMax(minPayout, est))
610+ let minP = $t02102021114._1
611+ let maxP = $t02102021114._2
612+ if ((minIssue > amt))
613+ then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN"))
614+ else {
615+ let maxAllowed = maxIssue(tokenId)
616+ if (if ((whitelist == ""))
617+ then (inv.payments[0].amount > maxAllowed)
618+ else false)
619+ then throw((("trying to issue more than pool can handle. Max attachment allowed = " + toString((maxAllowed / 1000000))) + " USDN"))
620+ else (enqueue(toBase58String(inv.transactionId), ISSUE, amt, tokenId, (oraclePriceIndex + 1), toString(inv.caller), minP, maxP) ++ [debug("requested", tokenId), debug("bull", BULL), debug("bear", BEAR)])
621+ }
622+ }
623+ }
624+
625+
626+func requestRedeemInternal (inv,minPayout) = {
627+ let amt = inv.payments[0].amount
628+ let tokenId = toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "bad token att"))
629+ if (if ((tokenId != BULL))
630+ then (tokenId != BEAR)
631+ else false)
632+ then throw("bad token req")
633+ else {
634+ let $t02215122290 = if ((tokenId == BULL))
635+ then $Tuple2(bullCol, bullCirc)
636+ else if ((tokenId == BEAR))
637+ then $Tuple2(bearCol, bearCirc)
638+ else throw("bad token req")
639+ let col = $t02215122290._1
640+ let circ = $t02215122290._2
641+ let est = fraction(amt, col, circ)
642+ let $t02233822432 = if ((minPayout == 0))
643+ then $Tuple2(0, MAX)
644+ else $Tuple2(minPayout, calcMax(minPayout, est))
645+ let minP = $t02233822432._1
646+ let maxP = $t02233822432._2
647+ if ((validateRequestRedeem(inv) == unit))
648+ then enqueue(toBase58String(inv.transactionId), REDEEM, amt, tokenId, (oraclePriceIndex + 1), toString(inv.caller), minP, maxP)
649+ else throw("doesn't happen")
650+ }
651+ }
652+
653+
654+func requestPoolInternal (inv,minPayout) = if (!(allowed(inv.caller)))
655+ then throw("only whitelisted can do")
656+ else {
657+ let errMessage = (("main token must be attached(" + mainToken) + ")")
658+ let pmt = inv.payments[0]
659+ if ((pmt.assetId != fromBase58String(mainToken)))
660+ then throw(errMessage)
661+ else if ((minPool > pmt.amount))
662+ then throw(((("pool at least " + toString(minPool)) + " ") + mainToken))
663+ else {
664+ let estimate = fraction(poolTokenCirculation, pmt.amount, poolValue)
665+ let $t02328023379 = if ((minPayout == 0))
666+ then $Tuple2(0, MAX)
667+ else $Tuple2(minPayout, calcMax(minPayout, estimate))
668+ let minP = $t02328023379._1
669+ let maxP = $t02328023379._2
670+ enqueue(toBase58String(inv.transactionId), POOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller), minP, maxP)
671+ }
672+ }
673+
674+
675+func requestUnpoolInternal (inv,minPayout) = {
676+ let errMessage = (("only pool token allowed(" + poolToken) + ")")
677+ let pmt = inv.payments[0]
678+ if ((pmt.assetId != fromBase58String(poolToken)))
679+ then throw(errMessage)
680+ else {
681+ let estimate = fraction(poolValue, pmt.amount, poolTokenCirculation)
682+ if ((minPool > estimate))
683+ then throw(((("unpool at least for" + toString(minPool)) + " ") + mainToken))
684+ else {
685+ let $t02403624135 = if ((minPayout == 0))
686+ then $Tuple2(0, MAX)
687+ else $Tuple2(minPayout, calcMax(minPayout, estimate))
688+ let minP = $t02403624135._1
689+ let maxP = $t02403624135._2
690+ enqueue(toBase58String(inv.transactionId), UNPOOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller), minP, maxP)
691+ }
692+ }
439693 }
440694
441695
442696 @Callable(inv)
443-func init (config,oraclePK,nameup,namedwn,descUp,descDwn,poolName,poolDesc,denom) = if (isDefined(getString(this, BULLKey)))
697+func init (config,oraclePK,nameup,namedwn,descUp,descDwn,poolName,poolDesc,defoAssetName,denom,lev) = if (isDefined(getString(this, BULLK)))
444698 then throw("already initialized")
445699 else {
446700 let totalOwnedMainToken = inv.payments[0].amount
454708 else (pools == 0))
455709 then throw("can't init balances")
456710 else {
457- let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey), "can't find last oracle price index")
711+ let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey(defoAssetName)), "can't find last oracle price index")
458712 let bull = Issue(nameup, descUp, ((100 * ten6) * ten6), 6, true)
459713 let bear = Issue(namedwn, descDwn, ((100 * ten6) * ten6), 6, true)
460714 let pool = Issue(poolName, poolDesc, ((100 * ten6) * ten6), 6, true)
461715 let buid = calculateAssetId(bull)
462716 let beid = calculateAssetId(bear)
463717 let poid = calculateAssetId(pool)
464-[bull, bear, pool, StringEntry(BULLKey, toBase58String(buid)), StringEntry(BEARKey, toBase58String(beid)), StringEntry(mainTokenKey, toBase58String(value(inv.payments[0].assetId))), StringEntry(poolTokenKey, toBase58String(poid)), StringEntry(oraclePKKey, oraclePK), IntegerEntry(lastRebalancePriceIndexKey, oracleCurrentPriceIndex), IntegerEntry(bullCollateralKey, bulls), IntegerEntry(bearCollateralKey, bears), IntegerEntry(bullCirculationKey, (bulls / denom)), IntegerEntry(bearCirculationKey, (bears / denom)), IntegerEntry(poolTokenCirculationKey, (pools / denom)), IntegerEntry(poolDwnKey, 0), IntegerEntry(poolUpKey, 0), IntegerEntry(poolMainTokenValueKey, pools), StringEntry(configProviderKey, config), ScriptTransfer(inv.caller, (bulls / denom), buid), ScriptTransfer(inv.caller, (bears / denom), beid), ScriptTransfer(inv.caller, (pools / denom), poid)]
718+[bull, bear, pool, SE(BULLK, toBase58String(buid)), SE(BEARK, toBase58String(beid)), SE(USDNK, toBase58String(value(inv.payments[0].assetId))), SE(POOLK, toBase58String(poid)), SE(ASSNAMEK, defoAssetName), SE(oraclePKKey, oraclePK), IE(REBIDXK, oracleCurrentPriceIndex), IE(BULLCOLK, bulls), IE(BEARCOLK, bears), IE(BULLCIRCK, (bulls / denom)), IE(BEARCIRCK, (bears / denom)), IE(POOLCIRCK, (pools / denom)), IE(POOLDWNK, 0), IE(POOLUPK, 0), IE(POOLUSDNK, pools), SE(configProviderKey, config), IE(LEVK, lev), ST(inv.caller, (bulls / denom), buid), ST(inv.caller, (bears / denom), beid), ST(inv.caller, (pools / denom), poid)]
465719 }
466720 }
467721
470724 @Callable(i)
471725 func withdrawFee (amount) = if ((amount > feesAccumulated))
472726 then throw(("too much. available: " + toString(feesAccumulated)))
473- else [IntegerEntry(feesAccumulatedKey, (feesAccumulated - amount)), ScriptTransfer(feeAddress, amount, fromBase58String(mainToken))]
727+ else [IE(FEEACCK, (feesAccumulated - amount)), ST(feeAddress, amount, fromBase58String(mainToken))]
474728
475729
476730
477731 @Callable(inv)
478-func requestRedeem () = if ((validateRequestRedeem(inv) == unit))
479- then {
480- let assetId = toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "waves are not accepted here"))
481- enqueue(toBase58String(inv.transactionId), REDEEM, inv.payments[0].amount, assetId, (oraclePriceIndex + 1), toString(inv.caller))
482- }
483- else throw("doesn't happen")
732+func requestRedeem () = requestRedeemInternal(inv, 0)
484733
485734
486735
487736 @Callable(inv)
488-func requestIssue (tokenId) = if ((inv.caller == this))
489- then throw("can't do")
490- else if (!(allowed(inv.caller)))
491- then throw("only whitelisted can do")
492- else {
493- let errorMessage = throw((((((("only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are available in exchange for USDN(") + mainToken) + ")"))
494- if (if ((tokenId != BULL))
495- then (tokenId != BEAR)
496- else false)
497- then errorMessage
498- else if ((inv.payments[0].assetId != fromBase58String(mainToken)))
499- then errorMessage
500- else if ((minIssue > inv.payments[0].amount))
501- then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN"))
502- else {
503- let maxAllowed = maxIssue(tokenId)
504- if (if ((whitelist == ""))
505- then (inv.payments[0].amount > maxAllowed)
506- else false)
507- then throw((("trying to issue more than pool can handle. Max attachment allowed = " + toString((maxAllowed / 1000000))) + " USDN"))
508- else enqueue(toBase58String(inv.transactionId), ISSUE, inv.payments[0].amount, tokenId, (oraclePriceIndex + 1), toString(inv.caller))
509- }
510- }
737+func requestRedeemSl (sl) = if (validatePMFee(inv, sl))
738+ then requestRedeemInternal(inv, sl)
739+ else throw()
740+
741+
742+
743+@Callable(inv)
744+func requestIssue (tokenId) = requestIssueInternal(inv, tokenId, 0)
745+
746+
747+
748+@Callable(inv)
749+func requestIssueSl (tokenId,sl) = if (validatePMFee(inv, sl))
750+ then requestIssueInternal(inv, tokenId, sl)
751+ else throw()
752+
753+
754+
755+@Callable(inv)
756+func requestPool () = requestPoolInternal(inv, 0)
757+
758+
759+
760+@Callable(inv)
761+func requestPoolSl (sl) = if (validatePMFee(inv, sl))
762+ then requestPoolInternal(inv, sl)
763+ else throw()
764+
765+
766+
767+@Callable(inv)
768+func requestUnpool () = requestUnpoolInternal(inv, 0)
769+
770+
771+
772+@Callable(inv)
773+func requestUnpoolSl (sl) = if (validatePMFee(inv, sl))
774+ then requestUnpoolInternal(inv, sl)
775+ else throw()
511776
512777
513778
520785 then rebalance()
521786 else throw("[OK] all done, carry on")
522787 else {
523- let data = split(valueOrErrorMessage(getString(this, headPointer), "bad head pointer"), "|")
788+ let data = split(valueOrErrorMessage(getString(this, headPointer), ("bad head pointer(settle): " + headPointer)), "|")
524789 let priceIndex = parseIntValue(data[3])
525790 if ((priceIndex > rebalancedPriceIndex))
526791 then if (canRebalance)
528793 else throw("[OK] need to wait")
529794 else if ((priceIndex == rebalancedPriceIndex))
530795 then dequeue()
531- else throw("corrupt data, future price id already rebalanced")
532- }
533- }
534-
535-
536-
537-@Callable(inv)
538-func requestPool () = if (!(allowed(inv.caller)))
539- then throw("only whitelisted can do")
540- else {
541- let errMessage = (("main token must be attached(" + mainToken) + ")")
542- let pmt = inv.payments[0]
543- if ((pmt.assetId != fromBase58String(mainToken)))
544- then throw(errMessage)
545- else if ((minPool > pmt.amount))
546- then throw(((("pool at least " + toString(minPool)) + " ") + mainToken))
547- else enqueue(toBase58String(inv.transactionId), POOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller))
548- }
549-
550-
551-
552-@Callable(inv)
553-func requestUnpool () = {
554- let errMessage = (("only pool token allowed(" + poolToken) + ")")
555- let pmt = inv.payments[0]
556- if ((pmt.assetId != fromBase58String(poolToken)))
557- then throw(errMessage)
558- else {
559- let estimate = fraction(poolValue, pmt.amount, poolTokenCirculation)
560- if ((minPool > estimate))
561- then throw(((("unpool at least for" + toString(minPool)) + " ") + mainToken))
562- else enqueue(toBase58String(inv.transactionId), UNPOOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller))
796+ else throw("future price already rebalanced")
563797 }
564798 }
565799
566800
567801 @Verifier(tx)
568802 func verify () = {
569- let initial = if (!(isDefined(getString(this, BULLKey))))
803+ let initial = if (!(isDefined(getString(this, BULLK))))
570804 then sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
571805 else false
572- let adminAction = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
806+ let adminAction = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(admins[0])))
573807 then 1
574- else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
808+ else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(admins[1])))
575809 then 1
576- else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
810+ else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(admins[2])))
577811 then 1
578812 else 0)) > 1)
579813 let stakingAction = match tx {
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 4 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4+func SE (k,v) = StringEntry(k, v)
5+
6+
7+func IE (k,v) = IntegerEntry(k, v)
8+
9+
10+func ST (a,amt,t) = ScriptTransfer(a, amt, t)
11+
12+
13+func debug (k,v) = SE(("__dbg__" + k), v)
14+
15+
416 let ten6 = 1000000
517
618 let ten8 = 100000000
19+
20+let MAX = 9223372036854775807
721
822 let configProviderKey = "configProvider"
923
1024 let configProvider = match getString(this, configProviderKey) {
1125 case s: String =>
1226 addressFromStringValue(s)
1327 case _ =>
1428 this
1529 }
1630
17-let BULLKey = "BULLId"
31+func localI (k,e) = valueOrErrorMessage(getInteger(this, k), e)
1832
19-let BEARKey = "BEARId"
2033
21-let mainTokenKey = "mainTokenId"
34+func localS (k,e) = valueOrErrorMessage(getString(this, k), e)
2235
23-let bullCollateralKey = "bullCollateral"
2436
25-let bearCollateralKey = "bearCollateral"
37+func confI (k,e) = valueOrErrorMessage(getInteger(configProvider, k), e)
2638
27-let bullCirculationKey = "bullCirculation"
2839
29-let bearCirculationKey = "bearCirculation"
40+func confS (k,e) = valueOrErrorMessage(getString(configProvider, k), e)
3041
31-let issuePercentileKey = "issuePercentile"
3242
33-let redeemPercentileKey = "redeemPercentile"
43+let BULLK = "BULLId"
3444
35-let minIssueKey = "minIssue"
45+let BEARK = "BEARId"
3646
37-let minRedeemKey = "minRedeem"
47+let USDNK = "mainTokenId"
3848
39-let minPoolKey = "minPool"
49+let BULLCOLK = "bullCollateral"
4050
41-let feesAccumulatedKey = "feesAccumulated"
51+let BEARCOLK = "bearCollateral"
4252
43-let whitelistKey = "issueWhiteList"
53+let BULLCIRCK = "bullCirculation"
54+
55+let BEARCIRCK = "bearCirculation"
56+
57+let ISSPERCK = "issuePercentile"
58+
59+let REDPERCK = "redeemPercentile"
60+
61+let MINISSK = "minIssue"
62+
63+let MINREDK = "minRedeem"
64+
65+let MINPOOLK = "minPool"
66+
67+let FEEACCK = "feesAccumulated"
68+
69+let WLISTK = "issueWhiteList"
70+
71+let REBPERCK = "rebalancePercentile"
72+
73+let REBIDXK = "lastSettlementPriceId"
74+
75+let HEADK = "headPointer"
76+
77+let TAILK = "tailPointer"
78+
79+let QSIZEK = "queueSize"
80+
81+let POOLUSDNK = "poolMainTokenValue"
82+
83+let POOLUPK = "poolUp"
84+
85+let POOLDWNK = "poolDwn"
86+
87+let POOLCIRCK = "poolTokenCirculation"
88+
89+let POOLK = "poolToken"
90+
91+let ASSNAMEK = "defoAssetName"
92+
93+let LEVK = "leverage"
94+
95+let WAVESFEEK = "wavesPacemakerFee"
96+
97+let USDNFEEK = "usdnPacemakerFee"
4498
4599 let oraclePKKey = "oracle"
46100
47-let lastPriceIndexKey = "price_index"
101+func lastPriceIndexKey (assetId) = if ((assetId == ""))
102+ then "price_index"
103+ else ("%s%s__idxCurrent__" + assetId)
48104
49-let priceIndexPrefix = "price_index_"
50105
51-let priceHeightPrefix = "price_"
106+func priceIndexPrefix (assetId) = if ((assetId == ""))
107+ then "price_index_"
108+ else (("%s%s%d__idx2Height__" + assetId) + "__")
52109
53-let oracleCurrentPriceIndexKey = "price_index"
54110
55-let lastRebalancePriceIndexKey = "lastSettlementPriceId"
111+func priceHeightPrefix (assetId) = if ((assetId == ""))
112+ then "price_"
113+ else (("%s%s%d__priceByHeight__" + assetId) + "__")
56114
57-let headPointerKey = "headPointer"
58115
59-let tailPointerKey = "tailPointer"
116+let minUsdnFee = valueOrElse(getInteger(configProvider, USDNFEEK), 0)
60117
61-let queueSizeKey = "queueSize"
118+let minWavesFee = valueOrElse(getInteger(configProvider, WAVESFEEK), 0)
62119
63-let poolMainTokenValueKey = "poolMainTokenValue"
120+let assetName = valueOrElse(getString(this, ASSNAMEK), "")
64121
65-let poolUpKey = "poolUp"
122+let bullCol = localI(BULLCOLK, "no 0")
66123
67-let poolDwnKey = "poolDwn"
124+let bearCol = localI(BEARCOLK, "no 1")
68125
69-let poolTokenCirculationKey = "poolTokenCirculation"
126+let bullCirc = localI(BULLCIRCK, "no 2")
70127
71-let poolTokenKey = "poolToken"
128+let bearCirc = localI(BEARCIRCK, "no 3")
72129
73-let bullCol = valueOrErrorMessage(getInteger(this, bullCollateralKey), "no bullCollateralKey")
130+let BULL = localS(BULLK, "no 14")
74131
75-let bearCol = valueOrErrorMessage(getInteger(this, bearCollateralKey), "no bearCollateralKey")
132+let BEAR = localS(BEARK, "no 15")
76133
77-let bullCirc = valueOrErrorMessage(getInteger(this, bullCirculationKey), "no bullCirculationKey")
134+let mainToken = localS(USDNK, "no 16")
78135
79-let bearCirc = valueOrErrorMessage(getInteger(this, bearCirculationKey), "no bearCirculationKey")
136+let issuePercentile = confI(ISSPERCK, "no 4")
80137
81-let BULL = valueOrErrorMessage(getString(this, BULLKey), "no BULLKey")
138+let redeemPercentile = confI(REDPERCK, "no 5")
82139
83-let BEAR = valueOrErrorMessage(getString(this, BEARKey), "no BEARKey")
140+let minIssue = confI(MINISSK, "no 6")
84141
85-let mainToken = valueOrErrorMessage(getString(this, mainTokenKey), "no mainTokenKey")
142+let minRedeem = confI(MINREDK, "no 7")
86143
87-let issuePercentile = valueOrErrorMessage(getInteger(configProvider, issuePercentileKey), "no issuePercentileKey")
144+let minPool = confI(MINPOOLK, "no 8")
88145
89-let redeemPercentile = valueOrErrorMessage(getInteger(configProvider, redeemPercentileKey), "no redeemPercentileKey")
146+let rebalancePercentile = valueOrElse(getInteger(configProvider, ((toString(this) + "_") + REBPERCK)), 0)
90147
91-let minIssue = valueOrErrorMessage(getInteger(configProvider, minIssueKey), "no minIssueKey")
92-
93-let minRedeem = valueOrErrorMessage(getInteger(configProvider, minRedeemKey), "no minRedeemKey")
94-
95-let minPool = valueOrErrorMessage(getInteger(configProvider, minPoolKey), "no minPoolKey")
96-
97-let whitelist = valueOrErrorMessage(getString(configProvider, whitelistKey), "no whitelistKey")
148+let whitelist = confS(WLISTK, "no 9")
98149
99150 func allowed (a) = if ((whitelist == ""))
100151 then true
101152 else isDefined(indexOf(whitelist, toString(a)))
102153
103154
104-let poolMain = valueOrErrorMessage(getInteger(this, poolMainTokenValueKey), "no poolMainTokenValueKey")
155+let poolMain = localI(POOLUSDNK, "no")
105156
106-let poolUp = valueOrErrorMessage(getInteger(this, poolUpKey), "no poolUpKey")
157+let poolUp = localI(POOLUPK, "no 10")
107158
108-let poolDwn = valueOrErrorMessage(getInteger(this, poolDwnKey), "no poolDwnKey")
159+let poolDwn = localI(POOLDWNK, "no 11")
109160
110-let poolToken = valueOrErrorMessage(getString(this, poolTokenKey), "no poolTokenKey")
161+let poolToken = localS(POOLK, "no 12")
111162
112-let poolTokenCirculation = valueOrErrorMessage(getInteger(this, poolTokenCirculationKey), "no poolTokenCirculationKey")
163+let poolTokenCirculation = localI(POOLCIRCK, "no 13")
113164
114165 let poolBullExposure = fraction(bullCol, poolUp, bullCirc)
115166
116167 let poolBearExposure = fraction(bearCol, poolDwn, bearCirc)
117168
118169 let poolValue = ((poolMain + poolBullExposure) + poolBearExposure)
119170
120171 let oracle = valueOrErrorMessage(addressFromPublicKey(fromBase58String(valueOrErrorMessage(getString(this, oraclePKKey), "no oraclePKKey"))), "bad oracle address")
121172
122-let rebalancedPriceIndex = valueOrErrorMessage(getInteger(this, lastRebalancePriceIndexKey), "no last rebalance price")
173+let rebalancedPriceIndex = valueOrErrorMessage(getInteger(this, REBIDXK), "no last rebalance price")
123174
124-let oraclePriceIndex = valueOrErrorMessage(getInteger(oracle, lastPriceIndexKey), ((("bad oracle data at " + toString(oracle)) + ": no integer at ") + lastPriceIndexKey))
175+let oraclePriceIndex = valueOrErrorMessage(getInteger(oracle, lastPriceIndexKey(assetName)), ((("bad oracle data at " + toString(oracle)) + ": no integer at ") + lastPriceIndexKey(assetName)))
125176
126-let queueSize = valueOrElse(getInteger(this, queueSizeKey), 0)
177+let leverage = valueOrElse(getInteger(this, LEVK), 3)
127178
128-let headPointer = valueOrElse(getString(this, headPointerKey), "")
179+func heightByIndex (assetName,priceIndex) = valueOrErrorMessage(getInteger(oracle, (priceIndexPrefix(assetName) + toString(priceIndex))), ("no data at index " + toString(priceIndex)))
129180
130-let tailPointer = valueOrElse(getString(this, tailPointerKey), "")
131181
132-let feesAccumulated = valueOrElse(getInteger(this, feesAccumulatedKey), 0)
182+func priceByHeight (assetName,priceHeight) = valueOrErrorMessage(getInteger(oracle, (priceHeightPrefix(assetName) + toString(priceHeight))), ("no data for height " + toString(priceHeight)))
183+
184+
185+func priceByIndex (assetName,priceIndex) = priceByHeight(assetName, heightByIndex(assetName, priceIndex))
186+
187+
188+let queueSize = valueOrElse(getInteger(this, QSIZEK), 0)
189+
190+let headPointer = valueOrElse(getString(this, HEADK), "")
191+
192+let tailPointer = valueOrElse(getString(this, TAILK), "")
193+
194+let feesAccumulated = valueOrElse(getInteger(this, FEEACCK), 0)
133195
134196 let ISSUE = "ISSUE"
135197
136198 let REDEEM = "REDEEM"
137199
138200 let POOL = "POOL"
139201
140202 let UNPOOL = "UNPOOL"
141203
142204 let feeAddrKey = "feeAddress"
143205
144206 let stakingAddrKey = "stakingAddress"
145207
146208 let daemonPubKeyKey = "daemonPublicKey"
147209
148-let feeAddress = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(configProvider, feeAddrKey), "no feeAddress")), "bad feeAddress")
210+let feeAddress = valueOrErrorMessage(addressFromString(confS(feeAddrKey, "no feeAddress")), "bad feeAddress")
149211
150-let stakingAddress = valueOrErrorMessage(getString(configProvider, stakingAddrKey), "no stakingAddress")
212+let stakingAddress = confS(stakingAddrKey, "no stakingAddress")
151213
152-let daemonPublicKey = fromBase58String(valueOrErrorMessage(getString(configProvider, daemonPubKeyKey), "no daemonPublicKey"))
214+let daemonPublicKey = fromBase58String(confS(daemonPubKeyKey, "no daemonPublicKey"))
153215
154216 let rpdAddress = addressFromString("3PNikM6yp4NqcSU8guxQtmR5onr2D4e8yTJ")
155217
156-let pubKeyAdminsList = ["2HHqV8W9DJayV5R6tBD2Sb8srphpoboDi7r1t1aPiumC", "5ZXe82RRASU7qshXM2J9JNYhqJ9GWYjjVq2gwUV5Naz9", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"]
218+let admins = ["2HHqV8W9DJayV5R6tBD2Sb8srphpoboDi7r1t1aPiumC", "5ZXe82RRASU7qshXM2J9JNYhqJ9GWYjjVq2gwUV5Naz9", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"]
157219
158-func safeFraction (a,b,c) = if (if ((a == 0))
159- then true
160- else (b == 0))
161- then 0
162- else fraction(a, b, c)
220+func buildNewItem (action,amt,token,priceIndex,invoker,minPayout,maxPayout) = (((((((((((((action + "|") + toString(amt)) + "|") + token) + "|") + toString(priceIndex)) + "|") + invoker) + "|") + toString(minPayout)) + "|") + toString(maxPayout)) + "|")
163221
164222
165-func buildNewItem (action,amt,token,priceIndex,invoker) = (((((((((action + "|") + toString(amt)) + "|") + token) + "|") + toString(priceIndex)) + "|") + invoker) + "|")
223+func userDiffAbs () = {
224+ let $t057975886 = $Tuple2((bullCol - poolBullExposure), (bearCol - poolBearExposure))
225+ let userBullCol = $t057975886._1
226+ let userBearCol = $t057975886._2
227+ let diff = (userBullCol - userBearCol)
228+ if ((diff > 0))
229+ then diff
230+ else (0 - diff)
231+ }
166232
167233
168234 func maxIssue (tokenId) = {
169235 let poolInvestment = if ((poolUp > 0))
170236 then BULL
171237 else BEAR
172238 if ((tokenId != poolInvestment))
173239 then poolMain
174- else {
175- let $t053745463 = $Tuple2((bullCol - poolBullExposure), (bearCol - poolBearExposure))
176- let userBullCol = $t053745463._1
177- let userBearCol = $t053745463._2
178- let diff = (userBullCol - userBearCol)
179- let diffAbs = if ((diff > 0))
180- then diff
181- else (0 - diff)
182- (diffAbs + poolValue)
183- }
240+ else (userDiffAbs() + poolValue)
184241 }
242+
243+
244+func validatePMFee (i,minPayout) = if ((0 > minPayout))
245+ then throw("negative min payout")
246+ else {
247+ let p = i.payments[1]
248+ let ok = match p.assetId {
249+ case bv: ByteVector =>
250+ if ((toBase58String(bv) == mainToken))
251+ then (p.amount >= minUsdnFee)
252+ else false
253+ case waves: Unit =>
254+ (p.amount >= minWavesFee)
255+ case _ =>
256+ throw("Match error")
257+ }
258+ if (!(ok))
259+ then throw("incorrect pacemaker fee")
260+ else true
261+ }
185262
186263
187264 func validateRequestRedeem (inv) = if ((inv.caller == this))
188265 then throw("can't do")
189266 else {
190- func errorMessage (got) = throw(((((("only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are accepted, received: ") + got))
267+ func errorMessage (got) = throw(((((("bad token att: only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are accepted, received: ") + got))
191268
192- let assetId = toBase58String(valueOrErrorMessage(value(inv.payments[0]).assetId, "waves are not accepted here"))
269+ let assetId = toBase58String(valueOrErrorMessage(value(inv.payments[0]).assetId, "bad token att"))
193270 if (if ((assetId != BEAR))
194271 then (assetId != BULL)
195272 else false)
196273 then errorMessage(assetId)
197274 else {
198275 let attachedAmount = inv.payments[0].amount
199276 let col = if ((assetId == BEAR))
200277 then bearCol
201278 else bullCol
202279 let circ = if ((assetId == BEAR))
203280 then bearCirc
204281 else bullCirc
205282 let estimated = fraction(col, attachedAmount, circ)
206283 if ((minRedeem > estimated))
207284 then throw((((((((((("Attached payment too small. Min redeem amount is " + toString((minRedeem / 1000000))) + " USDN, ") + "attached amount: ") + toString(attachedAmount)) + ", col: ") + toString(col)) + ", circ: ") + toString(circ)) + ", estimated: ") + toString(estimated)))
208285 else unit
209286 }
210287 }
211288
212289
213-func enqueue (id,action,amt,token,priceIndex,invoker) = {
214- let increaseQueueSize = IntegerEntry(queueSizeKey, (queueSize + 1))
215- let itm = buildNewItem(action, amt, token, priceIndex, invoker)
290+func enqueue (id,action,amt,token,priceIndex,invoker,minPayout,maxPayout) = {
291+ let increaseQueueSize = IE(QSIZEK, (queueSize + 1))
292+ let itm = buildNewItem(action, amt, token, priceIndex, invoker, minPayout, maxPayout)
216293 if ((queueSize == 0))
217- then [StringEntry(headPointerKey, id), StringEntry(tailPointerKey, id), StringEntry(id, itm), increaseQueueSize]
294+ then [SE(HEADK, id), SE(TAILK, id), SE(id, itm), increaseQueueSize]
218295 else {
219- let prevId = valueOrErrorMessage(getString(this, tailPointerKey), "can't get tail pointer")
220- let prevItm = split(valueOrErrorMessage(getString(this, prevId), "can't resolve pointer"), "|")
221- let updatedPrevItm = ((((((((((prevItm[0] + "|") + prevItm[1]) + "|") + prevItm[2]) + "|") + prevItm[3]) + "|") + prevItm[4]) + "|") + id)
222-[StringEntry(prevId, updatedPrevItm), StringEntry(id, itm), StringEntry(tailPointerKey, id), increaseQueueSize]
296+ let prevId = localS(TAILK, "can't get tail pointer")
297+ let prevItm = localS(prevId, "can't resolve pointer")
298+ let updatedPrevItm = (prevItm + id)
299+[SE(prevId, updatedPrevItm), SE(id, itm), SE(TAILK, id), increaseQueueSize]
223300 }
224301 }
225302
226303
227304 func poolSupport (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0,curPoolMain0,curPoolUp0,curPoolDwn0) = {
228- func closeUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
229- let diff = (curBullCol - curBearCol)
230- let exposure = fraction(curBullCol, curPoolUp, curBullCirc)
231- let liquidatedTokens = if ((diff > exposure))
232- then curPoolUp
233- else fraction(diff, curBullCirc, curBullCol)
234- let liquidatedValue = if ((diff > exposure))
235- then exposure
236- else fraction(liquidatedTokens, curBullCol, curBullCirc)
237- $Tuple7((curBullCol - liquidatedValue), curBearCol, (curBullCirc - liquidatedTokens), curBearCirc, (curPoolMain + liquidatedValue), (curPoolUp - liquidatedTokens), curPoolDwn)
305+ func closeUp (c1,c2,a0,a1,c0,pu,pd) = {
306+ let diff = (c1 - c2)
307+ let exp = fraction(c1, pu, a0)
308+ let liquidatedTokens = if ((diff > exp))
309+ then pu
310+ else fraction(diff, a0, c1)
311+ let liquidatedValue = if ((diff > exp))
312+ then exp
313+ else fraction(liquidatedTokens, c1, a0)
314+ $Tuple7((c1 - liquidatedValue), c2, (a0 - liquidatedTokens), a1, (c0 + liquidatedValue), (pu - liquidatedTokens), pd)
238315 }
239316
240- func closeDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
241- let diff = (curBearCol - curBullCol)
242- let exposure = fraction(curBearCol, curPoolDwn, curBearCirc)
243- let liquidatedTokens = if ((diff > exposure))
244- then curPoolDwn
245- else fraction(diff, curBearCirc, curBearCol)
246- let liquidatedValue = if ((diff > exposure))
247- then exposure
248- else fraction(liquidatedTokens, curBearCol, curBearCirc)
249- $Tuple7(curBullCol, (curBearCol - liquidatedValue), curBullCirc, (curBearCirc - liquidatedTokens), (curPoolMain + liquidatedValue), curPoolUp, (curPoolDwn - liquidatedTokens))
317+ func closeDwn (c1,c2,a0,a1,c0,pu,pd) = {
318+ let diff = (c2 - c1)
319+ let exp = fraction(c2, pd, a1)
320+ let liquidatedTokens = if ((diff > exp))
321+ then pd
322+ else fraction(diff, a1, c2)
323+ let liquidatedValue = if ((diff > exp))
324+ then exp
325+ else fraction(liquidatedTokens, c2, a1)
326+ $Tuple7(c1, (c2 - liquidatedValue), a0, (a1 - liquidatedTokens), (c0 + liquidatedValue), pu, (pd - liquidatedTokens))
250327 }
251328
252- func openDwn (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
253- let diff = (curBullCol - curBearCol)
254- let spentPoolValue = if ((curPoolMain > diff))
329+ func openDwn (c1,c2,a0,a1,c0,pu,pd) = {
330+ let diff = (c1 - c2)
331+ let spentPoolValue = if ((c0 > diff))
255332 then diff
256- else curPoolMain
257- let acquiredTokens = fraction(spentPoolValue, curBearCirc, curBearCol)
258- $Tuple7(curBullCol, (curBearCol + spentPoolValue), curBullCirc, (curBearCirc + acquiredTokens), (curPoolMain - spentPoolValue), curPoolUp, (curPoolDwn + acquiredTokens))
333+ else c0
334+ let acquiredTokens = fraction(spentPoolValue, a1, c2)
335+ $Tuple7(c1, (c2 + spentPoolValue), a0, (a1 + acquiredTokens), (c0 - spentPoolValue), pu, (pd + acquiredTokens))
259336 }
260337
261- func openUp (curBullCol,curBearCol,curBullCirc,curBearCirc,curPoolMain,curPoolUp,curPoolDwn) = {
262- let diff = (curBearCol - curBullCol)
263- let spentPoolValue = if ((curPoolMain > diff))
338+ func openUp (c1,c2,a0,a1,c0,pu,pd) = {
339+ let diff = (c2 - c1)
340+ let spentPoolValue = if ((c0 > diff))
264341 then diff
265- else curPoolMain
266- let acquiredTokens = fraction(spentPoolValue, curBullCirc, curBullCol)
267- $Tuple7((curBullCol + spentPoolValue), curBearCol, (curBullCirc + acquiredTokens), curBearCirc, (curPoolMain - spentPoolValue), (curPoolUp + acquiredTokens), curPoolDwn)
342+ else c0
343+ let acquiredTokens = fraction(spentPoolValue, a0, c1)
344+ $Tuple7((c1 + spentPoolValue), c2, (a0 + acquiredTokens), a1, (c0 - spentPoolValue), (pu + acquiredTokens), pd)
268345 }
269346
270- if ((curBullCol0 > curBearCol0))
347+ let $t01025511290 = if ((curBullCol0 > curBearCol0))
271348 then {
272349 let afterCloseUp = closeUp(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0)
273- let $t01047210609 = afterCloseUp
274- let a = $t01047210609._1
275- let b = $t01047210609._2
276- let c = $t01047210609._3
277- let d = $t01047210609._4
278- let e = $t01047210609._5
279- let f = $t01047210609._6
280- let g = $t01047210609._7
350+ let $t01048110618 = afterCloseUp
351+ let a = $t01048110618._1
352+ let b = $t01048110618._2
353+ let c = $t01048110618._3
354+ let d = $t01048110618._4
355+ let e = $t01048110618._5
356+ let f = $t01048110618._6
357+ let g = $t01048110618._7
281358 if ((f > 0))
282359 then afterCloseUp
283360 else if ((f == 0))
284361 then openDwn(a, b, c, d, e, f, g)
285362 else throw("poolUp < 0")
286363 }
287364 else {
288365 let afterCloseDwn = closeDwn(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, curPoolMain0, curPoolUp0, curPoolDwn0)
289- let $t01096011100 = afterCloseDwn
290- let a = $t01096011100._1
291- let b = $t01096011100._2
292- let c = $t01096011100._3
293- let d = $t01096011100._4
294- let e = $t01096011100._5
295- let f = $t01096011100._6
296- let g = $t01096011100._7
366+ let $t01096911109 = afterCloseDwn
367+ let a = $t01096911109._1
368+ let b = $t01096911109._2
369+ let c = $t01096911109._3
370+ let d = $t01096911109._4
371+ let e = $t01096911109._5
372+ let f = $t01096911109._6
373+ let g = $t01096911109._7
297374 if ((g > 0))
298375 then afterCloseDwn
299376 else if ((g == 0))
300377 then openUp(a, b, c, d, e, f, g)
301378 else throw("poolDwn < 0")
302379 }
380+ let c1 = $t01025511290._1
381+ let c2 = $t01025511290._2
382+ let a0 = $t01025511290._3
383+ let a1 = $t01025511290._4
384+ let c0 = $t01025511290._5
385+ let pu = $t01025511290._6
386+ let pd = $t01025511290._7
387+ let charge = fraction(userDiffAbs(), rebalancePercentile, ((1440 * 100) * 100))
388+ let percentileActivated = (height >= valueOrElse(getInteger(configProvider, "percentileActivationHeight"), 10000000))
389+ let c1SplitP = if (if (percentileActivated)
390+ then (pd > 0)
391+ else false)
392+ then charge
393+ else 0
394+ let c2SplitP = if (if (percentileActivated)
395+ then (pu > 0)
396+ else false)
397+ then charge
398+ else 0
399+ $Tuple7((c1 - c1SplitP), (c2 - c2SplitP), a0, a1, ((c0 + c1SplitP) + c2SplitP), pu, pd)
303400 }
304401
305402
306-func actionsWithMaybePool (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0) = {
307- let $t01139711580 = poolSupport(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, poolMain, poolUp, poolDwn)
308- let bullCol1 = $t01139711580._1
309- let bearCol1 = $t01139711580._2
310- let bullCic1 = $t01139711580._3
311- let bearCirc1 = $t01139711580._4
312- let poolMain1 = $t01139711580._5
313- let poolUp1 = $t01139711580._6
314- let poolDwn1 = $t01139711580._7
315-[IntegerEntry(bullCollateralKey, bullCol1), IntegerEntry(bullCirculationKey, bullCic1), IntegerEntry(bearCollateralKey, bearCol1), IntegerEntry(bearCirculationKey, bearCirc1), IntegerEntry(poolMainTokenValueKey, poolMain1), IntegerEntry(poolUpKey, poolUp1), IntegerEntry(poolDwnKey, poolDwn1)]
403+func poolSup (curBullCol0,curBearCol0,curBullCirc0,curBearCirc0) = {
404+ let $t01187112053 = poolSupport(curBullCol0, curBearCol0, curBullCirc0, curBearCirc0, poolMain, poolUp, poolDwn)
405+ let bullCol1 = $t01187112053._1
406+ let bearCol1 = $t01187112053._2
407+ let bullCic1 = $t01187112053._3
408+ let bearCirc1 = $t01187112053._4
409+ let poolMain1 = $t01187112053._5
410+ let poolUp1 = $t01187112053._6
411+ let poolDwn1 = $t01187112053._7
412+[IE(BULLCOLK, bullCol1), IE(BULLCIRCK, bullCic1), IE(BEARCOLK, bearCol1), IE(BEARCIRCK, bearCirc1), IE(POOLUSDNK, poolMain1), IE(POOLUPK, poolUp1), IE(POOLDWNK, poolDwn1)]
316413 }
317414
318415
319-func dequeue () = if ((queueSize == 0))
320- then throw("nothing to settle")
321- else {
322- func collectFee (fees) = IntegerEntry(feesAccumulatedKey, (feesAccumulated + fees))
416+func dequeue () = {
417+ func sp (a,mx) = if ((mx >= a))
418+ then $Tuple2(a, 0)
419+ else $Tuple2(mx, (a - mx))
323420
324- let decreaseQueueSize = IntegerEntry(queueSizeKey, (queueSize - 1))
325- let isLastElement = (headPointer == tailPointer)
326- let overwriteTail = StringEntry(tailPointerKey, "")
327- let data = split(valueOrErrorMessage(getString(this, headPointer), "bad head pointer"), "|")
328- let action = data[0]
329- let amt = parseIntValue(data[1])
330- let token = data[2]
331- let priceIndex = parseIntValue(data[3])
332- let invoker = addressFromStringValue(data[4])
333- let next = data[5]
334- let items = if ((rebalancedPriceIndex > priceIndex))
335- then throw(((("corrupt state, rebalancedPriceIndex=" + toString(rebalancedPriceIndex)) + ", request price id=") + toString(priceIndex)))
336- else if ((priceIndex > rebalancedPriceIndex))
337- then throw("can't dequeue, too early, rebalance first")
338- else if ((action == ISSUE))
339- then {
340- let feeSize = fraction(amt, issuePercentile, 10000)
341- let addedCollateral = (amt - feeSize)
342- if ((token == BULL))
421+ if ((queueSize == 0))
422+ then throw("nothing to settle")
423+ else {
424+ func collectFee (fees) = IE(FEEACCK, (feesAccumulated + fees))
425+
426+ let decreaseQueueSize = IE(QSIZEK, (queueSize - 1))
427+ let isLastElement = (headPointer == tailPointer)
428+ let overwriteTail = SE(TAILK, "")
429+ let dataStr = localS(headPointer, "bad head pointer(dequeue)")
430+ let data = split(dataStr, "|")
431+ let action = data[0]
432+ let amt = parseIntValue(data[1])
433+ let token = data[2]
434+ let priceIndex = parseIntValue(data[3])
435+ let invoker = addressFromStringValue(data[4])
436+ let minPayout = if ((8 > size(data)))
437+ then 0
438+ else parseIntValue(data[5])
439+ let maxPayout = if ((8 > size(data)))
440+ then MAX
441+ else parseIntValue(data[6])
442+ let next = data[(size(data) - 1)]
443+ func payback (tkn) = [SE(HEADK, next), decreaseQueueSize, ST(invoker, amt, fromBase58String(tkn))]
444+
445+ let items = if ((rebalancedPriceIndex > priceIndex))
446+ then throw(((("corrupt state, rebalancedPriceIndex=" + toString(rebalancedPriceIndex)) + ", request price id=") + toString(priceIndex)))
447+ else if ((priceIndex > rebalancedPriceIndex))
448+ then throw("can't dequeue, too early, rebalance first")
449+ else if ((action == ISSUE))
450+ then {
451+ let feeSize = fraction(amt, issuePercentile, 10000)
452+ let addedCollateral = (amt - feeSize)
453+ let a = if ((token == BULL))
454+ then fraction(bullCirc, addedCollateral, bullCol)
455+ else if ((token == BEAR))
456+ then fraction(bearCirc, addedCollateral, bearCol)
457+ else throw("bad token id")
458+ let $t01416714223 = sp(a, maxPayout)
459+ let addedToCirculation = $t01416714223._1
460+ let extraTokens = $t01416714223._2
461+ let $t01424014411 = if ((token == BULL))
462+ then $Tuple4(addedToCirculation, addedCollateral, 0, 0)
463+ else $Tuple4(0, 0, addedToCirculation, addedCollateral)
464+ let plusBulls = $t01424014411._1
465+ let plusBullCol = $t01424014411._2
466+ let plusBears = $t01424014411._3
467+ let plusBearCol = $t01424014411._4
468+ if ((minPayout > addedToCirculation))
469+ then payback(mainToken)
470+ else (poolSup((bullCol + plusBullCol), (bearCol + plusBearCol), (bullCirc + plusBulls), (bearCirc + plusBears)) ++ [SE(HEADK, next), collectFee(feeSize), decreaseQueueSize, ST(invoker, addedToCirculation, fromBase58String(token)), ST(feeAddress, extraTokens, fromBase58String(token))])
471+ }
472+ else if ((action == REDEEM))
343473 then {
344- let addedToCirculation = fraction(bullCirc, addedCollateral, bullCol)
345- (actionsWithMaybePool((bullCol + addedCollateral), bearCol, (bullCirc + addedToCirculation), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BULL))])
474+ let removedTokens = amt
475+ let calcPo = if ((token == BULL))
476+ then fraction(bullCol, removedTokens, bullCirc)
477+ else if ((token == BEAR))
478+ then fraction(bearCol, removedTokens, bearCirc)
479+ else throw("bad token id")
480+ let $t01532615375 = sp(calcPo, maxPayout)
481+ let payoutCapped = $t01532615375._1
482+ let extra = $t01532615375._2
483+ let feeSize = fraction(payoutCapped, redeemPercentile, 10000)
484+ let payout = if ((payoutCapped > feeSize))
485+ then (payoutCapped - feeSize)
486+ else 0
487+ let $t01556115720 = if ((token == BULL))
488+ then $Tuple4(removedTokens, payoutCapped, 0, 0)
489+ else $Tuple4(0, 0, removedTokens, payoutCapped)
490+ let minusBulls = $t01556115720._1
491+ let minusBullCol = $t01556115720._2
492+ let minusBears = $t01556115720._3
493+ let minusBearCol = $t01556115720._4
494+ if ((minPayout > payout))
495+ then payback(token)
496+ else (poolSup((bullCol - minusBullCol), (bearCol - minusBearCol), (bullCirc - minusBulls), (bearCirc - minusBears)) ++ [SE(HEADK, next), collectFee(feeSize), decreaseQueueSize, ST(invoker, payout, fromBase58String(mainToken)), ST(feeAddress, extra, fromBase58String(mainToken))])
346497 }
347- else if ((token == BEAR))
498+ else if ((action == POOL))
348499 then {
349- let addedToCirculation = fraction(bearCirc, addedCollateral, bearCol)
350- (actionsWithMaybePool(bullCol, (bearCol + addedCollateral), bullCirc, (bearCirc + addedToCirculation)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, addedToCirculation, fromBase58String(BEAR))])
500+ let issueTokens = fraction(poolTokenCirculation, amt, poolValue)
501+ if ((minPayout > issueTokens))
502+ then payback(mainToken)
503+ else [IE(POOLUSDNK, (poolMain + amt)), IE(POOLCIRCK, (poolTokenCirculation + issueTokens)), SE(HEADK, next), decreaseQueueSize, ST(invoker, issueTokens, fromBase58String(poolToken))]
351504 }
352- else throw("bad token id")
353- }
354- else if ((action == REDEEM))
355- then {
356- let removedTokens = amt
357- if ((token == BULL))
358- then {
359- let removedCollateral = fraction(bullCol, removedTokens, bullCirc)
360- let feeSize = fraction(removedCollateral, redeemPercentile, 10000)
361- let payout = if ((removedCollateral > feeSize))
362- then (removedCollateral - feeSize)
363- else 0
364- (actionsWithMaybePool((bullCol - removedCollateral), bearCol, (bullCirc - removedTokens), bearCirc) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))])
365- }
366- else if ((token == BEAR))
505+ else if ((action == UNPOOL))
367506 then {
368- let removedCollateral = fraction(bearCol, removedTokens, bearCirc)
369- let feeSize = fraction(removedCollateral, redeemPercentile, 10000)
370- let payout = if ((removedCollateral > feeSize))
371- then (removedCollateral - feeSize)
372- else 0
373- (actionsWithMaybePool(bullCol, (bearCol - removedCollateral), bullCirc, (bearCirc - removedTokens)) ++ [StringEntry(headPointerKey, next), collectFee(feeSize), decreaseQueueSize, ScriptTransfer(invoker, payout, fromBase58String(mainToken))])
507+ func share (a) = fraction(a, amt, poolTokenCirculation)
508+
509+ let unpooledMain = share(poolMain)
510+ let unpooledUp = share(poolUp)
511+ let unpooledDwn = share(poolDwn)
512+ let unpooledUpValue = fraction(unpooledUp, bullCol, bullCirc)
513+ let unpooledDwnValue = fraction(unpooledDwn, bearCol, bearCirc)
514+ let totalUnpooledValue = ((unpooledMain + unpooledUpValue) + unpooledDwnValue)
515+ if ((minPayout > totalUnpooledValue))
516+ then payback(poolToken)
517+ else [IE(POOLUSDNK, (poolMain - unpooledMain)), IE(POOLCIRCK, (poolTokenCirculation - amt)), IE(POOLUPK, (poolUp - unpooledUp)), IE(POOLDWNK, (poolDwn - unpooledDwn)), IE(BULLCIRCK, (bullCirc - unpooledUp)), IE(BEARCIRCK, (bearCirc - unpooledDwn)), IE(BULLCOLK, (bullCol - unpooledUpValue)), IE(BEARCOLK, (bearCol - unpooledDwnValue)), SE(HEADK, next), decreaseQueueSize, ST(invoker, totalUnpooledValue, fromBase58String(mainToken))]
374518 }
375- else throw("bad token id")
376- }
377- else if ((action == POOL))
378- then {
379- let issueTokens = fraction(poolTokenCirculation, amt, poolValue)
380-[IntegerEntry(poolMainTokenValueKey, (poolMain + amt)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation + issueTokens)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, issueTokens, fromBase58String(poolToken))]
381- }
382- else if ((action == UNPOOL))
383- then {
384- func share (a) = fraction(a, amt, poolTokenCirculation)
385-
386- let unpooledMain = share(poolMain)
387- let unpooledUp = share(poolUp)
388- let unpooledDwn = share(poolDwn)
389- let unpooledUpValue = fraction(unpooledUp, bullCol, bullCirc)
390- let unpooledDwnValue = fraction(unpooledDwn, bearCol, bearCirc)
391-[IntegerEntry(poolMainTokenValueKey, (poolMain - unpooledMain)), IntegerEntry(poolTokenCirculationKey, (poolTokenCirculation - amt)), IntegerEntry(poolUpKey, (poolUp - unpooledUp)), IntegerEntry(poolDwnKey, (poolDwn - unpooledDwn)), IntegerEntry(bullCirculationKey, (bullCirc - unpooledUp)), IntegerEntry(bearCirculationKey, (bearCirc - unpooledDwn)), IntegerEntry(bullCollateralKey, (bullCol - unpooledUpValue)), IntegerEntry(bearCollateralKey, (bearCol - unpooledDwnValue)), StringEntry(headPointerKey, next), decreaseQueueSize, ScriptTransfer(invoker, ((unpooledMain + unpooledUpValue) + unpooledDwnValue), fromBase58String(mainToken))]
392- }
393- else throw(("bad action: " + action))
394- if (isLastElement)
395- then overwriteTail :: items
396- else items
397- }
519+ else throw(("bad action: " + action))
520+ if (isLastElement)
521+ then overwriteTail :: items
522+ else items
523+ }
524+ }
398525
399526
400527 func rebalance () = {
401- func LV (v,p0,p1) = {
402- let denom = 100
528+ func LV (v,p0,p1,m) = {
529+ let denom = {
530+ let md = (((2 * (if ((p1 > p0))
531+ then p1
532+ else p0)) * m) / 3037000499)
533+ if ((10 > md))
534+ then 10
535+ else if ((100 > md))
536+ then 100
537+ else 1000
538+ }
403539 let pmax = ((if ((p1 > p0))
404540 then p1
405541 else p0) / denom)
406542 let pmin = ((if ((p0 > p1))
407543 then p1
408544 else p0) / denom)
409545 let a = (pmin * pmin)
410- let b = (((9 * pmax) * pmax) - ((15 * pmax) * pmin))
411- fraction(v, ((6 * a) + b), ((7 * a) + b))
546+ let b = ((((m * m) * pmax) * pmax) - (((((2 * m) * m) - m) * pmax) * pmin))
547+ let ma = ((m * m) - m)
548+ fraction(v, ((ma * a) + b), (((ma + 1) * a) + b))
412549 }
413550
414- let settledPriceIndex = valueOrErrorMessage(getInteger(this, lastRebalancePriceIndexKey), "inconsistent data")
551+ let settledPriceIndex = valueOrErrorMessage(getInteger(this, REBIDXK), "inconsistent data")
415552 let unsettledPriceIndex = (settledPriceIndex + 1)
416- let settledPriceHeight = valueOrErrorMessage(getInteger(oracle, ("price_index_" + toString(settledPriceIndex))), "bad oracle data for settled price height")
417- let settledPrice = valueOrErrorMessage(getInteger(oracle, ("price_" + toString(settledPriceHeight))), "bad oracle data for price")
418- let nextPriceHeight = valueOrErrorMessage(getInteger(oracle, ("price_index_" + toString(unsettledPriceIndex))), "no next price height")
419- let nextPrice = valueOrErrorMessage(getInteger(oracle, ("price_" + toString(nextPriceHeight))), "no next price")
553+ let settledPrice = priceByIndex(assetName, settledPriceIndex)
554+ let nextPrice = priceByIndex(assetName, unsettledPriceIndex)
420555 let minVol = if ((bearCol > bullCol))
421556 then bullCol
422557 else bearCol
423- let redist = LV(minVol, settledPrice, nextPrice)
424- let newBullCol = if ((nextPrice > settledPrice))
558+ let redist = LV(minVol, settledPrice, nextPrice, leverage)
559+ let priceUpGoodForBulls = (assetName == "")
560+ let priceGoesUp = (nextPrice > settledPrice)
561+ let bullsEarn = (priceUpGoodForBulls == priceGoesUp)
562+ let newBullCol = if (bullsEarn)
425563 then (bullCol + redist)
426564 else (bullCol - redist)
427- let newBearCol = if ((nextPrice > settledPrice))
565+ let newBearCol = if (bullsEarn)
428566 then (bearCol - redist)
429567 else (bearCol + redist)
430- let $t01944619633 = poolSupport(newBullCol, newBearCol, bullCirc, bearCirc, poolMain, poolUp, poolDwn)
431- let updBullCol = $t01944619633._1
432- let updBearCol = $t01944619633._2
433- let updBullCirc = $t01944619633._3
434- let updBearCirc = $t01944619633._4
435- let updPoolMain = $t01944619633._5
436- let updPoolUp = $t01944619633._6
437- let updPoolDwn = $t01944619633._7
438-[IntegerEntry(bullCollateralKey, updBullCol), IntegerEntry(bearCollateralKey, updBearCol), IntegerEntry(bullCirculationKey, updBullCirc), IntegerEntry(bearCirculationKey, updBearCirc), IntegerEntry(poolMainTokenValueKey, updPoolMain), IntegerEntry(poolUpKey, updPoolUp), IntegerEntry(poolDwnKey, updPoolDwn), IntegerEntry(lastRebalancePriceIndexKey, unsettledPriceIndex)]
568+ let $t01960819794 = poolSupport(newBullCol, newBearCol, bullCirc, bearCirc, poolMain, poolUp, poolDwn)
569+ let updBullCol = $t01960819794._1
570+ let updBearCol = $t01960819794._2
571+ let updBullCirc = $t01960819794._3
572+ let updBearCirc = $t01960819794._4
573+ let updPoolMain = $t01960819794._5
574+ let updPoolUp = $t01960819794._6
575+ let updPoolDwn = $t01960819794._7
576+[IE(BULLCOLK, updBullCol), IE(BEARCOLK, updBearCol), IE(BULLCIRCK, updBullCirc), IE(BEARCIRCK, updBearCirc), IE(POOLUSDNK, updPoolMain), IE(POOLUPK, updPoolUp), IE(POOLDWNK, updPoolDwn), IE(REBIDXK, unsettledPriceIndex)]
577+ }
578+
579+
580+func calcMax (min,avg) = if ((min > avg))
581+ then throw(((("price too old: minPayout " + toString(min)) + " > avg = ") + toString(avg)))
582+ else ((avg + avg) - min)
583+
584+
585+func requestIssueInternal (inv,tokenId,minPayout) = if (if ((tokenId != BULL))
586+ then (tokenId != BEAR)
587+ else false)
588+ then throw("bad token req")
589+ else if ((inv.caller == this))
590+ then throw("can't do")
591+ else if (!(allowed(inv.caller)))
592+ then throw("only whitelisted can do")
593+ else {
594+ let errorMessage = (((("bad token req, only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") allowed")
595+ if ((inv.payments[0].assetId != fromBase58String(mainToken)))
596+ then throw("bad token att")
597+ else {
598+ let amt = inv.payments[0].amount
599+ let $t02080020978 = if ((tokenId == BULL))
600+ then $Tuple2(bullCol, bullCirc)
601+ else if ((tokenId == BEAR))
602+ then $Tuple2(bearCol, bearCirc)
603+ else throw(errorMessage)
604+ let col = $t02080020978._1
605+ let circ = $t02080020978._2
606+ let est = fraction(amt, circ, col)
607+ let $t02102021114 = if ((minPayout == 0))
608+ then $Tuple2(0, MAX)
609+ else $Tuple2(minPayout, calcMax(minPayout, est))
610+ let minP = $t02102021114._1
611+ let maxP = $t02102021114._2
612+ if ((minIssue > amt))
613+ then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN"))
614+ else {
615+ let maxAllowed = maxIssue(tokenId)
616+ if (if ((whitelist == ""))
617+ then (inv.payments[0].amount > maxAllowed)
618+ else false)
619+ then throw((("trying to issue more than pool can handle. Max attachment allowed = " + toString((maxAllowed / 1000000))) + " USDN"))
620+ else (enqueue(toBase58String(inv.transactionId), ISSUE, amt, tokenId, (oraclePriceIndex + 1), toString(inv.caller), minP, maxP) ++ [debug("requested", tokenId), debug("bull", BULL), debug("bear", BEAR)])
621+ }
622+ }
623+ }
624+
625+
626+func requestRedeemInternal (inv,minPayout) = {
627+ let amt = inv.payments[0].amount
628+ let tokenId = toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "bad token att"))
629+ if (if ((tokenId != BULL))
630+ then (tokenId != BEAR)
631+ else false)
632+ then throw("bad token req")
633+ else {
634+ let $t02215122290 = if ((tokenId == BULL))
635+ then $Tuple2(bullCol, bullCirc)
636+ else if ((tokenId == BEAR))
637+ then $Tuple2(bearCol, bearCirc)
638+ else throw("bad token req")
639+ let col = $t02215122290._1
640+ let circ = $t02215122290._2
641+ let est = fraction(amt, col, circ)
642+ let $t02233822432 = if ((minPayout == 0))
643+ then $Tuple2(0, MAX)
644+ else $Tuple2(minPayout, calcMax(minPayout, est))
645+ let minP = $t02233822432._1
646+ let maxP = $t02233822432._2
647+ if ((validateRequestRedeem(inv) == unit))
648+ then enqueue(toBase58String(inv.transactionId), REDEEM, amt, tokenId, (oraclePriceIndex + 1), toString(inv.caller), minP, maxP)
649+ else throw("doesn't happen")
650+ }
651+ }
652+
653+
654+func requestPoolInternal (inv,minPayout) = if (!(allowed(inv.caller)))
655+ then throw("only whitelisted can do")
656+ else {
657+ let errMessage = (("main token must be attached(" + mainToken) + ")")
658+ let pmt = inv.payments[0]
659+ if ((pmt.assetId != fromBase58String(mainToken)))
660+ then throw(errMessage)
661+ else if ((minPool > pmt.amount))
662+ then throw(((("pool at least " + toString(minPool)) + " ") + mainToken))
663+ else {
664+ let estimate = fraction(poolTokenCirculation, pmt.amount, poolValue)
665+ let $t02328023379 = if ((minPayout == 0))
666+ then $Tuple2(0, MAX)
667+ else $Tuple2(minPayout, calcMax(minPayout, estimate))
668+ let minP = $t02328023379._1
669+ let maxP = $t02328023379._2
670+ enqueue(toBase58String(inv.transactionId), POOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller), minP, maxP)
671+ }
672+ }
673+
674+
675+func requestUnpoolInternal (inv,minPayout) = {
676+ let errMessage = (("only pool token allowed(" + poolToken) + ")")
677+ let pmt = inv.payments[0]
678+ if ((pmt.assetId != fromBase58String(poolToken)))
679+ then throw(errMessage)
680+ else {
681+ let estimate = fraction(poolValue, pmt.amount, poolTokenCirculation)
682+ if ((minPool > estimate))
683+ then throw(((("unpool at least for" + toString(minPool)) + " ") + mainToken))
684+ else {
685+ let $t02403624135 = if ((minPayout == 0))
686+ then $Tuple2(0, MAX)
687+ else $Tuple2(minPayout, calcMax(minPayout, estimate))
688+ let minP = $t02403624135._1
689+ let maxP = $t02403624135._2
690+ enqueue(toBase58String(inv.transactionId), UNPOOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller), minP, maxP)
691+ }
692+ }
439693 }
440694
441695
442696 @Callable(inv)
443-func init (config,oraclePK,nameup,namedwn,descUp,descDwn,poolName,poolDesc,denom) = if (isDefined(getString(this, BULLKey)))
697+func init (config,oraclePK,nameup,namedwn,descUp,descDwn,poolName,poolDesc,defoAssetName,denom,lev) = if (isDefined(getString(this, BULLK)))
444698 then throw("already initialized")
445699 else {
446700 let totalOwnedMainToken = inv.payments[0].amount
447701 let bulls = (totalOwnedMainToken / 3)
448702 let bears = bulls
449703 let pools = ((totalOwnedMainToken - bulls) - bears)
450704 if (if (if ((bears == 0))
451705 then true
452706 else (bulls == 0))
453707 then true
454708 else (pools == 0))
455709 then throw("can't init balances")
456710 else {
457- let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey), "can't find last oracle price index")
711+ let oracleCurrentPriceIndex = valueOrErrorMessage(getInteger(valueOrErrorMessage(addressFromPublicKey(fromBase58String(oraclePK)), "bad oracle address"), lastPriceIndexKey(defoAssetName)), "can't find last oracle price index")
458712 let bull = Issue(nameup, descUp, ((100 * ten6) * ten6), 6, true)
459713 let bear = Issue(namedwn, descDwn, ((100 * ten6) * ten6), 6, true)
460714 let pool = Issue(poolName, poolDesc, ((100 * ten6) * ten6), 6, true)
461715 let buid = calculateAssetId(bull)
462716 let beid = calculateAssetId(bear)
463717 let poid = calculateAssetId(pool)
464-[bull, bear, pool, StringEntry(BULLKey, toBase58String(buid)), StringEntry(BEARKey, toBase58String(beid)), StringEntry(mainTokenKey, toBase58String(value(inv.payments[0].assetId))), StringEntry(poolTokenKey, toBase58String(poid)), StringEntry(oraclePKKey, oraclePK), IntegerEntry(lastRebalancePriceIndexKey, oracleCurrentPriceIndex), IntegerEntry(bullCollateralKey, bulls), IntegerEntry(bearCollateralKey, bears), IntegerEntry(bullCirculationKey, (bulls / denom)), IntegerEntry(bearCirculationKey, (bears / denom)), IntegerEntry(poolTokenCirculationKey, (pools / denom)), IntegerEntry(poolDwnKey, 0), IntegerEntry(poolUpKey, 0), IntegerEntry(poolMainTokenValueKey, pools), StringEntry(configProviderKey, config), ScriptTransfer(inv.caller, (bulls / denom), buid), ScriptTransfer(inv.caller, (bears / denom), beid), ScriptTransfer(inv.caller, (pools / denom), poid)]
718+[bull, bear, pool, SE(BULLK, toBase58String(buid)), SE(BEARK, toBase58String(beid)), SE(USDNK, toBase58String(value(inv.payments[0].assetId))), SE(POOLK, toBase58String(poid)), SE(ASSNAMEK, defoAssetName), SE(oraclePKKey, oraclePK), IE(REBIDXK, oracleCurrentPriceIndex), IE(BULLCOLK, bulls), IE(BEARCOLK, bears), IE(BULLCIRCK, (bulls / denom)), IE(BEARCIRCK, (bears / denom)), IE(POOLCIRCK, (pools / denom)), IE(POOLDWNK, 0), IE(POOLUPK, 0), IE(POOLUSDNK, pools), SE(configProviderKey, config), IE(LEVK, lev), ST(inv.caller, (bulls / denom), buid), ST(inv.caller, (bears / denom), beid), ST(inv.caller, (pools / denom), poid)]
465719 }
466720 }
467721
468722
469723
470724 @Callable(i)
471725 func withdrawFee (amount) = if ((amount > feesAccumulated))
472726 then throw(("too much. available: " + toString(feesAccumulated)))
473- else [IntegerEntry(feesAccumulatedKey, (feesAccumulated - amount)), ScriptTransfer(feeAddress, amount, fromBase58String(mainToken))]
727+ else [IE(FEEACCK, (feesAccumulated - amount)), ST(feeAddress, amount, fromBase58String(mainToken))]
474728
475729
476730
477731 @Callable(inv)
478-func requestRedeem () = if ((validateRequestRedeem(inv) == unit))
479- then {
480- let assetId = toBase58String(valueOrErrorMessage(inv.payments[0].assetId, "waves are not accepted here"))
481- enqueue(toBase58String(inv.transactionId), REDEEM, inv.payments[0].amount, assetId, (oraclePriceIndex + 1), toString(inv.caller))
482- }
483- else throw("doesn't happen")
732+func requestRedeem () = requestRedeemInternal(inv, 0)
484733
485734
486735
487736 @Callable(inv)
488-func requestIssue (tokenId) = if ((inv.caller == this))
489- then throw("can't do")
490- else if (!(allowed(inv.caller)))
491- then throw("only whitelisted can do")
492- else {
493- let errorMessage = throw((((((("only BULL(" + BULL) + ") or BEAR(") + BEAR) + ") tokens are available in exchange for USDN(") + mainToken) + ")"))
494- if (if ((tokenId != BULL))
495- then (tokenId != BEAR)
496- else false)
497- then errorMessage
498- else if ((inv.payments[0].assetId != fromBase58String(mainToken)))
499- then errorMessage
500- else if ((minIssue > inv.payments[0].amount))
501- then throw((("Attached payment too small. Min required: " + toString((minIssue / 1000000))) + " USDN"))
502- else {
503- let maxAllowed = maxIssue(tokenId)
504- if (if ((whitelist == ""))
505- then (inv.payments[0].amount > maxAllowed)
506- else false)
507- then throw((("trying to issue more than pool can handle. Max attachment allowed = " + toString((maxAllowed / 1000000))) + " USDN"))
508- else enqueue(toBase58String(inv.transactionId), ISSUE, inv.payments[0].amount, tokenId, (oraclePriceIndex + 1), toString(inv.caller))
509- }
510- }
737+func requestRedeemSl (sl) = if (validatePMFee(inv, sl))
738+ then requestRedeemInternal(inv, sl)
739+ else throw()
740+
741+
742+
743+@Callable(inv)
744+func requestIssue (tokenId) = requestIssueInternal(inv, tokenId, 0)
745+
746+
747+
748+@Callable(inv)
749+func requestIssueSl (tokenId,sl) = if (validatePMFee(inv, sl))
750+ then requestIssueInternal(inv, tokenId, sl)
751+ else throw()
752+
753+
754+
755+@Callable(inv)
756+func requestPool () = requestPoolInternal(inv, 0)
757+
758+
759+
760+@Callable(inv)
761+func requestPoolSl (sl) = if (validatePMFee(inv, sl))
762+ then requestPoolInternal(inv, sl)
763+ else throw()
764+
765+
766+
767+@Callable(inv)
768+func requestUnpool () = requestUnpoolInternal(inv, 0)
769+
770+
771+
772+@Callable(inv)
773+func requestUnpoolSl (sl) = if (validatePMFee(inv, sl))
774+ then requestUnpoolInternal(inv, sl)
775+ else throw()
511776
512777
513778
514779 @Callable(inv)
515780 func settle () = {
516781 let queueEmpty = (headPointer == "")
517782 let canRebalance = (oraclePriceIndex > rebalancedPriceIndex)
518783 if (queueEmpty)
519784 then if (canRebalance)
520785 then rebalance()
521786 else throw("[OK] all done, carry on")
522787 else {
523- let data = split(valueOrErrorMessage(getString(this, headPointer), "bad head pointer"), "|")
788+ let data = split(valueOrErrorMessage(getString(this, headPointer), ("bad head pointer(settle): " + headPointer)), "|")
524789 let priceIndex = parseIntValue(data[3])
525790 if ((priceIndex > rebalancedPriceIndex))
526791 then if (canRebalance)
527792 then rebalance()
528793 else throw("[OK] need to wait")
529794 else if ((priceIndex == rebalancedPriceIndex))
530795 then dequeue()
531- else throw("corrupt data, future price id already rebalanced")
532- }
533- }
534-
535-
536-
537-@Callable(inv)
538-func requestPool () = if (!(allowed(inv.caller)))
539- then throw("only whitelisted can do")
540- else {
541- let errMessage = (("main token must be attached(" + mainToken) + ")")
542- let pmt = inv.payments[0]
543- if ((pmt.assetId != fromBase58String(mainToken)))
544- then throw(errMessage)
545- else if ((minPool > pmt.amount))
546- then throw(((("pool at least " + toString(minPool)) + " ") + mainToken))
547- else enqueue(toBase58String(inv.transactionId), POOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller))
548- }
549-
550-
551-
552-@Callable(inv)
553-func requestUnpool () = {
554- let errMessage = (("only pool token allowed(" + poolToken) + ")")
555- let pmt = inv.payments[0]
556- if ((pmt.assetId != fromBase58String(poolToken)))
557- then throw(errMessage)
558- else {
559- let estimate = fraction(poolValue, pmt.amount, poolTokenCirculation)
560- if ((minPool > estimate))
561- then throw(((("unpool at least for" + toString(minPool)) + " ") + mainToken))
562- else enqueue(toBase58String(inv.transactionId), UNPOOL, inv.payments[0].amount, "", (oraclePriceIndex + 1), toString(inv.caller))
796+ else throw("future price already rebalanced")
563797 }
564798 }
565799
566800
567801 @Verifier(tx)
568802 func verify () = {
569- let initial = if (!(isDefined(getString(this, BULLKey))))
803+ let initial = if (!(isDefined(getString(this, BULLK))))
570804 then sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
571805 else false
572- let adminAction = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
806+ let adminAction = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(admins[0])))
573807 then 1
574- else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
808+ else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(admins[1])))
575809 then 1
576- else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
810+ else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(admins[2])))
577811 then 1
578812 else 0)) > 1)
579813 let stakingAction = match tx {
580814 case tx: InvokeScriptTransaction =>
581815 let signedCorrectly = sigVerify(tx.bodyBytes, tx.proofs[0], daemonPublicKey)
582816 let feesCorrect = if ((tx.feeAssetId == unit))
583817 then ((1000 * 1000) >= tx.fee)
584818 else false
585819 let dappCorrect = (tx.dApp == rpdAddress)
586820 let unlock = (tx.function == "unlockNeutrino")
587821 let lock = if (if ((tx.function == "lockNeutrinoSP"))
588822 then (tx.args[0] == stakingAddress)
589823 else false)
590824 then (wavesBalance(this).available >= ten8)
591825 else false
592826 let funcCorrect = if (lock)
593827 then true
594828 else unlock
595829 if (if (if (signedCorrectly)
596830 then feesCorrect
597831 else false)
598832 then dappCorrect
599833 else false)
600834 then funcCorrect
601835 else false
602836 case _ =>
603837 false
604838 }
605839 if (if (initial)
606840 then true
607841 else adminAction)
608842 then true
609843 else stakingAction
610844 }
611845

github/deemru/w8io/786bc32 
368.59 ms