2021.09.17 13:37 [2771855] smart account 3PPtpEVDy6suxgBQTPMwaVosinkhoVL7QUn > SELF 0.00000000 Waves

{ "type": 13, "id": "6GvUBUxLDnkSQzsBTJySp81fkwnwt1CUFFSjwBQTXX5B", "fee": 1400000, "feeAssetId": null, "timestamp": 1631875018803, "version": 2, "chainId": 87, "sender": "3PPtpEVDy6suxgBQTPMwaVosinkhoVL7QUn", "senderPublicKey": "UyE7XjLQbZAuf3NtHZKDgn2H3ek8rCCpfuEVY2z3DmR", "proofs": [ "", "2MxBUc1Xvdwy9yaKdUh3RZD35rkbgcvUCSk9YGRS8UmQiiV2KwZ4LdjFUiYEM8419YhqEud3yJnZmNtzR2Yukey8", "5Dy5RDv33VYuKrKFsTh1cAG6217iLaQaT4jx1fEq6Hjt2JzTHo5XBbzCRz7gWLz7nw5P7HZWwjAQcS3NsET6ijgF" ], "script": "base64:AAIFAAAAAAAADosIAhIDCgEEEgcKBQEBCAgEEgMKAQESAwoBARIAEgMKAQESABIAEgMKAQEaDQoCYTESB3ZlcnNpb24aEAoCYTISCmtleVZlcnNpb24aDwoCYTMSCWtleUFjdGl2ZRoRCgJhNBILa2V5QXNzZXRJZEEaEQoCYTUSC2tleUFzc2V0SWRCGhEKAmE2EgtrZXlCYWxhbmNlQRoRCgJhNxILa2V5QmFsYW5jZUIaFQoCYTgSD2tleUJhbGFuY2VJbml0QRoVCgJhORIPa2V5QmFsYW5jZUluaXRCGhUKAmIxEg9rZXlTaGFyZUFzc2V0SWQaGQoCYjISE2tleVNoYXJlQXNzZXRTdXBwbHkaEwoCYjMSDWtleUNvbW1pc3Npb24aIQoCYjQSG2tleUNvbW1pc3Npb25TY2FsZURlbGltaXRlchoOCgJiNRIIa2V5Q2F1c2UaFQoCYjYSD2tleUZpcnN0SGFydmVzdBobCgJiNxIVa2V5Rmlyc3RIYXJ2ZXN0SGVpZ2h0GhEKAmI4EgtrU2hhcmVMaW1pdBoRCgJiORILa0Jhc2VQZXJpb2QaEwoCYzESDWtQZXJpb2RMZW5ndGgaEgoCYzISDGtTdGFydEhlaWdodBoZCgJjMxITa0ZpcnN0SGFydmVzdEhlaWdodBoVCgJjNBIPa2V5QWRtaW5QdWJLZXkxGhUKAmM1Eg9rZXlBZG1pblB1YktleTIaFQoCYzYSD2tleUFkbWluUHViS2V5MxoMCgJjNxIGb3JhY2xlGhEKAmM4EgtnZXRBZG1pblB1YhoRCgJjORILa2V5QWRtaW5QdWIaDQoCZDESByRtYXRjaDAaDAoCZDISBnN0cmluZxoNCgJkMxIHbm90aGluZxoSCgJkNBIMYWRtaW5QdWJLZXkxGhIKAmQ1EgxhZG1pblB1YktleTIaEgoCZDYSDGFkbWluUHViS2V5MxoaCgJkNxIUYWRtaW5QdWJLZXlTdGFydFN0b3AaGAoCZDgSEmFkbWluUHViS2V5U3Rha2luZxoTCgJkORINd2FsbGV0QWRkcmVzcxoTCgJlMRINdm90aW5nQWRkcmVzcxoKCgJlMhIEVVNEThoKCgJlMxIETlNCVBoKCgJlNBIEU1dPUBoKCgJlNRIERVVSThocCgJlNhIWc3Rha2luZ1VTRE5OU0JUQWRkcmVzcxoYCgJlNxISc3Rha2luZ0VVUk5BZGRyZXNzGhoKAmU4EhRVU0ROVG9XYXZlc0V4Y2hhbmdlchoZCgJlORITVVNETlRvTlNCVEV4Y2hhbmdlchoWCgJmMRIQc3Rha2luZ0ZlZUluVVNEThoWCgJmMhIQc3Rha2luZ0ZlZUluRVVSThoQCgJmMxIKYmFzZVBlcmlvZBoRCgJmNBILc3RhcnRIZWlnaHQaEgoCZjUSDHBlcmlvZExlbmd0aBobCgJmNhIVZmlyc3RIYXJ2ZXN0RW5kUGVyaW9kGg4KAmY3Eghpc0FjdGl2ZRoRCgJmOBILc3RyQXNzZXRJZEEaEQoCZjkSC3N0ckFzc2V0SWRCGg4KAmcxEghhc3NldElkQRoOCgJnMhIIYXNzZXRJZEIaEAoCZzMSCmFzc2V0TmFtZUEaCAoCZzQSAmlkGgsKAmc1EgV3YXZlcxoQCgJnNhIKYXNzZXROYW1lQhoOCgJnNxIIYmFsYW5jZUEaDgoCZzgSCGJhbGFuY2VCGhIKAmc5EgxzaGFyZUFzc2V0SWQaFgoCaDESEHNoYXJlQXNzZXRTdXBwbHkaEAoCaDISCmNvbW1pc3Npb24aGgoCaDMSFGNvbW1pc3Npb25Hb3Zlcm5hbmNlGh4KAmg0Ehhjb21taXNzaW9uU2NhbGVEZWxpbWl0ZXIaEQoCaDUSC3NjYWxlVmFsdWUzGhEKAmg2EgtzY2FsZVZhbHVlOBogCgJoNxIac2xpcHBhZ2VUb2xlcmFuY2VEZWxpbWl0ZXIaFwoCaDgSEXNjYWxlVmFsdWU4RGlnaXRzGhQKAmg5Eg5hY2NvdW50QmFsYW5jZRoNCgJpMRIHYXNzZXRJZBoSCgJpMhIMc3Rha2VkQW1vdW50GhwKAmkzEhZzdGFrZWRBbW91bnRDYWxjdWxhdGVkGgkKAmk0EgNhSWQaBwoCaTUSAWkaEwoCaTYSDXN0YWtlZEFtb3VudEEaEwoCaTcSDXN0YWtlZEFtb3VudEIaEAoCaTgSCmFzc2V0SW5pdEEaEAoCaTkSCmFzc2V0SW5pdEIaFwoCajESEWF2YWlsYWJsZUJhbGFuY2VBGhcKAmoyEhFhdmFpbGFibGVCYWxhbmNlQhofCgJqMxIZYWNjb3VudEJhbGFuY2VXaXRoU3Rha2VkQRofCgJqNBIZYWNjb3VudEJhbGFuY2VXaXRoU3Rha2VkQhoWCgJqNRIQaGFzRW5vdWdoQmFsYW5jZRoSCgJqNhIMZ2V0QXNzZXRJbmZvGg4KAmo3EghzdHJpbmdJZBoKCgJqOBIEaW5mbxocCgJqORIWZ2V0QXNzZXRJbmZvRnJvbVN0cmluZxoOCgJrMRIIYXNzZXRTdHIaDQoCazISB3N1c3BlbmQaCwoCazMSBWNhdXNlGhYKAms0EhBkZWR1Y3RTdGFraW5nRmVlGgwKAms1EgZhbW91bnQaEwoCazYSDXNlY29uZEFzc2V0SWQaDwoCazcSCXN0YWtpbkZlZRoMCgJrOBIGcmVzdWx0GhMKAms5Eg1nZXRTdGFraW5nRmVlGicKAmwxEiF0aHJvd0luc3VmZmljaWVudEF2YWlsYWJsZUJhbGFuY2UaDwoCbDISCWF2YWlsYWJsZRoPCgJsMxIJYXNzZXROYW1lGigKAmw0EiJ0aHJvd0luc3VmZmljaWVudEF2YWlsYWJsZUJhbGFuY2VzGg0KAmw1EgdhbW91bnRBGg0KAmw2EgdhbW91bnRCGhcKAmw3EhFzdXNwZW5kU3VzcGljaW91cxoSCgJsOBIMZmlyc3RIYXJ2ZXN0GhEKAmw5EgskdDA4MDAwODA3NxoQCgJtMRIKcG10QW1vdW50QRoRCgJtMhILcG10QXNzZXRJZEEaEQoCbTMSCyR0MDgwODI4MTU5GhAKAm00EgpwbXRBbW91bnRCGhEKAm01EgtwbXRBc3NldElkQhoRCgJtNhILJHQwODE2NDgyNDEaFAoCbTcSDnBtdFN0ckFzc2V0SWRBGhMKAm04Eg1wbXRBc3NldE5hbWVBGhIKAm05EgxwbXREZWNpbWFsc0EaEQoCbjESCyR0MDgyNDY4MzIzGhQKAm4yEg5wbXRTdHJBc3NldElkQhoTCgJuMxINcG10QXNzZXROYW1lQhoSCgJuNBIMcG10RGVjaW1hbHNCGg8KAm41EglzaGFyZU5hbWUaFgoCbjYSEHNoYXJlRGVzY3JpcHRpb24aEwoCbjcSDXNoYXJlRGVjaW1hbHMaCgoCbjgSBGFyZzEaCgoCbjkSBGFyZzIaCgoCbzESBGFyZzMaGAoCbzISEnNoYXJlSW5pdGlhbFN1cHBseRoQCgJvMxIKc2hhcmVJc3N1ZRoSCgJvNBIMc2hhcmVJc3N1ZUlkGg8KAm81EgliYXNlRW50cnkaDwoCbzYSCWFtdEFzc2V0QRoPCgJvNxIJYW10QXNzZXRCGhMKAm84Eg0kdDAxMDU2ODEwNjU1GhMKAm85Eg0kdDAxMDY2MDEwNzQ3GhAKAnAxEgpzaGFyZUxpbWl0GhcKAnAyEhFzbGlwcGFnZVRvbGVyYW5jZRoTCgJwMxINJHQwMTM0NTgxMzUzNRoTCgJwNBINJHQwMTM1NDQxMzYyMRoQCgJwNRIKdG9rZW5SYXRpbxoZCgJwNhITcmF0aW9TaGFyZVRva2Vuc0luQRoZCgJwNxITcmF0aW9TaGFyZVRva2Vuc0luQhobCgJwOBIVc2hhcmVUb2tlblRvUGF5QW1vdW50GhMKAnA5Eg0kdDAxODAyMDE4MTcwGg8KAnExEglwbXRBbW91bnQaEAoCcTISCnBtdEFzc2V0SWQaEgoCcTMSDGFtb3VudFRvUGF5QRoSCgJxNBIMYW1vdW50VG9QYXlCGhgKAnE1EhJtaW5BbW91bnRUb1JlY2VpdmUaEwoCcTYSDSR0MDE5Mzk2MTk0NzEaEwoCcTcSDWNhbGN1bGF0ZUZlZXMaDwoCcTgSCXRva2VuRnJvbRoNCgJxORIHdG9rZW5UbxoWCgJyMRIQYW1vdW50V2l0aG91dEZlZRoTCgJyMhINYW1vdW50V2l0aEZlZRoWCgJyMxIQZ292ZXJuYW5jZVJld2FyZBoRCgJyNBILYXNzZXRJZFNlbmQaEwoCcjUSDSR0MDIwNzQ1MjA4MzYaEQoCcjYSC25ld0JhbGFuY2VBGhEKAnI3EgtuZXdCYWxhbmNlQhoTCgJyOBINJHQwMjE2NTUyMTc0NhoRCgJyORILYW1vdW50TGVhdmUaIwoCczESHXVuY291bnRhYmxlQW1vdW50RW5yb2xsQXNzZXRBGiMKAnMyEh11bmNvdW50YWJsZUFtb3VudEVucm9sbEFzc2V0QhoTCgJzMxINYW1vdW50RW5yb2xsQRoTCgJzNBINYW1vdW50RW5yb2xsQhoICgJzNRICdHgaDAoCczYSBnZlcmlmeRoZCgJzNxITbXVsdGlTaWduZWRCeUFkbWlucxoYCgJzOBISYWRtaW5QdWJLZXkxU2lnbmVkGhgKAnM5EhJhZG1pblB1YktleTJTaWduZWQaGAoCdDESEmFkbWluUHVi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", "height": 2771855, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 5qGz8i7CSmDmgiaFU1VJojNmeUXnqBtk6Xjp6Rmi5MYV Next: DFFmZE3LXYQDh7UQfSXaX4DFJ4Fh3jZUPJSD28J5cR7v Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 5 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let version = "2.0.0"
4+let version = "1.0.0"
55
6-let kVersion = "version"
6+let keyVersion = "version"
77
8-let kActive = "active"
8+let keyActive = "active"
99
10-let kAssetIdA = "A_asset_id"
10+let keyAssetIdA = "A_asset_id"
1111
12-let kAssetIdB = "B_asset_id"
12+let keyAssetIdB = "B_asset_id"
1313
14-let kBalanceA = "A_asset_balance"
14+let keyBalanceA = "A_asset_balance"
1515
16-let kBalanceB = "B_asset_balance"
16+let keyBalanceB = "B_asset_balance"
1717
18-let kShareAssetId = "share_asset_id"
18+let keyBalanceInitA = "A_asset_init"
1919
20-let kShareAssetSupply = "share_asset_supply"
20+let keyBalanceInitB = "B_asset_init"
2121
22-let kFee = "commission"
22+let keyShareAssetId = "share_asset_id"
2323
24-let kFeeScaleDelimiter = "commission_scale_delimiter"
24+let keyShareAssetSupply = "share_asset_supply"
2525
26-let kInvariant = "invariant"
26+let keyCommission = "commission"
2727
28-let kFirstHarvest = "first_harvest"
28+let keyCommissionScaleDelimiter = "commission_scale_delimiter"
2929
30-let kFirstHarvestHeight = "first_harvest_height"
30+let keyCause = "shutdown_cause"
31+
32+let keyFirstHarvest = "first_harvest"
33+
34+let keyFirstHarvestHeight = "first_harvest_height"
3135
3236 let kShareLimit = "share_limit_on_first_harvest"
3337
3741
3842 let kStartHeight = "start_height"
3943
40-let kCause = "shutdown_cause"
44+let kFirstHarvestHeight = "first_harvest_height"
4145
4246 let keyAdminPubKey1 = "admin_pub_1"
4347
4448 let keyAdminPubKey2 = "admin_pub_2"
4549
4650 let keyAdminPubKey3 = "admin_pub_3"
47-
48-let USDNToWavesExchanger = Address(base58'3PHaNgomBkrvEL2QnuJarQVJa71wjw9qiqG')
4951
5052 let oracle = Address(base58'3PEbqViERCoKnmcSULh6n2aiMvUdSQdCsom')
5153
6365
6466 let adminPubKey3 = getAdminPub(keyAdminPubKey3)
6567
66-let admStartStop = base58'EtVkT6ed8GtbUiVVEqdmEqsp2J4qbb3rre2HFgxeVYdg'
68+let adminPubKeyStartStop = base58'EtVkT6ed8GtbUiVVEqdmEqsp2J4qbb3rre2HFgxeVYdg'
6769
68-let admStaking = base58'Czn4yoAuUZCVCLJDRfskn8URfkwpknwBTZDbs1wFrY7h'
70+let adminPubKeyStaking = base58'Czn4yoAuUZCVCLJDRfskn8URfkwpknwBTZDbs1wFrY7h'
6971
70-let govAddr = Address(base58'3P6J84oH51DzY6xk2mT5TheXRbrCwBMxonp')
71-
72-let stakingAddress = Address(base58'3PNikM6yp4NqcSU8guxQtmR5onr2D4e8yTJ')
72+let walletAddress = Address(base58'3P6J84oH51DzY6xk2mT5TheXRbrCwBMxonp')
7373
7474 let votingAddress = Address(base58'3PQZWxShKGRgBN1qoJw6B4s9YWS9FneZTPg')
7575
7676 let USDN = base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
7777
78+let NSBT = base58'6nSpVyNH7yM69eg446wrQR94ipbbcmZMU1ENPwanC97g'
79+
80+let SWOP = base58'Ehie5xYpeN8op1Cctc6aGUrqx8jq3jtf1DSjXDbfm7aT'
81+
82+let EURN = base58'DUk2YTxhRoAqMJLus4G2b3fR8hMHVh6eiyFx5r29VR6t'
83+
84+let stakingUSDNNSBTAddress = Address(base58'3PNikM6yp4NqcSU8guxQtmR5onr2D4e8yTJ')
85+
86+let stakingEURNAddress = Address(base58'3PFhcMmEZoQTQ6ohA844c7C9M8ZJ18P8dDj')
87+
88+let USDNToWavesExchanger = Address(base58'3PHaNgomBkrvEL2QnuJarQVJa71wjw9qiqG')
89+
90+let USDNToNSBTExchanger = Address(base58'3P2V63Xd6BviDkeMzxhUw2SJyojByRz8a8m')
91+
7892 let stakingFeeInUSDN = 270000
93+
94+let stakingFeeInEURN = 234000
7995
8096 let basePeriod = valueOrErrorMessage(getInteger(votingAddress, kBasePeriod), "Empty kBasePeriod")
8197
85101
86102 let firstHarvestEndPeriod = ((basePeriod + ((height - startHeight) / periodLength)) + 3)
87103
88-let isActive = getBooleanValue(this, kActive)
104+let isActive = getBooleanValue(this, keyActive)
89105
90-let strAssetIdA = getStringValue(this, kAssetIdA)
106+let strAssetIdA = getStringValue(this, keyAssetIdA)
91107
92-let strAssetIdB = getStringValue(this, kAssetIdB)
108+let strAssetIdB = getStringValue(this, keyAssetIdB)
93109
94110 let assetIdA = if ((strAssetIdA == "WAVES"))
95111 then unit
117133 throw("Match error")
118134 }
119135
120-let balanceA = getIntegerValue(this, kBalanceA)
136+let balanceA = getIntegerValue(this, keyBalanceA)
121137
122-let balanceB = getIntegerValue(this, kBalanceB)
138+let balanceB = getIntegerValue(this, keyBalanceB)
123139
124-let shareAssetId = fromBase58String(getStringValue(this, kShareAssetId))
140+let shareAssetId = fromBase58String(getStringValue(this, keyShareAssetId))
125141
126-let shareAssetSupply = getIntegerValue(this, kShareAssetSupply)
142+let shareAssetSupply = getIntegerValue(this, keyShareAssetSupply)
127143
128-let invariant = getIntegerValue(this, kInvariant)
144+let commission = 3000
129145
130-let fee = 500
146+let commissionGovernance = 1200
131147
132-let feeGovernance = 200
148+let commissionScaleDelimiter = 1000000
133149
134-let feeScale6 = 1000000
150+let scaleValue3 = 1000
135151
136-let scale3 = 1000
152+let scaleValue8 = 100000000
137153
138-let scale8 = 100000000
154+let slippageToleranceDelimiter = 1000
139155
140-let scale12 = 1000000000000
141-
142-let slippageScale3 = 1000
143-
144-let digits8 = 8
145-
146-let dAppThreshold = 50
147-
148-let dAppThresholdScale2 = 100
149-
150-let exchangeRatioLimitMin = 90000000
151-
152-let exchangeRatioLimitMax = 110000000
153-
154-let alpha = 50
155-
156-let alphaDigits = 2
157-
158-let beta = 46000000
156+let scaleValue8Digits = 8
159157
160158 func accountBalance (assetId) = match assetId {
161159 case id: ByteVector =>
167165 }
168166
169167
170-let stakedAmountUSDN = match getInteger(stakingAddress, ((("rpd_balance_" + toBase58String(USDN)) + "_") + toString(this))) {
171- case staked: Int =>
172- staked
173- case nothing: Unit =>
174- 0
175- case _ =>
176- throw("Match error")
177-}
168+func stakedAmount (assetId) = {
169+ let stakedAmountCalculated = match assetId {
170+ case aId: ByteVector =>
171+ if (if ((aId == USDN))
172+ then true
173+ else (aId == NSBT))
174+ then getInteger(stakingUSDNNSBTAddress, ((("rpd_balance_" + toBase58String(aId)) + "_") + toString(this)))
175+ else if ((aId == EURN))
176+ then getInteger(stakingEURNAddress, ((("%s%s%s__stakingBalance__" + toBase58String(aId)) + "__") + toString(this)))
177+ else 0
178+ case _: Unit =>
179+ 0
180+ case _ =>
181+ throw("Match error")
182+ }
183+ match stakedAmountCalculated {
184+ case i: Int =>
185+ i
186+ case _ =>
187+ 0
188+ }
189+ }
178190
179-let availableBalanceA = (balanceA - (if ((assetIdA == USDN))
180- then stakedAmountUSDN
181- else 0))
182191
183-let availableBalanceB = (balanceB - (if ((assetIdB == USDN))
184- then stakedAmountUSDN
185- else 0))
192+let stakedAmountA = stakedAmount(assetIdA)
186193
187-let accountBalanceWithStakedA = (accountBalance(assetIdA) + (if ((assetIdA == USDN))
188- then stakedAmountUSDN
189- else 0))
194+let stakedAmountB = stakedAmount(assetIdB)
190195
191-let accountBalanceWithStakedB = (accountBalance(assetIdB) + (if ((assetIdB == USDN))
192- then stakedAmountUSDN
193- else 0))
196+let assetInitA = getIntegerValue(this, keyBalanceInitA)
197+
198+let assetInitB = getIntegerValue(this, keyBalanceInitB)
199+
200+let availableBalanceA = (balanceA - stakedAmountA)
201+
202+let availableBalanceB = (balanceB - stakedAmountB)
203+
204+let accountBalanceWithStakedA = (accountBalance(assetIdA) + stakedAmountA)
205+
206+let accountBalanceWithStakedB = (accountBalance(assetIdB) + stakedAmountB)
194207
195208 let hasEnoughBalance = if ((accountBalanceWithStakedA >= balanceA))
196209 then (accountBalanceWithStakedB >= balanceB)
197210 else false
198-
199-func skewness (x,y) = (((fraction(scale12, x, y) + fraction(scale12, y, x)) / 2) / 10000)
200-
201-
202-func invariantCalc (x,y) = {
203- let sk = skewness(x, y)
204- (fraction((x + y), scale8, pow(sk, digits8, alpha, alphaDigits, digits8, CEILING)) + (2 * fraction(pow(fraction(x, y, scale8), 0, 5, 1, (digits8 / 2), DOWN), pow((sk - beta), digits8, alpha, alphaDigits, digits8, DOWN), scale8)))
205- }
206-
207-
208-func calculateSendAmount (amountToSendEstimated,minTokenReceiveAmount,tokenReceiveAmount,tokenId) = {
209- let slippageValue = (scale8 - ((scale8 * 1) / 10000000))
210- let deltaBetweenMaxAndMinSendValue = (amountToSendEstimated - minTokenReceiveAmount)
211- let x = (balanceA + tokenReceiveAmount)
212- let y = (balanceB + tokenReceiveAmount)
213- let invariantNew = if ((tokenId == assetIdA))
214- then invariantCalc(x, (balanceB - amountToSendEstimated))
215- else if ((tokenId == assetIdB))
216- then invariantCalc((balanceA - amountToSendEstimated), y)
217- else throw("Wrong asset in payment")
218- let invariantEstimatedRatio = fraction(scale8, invariant, invariantNew)
219- func getStepAmount (acc,step) = if ((acc == -1))
220- then {
221- let amountToSend = (amountToSendEstimated - ((step * deltaBetweenMaxAndMinSendValue) / 5))
222- let stepInvariant = if ((tokenId == assetIdA))
223- then invariantCalc(x, (balanceB - amountToSend))
224- else invariantCalc((balanceA - amountToSend), y)
225- if ((stepInvariant > invariant))
226- then amountToSend
227- else -1
228- }
229- else acc
230-
231- let stepAmount = {
232- let $list67186761 = [1, 2, 3, 4, 5]
233- let $size67186761 = size($list67186761)
234- let $acc067186761 = -1
235- if (($size67186761 == 0))
236- then $acc067186761
237- else {
238- let $acc167186761 = getStepAmount($acc067186761, $list67186761[0])
239- if (($size67186761 == 1))
240- then $acc167186761
241- else {
242- let $acc267186761 = getStepAmount($acc167186761, $list67186761[1])
243- if (($size67186761 == 2))
244- then $acc267186761
245- else {
246- let $acc367186761 = getStepAmount($acc267186761, $list67186761[2])
247- if (($size67186761 == 3))
248- then $acc367186761
249- else {
250- let $acc467186761 = getStepAmount($acc367186761, $list67186761[3])
251- if (($size67186761 == 4))
252- then $acc467186761
253- else {
254- let $acc567186761 = getStepAmount($acc467186761, $list67186761[4])
255- if (($size67186761 == 5))
256- then $acc567186761
257- else {
258- let $acc667186761 = getStepAmount($acc567186761, $list67186761[5])
259- throw("List size exceed 5")
260- }
261- }
262- }
263- }
264- }
265- }
266- }
267- if ((0 > stepAmount))
268- then throw("something went wrong while working with amountToSend")
269- else if (if ((invariantEstimatedRatio > slippageValue))
270- then (invariantNew > invariant)
271- else false)
272- then amountToSendEstimated
273- else stepAmount
274- }
275-
276211
277212 func getAssetInfo (assetId) = match assetId {
278213 case id: ByteVector =>
286221 }
287222
288223
289-func suspend (cause) = [BooleanEntry(kActive, false), StringEntry(kCause, cause)]
224+func getAssetInfoFromString (assetStr) = if ((assetStr == "WAVES"))
225+ then $Tuple3("WAVES", "WAVES", 8)
226+ else {
227+ let stringId = assetStr
228+ let id = fromBase58String(assetStr)
229+ let info = valueOrErrorMessage(assetInfo(id), (("Asset " + stringId) + " doesn't exist"))
230+ $Tuple3(stringId, info.name, info.decimals)
231+ }
290232
291233
292-func deductStakingFee (amount,assetId) = if ((assetId == USDN))
234+func suspend (cause) = [BooleanEntry(keyActive, false), StringEntry(keyCause, cause)]
235+
236+
237+func deductStakingFee (amount,assetId,secondAssetId) = if (if ((assetId == USDN))
238+ then true
239+ else (assetId == EURN))
293240 then {
294- let result = (amount - stakingFeeInUSDN)
241+ let stakinFee = if ((assetId == USDN))
242+ then (stakingFeeInUSDN * (if ((secondAssetId == NSBT))
243+ then 2
244+ else 1))
245+ else if ((assetId == EURN))
246+ then stakingFeeInEURN
247+ else 0
248+ let result = (amount - stakinFee)
295249 if ((0 >= result))
296- then throw((((("Insufficient amount " + toString(amount)) + " to deduct staking fee ") + toString(stakingFeeInUSDN)) + " USD-N"))
250+ then throw((((("Insufficient amount " + toString(amount)) + " to deduct staking fee ") + toString(stakinFee)) + "USDN/EURN"))
297251 else result
298252 }
299253 else amount
300254
301255
302-func throwIsActive () = throw("DApp is already active")
303-
304-
305-func throwIsInactive () = throw("DApp is inactive at this moment")
306-
307-
308-func throwOnlyAdmin () = throw("Only admin can call this function")
309-
310-
311-func throwAssets () = throw(((("Incorrect assets attached. Expected: " + strAssetIdA) + " and ") + strAssetIdB))
312-
313-
314-func throwThreshold (threshold,amountA,amountB) = throw(((((((((("New balance in assets of the DApp is less than threshold " + toString(threshold)) + ": ") + toString(amountA)) + " ") + assetNameA) + ", ") + toString(amountB)) + " ") + assetNameB))
256+func getStakingFee (assetId,secondAssetId) = if ((assetId == USDN))
257+ then (stakingFeeInUSDN * (if ((secondAssetId == NSBT))
258+ then 2
259+ else 1))
260+ else if ((assetId == EURN))
261+ then stakingFeeInEURN
262+ else 0
315263
316264
317265 func throwInsufficientAvailableBalance (amount,available,assetName) = throw((((((((("Insufficient DApp balance to pay " + toString(amount)) + " ") + assetName) + " due to staking. Available: ") + toString(available)) + " ") + assetName) + ". Please contact support in Telegram: https://t.me/swopfisupport"))
320268 func throwInsufficientAvailableBalances (amountA,amountB) = throw((((((((((((((((("Insufficient DApp balance to pay " + toString(amountA)) + " ") + assetNameA) + " and ") + toString(amountB)) + " ") + assetNameB) + " due to staking. Available: ") + toString(availableBalanceA)) + " ") + assetNameA) + " and ") + toString(availableBalanceB)) + " ") + assetNameB) + ". Please contact support in Telegram: https://t.me/swopfisupport"))
321269
322270
323-func suspendSuspicious () = suspend(((((((((((((((("Suspicious state. Actual balances: " + toString(balanceA)) + " ") + assetNameA) + ", ") + toString(balanceB)) + " ") + assetNameB) + ". State: ") + toString(accountBalance(assetIdA))) + " ") + assetNameA) + ", ") + toString(accountBalance(assetIdB))) + " ") + assetNameB))
271+func suspendSuspicious () = suspend(((((((((((((((("Suspicious state. Actual balances: " + toString(accountBalanceWithStakedA)) + " ") + assetNameA) + ", ") + toString(accountBalanceWithStakedB)) + " ") + assetNameB) + ". State: ") + toString(balanceA)) + " ") + assetNameA) + ", ") + toString(balanceB)) + " ") + assetNameB))
324272
325273
326274 @Callable(i)
327275 func init (firstHarvest) = {
328- let $t094589535 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
329- let pmtAmountA = $t094589535._1
330- let pmtAssetIdA = $t094589535._2
331- let $t095409617 = $Tuple2(i.payments[1].amount, i.payments[1].assetId)
332- let pmtAmountB = $t095409617._1
333- let pmtAssetIdB = $t095409617._2
334- let $t096229699 = getAssetInfo(pmtAssetIdA)
335- let pmtStrAssetIdA = $t096229699._1
336- let pmtAssetNameA = $t096229699._2
337- let pmtDecimalsA = $t096229699._3
338- let $t097049781 = getAssetInfo(pmtAssetIdB)
339- let pmtStrAssetIdB = $t097049781._1
340- let pmtAssetNameB = $t097049781._2
341- let pmtDecimalsB = $t097049781._3
342- if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStaking], i.callerPublicKey)))
276+ let $t080008077 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
277+ let pmtAmountA = $t080008077._1
278+ let pmtAssetIdA = $t080008077._2
279+ let $t080828159 = $Tuple2(i.payments[1].amount, i.payments[1].assetId)
280+ let pmtAmountB = $t080828159._1
281+ let pmtAssetIdB = $t080828159._2
282+ let $t081648241 = getAssetInfo(pmtAssetIdA)
283+ let pmtStrAssetIdA = $t081648241._1
284+ let pmtAssetNameA = $t081648241._2
285+ let pmtDecimalsA = $t081648241._3
286+ let $t082468323 = getAssetInfo(pmtAssetIdB)
287+ let pmtStrAssetIdB = $t082468323._1
288+ let pmtAssetNameB = $t082468323._2
289+ let pmtDecimalsB = $t082468323._3
290+ if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStaking], i.callerPublicKey)))
343291 then throw("Only admin can call this function")
344- else if (isDefined(getBoolean(this, kActive)))
345- then throwIsActive()
292+ else if (isDefined(getBoolean(this, keyActive)))
293+ then throw("DApp is already active")
346294 else if ((pmtAssetIdA == pmtAssetIdB))
347295 then throw("Assets must be different")
348296 else {
349297 let shareName = ((("s" + take(pmtAssetNameA, 7)) + "_") + take(pmtAssetNameB, 7))
350298 let shareDescription = ((((("ShareToken of SwopFi protocol for " + pmtAssetNameA) + " and ") + pmtAssetNameB) + " at address ") + toString(this))
351299 let shareDecimals = ((pmtDecimalsA + pmtDecimalsB) / 2)
352- let shareInitialSupply = fraction(pow(pmtAmountA, pmtDecimalsA, 5, 1, pmtDecimalsA, DOWN), pow(pmtAmountB, pmtDecimalsB, 5, 1, pmtDecimalsB, DOWN), pow(10, 0, shareDecimals, 0, 0, DOWN))
300+ let arg1 = pow(pmtAmountA, pmtDecimalsA, 5, 1, pmtDecimalsA, DOWN)
301+ let arg2 = pow(pmtAmountB, pmtDecimalsB, 5, 1, pmtDecimalsB, DOWN)
302+ let arg3 = pow(10, 0, shareDecimals, 0, 0, DOWN)
303+ let shareInitialSupply = fraction(arg1, arg2, arg3)
353304 let shareIssue = Issue(shareName, shareDescription, shareInitialSupply, shareDecimals, true)
354305 let shareIssueId = calculateAssetId(shareIssue)
355- let invariantCalculated = invariantCalc(pmtAmountA, pmtAmountB)
356- let baseEntry = [StringEntry(kVersion, version), BooleanEntry(kActive, true), StringEntry(kAssetIdA, pmtStrAssetIdA), StringEntry(kAssetIdB, pmtStrAssetIdB), IntegerEntry(kBalanceA, pmtAmountA), IntegerEntry(kBalanceB, pmtAmountB), IntegerEntry(kInvariant, invariantCalculated), IntegerEntry(kFee, fee), IntegerEntry(kFeeScaleDelimiter, feeScale6), shareIssue, StringEntry(kShareAssetId, toBase58String(shareIssueId)), IntegerEntry(kShareAssetSupply, shareInitialSupply), ScriptTransfer(i.caller, shareInitialSupply, shareIssueId)]
306+ let baseEntry = [StringEntry(keyVersion, version), BooleanEntry(keyActive, true), StringEntry(keyAssetIdA, pmtStrAssetIdA), StringEntry(keyAssetIdB, pmtStrAssetIdB), IntegerEntry(keyBalanceA, pmtAmountA), IntegerEntry(keyBalanceB, pmtAmountB), IntegerEntry(keyCommission, commission), IntegerEntry(keyCommissionScaleDelimiter, commissionScaleDelimiter), shareIssue, StringEntry(keyShareAssetId, toBase58String(shareIssueId)), IntegerEntry(keyShareAssetSupply, shareInitialSupply), ScriptTransfer(i.caller, shareInitialSupply, shareIssueId)]
357307 if (firstHarvest)
358- then (baseEntry ++ [BooleanEntry(kFirstHarvest, firstHarvest), IntegerEntry(kFirstHarvestHeight, (startHeight + (firstHarvestEndPeriod * periodLength)))])
308+ then (baseEntry ++ [BooleanEntry(keyFirstHarvest, firstHarvest), IntegerEntry(keyFirstHarvestHeight, (startHeight + (firstHarvestEndPeriod * periodLength)))])
359309 else baseEntry
360310 }
361311 }
363313
364314
365315 @Callable(i)
366-func replenishWithTwoTokens (slippageTolerance) = {
367- let pmtAssetIdA = i.payments[0].assetId
368- let pmtAssetIdB = i.payments[1].assetId
369- let pmtAmountA = deductStakingFee(i.payments[0].amount, pmtAssetIdA)
370- let pmtAmountB = deductStakingFee(i.payments[1].amount, pmtAssetIdB)
371- let tokenRatio = fraction(fraction(scale8, balanceA, pmtAmountA), scale3, fraction(scale8, balanceB, pmtAmountB))
372- let ratioShareTokensInA = fraction(scale8, pmtAmountA, balanceA)
373- let ratioShareTokensInB = fraction(scale8, pmtAmountB, balanceB)
374- let shareTokenToPayAmount = fraction(min([ratioShareTokensInA, ratioShareTokensInB]), shareAssetSupply, scale8)
375- let invariantCalculated = invariantCalc((balanceA + pmtAmountA), (balanceB + pmtAmountB))
376- if (!(isActive))
377- then throwIsInactive()
378- else if (if ((0 > slippageTolerance))
379- then true
380- else (slippageTolerance > 10))
381- then throw("Slippage tolerance must be <= 1%")
382- else if ((size(i.payments) != 2))
383- then throw("Two attached assets expected")
384- else if (if ((pmtAssetIdA != assetIdA))
385- then true
386- else (pmtAssetIdB != assetIdB))
387- then throwAssets()
388- else if (if ((((scale3 * (slippageScale3 - slippageTolerance)) / slippageScale3) > tokenRatio))
389- then true
390- else (tokenRatio > ((scale3 * (slippageScale3 + slippageTolerance)) / slippageScale3)))
391- then throw("Incorrect assets amount: amounts must have the contract ratio")
392- else if ((shareTokenToPayAmount == 0))
393- then throw("Too small amount to replenish")
394- else if (!(hasEnoughBalance))
395- then ([ScriptTransfer(i.caller, pmtAmountA, pmtAssetIdA), ScriptTransfer(i.caller, pmtAmountB, pmtAssetIdB)] ++ suspendSuspicious())
396- else [IntegerEntry(kBalanceA, (balanceA + pmtAmountA)), IntegerEntry(kBalanceB, (balanceB + pmtAmountB)), IntegerEntry(kShareAssetSupply, (shareAssetSupply + shareTokenToPayAmount)), IntegerEntry(kInvariant, invariantCalculated), Reissue(shareAssetId, shareTokenToPayAmount, true), ScriptTransfer(i.caller, shareTokenToPayAmount, shareAssetId)]
316+func initWithInitRatio (amtAssetA,amtAssetB,strAssetIdA,strAssetIdB,firstHarvest) = {
317+ let $t01056810655 = getAssetInfoFromString(strAssetIdA)
318+ let pmtStrAssetIdA = $t01056810655._1
319+ let pmtAssetNameA = $t01056810655._2
320+ let pmtDecimalsA = $t01056810655._3
321+ let $t01066010747 = getAssetInfoFromString(strAssetIdB)
322+ let pmtStrAssetIdB = $t01066010747._1
323+ let pmtAssetNameB = $t01066010747._2
324+ let pmtDecimalsB = $t01066010747._3
325+ if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStaking], i.callerPublicKey)))
326+ then throw("Only admin can call this function")
327+ else if (isDefined(getBoolean(this, keyActive)))
328+ then throw("DApp is already active")
329+ else if ((strAssetIdA == strAssetIdB))
330+ then throw("Assets must be different")
331+ else {
332+ let shareName = ((("s" + take(pmtAssetNameA, 7)) + "_") + take(pmtAssetNameB, 7))
333+ let shareDescription = ((((("ShareToken of SwopFi protocol for " + pmtAssetNameA) + " and ") + pmtAssetNameB) + " at address ") + toString(this))
334+ let shareDecimals = ((pmtDecimalsA + pmtDecimalsB) / 2)
335+ let shareInitialSupply = 0
336+ let shareIssue = Issue(shareName, shareDescription, shareInitialSupply, shareDecimals, true)
337+ let shareIssueId = calculateAssetId(shareIssue)
338+ let baseEntry = [StringEntry(keyVersion, version), BooleanEntry(keyActive, true), StringEntry(keyAssetIdA, pmtStrAssetIdA), StringEntry(keyAssetIdB, pmtStrAssetIdB), IntegerEntry(keyBalanceInitA, amtAssetA), IntegerEntry(keyBalanceInitB, amtAssetB), IntegerEntry(keyBalanceA, 0), IntegerEntry(keyBalanceB, 0), IntegerEntry(keyCommission, commission), IntegerEntry(keyCommissionScaleDelimiter, commissionScaleDelimiter), shareIssue, StringEntry(keyShareAssetId, toBase58String(shareIssueId)), IntegerEntry(keyShareAssetSupply, shareInitialSupply)]
339+ if (firstHarvest)
340+ then (baseEntry ++ [BooleanEntry(keyFirstHarvest, firstHarvest), IntegerEntry(keyFirstHarvestHeight, (startHeight + (firstHarvestEndPeriod * periodLength)))])
341+ else baseEntry
342+ }
397343 }
398344
399345
400346
401347 @Callable(i)
402-func replenishWithOneToken (virtualSwapTokenPay,virtualSwapTokenGet) = {
403- let $t01458314658 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
404- let pmtAmount = $t01458314658._1
405- let pmtAssetId = $t01458314658._2
406- let pmtMinThreshold = 5000000
407- let thresholdValueForMinTolerance = 50000000
408- let tolerance = if ((thresholdValueForMinTolerance > pmtAmount))
409- then 100000
410- else 1
411- let slippageValueMinForReplenish = (scale8 - ((scale8 * tolerance) / 10000000))
412- let slippageValueMaxForReplenish = (scale8 + ((scale8 * tolerance) / 10000000))
413- let slippageValueMinForSwap = (scale8 - ((scale8 * 1) / 10000000))
414- if (!(isActive))
415- then throwIsInactive()
416- else if ((pmtMinThreshold > pmtAmount))
417- then throw((((("Payment amount " + toString(pmtAmount)) + " does not exceed the minimum amount of ") + toString(pmtMinThreshold)) + " tokens"))
418- else if ((size(i.payments) != 1))
419- then throw("One attached payment expected")
420- else if (!(hasEnoughBalance))
421- then ([ScriptTransfer(i.caller, pmtAmount, pmtAssetId)] ++ suspendSuspicious())
422- else if (if ((pmtAssetId != assetIdA))
423- then (pmtAssetId != assetIdB)
424- else false)
425- then throwAssets()
426- else {
427- let $t01567016435 = if ((pmtAssetId == assetIdA))
428- then $Tuple7((pmtAmount - virtualSwapTokenPay), virtualSwapTokenGet, (balanceA + virtualSwapTokenPay), (balanceB - virtualSwapTokenGet), invariantCalc((balanceA + pmtAmount), balanceB), (balanceA + pmtAmount), balanceB)
429- else $Tuple7(virtualSwapTokenGet, (pmtAmount - virtualSwapTokenPay), (balanceA - virtualSwapTokenGet), (balanceB + virtualSwapTokenPay), invariantCalc(balanceA, (balanceB + pmtAmount)), balanceA, (balanceB + pmtAmount))
430- let virtualReplenishA = $t01567016435._1
431- let virtualReplenishB = $t01567016435._2
432- let balanceAfterSwapA = $t01567016435._3
433- let balanceAfterSwapB = $t01567016435._4
434- let invariantCalculated = $t01567016435._5
435- let newBalanceA = $t01567016435._6
436- let newBalanceB = $t01567016435._7
437- let newBalanceEntry = if ((pmtAssetId == assetIdA))
438- then IntegerEntry(kBalanceA, newBalanceA)
439- else IntegerEntry(kBalanceB, newBalanceB)
440- let invariantNew = invariantCalc(balanceAfterSwapA, balanceAfterSwapB)
441- let invariantEstimatedRatio = fraction(scale8, invariant, invariantNew)
442- let ratioVirtualBalanceToVirtualReplenish = (fraction((scale8 * scale8), balanceAfterSwapA, balanceAfterSwapB) / fraction(scale8, virtualReplenishA, virtualReplenishB))
443- let dAppThresholdAmount = fraction((newBalanceA + newBalanceB), dAppThreshold, (2 * dAppThresholdScale2))
444- if (if ((slippageValueMinForSwap >= invariantEstimatedRatio))
348+func keepLimitForFirstHarvest (shareLimit) = if (!(isActive))
349+ then throw("DApp is inactive at this moment")
350+ else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStaking], i.callerPublicKey)))
351+ then throw("Only admin can call this function")
352+ else [IntegerEntry(kShareLimit, shareLimit)]
353+
354+
355+
356+@Callable(i)
357+func replenishWithTwoTokens (slippageTolerance) = {
358+ let pmtAssetIdA = i.payments[0].assetId
359+ let pmtAssetIdB = i.payments[1].assetId
360+ let pmtAmountA = deductStakingFee(i.payments[0].amount, pmtAssetIdA, pmtAssetIdB)
361+ let pmtAmountB = deductStakingFee(i.payments[1].amount, pmtAssetIdB, pmtAssetIdA)
362+ if (if ((balanceA == 0))
363+ then (balanceB == 0)
364+ else false)
365+ then {
366+ let $t01345813535 = getAssetInfo(pmtAssetIdA)
367+ let pmtStrAssetIdA = $t01345813535._1
368+ let pmtAssetNameA = $t01345813535._2
369+ let pmtDecimalsA = $t01345813535._3
370+ let $t01354413621 = getAssetInfo(pmtAssetIdB)
371+ let pmtStrAssetIdB = $t01354413621._1
372+ let pmtAssetNameB = $t01354413621._2
373+ let pmtDecimalsB = $t01354413621._3
374+ let tokenRatio = fraction(fraction(assetInitA, scaleValue8, pmtAmountA), scaleValue3, fraction(assetInitB, scaleValue8, pmtAmountB))
375+ if ((pmtAssetIdA == pmtAssetIdB))
376+ then throw("Assets must be different")
377+ else {
378+ let shareDecimals = ((pmtDecimalsA + pmtDecimalsB) / 2)
379+ let shareInitialSupply = fraction(pow(pmtAmountA, pmtDecimalsA, 5, 1, pmtDecimalsA, DOWN), pow(pmtAmountB, pmtDecimalsB, 5, 1, pmtDecimalsB, DOWN), pow(10, 0, shareDecimals, 0, 0, DOWN))
380+ if (!(isActive))
381+ then throw("DApp is inactive at this moment")
382+ else if (if ((0 > slippageTolerance))
383+ then true
384+ else (slippageTolerance > slippageToleranceDelimiter))
385+ then throw(((("Slippage tolerance must be between 0 and " + toString(slippageToleranceDelimiter)) + " inclusively. Actual: ") + toString(slippageTolerance)))
386+ else if ((size(i.payments) != 2))
387+ then throw("Two attached assets expected")
388+ else if (if ((((scaleValue3 * (slippageToleranceDelimiter - slippageTolerance)) / slippageToleranceDelimiter) > tokenRatio))
389+ then true
390+ else (tokenRatio > ((scaleValue3 * (slippageToleranceDelimiter + slippageTolerance)) / slippageToleranceDelimiter)))
391+ then throw("Incorrect assets amount: amounts must have the contract ratio")
392+ else if (if ((pmtAssetIdA != assetIdA))
393+ then true
394+ else (pmtAssetIdB != assetIdB))
395+ then throw(((("Incorrect assets attached. Expected: " + strAssetIdA) + " and ") + strAssetIdB))
396+ else if ((shareInitialSupply == 0))
397+ then throw("Too small amount to replenish")
398+ else if (!(hasEnoughBalance))
399+ then ([ScriptTransfer(i.caller, pmtAmountA, pmtAssetIdA), ScriptTransfer(i.caller, pmtAmountB, pmtAssetIdB)] ++ suspendSuspicious())
400+ else [Reissue(shareAssetId, shareInitialSupply, true), IntegerEntry(keyBalanceA, pmtAmountA), IntegerEntry(keyBalanceB, pmtAmountB), IntegerEntry(keyShareAssetSupply, shareInitialSupply), ScriptTransfer(i.caller, shareInitialSupply, shareAssetId)]
401+ }
402+ }
403+ else {
404+ let tokenRatio = fraction(fraction(balanceA, scaleValue8, pmtAmountA), scaleValue3, fraction(balanceB, scaleValue8, pmtAmountB))
405+ let ratioShareTokensInA = fraction(pmtAmountA, scaleValue8, balanceA)
406+ let ratioShareTokensInB = fraction(pmtAmountB, scaleValue8, balanceB)
407+ let shareTokenToPayAmount = fraction(min([ratioShareTokensInA, ratioShareTokensInB]), shareAssetSupply, scaleValue8)
408+ if (!(isActive))
409+ then throw("DApp is inactive at this moment")
410+ else if (if ((0 > slippageTolerance))
411+ then true
412+ else (slippageTolerance > slippageToleranceDelimiter))
413+ then throw(((("Slippage tolerance must be between 0 and " + toString(slippageToleranceDelimiter)) + " inclusively. Actual: ") + toString(slippageTolerance)))
414+ else if ((size(i.payments) != 2))
415+ then throw("Two attached assets expected")
416+ else if (if ((pmtAssetIdA != assetIdA))
417+ then true
418+ else (pmtAssetIdB != assetIdB))
419+ then throw(((("Incorrect assets attached. Expected: " + strAssetIdA) + " and ") + strAssetIdB))
420+ else if (if ((((scaleValue3 * (slippageToleranceDelimiter - slippageTolerance)) / slippageToleranceDelimiter) > tokenRatio))
445421 then true
446- else (invariant > invariantNew))
447- then throw("Incorrect virtualSwapTokenPay or virtualSwapTokenGet value")
448- else if (if ((slippageValueMinForReplenish > ratioVirtualBalanceToVirtualReplenish))
449- then true
450- else (ratioVirtualBalanceToVirtualReplenish > slippageValueMaxForReplenish))
451- then throw("Swap with virtualSwapTokenPay and virtualSwapTokenGet is possible, but ratio after virtual swap is incorrect")
452- else if (if ((dAppThresholdAmount > newBalanceA))
453- then true
454- else (dAppThresholdAmount > newBalanceB))
455- then throwThreshold(dAppThresholdAmount, newBalanceA, newBalanceB)
456- else {
457- let ratioShareTokensInA = fraction(deductStakingFee(virtualReplenishA, assetIdA), scale8, balanceAfterSwapA)
458- let ratioShareTokensInB = fraction(deductStakingFee(virtualReplenishB, assetIdB), scale8, balanceAfterSwapB)
459- let shareTokenToPayAmount = fraction(min([ratioShareTokensInA, ratioShareTokensInB]), shareAssetSupply, scale8)
460-[Reissue(shareAssetId, shareTokenToPayAmount, true), ScriptTransfer(i.caller, shareTokenToPayAmount, shareAssetId), IntegerEntry(kShareAssetSupply, (shareAssetSupply + shareTokenToPayAmount)), newBalanceEntry, IntegerEntry(kInvariant, invariantCalculated)]
461- }
462- }
422+ else (tokenRatio > ((scaleValue3 * (slippageToleranceDelimiter + slippageTolerance)) / slippageToleranceDelimiter)))
423+ then throw("Incorrect assets amount: amounts must have the contract ratio")
424+ else if ((shareTokenToPayAmount == 0))
425+ then throw("Too small amount to replenish")
426+ else if (!(hasEnoughBalance))
427+ then ([ScriptTransfer(i.caller, pmtAmountA, pmtAssetIdA), ScriptTransfer(i.caller, pmtAmountB, pmtAssetIdB)] ++ suspendSuspicious())
428+ else [IntegerEntry(keyBalanceA, (balanceA + pmtAmountA)), IntegerEntry(keyBalanceB, (balanceB + pmtAmountB)), IntegerEntry(keyShareAssetSupply, (shareAssetSupply + shareTokenToPayAmount)), Reissue(shareAssetId, shareTokenToPayAmount, true), ScriptTransfer(i.caller, shareTokenToPayAmount, shareAssetId)]
429+ }
463430 }
464431
465432
466433
467434 @Callable(i)
468435 func withdraw () = {
469- let $t01858018723 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
470- let pmtAmount = $t01858018723._1
471- let pmtAssetId = $t01858018723._2
472- let amountToPayA = deductStakingFee(fraction(pmtAmount, balanceA, shareAssetSupply), assetIdA)
473- let amountToPayB = deductStakingFee(fraction(pmtAmount, balanceB, shareAssetSupply), assetIdB)
474- let invariantCalculated = invariantCalc((balanceA - amountToPayA), (balanceB - amountToPayB))
436+ let $t01802018170 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
437+ let pmtAmount = $t01802018170._1
438+ let pmtAssetId = $t01802018170._2
439+ let amountToPayA = deductStakingFee(fraction(pmtAmount, balanceA, shareAssetSupply), assetIdA, assetIdB)
440+ let amountToPayB = deductStakingFee(fraction(pmtAmount, balanceB, shareAssetSupply), assetIdB, assetIdA)
475441 if (!(isActive))
476- then throwIsInactive()
442+ then throw("DApp is inactive at this moment")
477443 else if ((size(i.payments) != 1))
478444 then throw("One attached payment expected")
479445 else if ((pmtAssetId != shareAssetId))
484450 then true
485451 else (amountToPayB > availableBalanceB))
486452 then throwInsufficientAvailableBalances(amountToPayA, amountToPayB)
487- else [IntegerEntry(kBalanceA, (balanceA - amountToPayA)), IntegerEntry(kBalanceB, (balanceB - amountToPayB)), IntegerEntry(kShareAssetSupply, (shareAssetSupply - pmtAmount)), IntegerEntry(kInvariant, invariantCalculated), Burn(shareAssetId, pmtAmount), ScriptTransfer(i.caller, amountToPayA, assetIdA), ScriptTransfer(i.caller, amountToPayB, assetIdB)]
453+ else [IntegerEntry(keyBalanceA, (balanceA - amountToPayA)), IntegerEntry(keyBalanceB, (balanceB - amountToPayB)), IntegerEntry(keyShareAssetSupply, (shareAssetSupply - pmtAmount)), Burn(shareAssetId, pmtAmount), ScriptTransfer(i.caller, amountToPayA, assetIdA), ScriptTransfer(i.caller, amountToPayB, assetIdB)]
488454 }
489455
490456
491457
492458 @Callable(i)
493-func exchange (estimatedAmountToReceive,minAmountToReceive) = {
494- let $t02008120156 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
495- let pmtAmount = $t02008120156._1
496- let pmtAssetId = $t02008120156._2
459+func exchange (minAmountToReceive) = {
460+ let $t01939619471 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
461+ let pmtAmount = $t01939619471._1
462+ let pmtAssetId = $t01939619471._2
463+ func calculateFees (tokenFrom,tokenTo) = {
464+ let amountWithoutFee = fraction(tokenTo, pmtAmount, (pmtAmount + tokenFrom))
465+ let amountWithFee = fraction(amountWithoutFee, (commissionScaleDelimiter - commission), commissionScaleDelimiter)
466+ let governanceReward = fraction(amountWithoutFee, commissionGovernance, commissionScaleDelimiter)
467+ if ((minAmountToReceive > amountWithFee))
468+ then throw(((("Calculated amount to receive " + toString(amountWithFee)) + " is less than specified minimum ") + toString(minAmountToReceive)))
469+ else $Tuple3(amountWithoutFee, amountWithFee, governanceReward)
470+ }
471+
497472 if (!(isActive))
498- then throwIsInactive()
499- else if ((0 >= estimatedAmountToReceive))
500- then throw(("Estimated amount must be positive. Actual: " + toString(estimatedAmountToReceive)))
501- else if ((minAmountToReceive > estimatedAmountToReceive))
502- then throw(((("Minimal amount can't be greater than estimated. Estimated: " + toString(estimatedAmountToReceive)) + ". Minimal: ") + toString(minAmountToReceive)))
473+ then throw("DApp is inactive at this moment")
474+ else if (if ((balanceA == 0))
475+ then true
476+ else (balanceB == 0))
477+ then throw("Can't exchange with zero balance")
478+ else if ((0 >= minAmountToReceive))
479+ then throw(("Minimal amount to receive must be positive. Actual: " + toString(minAmountToReceive)))
503480 else if ((size(i.payments) != 1))
504481 then throw("One attached payment expected")
505482 else if (!(hasEnoughBalance))
506483 then ([ScriptTransfer(i.caller, pmtAmount, pmtAssetId)] ++ suspendSuspicious())
507- else if (if ((pmtAssetId != assetIdA))
508- then (pmtAssetId != assetIdB)
509- else false)
510- then throwAssets()
511- else if ((10000000 > pmtAmount))
512- then throw("Only swap of 10.000000 or more tokens is allowed")
513- else if (if ((exchangeRatioLimitMin > fraction(scale8, minAmountToReceive, pmtAmount)))
484+ else if ((pmtAssetId == assetIdA))
485+ then {
486+ let assetIdSend = assetIdB
487+ let $t02074520836 = calculateFees(balanceA, balanceB)
488+ let amountWithoutFee = $t02074520836._1
489+ let amountWithFee = $t02074520836._2
490+ let governanceReward = $t02074520836._3
491+ let newBalanceA = (balanceA + pmtAmount)
492+ let newBalanceB = ((balanceB - amountWithFee) - governanceReward)
493+ if (if ((stakedAmountA >= newBalanceA))
514494 then true
515- else (fraction(scale8, estimatedAmountToReceive, pmtAmount) > exchangeRatioLimitMax))
516- then throw("Incorrect args and pmt ratio")
517- else {
518- let sendAssetId = if ((pmtAssetId == assetIdA))
519- then assetIdB
520- else assetIdA
521- let amount = calculateSendAmount(estimatedAmountToReceive, minAmountToReceive, pmtAmount, pmtAssetId)
522- let governanceReward = fraction(amount, feeGovernance, feeScale6)
523- let amountMinusFee = fraction(amount, (feeScale6 - fee), feeScale6)
524- let $t02157821840 = if ((pmtAssetId == assetIdA))
525- then $Tuple2((balanceA + pmtAmount), ((balanceB - amountMinusFee) - governanceReward))
526- else $Tuple2(((balanceA - amountMinusFee) - governanceReward), (balanceB + pmtAmount))
527- let newBalanceA = $t02157821840._1
528- let newBalanceB = $t02157821840._2
529- let dAppThresholdAmount = fraction((newBalanceA + newBalanceB), dAppThreshold, (2 * dAppThresholdScale2))
530- if (if ((dAppThresholdAmount > newBalanceA))
531- then true
532- else (dAppThresholdAmount > newBalanceB))
533- then throwThreshold(dAppThresholdAmount, newBalanceA, newBalanceB)
534- else if (if (if ((assetIdA == USDN))
535- then (sendAssetId == assetIdA)
536- else false)
537- then (stakedAmountUSDN >= newBalanceA)
538- else false)
539- then throwInsufficientAvailableBalance(amountMinusFee, availableBalanceA, assetNameA)
540- else if (if (if ((assetIdB == USDN))
541- then (sendAssetId == assetIdB)
542- else false)
543- then (stakedAmountUSDN >= newBalanceB)
544- else false)
545- then throwInsufficientAvailableBalance(amountMinusFee, availableBalanceB, assetNameB)
546- else [IntegerEntry(kBalanceA, newBalanceA), IntegerEntry(kBalanceB, newBalanceB), IntegerEntry(kInvariant, invariantCalc(newBalanceA, newBalanceB)), ScriptTransfer(i.caller, amountMinusFee, sendAssetId), ScriptTransfer(govAddr, governanceReward, sendAssetId)]
547- }
495+ else (stakedAmountB >= newBalanceB))
496+ then throwInsufficientAvailableBalance(amountWithFee, availableBalanceB, assetNameB)
497+ else [IntegerEntry(keyBalanceA, newBalanceA), IntegerEntry(keyBalanceB, newBalanceB), ScriptTransfer(i.caller, amountWithFee, assetIdSend), ScriptTransfer(walletAddress, governanceReward, assetIdSend)]
498+ }
499+ else if ((pmtAssetId == assetIdB))
500+ then {
501+ let assetIdSend = assetIdA
502+ let $t02165521746 = calculateFees(balanceB, balanceA)
503+ let amountWithoutFee = $t02165521746._1
504+ let amountWithFee = $t02165521746._2
505+ let governanceReward = $t02165521746._3
506+ let newBalanceA = ((balanceA - amountWithFee) - governanceReward)
507+ let newBalanceB = (balanceB + pmtAmount)
508+ if (if ((stakedAmountA >= newBalanceA))
509+ then true
510+ else (stakedAmountB >= newBalanceB))
511+ then throwInsufficientAvailableBalance(amountWithFee, availableBalanceA, assetNameA)
512+ else [IntegerEntry(keyBalanceA, newBalanceA), IntegerEntry(keyBalanceB, newBalanceB), ScriptTransfer(i.caller, amountWithFee, assetIdSend), ScriptTransfer(walletAddress, governanceReward, assetIdSend)]
513+ }
514+ else throw(((("Incorrect asset attached. Expected: " + strAssetIdA) + " or ") + strAssetIdB))
548515 }
549516
550517
551518
552519 @Callable(i)
553520 func shutdown () = if (!(isActive))
554- then throw(("DApp is already suspended. Cause: " + valueOrElse(getString(this, kCause), "the cause wasn't specified")))
555- else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStartStop], i.callerPublicKey)))
556- then throwOnlyAdmin()
521+ then throw(("DApp is already suspended. Cause: " + valueOrElse(getString(this, keyCause), "the cause wasn't specified")))
522+ else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStartStop], i.callerPublicKey)))
523+ then throw("Only admin can call this function")
557524 else suspend("Paused by admin")
558525
559526
560527
561528 @Callable(i)
562529 func activate () = if (isActive)
563- then throwIsActive()
564- else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStartStop], i.callerPublicKey)))
565- then throwOnlyAdmin()
566- else [BooleanEntry(kActive, true), DeleteEntry(kCause)]
530+ then throw("DApp is already active")
531+ else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStartStop], i.callerPublicKey)))
532+ then throw("Only admin can call this function")
533+ else [BooleanEntry(keyActive, true), DeleteEntry(keyCause)]
567534
568535
569536
570537 @Callable(i)
571538 func takeIntoAccountExtraFunds (amountLeave) = {
572- let uncountableA = (accountBalanceWithStakedA - balanceA)
573- let uncountableB = (accountBalanceWithStakedB - balanceB)
574- let amountEnrollA = (uncountableA - (if ((assetIdA == unit))
539+ let uncountableAmountEnrollAssetA = (accountBalanceWithStakedA - balanceA)
540+ let uncountableAmountEnrollAssetB = (accountBalanceWithStakedB - balanceB)
541+ let amountEnrollA = (uncountableAmountEnrollAssetA - (if ((assetIdA == unit))
575542 then amountLeave
576543 else 0))
577- let amountEnrollB = (uncountableB - (if ((assetIdB == unit))
544+ let amountEnrollB = (uncountableAmountEnrollAssetB - (if ((assetIdB == unit))
578545 then amountLeave
579546 else 0))
580- let invariantNew = invariantCalc((balanceA + amountEnrollA), (balanceB + amountEnrollB))
581547 if (!(isActive))
582- then throwIsInactive()
548+ then throw("DApp is inactive at this moment")
583549 else if ((i.caller != this))
584- then throwOnlyAdmin()
550+ then throw("Only the DApp itself can call this function")
585551 else if ((0 > amountLeave))
586552 then throw(("Argument 'amountLeave' cannot be negative. Actual: " + toString(amountLeave)))
587- else if (if ((0 > uncountableA))
553+ else if (if ((0 > uncountableAmountEnrollAssetA))
588554 then true
589- else (0 > uncountableB))
555+ else (0 > uncountableAmountEnrollAssetB))
590556 then suspend("Enroll amount negative")
591557 else if (if ((0 > amountEnrollA))
592558 then true
593559 else (0 > amountEnrollB))
594560 then throw("Too large amountLeave")
595- else [IntegerEntry(kInvariant, invariantNew), IntegerEntry(kBalanceA, (balanceA + amountEnrollA)), IntegerEntry(kBalanceB, (balanceB + amountEnrollB)), IntegerEntry(("last_income_" + strAssetIdA), amountEnrollA), IntegerEntry(("last_income_" + strAssetIdB), amountEnrollB)]
561+ else [IntegerEntry(keyBalanceA, (balanceA + amountEnrollA)), IntegerEntry(keyBalanceB, (balanceB + amountEnrollB)), IntegerEntry(("last_income_" + strAssetIdA), amountEnrollA), IntegerEntry(("last_income_" + strAssetIdB), amountEnrollB)]
596562 }
597-
598-
599-
600-@Callable(i)
601-func keepLimitForFirstHarvest (shareLimit) = if (!(isActive))
602- then throw("DApp is inactive at this moment")
603- else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStaking], i.callerPublicKey)))
604- then throw("Only admin can call this function")
605- else [IntegerEntry(kShareLimit, shareLimit)]
606563
607564
608565 @Verifier(tx)
624581 let callTakeIntoAccount = if ((inv.dApp == this))
625582 then (inv.function == "takeIntoAccountExtraFunds")
626583 else false
627- let callStaking = if ((inv.dApp == stakingAddress))
628- then if (if (if ((inv.function == "lockNeutrino"))
584+ let callStaking = if (if ((inv.dApp == stakingUSDNNSBTAddress))
585+ then if (if (if (containsElement(["lockNeutrino", "lockNsbt"], inv.function))
629586 then (size(inv.payments) == 1)
630587 else false)
631- then (inv.payments[0].assetId == USDN)
588+ then if ((inv.payments[0].assetId == USDN))
589+ then true
590+ else (inv.payments[0].assetId == NSBT)
632591 else false)
633592 then true
634- else if ((inv.function == "unlockNeutrino"))
593+ else if (containsElement(["unlockNeutrino", "unlockNsbt"], inv.function))
635594 then (size(inv.payments) == 0)
636595 else false
637- else false
596+ else false)
597+ then true
598+ else if ((inv.dApp == stakingEURNAddress))
599+ then if (if (if ((inv.function == "startStaking"))
600+ then (size(inv.payments) == 1)
601+ else false)
602+ then (inv.payments[0].assetId == EURN)
603+ else false)
604+ then true
605+ else if ((inv.function == "stopStaking"))
606+ then (size(inv.payments) == 0)
607+ else false
608+ else false
638609 let exchangeToWaves = if (if (if ((inv.dApp == USDNToWavesExchanger))
639610 then (inv.function == "exchange")
640611 else false)
646617 else false)
647618 then (inv.payments[0].assetId == USDN)
648619 else false
620+ let exchangeToNSBTs = if (if (if ((inv.dApp == USDNToNSBTExchanger))
621+ then (inv.function == "exchange")
622+ else false)
623+ then (assetIdA == NSBT)
624+ else false)
625+ then true
626+ else if (if ((assetIdB == NSBT))
627+ then (size(inv.payments) == 1)
628+ else false)
629+ then (inv.payments[0].assetId == USDN)
630+ else false
649631 let signedByAdmin = if (if (if (sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKey1))
650632 then true
651633 else sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKey2))
652634 then true
653635 else sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKey3))
654636 then true
655- else sigVerify(tx.bodyBytes, tx.proofs[0], admStaking)
656- if (if (if (if (callTakeIntoAccount)
637+ else sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKeyStaking)
638+ if (if (if (if (if (callTakeIntoAccount)
657639 then true
658640 else callStaking)
659641 then true
660642 else exchangeToWaves)
643+ then true
644+ else exchangeToNSBTs)
661645 then signedByAdmin
662646 else false)
663647 then true
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 5 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let version = "2.0.0"
4+let version = "1.0.0"
55
6-let kVersion = "version"
6+let keyVersion = "version"
77
8-let kActive = "active"
8+let keyActive = "active"
99
10-let kAssetIdA = "A_asset_id"
10+let keyAssetIdA = "A_asset_id"
1111
12-let kAssetIdB = "B_asset_id"
12+let keyAssetIdB = "B_asset_id"
1313
14-let kBalanceA = "A_asset_balance"
14+let keyBalanceA = "A_asset_balance"
1515
16-let kBalanceB = "B_asset_balance"
16+let keyBalanceB = "B_asset_balance"
1717
18-let kShareAssetId = "share_asset_id"
18+let keyBalanceInitA = "A_asset_init"
1919
20-let kShareAssetSupply = "share_asset_supply"
20+let keyBalanceInitB = "B_asset_init"
2121
22-let kFee = "commission"
22+let keyShareAssetId = "share_asset_id"
2323
24-let kFeeScaleDelimiter = "commission_scale_delimiter"
24+let keyShareAssetSupply = "share_asset_supply"
2525
26-let kInvariant = "invariant"
26+let keyCommission = "commission"
2727
28-let kFirstHarvest = "first_harvest"
28+let keyCommissionScaleDelimiter = "commission_scale_delimiter"
2929
30-let kFirstHarvestHeight = "first_harvest_height"
30+let keyCause = "shutdown_cause"
31+
32+let keyFirstHarvest = "first_harvest"
33+
34+let keyFirstHarvestHeight = "first_harvest_height"
3135
3236 let kShareLimit = "share_limit_on_first_harvest"
3337
3438 let kBasePeriod = "base_period"
3539
3640 let kPeriodLength = "period_length"
3741
3842 let kStartHeight = "start_height"
3943
40-let kCause = "shutdown_cause"
44+let kFirstHarvestHeight = "first_harvest_height"
4145
4246 let keyAdminPubKey1 = "admin_pub_1"
4347
4448 let keyAdminPubKey2 = "admin_pub_2"
4549
4650 let keyAdminPubKey3 = "admin_pub_3"
47-
48-let USDNToWavesExchanger = Address(base58'3PHaNgomBkrvEL2QnuJarQVJa71wjw9qiqG')
4951
5052 let oracle = Address(base58'3PEbqViERCoKnmcSULh6n2aiMvUdSQdCsom')
5153
5254 func getAdminPub (keyAdminPub) = match getString(oracle, keyAdminPub) {
5355 case string: String =>
5456 fromBase58String(string)
5557 case nothing =>
5658 throw("Admin public key is empty")
5759 }
5860
5961
6062 let adminPubKey1 = getAdminPub(keyAdminPubKey1)
6163
6264 let adminPubKey2 = getAdminPub(keyAdminPubKey2)
6365
6466 let adminPubKey3 = getAdminPub(keyAdminPubKey3)
6567
66-let admStartStop = base58'EtVkT6ed8GtbUiVVEqdmEqsp2J4qbb3rre2HFgxeVYdg'
68+let adminPubKeyStartStop = base58'EtVkT6ed8GtbUiVVEqdmEqsp2J4qbb3rre2HFgxeVYdg'
6769
68-let admStaking = base58'Czn4yoAuUZCVCLJDRfskn8URfkwpknwBTZDbs1wFrY7h'
70+let adminPubKeyStaking = base58'Czn4yoAuUZCVCLJDRfskn8URfkwpknwBTZDbs1wFrY7h'
6971
70-let govAddr = Address(base58'3P6J84oH51DzY6xk2mT5TheXRbrCwBMxonp')
71-
72-let stakingAddress = Address(base58'3PNikM6yp4NqcSU8guxQtmR5onr2D4e8yTJ')
72+let walletAddress = Address(base58'3P6J84oH51DzY6xk2mT5TheXRbrCwBMxonp')
7373
7474 let votingAddress = Address(base58'3PQZWxShKGRgBN1qoJw6B4s9YWS9FneZTPg')
7575
7676 let USDN = base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
7777
78+let NSBT = base58'6nSpVyNH7yM69eg446wrQR94ipbbcmZMU1ENPwanC97g'
79+
80+let SWOP = base58'Ehie5xYpeN8op1Cctc6aGUrqx8jq3jtf1DSjXDbfm7aT'
81+
82+let EURN = base58'DUk2YTxhRoAqMJLus4G2b3fR8hMHVh6eiyFx5r29VR6t'
83+
84+let stakingUSDNNSBTAddress = Address(base58'3PNikM6yp4NqcSU8guxQtmR5onr2D4e8yTJ')
85+
86+let stakingEURNAddress = Address(base58'3PFhcMmEZoQTQ6ohA844c7C9M8ZJ18P8dDj')
87+
88+let USDNToWavesExchanger = Address(base58'3PHaNgomBkrvEL2QnuJarQVJa71wjw9qiqG')
89+
90+let USDNToNSBTExchanger = Address(base58'3P2V63Xd6BviDkeMzxhUw2SJyojByRz8a8m')
91+
7892 let stakingFeeInUSDN = 270000
93+
94+let stakingFeeInEURN = 234000
7995
8096 let basePeriod = valueOrErrorMessage(getInteger(votingAddress, kBasePeriod), "Empty kBasePeriod")
8197
8298 let startHeight = valueOrErrorMessage(getInteger(votingAddress, kStartHeight), "Empty kStartHeight")
8399
84100 let periodLength = valueOrErrorMessage(getInteger(votingAddress, kPeriodLength), "Empty kPeriodLength")
85101
86102 let firstHarvestEndPeriod = ((basePeriod + ((height - startHeight) / periodLength)) + 3)
87103
88-let isActive = getBooleanValue(this, kActive)
104+let isActive = getBooleanValue(this, keyActive)
89105
90-let strAssetIdA = getStringValue(this, kAssetIdA)
106+let strAssetIdA = getStringValue(this, keyAssetIdA)
91107
92-let strAssetIdB = getStringValue(this, kAssetIdB)
108+let strAssetIdB = getStringValue(this, keyAssetIdB)
93109
94110 let assetIdA = if ((strAssetIdA == "WAVES"))
95111 then unit
96112 else fromBase58String(strAssetIdA)
97113
98114 let assetIdB = if ((strAssetIdB == "WAVES"))
99115 then unit
100116 else fromBase58String(strAssetIdB)
101117
102118 let assetNameA = match assetIdA {
103119 case id: ByteVector =>
104120 value(assetInfo(id)).name
105121 case waves: Unit =>
106122 "WAVES"
107123 case _ =>
108124 throw("Match error")
109125 }
110126
111127 let assetNameB = match assetIdB {
112128 case id: ByteVector =>
113129 value(assetInfo(id)).name
114130 case waves: Unit =>
115131 "WAVES"
116132 case _ =>
117133 throw("Match error")
118134 }
119135
120-let balanceA = getIntegerValue(this, kBalanceA)
136+let balanceA = getIntegerValue(this, keyBalanceA)
121137
122-let balanceB = getIntegerValue(this, kBalanceB)
138+let balanceB = getIntegerValue(this, keyBalanceB)
123139
124-let shareAssetId = fromBase58String(getStringValue(this, kShareAssetId))
140+let shareAssetId = fromBase58String(getStringValue(this, keyShareAssetId))
125141
126-let shareAssetSupply = getIntegerValue(this, kShareAssetSupply)
142+let shareAssetSupply = getIntegerValue(this, keyShareAssetSupply)
127143
128-let invariant = getIntegerValue(this, kInvariant)
144+let commission = 3000
129145
130-let fee = 500
146+let commissionGovernance = 1200
131147
132-let feeGovernance = 200
148+let commissionScaleDelimiter = 1000000
133149
134-let feeScale6 = 1000000
150+let scaleValue3 = 1000
135151
136-let scale3 = 1000
152+let scaleValue8 = 100000000
137153
138-let scale8 = 100000000
154+let slippageToleranceDelimiter = 1000
139155
140-let scale12 = 1000000000000
141-
142-let slippageScale3 = 1000
143-
144-let digits8 = 8
145-
146-let dAppThreshold = 50
147-
148-let dAppThresholdScale2 = 100
149-
150-let exchangeRatioLimitMin = 90000000
151-
152-let exchangeRatioLimitMax = 110000000
153-
154-let alpha = 50
155-
156-let alphaDigits = 2
157-
158-let beta = 46000000
156+let scaleValue8Digits = 8
159157
160158 func accountBalance (assetId) = match assetId {
161159 case id: ByteVector =>
162160 assetBalance(this, id)
163161 case waves: Unit =>
164162 wavesBalance(this).available
165163 case _ =>
166164 throw("Match error")
167165 }
168166
169167
170-let stakedAmountUSDN = match getInteger(stakingAddress, ((("rpd_balance_" + toBase58String(USDN)) + "_") + toString(this))) {
171- case staked: Int =>
172- staked
173- case nothing: Unit =>
174- 0
175- case _ =>
176- throw("Match error")
177-}
168+func stakedAmount (assetId) = {
169+ let stakedAmountCalculated = match assetId {
170+ case aId: ByteVector =>
171+ if (if ((aId == USDN))
172+ then true
173+ else (aId == NSBT))
174+ then getInteger(stakingUSDNNSBTAddress, ((("rpd_balance_" + toBase58String(aId)) + "_") + toString(this)))
175+ else if ((aId == EURN))
176+ then getInteger(stakingEURNAddress, ((("%s%s%s__stakingBalance__" + toBase58String(aId)) + "__") + toString(this)))
177+ else 0
178+ case _: Unit =>
179+ 0
180+ case _ =>
181+ throw("Match error")
182+ }
183+ match stakedAmountCalculated {
184+ case i: Int =>
185+ i
186+ case _ =>
187+ 0
188+ }
189+ }
178190
179-let availableBalanceA = (balanceA - (if ((assetIdA == USDN))
180- then stakedAmountUSDN
181- else 0))
182191
183-let availableBalanceB = (balanceB - (if ((assetIdB == USDN))
184- then stakedAmountUSDN
185- else 0))
192+let stakedAmountA = stakedAmount(assetIdA)
186193
187-let accountBalanceWithStakedA = (accountBalance(assetIdA) + (if ((assetIdA == USDN))
188- then stakedAmountUSDN
189- else 0))
194+let stakedAmountB = stakedAmount(assetIdB)
190195
191-let accountBalanceWithStakedB = (accountBalance(assetIdB) + (if ((assetIdB == USDN))
192- then stakedAmountUSDN
193- else 0))
196+let assetInitA = getIntegerValue(this, keyBalanceInitA)
197+
198+let assetInitB = getIntegerValue(this, keyBalanceInitB)
199+
200+let availableBalanceA = (balanceA - stakedAmountA)
201+
202+let availableBalanceB = (balanceB - stakedAmountB)
203+
204+let accountBalanceWithStakedA = (accountBalance(assetIdA) + stakedAmountA)
205+
206+let accountBalanceWithStakedB = (accountBalance(assetIdB) + stakedAmountB)
194207
195208 let hasEnoughBalance = if ((accountBalanceWithStakedA >= balanceA))
196209 then (accountBalanceWithStakedB >= balanceB)
197210 else false
198-
199-func skewness (x,y) = (((fraction(scale12, x, y) + fraction(scale12, y, x)) / 2) / 10000)
200-
201-
202-func invariantCalc (x,y) = {
203- let sk = skewness(x, y)
204- (fraction((x + y), scale8, pow(sk, digits8, alpha, alphaDigits, digits8, CEILING)) + (2 * fraction(pow(fraction(x, y, scale8), 0, 5, 1, (digits8 / 2), DOWN), pow((sk - beta), digits8, alpha, alphaDigits, digits8, DOWN), scale8)))
205- }
206-
207-
208-func calculateSendAmount (amountToSendEstimated,minTokenReceiveAmount,tokenReceiveAmount,tokenId) = {
209- let slippageValue = (scale8 - ((scale8 * 1) / 10000000))
210- let deltaBetweenMaxAndMinSendValue = (amountToSendEstimated - minTokenReceiveAmount)
211- let x = (balanceA + tokenReceiveAmount)
212- let y = (balanceB + tokenReceiveAmount)
213- let invariantNew = if ((tokenId == assetIdA))
214- then invariantCalc(x, (balanceB - amountToSendEstimated))
215- else if ((tokenId == assetIdB))
216- then invariantCalc((balanceA - amountToSendEstimated), y)
217- else throw("Wrong asset in payment")
218- let invariantEstimatedRatio = fraction(scale8, invariant, invariantNew)
219- func getStepAmount (acc,step) = if ((acc == -1))
220- then {
221- let amountToSend = (amountToSendEstimated - ((step * deltaBetweenMaxAndMinSendValue) / 5))
222- let stepInvariant = if ((tokenId == assetIdA))
223- then invariantCalc(x, (balanceB - amountToSend))
224- else invariantCalc((balanceA - amountToSend), y)
225- if ((stepInvariant > invariant))
226- then amountToSend
227- else -1
228- }
229- else acc
230-
231- let stepAmount = {
232- let $list67186761 = [1, 2, 3, 4, 5]
233- let $size67186761 = size($list67186761)
234- let $acc067186761 = -1
235- if (($size67186761 == 0))
236- then $acc067186761
237- else {
238- let $acc167186761 = getStepAmount($acc067186761, $list67186761[0])
239- if (($size67186761 == 1))
240- then $acc167186761
241- else {
242- let $acc267186761 = getStepAmount($acc167186761, $list67186761[1])
243- if (($size67186761 == 2))
244- then $acc267186761
245- else {
246- let $acc367186761 = getStepAmount($acc267186761, $list67186761[2])
247- if (($size67186761 == 3))
248- then $acc367186761
249- else {
250- let $acc467186761 = getStepAmount($acc367186761, $list67186761[3])
251- if (($size67186761 == 4))
252- then $acc467186761
253- else {
254- let $acc567186761 = getStepAmount($acc467186761, $list67186761[4])
255- if (($size67186761 == 5))
256- then $acc567186761
257- else {
258- let $acc667186761 = getStepAmount($acc567186761, $list67186761[5])
259- throw("List size exceed 5")
260- }
261- }
262- }
263- }
264- }
265- }
266- }
267- if ((0 > stepAmount))
268- then throw("something went wrong while working with amountToSend")
269- else if (if ((invariantEstimatedRatio > slippageValue))
270- then (invariantNew > invariant)
271- else false)
272- then amountToSendEstimated
273- else stepAmount
274- }
275-
276211
277212 func getAssetInfo (assetId) = match assetId {
278213 case id: ByteVector =>
279214 let stringId = toBase58String(id)
280215 let info = valueOrErrorMessage(assetInfo(id), (("Asset " + stringId) + " doesn't exist"))
281216 $Tuple3(stringId, info.name, info.decimals)
282217 case waves: Unit =>
283218 $Tuple3("WAVES", "WAVES", 8)
284219 case _ =>
285220 throw("Match error")
286221 }
287222
288223
289-func suspend (cause) = [BooleanEntry(kActive, false), StringEntry(kCause, cause)]
224+func getAssetInfoFromString (assetStr) = if ((assetStr == "WAVES"))
225+ then $Tuple3("WAVES", "WAVES", 8)
226+ else {
227+ let stringId = assetStr
228+ let id = fromBase58String(assetStr)
229+ let info = valueOrErrorMessage(assetInfo(id), (("Asset " + stringId) + " doesn't exist"))
230+ $Tuple3(stringId, info.name, info.decimals)
231+ }
290232
291233
292-func deductStakingFee (amount,assetId) = if ((assetId == USDN))
234+func suspend (cause) = [BooleanEntry(keyActive, false), StringEntry(keyCause, cause)]
235+
236+
237+func deductStakingFee (amount,assetId,secondAssetId) = if (if ((assetId == USDN))
238+ then true
239+ else (assetId == EURN))
293240 then {
294- let result = (amount - stakingFeeInUSDN)
241+ let stakinFee = if ((assetId == USDN))
242+ then (stakingFeeInUSDN * (if ((secondAssetId == NSBT))
243+ then 2
244+ else 1))
245+ else if ((assetId == EURN))
246+ then stakingFeeInEURN
247+ else 0
248+ let result = (amount - stakinFee)
295249 if ((0 >= result))
296- then throw((((("Insufficient amount " + toString(amount)) + " to deduct staking fee ") + toString(stakingFeeInUSDN)) + " USD-N"))
250+ then throw((((("Insufficient amount " + toString(amount)) + " to deduct staking fee ") + toString(stakinFee)) + "USDN/EURN"))
297251 else result
298252 }
299253 else amount
300254
301255
302-func throwIsActive () = throw("DApp is already active")
303-
304-
305-func throwIsInactive () = throw("DApp is inactive at this moment")
306-
307-
308-func throwOnlyAdmin () = throw("Only admin can call this function")
309-
310-
311-func throwAssets () = throw(((("Incorrect assets attached. Expected: " + strAssetIdA) + " and ") + strAssetIdB))
312-
313-
314-func throwThreshold (threshold,amountA,amountB) = throw(((((((((("New balance in assets of the DApp is less than threshold " + toString(threshold)) + ": ") + toString(amountA)) + " ") + assetNameA) + ", ") + toString(amountB)) + " ") + assetNameB))
256+func getStakingFee (assetId,secondAssetId) = if ((assetId == USDN))
257+ then (stakingFeeInUSDN * (if ((secondAssetId == NSBT))
258+ then 2
259+ else 1))
260+ else if ((assetId == EURN))
261+ then stakingFeeInEURN
262+ else 0
315263
316264
317265 func throwInsufficientAvailableBalance (amount,available,assetName) = throw((((((((("Insufficient DApp balance to pay " + toString(amount)) + " ") + assetName) + " due to staking. Available: ") + toString(available)) + " ") + assetName) + ". Please contact support in Telegram: https://t.me/swopfisupport"))
318266
319267
320268 func throwInsufficientAvailableBalances (amountA,amountB) = throw((((((((((((((((("Insufficient DApp balance to pay " + toString(amountA)) + " ") + assetNameA) + " and ") + toString(amountB)) + " ") + assetNameB) + " due to staking. Available: ") + toString(availableBalanceA)) + " ") + assetNameA) + " and ") + toString(availableBalanceB)) + " ") + assetNameB) + ". Please contact support in Telegram: https://t.me/swopfisupport"))
321269
322270
323-func suspendSuspicious () = suspend(((((((((((((((("Suspicious state. Actual balances: " + toString(balanceA)) + " ") + assetNameA) + ", ") + toString(balanceB)) + " ") + assetNameB) + ". State: ") + toString(accountBalance(assetIdA))) + " ") + assetNameA) + ", ") + toString(accountBalance(assetIdB))) + " ") + assetNameB))
271+func suspendSuspicious () = suspend(((((((((((((((("Suspicious state. Actual balances: " + toString(accountBalanceWithStakedA)) + " ") + assetNameA) + ", ") + toString(accountBalanceWithStakedB)) + " ") + assetNameB) + ". State: ") + toString(balanceA)) + " ") + assetNameA) + ", ") + toString(balanceB)) + " ") + assetNameB))
324272
325273
326274 @Callable(i)
327275 func init (firstHarvest) = {
328- let $t094589535 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
329- let pmtAmountA = $t094589535._1
330- let pmtAssetIdA = $t094589535._2
331- let $t095409617 = $Tuple2(i.payments[1].amount, i.payments[1].assetId)
332- let pmtAmountB = $t095409617._1
333- let pmtAssetIdB = $t095409617._2
334- let $t096229699 = getAssetInfo(pmtAssetIdA)
335- let pmtStrAssetIdA = $t096229699._1
336- let pmtAssetNameA = $t096229699._2
337- let pmtDecimalsA = $t096229699._3
338- let $t097049781 = getAssetInfo(pmtAssetIdB)
339- let pmtStrAssetIdB = $t097049781._1
340- let pmtAssetNameB = $t097049781._2
341- let pmtDecimalsB = $t097049781._3
342- if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStaking], i.callerPublicKey)))
276+ let $t080008077 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
277+ let pmtAmountA = $t080008077._1
278+ let pmtAssetIdA = $t080008077._2
279+ let $t080828159 = $Tuple2(i.payments[1].amount, i.payments[1].assetId)
280+ let pmtAmountB = $t080828159._1
281+ let pmtAssetIdB = $t080828159._2
282+ let $t081648241 = getAssetInfo(pmtAssetIdA)
283+ let pmtStrAssetIdA = $t081648241._1
284+ let pmtAssetNameA = $t081648241._2
285+ let pmtDecimalsA = $t081648241._3
286+ let $t082468323 = getAssetInfo(pmtAssetIdB)
287+ let pmtStrAssetIdB = $t082468323._1
288+ let pmtAssetNameB = $t082468323._2
289+ let pmtDecimalsB = $t082468323._3
290+ if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStaking], i.callerPublicKey)))
343291 then throw("Only admin can call this function")
344- else if (isDefined(getBoolean(this, kActive)))
345- then throwIsActive()
292+ else if (isDefined(getBoolean(this, keyActive)))
293+ then throw("DApp is already active")
346294 else if ((pmtAssetIdA == pmtAssetIdB))
347295 then throw("Assets must be different")
348296 else {
349297 let shareName = ((("s" + take(pmtAssetNameA, 7)) + "_") + take(pmtAssetNameB, 7))
350298 let shareDescription = ((((("ShareToken of SwopFi protocol for " + pmtAssetNameA) + " and ") + pmtAssetNameB) + " at address ") + toString(this))
351299 let shareDecimals = ((pmtDecimalsA + pmtDecimalsB) / 2)
352- let shareInitialSupply = fraction(pow(pmtAmountA, pmtDecimalsA, 5, 1, pmtDecimalsA, DOWN), pow(pmtAmountB, pmtDecimalsB, 5, 1, pmtDecimalsB, DOWN), pow(10, 0, shareDecimals, 0, 0, DOWN))
300+ let arg1 = pow(pmtAmountA, pmtDecimalsA, 5, 1, pmtDecimalsA, DOWN)
301+ let arg2 = pow(pmtAmountB, pmtDecimalsB, 5, 1, pmtDecimalsB, DOWN)
302+ let arg3 = pow(10, 0, shareDecimals, 0, 0, DOWN)
303+ let shareInitialSupply = fraction(arg1, arg2, arg3)
353304 let shareIssue = Issue(shareName, shareDescription, shareInitialSupply, shareDecimals, true)
354305 let shareIssueId = calculateAssetId(shareIssue)
355- let invariantCalculated = invariantCalc(pmtAmountA, pmtAmountB)
356- let baseEntry = [StringEntry(kVersion, version), BooleanEntry(kActive, true), StringEntry(kAssetIdA, pmtStrAssetIdA), StringEntry(kAssetIdB, pmtStrAssetIdB), IntegerEntry(kBalanceA, pmtAmountA), IntegerEntry(kBalanceB, pmtAmountB), IntegerEntry(kInvariant, invariantCalculated), IntegerEntry(kFee, fee), IntegerEntry(kFeeScaleDelimiter, feeScale6), shareIssue, StringEntry(kShareAssetId, toBase58String(shareIssueId)), IntegerEntry(kShareAssetSupply, shareInitialSupply), ScriptTransfer(i.caller, shareInitialSupply, shareIssueId)]
306+ let baseEntry = [StringEntry(keyVersion, version), BooleanEntry(keyActive, true), StringEntry(keyAssetIdA, pmtStrAssetIdA), StringEntry(keyAssetIdB, pmtStrAssetIdB), IntegerEntry(keyBalanceA, pmtAmountA), IntegerEntry(keyBalanceB, pmtAmountB), IntegerEntry(keyCommission, commission), IntegerEntry(keyCommissionScaleDelimiter, commissionScaleDelimiter), shareIssue, StringEntry(keyShareAssetId, toBase58String(shareIssueId)), IntegerEntry(keyShareAssetSupply, shareInitialSupply), ScriptTransfer(i.caller, shareInitialSupply, shareIssueId)]
357307 if (firstHarvest)
358- then (baseEntry ++ [BooleanEntry(kFirstHarvest, firstHarvest), IntegerEntry(kFirstHarvestHeight, (startHeight + (firstHarvestEndPeriod * periodLength)))])
308+ then (baseEntry ++ [BooleanEntry(keyFirstHarvest, firstHarvest), IntegerEntry(keyFirstHarvestHeight, (startHeight + (firstHarvestEndPeriod * periodLength)))])
359309 else baseEntry
360310 }
361311 }
362312
363313
364314
365315 @Callable(i)
366-func replenishWithTwoTokens (slippageTolerance) = {
367- let pmtAssetIdA = i.payments[0].assetId
368- let pmtAssetIdB = i.payments[1].assetId
369- let pmtAmountA = deductStakingFee(i.payments[0].amount, pmtAssetIdA)
370- let pmtAmountB = deductStakingFee(i.payments[1].amount, pmtAssetIdB)
371- let tokenRatio = fraction(fraction(scale8, balanceA, pmtAmountA), scale3, fraction(scale8, balanceB, pmtAmountB))
372- let ratioShareTokensInA = fraction(scale8, pmtAmountA, balanceA)
373- let ratioShareTokensInB = fraction(scale8, pmtAmountB, balanceB)
374- let shareTokenToPayAmount = fraction(min([ratioShareTokensInA, ratioShareTokensInB]), shareAssetSupply, scale8)
375- let invariantCalculated = invariantCalc((balanceA + pmtAmountA), (balanceB + pmtAmountB))
376- if (!(isActive))
377- then throwIsInactive()
378- else if (if ((0 > slippageTolerance))
379- then true
380- else (slippageTolerance > 10))
381- then throw("Slippage tolerance must be <= 1%")
382- else if ((size(i.payments) != 2))
383- then throw("Two attached assets expected")
384- else if (if ((pmtAssetIdA != assetIdA))
385- then true
386- else (pmtAssetIdB != assetIdB))
387- then throwAssets()
388- else if (if ((((scale3 * (slippageScale3 - slippageTolerance)) / slippageScale3) > tokenRatio))
389- then true
390- else (tokenRatio > ((scale3 * (slippageScale3 + slippageTolerance)) / slippageScale3)))
391- then throw("Incorrect assets amount: amounts must have the contract ratio")
392- else if ((shareTokenToPayAmount == 0))
393- then throw("Too small amount to replenish")
394- else if (!(hasEnoughBalance))
395- then ([ScriptTransfer(i.caller, pmtAmountA, pmtAssetIdA), ScriptTransfer(i.caller, pmtAmountB, pmtAssetIdB)] ++ suspendSuspicious())
396- else [IntegerEntry(kBalanceA, (balanceA + pmtAmountA)), IntegerEntry(kBalanceB, (balanceB + pmtAmountB)), IntegerEntry(kShareAssetSupply, (shareAssetSupply + shareTokenToPayAmount)), IntegerEntry(kInvariant, invariantCalculated), Reissue(shareAssetId, shareTokenToPayAmount, true), ScriptTransfer(i.caller, shareTokenToPayAmount, shareAssetId)]
316+func initWithInitRatio (amtAssetA,amtAssetB,strAssetIdA,strAssetIdB,firstHarvest) = {
317+ let $t01056810655 = getAssetInfoFromString(strAssetIdA)
318+ let pmtStrAssetIdA = $t01056810655._1
319+ let pmtAssetNameA = $t01056810655._2
320+ let pmtDecimalsA = $t01056810655._3
321+ let $t01066010747 = getAssetInfoFromString(strAssetIdB)
322+ let pmtStrAssetIdB = $t01066010747._1
323+ let pmtAssetNameB = $t01066010747._2
324+ let pmtDecimalsB = $t01066010747._3
325+ if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStaking], i.callerPublicKey)))
326+ then throw("Only admin can call this function")
327+ else if (isDefined(getBoolean(this, keyActive)))
328+ then throw("DApp is already active")
329+ else if ((strAssetIdA == strAssetIdB))
330+ then throw("Assets must be different")
331+ else {
332+ let shareName = ((("s" + take(pmtAssetNameA, 7)) + "_") + take(pmtAssetNameB, 7))
333+ let shareDescription = ((((("ShareToken of SwopFi protocol for " + pmtAssetNameA) + " and ") + pmtAssetNameB) + " at address ") + toString(this))
334+ let shareDecimals = ((pmtDecimalsA + pmtDecimalsB) / 2)
335+ let shareInitialSupply = 0
336+ let shareIssue = Issue(shareName, shareDescription, shareInitialSupply, shareDecimals, true)
337+ let shareIssueId = calculateAssetId(shareIssue)
338+ let baseEntry = [StringEntry(keyVersion, version), BooleanEntry(keyActive, true), StringEntry(keyAssetIdA, pmtStrAssetIdA), StringEntry(keyAssetIdB, pmtStrAssetIdB), IntegerEntry(keyBalanceInitA, amtAssetA), IntegerEntry(keyBalanceInitB, amtAssetB), IntegerEntry(keyBalanceA, 0), IntegerEntry(keyBalanceB, 0), IntegerEntry(keyCommission, commission), IntegerEntry(keyCommissionScaleDelimiter, commissionScaleDelimiter), shareIssue, StringEntry(keyShareAssetId, toBase58String(shareIssueId)), IntegerEntry(keyShareAssetSupply, shareInitialSupply)]
339+ if (firstHarvest)
340+ then (baseEntry ++ [BooleanEntry(keyFirstHarvest, firstHarvest), IntegerEntry(keyFirstHarvestHeight, (startHeight + (firstHarvestEndPeriod * periodLength)))])
341+ else baseEntry
342+ }
397343 }
398344
399345
400346
401347 @Callable(i)
402-func replenishWithOneToken (virtualSwapTokenPay,virtualSwapTokenGet) = {
403- let $t01458314658 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
404- let pmtAmount = $t01458314658._1
405- let pmtAssetId = $t01458314658._2
406- let pmtMinThreshold = 5000000
407- let thresholdValueForMinTolerance = 50000000
408- let tolerance = if ((thresholdValueForMinTolerance > pmtAmount))
409- then 100000
410- else 1
411- let slippageValueMinForReplenish = (scale8 - ((scale8 * tolerance) / 10000000))
412- let slippageValueMaxForReplenish = (scale8 + ((scale8 * tolerance) / 10000000))
413- let slippageValueMinForSwap = (scale8 - ((scale8 * 1) / 10000000))
414- if (!(isActive))
415- then throwIsInactive()
416- else if ((pmtMinThreshold > pmtAmount))
417- then throw((((("Payment amount " + toString(pmtAmount)) + " does not exceed the minimum amount of ") + toString(pmtMinThreshold)) + " tokens"))
418- else if ((size(i.payments) != 1))
419- then throw("One attached payment expected")
420- else if (!(hasEnoughBalance))
421- then ([ScriptTransfer(i.caller, pmtAmount, pmtAssetId)] ++ suspendSuspicious())
422- else if (if ((pmtAssetId != assetIdA))
423- then (pmtAssetId != assetIdB)
424- else false)
425- then throwAssets()
426- else {
427- let $t01567016435 = if ((pmtAssetId == assetIdA))
428- then $Tuple7((pmtAmount - virtualSwapTokenPay), virtualSwapTokenGet, (balanceA + virtualSwapTokenPay), (balanceB - virtualSwapTokenGet), invariantCalc((balanceA + pmtAmount), balanceB), (balanceA + pmtAmount), balanceB)
429- else $Tuple7(virtualSwapTokenGet, (pmtAmount - virtualSwapTokenPay), (balanceA - virtualSwapTokenGet), (balanceB + virtualSwapTokenPay), invariantCalc(balanceA, (balanceB + pmtAmount)), balanceA, (balanceB + pmtAmount))
430- let virtualReplenishA = $t01567016435._1
431- let virtualReplenishB = $t01567016435._2
432- let balanceAfterSwapA = $t01567016435._3
433- let balanceAfterSwapB = $t01567016435._4
434- let invariantCalculated = $t01567016435._5
435- let newBalanceA = $t01567016435._6
436- let newBalanceB = $t01567016435._7
437- let newBalanceEntry = if ((pmtAssetId == assetIdA))
438- then IntegerEntry(kBalanceA, newBalanceA)
439- else IntegerEntry(kBalanceB, newBalanceB)
440- let invariantNew = invariantCalc(balanceAfterSwapA, balanceAfterSwapB)
441- let invariantEstimatedRatio = fraction(scale8, invariant, invariantNew)
442- let ratioVirtualBalanceToVirtualReplenish = (fraction((scale8 * scale8), balanceAfterSwapA, balanceAfterSwapB) / fraction(scale8, virtualReplenishA, virtualReplenishB))
443- let dAppThresholdAmount = fraction((newBalanceA + newBalanceB), dAppThreshold, (2 * dAppThresholdScale2))
444- if (if ((slippageValueMinForSwap >= invariantEstimatedRatio))
348+func keepLimitForFirstHarvest (shareLimit) = if (!(isActive))
349+ then throw("DApp is inactive at this moment")
350+ else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStaking], i.callerPublicKey)))
351+ then throw("Only admin can call this function")
352+ else [IntegerEntry(kShareLimit, shareLimit)]
353+
354+
355+
356+@Callable(i)
357+func replenishWithTwoTokens (slippageTolerance) = {
358+ let pmtAssetIdA = i.payments[0].assetId
359+ let pmtAssetIdB = i.payments[1].assetId
360+ let pmtAmountA = deductStakingFee(i.payments[0].amount, pmtAssetIdA, pmtAssetIdB)
361+ let pmtAmountB = deductStakingFee(i.payments[1].amount, pmtAssetIdB, pmtAssetIdA)
362+ if (if ((balanceA == 0))
363+ then (balanceB == 0)
364+ else false)
365+ then {
366+ let $t01345813535 = getAssetInfo(pmtAssetIdA)
367+ let pmtStrAssetIdA = $t01345813535._1
368+ let pmtAssetNameA = $t01345813535._2
369+ let pmtDecimalsA = $t01345813535._3
370+ let $t01354413621 = getAssetInfo(pmtAssetIdB)
371+ let pmtStrAssetIdB = $t01354413621._1
372+ let pmtAssetNameB = $t01354413621._2
373+ let pmtDecimalsB = $t01354413621._3
374+ let tokenRatio = fraction(fraction(assetInitA, scaleValue8, pmtAmountA), scaleValue3, fraction(assetInitB, scaleValue8, pmtAmountB))
375+ if ((pmtAssetIdA == pmtAssetIdB))
376+ then throw("Assets must be different")
377+ else {
378+ let shareDecimals = ((pmtDecimalsA + pmtDecimalsB) / 2)
379+ let shareInitialSupply = fraction(pow(pmtAmountA, pmtDecimalsA, 5, 1, pmtDecimalsA, DOWN), pow(pmtAmountB, pmtDecimalsB, 5, 1, pmtDecimalsB, DOWN), pow(10, 0, shareDecimals, 0, 0, DOWN))
380+ if (!(isActive))
381+ then throw("DApp is inactive at this moment")
382+ else if (if ((0 > slippageTolerance))
383+ then true
384+ else (slippageTolerance > slippageToleranceDelimiter))
385+ then throw(((("Slippage tolerance must be between 0 and " + toString(slippageToleranceDelimiter)) + " inclusively. Actual: ") + toString(slippageTolerance)))
386+ else if ((size(i.payments) != 2))
387+ then throw("Two attached assets expected")
388+ else if (if ((((scaleValue3 * (slippageToleranceDelimiter - slippageTolerance)) / slippageToleranceDelimiter) > tokenRatio))
389+ then true
390+ else (tokenRatio > ((scaleValue3 * (slippageToleranceDelimiter + slippageTolerance)) / slippageToleranceDelimiter)))
391+ then throw("Incorrect assets amount: amounts must have the contract ratio")
392+ else if (if ((pmtAssetIdA != assetIdA))
393+ then true
394+ else (pmtAssetIdB != assetIdB))
395+ then throw(((("Incorrect assets attached. Expected: " + strAssetIdA) + " and ") + strAssetIdB))
396+ else if ((shareInitialSupply == 0))
397+ then throw("Too small amount to replenish")
398+ else if (!(hasEnoughBalance))
399+ then ([ScriptTransfer(i.caller, pmtAmountA, pmtAssetIdA), ScriptTransfer(i.caller, pmtAmountB, pmtAssetIdB)] ++ suspendSuspicious())
400+ else [Reissue(shareAssetId, shareInitialSupply, true), IntegerEntry(keyBalanceA, pmtAmountA), IntegerEntry(keyBalanceB, pmtAmountB), IntegerEntry(keyShareAssetSupply, shareInitialSupply), ScriptTransfer(i.caller, shareInitialSupply, shareAssetId)]
401+ }
402+ }
403+ else {
404+ let tokenRatio = fraction(fraction(balanceA, scaleValue8, pmtAmountA), scaleValue3, fraction(balanceB, scaleValue8, pmtAmountB))
405+ let ratioShareTokensInA = fraction(pmtAmountA, scaleValue8, balanceA)
406+ let ratioShareTokensInB = fraction(pmtAmountB, scaleValue8, balanceB)
407+ let shareTokenToPayAmount = fraction(min([ratioShareTokensInA, ratioShareTokensInB]), shareAssetSupply, scaleValue8)
408+ if (!(isActive))
409+ then throw("DApp is inactive at this moment")
410+ else if (if ((0 > slippageTolerance))
411+ then true
412+ else (slippageTolerance > slippageToleranceDelimiter))
413+ then throw(((("Slippage tolerance must be between 0 and " + toString(slippageToleranceDelimiter)) + " inclusively. Actual: ") + toString(slippageTolerance)))
414+ else if ((size(i.payments) != 2))
415+ then throw("Two attached assets expected")
416+ else if (if ((pmtAssetIdA != assetIdA))
417+ then true
418+ else (pmtAssetIdB != assetIdB))
419+ then throw(((("Incorrect assets attached. Expected: " + strAssetIdA) + " and ") + strAssetIdB))
420+ else if (if ((((scaleValue3 * (slippageToleranceDelimiter - slippageTolerance)) / slippageToleranceDelimiter) > tokenRatio))
445421 then true
446- else (invariant > invariantNew))
447- then throw("Incorrect virtualSwapTokenPay or virtualSwapTokenGet value")
448- else if (if ((slippageValueMinForReplenish > ratioVirtualBalanceToVirtualReplenish))
449- then true
450- else (ratioVirtualBalanceToVirtualReplenish > slippageValueMaxForReplenish))
451- then throw("Swap with virtualSwapTokenPay and virtualSwapTokenGet is possible, but ratio after virtual swap is incorrect")
452- else if (if ((dAppThresholdAmount > newBalanceA))
453- then true
454- else (dAppThresholdAmount > newBalanceB))
455- then throwThreshold(dAppThresholdAmount, newBalanceA, newBalanceB)
456- else {
457- let ratioShareTokensInA = fraction(deductStakingFee(virtualReplenishA, assetIdA), scale8, balanceAfterSwapA)
458- let ratioShareTokensInB = fraction(deductStakingFee(virtualReplenishB, assetIdB), scale8, balanceAfterSwapB)
459- let shareTokenToPayAmount = fraction(min([ratioShareTokensInA, ratioShareTokensInB]), shareAssetSupply, scale8)
460-[Reissue(shareAssetId, shareTokenToPayAmount, true), ScriptTransfer(i.caller, shareTokenToPayAmount, shareAssetId), IntegerEntry(kShareAssetSupply, (shareAssetSupply + shareTokenToPayAmount)), newBalanceEntry, IntegerEntry(kInvariant, invariantCalculated)]
461- }
462- }
422+ else (tokenRatio > ((scaleValue3 * (slippageToleranceDelimiter + slippageTolerance)) / slippageToleranceDelimiter)))
423+ then throw("Incorrect assets amount: amounts must have the contract ratio")
424+ else if ((shareTokenToPayAmount == 0))
425+ then throw("Too small amount to replenish")
426+ else if (!(hasEnoughBalance))
427+ then ([ScriptTransfer(i.caller, pmtAmountA, pmtAssetIdA), ScriptTransfer(i.caller, pmtAmountB, pmtAssetIdB)] ++ suspendSuspicious())
428+ else [IntegerEntry(keyBalanceA, (balanceA + pmtAmountA)), IntegerEntry(keyBalanceB, (balanceB + pmtAmountB)), IntegerEntry(keyShareAssetSupply, (shareAssetSupply + shareTokenToPayAmount)), Reissue(shareAssetId, shareTokenToPayAmount, true), ScriptTransfer(i.caller, shareTokenToPayAmount, shareAssetId)]
429+ }
463430 }
464431
465432
466433
467434 @Callable(i)
468435 func withdraw () = {
469- let $t01858018723 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
470- let pmtAmount = $t01858018723._1
471- let pmtAssetId = $t01858018723._2
472- let amountToPayA = deductStakingFee(fraction(pmtAmount, balanceA, shareAssetSupply), assetIdA)
473- let amountToPayB = deductStakingFee(fraction(pmtAmount, balanceB, shareAssetSupply), assetIdB)
474- let invariantCalculated = invariantCalc((balanceA - amountToPayA), (balanceB - amountToPayB))
436+ let $t01802018170 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
437+ let pmtAmount = $t01802018170._1
438+ let pmtAssetId = $t01802018170._2
439+ let amountToPayA = deductStakingFee(fraction(pmtAmount, balanceA, shareAssetSupply), assetIdA, assetIdB)
440+ let amountToPayB = deductStakingFee(fraction(pmtAmount, balanceB, shareAssetSupply), assetIdB, assetIdA)
475441 if (!(isActive))
476- then throwIsInactive()
442+ then throw("DApp is inactive at this moment")
477443 else if ((size(i.payments) != 1))
478444 then throw("One attached payment expected")
479445 else if ((pmtAssetId != shareAssetId))
480446 then throw(("Incorrect asset attached. Expected: " + toBase58String(shareAssetId)))
481447 else if (!(hasEnoughBalance))
482448 then ([ScriptTransfer(i.caller, pmtAmount, pmtAssetId)] ++ suspendSuspicious())
483449 else if (if ((amountToPayA > availableBalanceA))
484450 then true
485451 else (amountToPayB > availableBalanceB))
486452 then throwInsufficientAvailableBalances(amountToPayA, amountToPayB)
487- else [IntegerEntry(kBalanceA, (balanceA - amountToPayA)), IntegerEntry(kBalanceB, (balanceB - amountToPayB)), IntegerEntry(kShareAssetSupply, (shareAssetSupply - pmtAmount)), IntegerEntry(kInvariant, invariantCalculated), Burn(shareAssetId, pmtAmount), ScriptTransfer(i.caller, amountToPayA, assetIdA), ScriptTransfer(i.caller, amountToPayB, assetIdB)]
453+ else [IntegerEntry(keyBalanceA, (balanceA - amountToPayA)), IntegerEntry(keyBalanceB, (balanceB - amountToPayB)), IntegerEntry(keyShareAssetSupply, (shareAssetSupply - pmtAmount)), Burn(shareAssetId, pmtAmount), ScriptTransfer(i.caller, amountToPayA, assetIdA), ScriptTransfer(i.caller, amountToPayB, assetIdB)]
488454 }
489455
490456
491457
492458 @Callable(i)
493-func exchange (estimatedAmountToReceive,minAmountToReceive) = {
494- let $t02008120156 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
495- let pmtAmount = $t02008120156._1
496- let pmtAssetId = $t02008120156._2
459+func exchange (minAmountToReceive) = {
460+ let $t01939619471 = $Tuple2(i.payments[0].amount, i.payments[0].assetId)
461+ let pmtAmount = $t01939619471._1
462+ let pmtAssetId = $t01939619471._2
463+ func calculateFees (tokenFrom,tokenTo) = {
464+ let amountWithoutFee = fraction(tokenTo, pmtAmount, (pmtAmount + tokenFrom))
465+ let amountWithFee = fraction(amountWithoutFee, (commissionScaleDelimiter - commission), commissionScaleDelimiter)
466+ let governanceReward = fraction(amountWithoutFee, commissionGovernance, commissionScaleDelimiter)
467+ if ((minAmountToReceive > amountWithFee))
468+ then throw(((("Calculated amount to receive " + toString(amountWithFee)) + " is less than specified minimum ") + toString(minAmountToReceive)))
469+ else $Tuple3(amountWithoutFee, amountWithFee, governanceReward)
470+ }
471+
497472 if (!(isActive))
498- then throwIsInactive()
499- else if ((0 >= estimatedAmountToReceive))
500- then throw(("Estimated amount must be positive. Actual: " + toString(estimatedAmountToReceive)))
501- else if ((minAmountToReceive > estimatedAmountToReceive))
502- then throw(((("Minimal amount can't be greater than estimated. Estimated: " + toString(estimatedAmountToReceive)) + ". Minimal: ") + toString(minAmountToReceive)))
473+ then throw("DApp is inactive at this moment")
474+ else if (if ((balanceA == 0))
475+ then true
476+ else (balanceB == 0))
477+ then throw("Can't exchange with zero balance")
478+ else if ((0 >= minAmountToReceive))
479+ then throw(("Minimal amount to receive must be positive. Actual: " + toString(minAmountToReceive)))
503480 else if ((size(i.payments) != 1))
504481 then throw("One attached payment expected")
505482 else if (!(hasEnoughBalance))
506483 then ([ScriptTransfer(i.caller, pmtAmount, pmtAssetId)] ++ suspendSuspicious())
507- else if (if ((pmtAssetId != assetIdA))
508- then (pmtAssetId != assetIdB)
509- else false)
510- then throwAssets()
511- else if ((10000000 > pmtAmount))
512- then throw("Only swap of 10.000000 or more tokens is allowed")
513- else if (if ((exchangeRatioLimitMin > fraction(scale8, minAmountToReceive, pmtAmount)))
484+ else if ((pmtAssetId == assetIdA))
485+ then {
486+ let assetIdSend = assetIdB
487+ let $t02074520836 = calculateFees(balanceA, balanceB)
488+ let amountWithoutFee = $t02074520836._1
489+ let amountWithFee = $t02074520836._2
490+ let governanceReward = $t02074520836._3
491+ let newBalanceA = (balanceA + pmtAmount)
492+ let newBalanceB = ((balanceB - amountWithFee) - governanceReward)
493+ if (if ((stakedAmountA >= newBalanceA))
514494 then true
515- else (fraction(scale8, estimatedAmountToReceive, pmtAmount) > exchangeRatioLimitMax))
516- then throw("Incorrect args and pmt ratio")
517- else {
518- let sendAssetId = if ((pmtAssetId == assetIdA))
519- then assetIdB
520- else assetIdA
521- let amount = calculateSendAmount(estimatedAmountToReceive, minAmountToReceive, pmtAmount, pmtAssetId)
522- let governanceReward = fraction(amount, feeGovernance, feeScale6)
523- let amountMinusFee = fraction(amount, (feeScale6 - fee), feeScale6)
524- let $t02157821840 = if ((pmtAssetId == assetIdA))
525- then $Tuple2((balanceA + pmtAmount), ((balanceB - amountMinusFee) - governanceReward))
526- else $Tuple2(((balanceA - amountMinusFee) - governanceReward), (balanceB + pmtAmount))
527- let newBalanceA = $t02157821840._1
528- let newBalanceB = $t02157821840._2
529- let dAppThresholdAmount = fraction((newBalanceA + newBalanceB), dAppThreshold, (2 * dAppThresholdScale2))
530- if (if ((dAppThresholdAmount > newBalanceA))
531- then true
532- else (dAppThresholdAmount > newBalanceB))
533- then throwThreshold(dAppThresholdAmount, newBalanceA, newBalanceB)
534- else if (if (if ((assetIdA == USDN))
535- then (sendAssetId == assetIdA)
536- else false)
537- then (stakedAmountUSDN >= newBalanceA)
538- else false)
539- then throwInsufficientAvailableBalance(amountMinusFee, availableBalanceA, assetNameA)
540- else if (if (if ((assetIdB == USDN))
541- then (sendAssetId == assetIdB)
542- else false)
543- then (stakedAmountUSDN >= newBalanceB)
544- else false)
545- then throwInsufficientAvailableBalance(amountMinusFee, availableBalanceB, assetNameB)
546- else [IntegerEntry(kBalanceA, newBalanceA), IntegerEntry(kBalanceB, newBalanceB), IntegerEntry(kInvariant, invariantCalc(newBalanceA, newBalanceB)), ScriptTransfer(i.caller, amountMinusFee, sendAssetId), ScriptTransfer(govAddr, governanceReward, sendAssetId)]
547- }
495+ else (stakedAmountB >= newBalanceB))
496+ then throwInsufficientAvailableBalance(amountWithFee, availableBalanceB, assetNameB)
497+ else [IntegerEntry(keyBalanceA, newBalanceA), IntegerEntry(keyBalanceB, newBalanceB), ScriptTransfer(i.caller, amountWithFee, assetIdSend), ScriptTransfer(walletAddress, governanceReward, assetIdSend)]
498+ }
499+ else if ((pmtAssetId == assetIdB))
500+ then {
501+ let assetIdSend = assetIdA
502+ let $t02165521746 = calculateFees(balanceB, balanceA)
503+ let amountWithoutFee = $t02165521746._1
504+ let amountWithFee = $t02165521746._2
505+ let governanceReward = $t02165521746._3
506+ let newBalanceA = ((balanceA - amountWithFee) - governanceReward)
507+ let newBalanceB = (balanceB + pmtAmount)
508+ if (if ((stakedAmountA >= newBalanceA))
509+ then true
510+ else (stakedAmountB >= newBalanceB))
511+ then throwInsufficientAvailableBalance(amountWithFee, availableBalanceA, assetNameA)
512+ else [IntegerEntry(keyBalanceA, newBalanceA), IntegerEntry(keyBalanceB, newBalanceB), ScriptTransfer(i.caller, amountWithFee, assetIdSend), ScriptTransfer(walletAddress, governanceReward, assetIdSend)]
513+ }
514+ else throw(((("Incorrect asset attached. Expected: " + strAssetIdA) + " or ") + strAssetIdB))
548515 }
549516
550517
551518
552519 @Callable(i)
553520 func shutdown () = if (!(isActive))
554- then throw(("DApp is already suspended. Cause: " + valueOrElse(getString(this, kCause), "the cause wasn't specified")))
555- else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStartStop], i.callerPublicKey)))
556- then throwOnlyAdmin()
521+ then throw(("DApp is already suspended. Cause: " + valueOrElse(getString(this, keyCause), "the cause wasn't specified")))
522+ else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStartStop], i.callerPublicKey)))
523+ then throw("Only admin can call this function")
557524 else suspend("Paused by admin")
558525
559526
560527
561528 @Callable(i)
562529 func activate () = if (isActive)
563- then throwIsActive()
564- else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStartStop], i.callerPublicKey)))
565- then throwOnlyAdmin()
566- else [BooleanEntry(kActive, true), DeleteEntry(kCause)]
530+ then throw("DApp is already active")
531+ else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, adminPubKeyStartStop], i.callerPublicKey)))
532+ then throw("Only admin can call this function")
533+ else [BooleanEntry(keyActive, true), DeleteEntry(keyCause)]
567534
568535
569536
570537 @Callable(i)
571538 func takeIntoAccountExtraFunds (amountLeave) = {
572- let uncountableA = (accountBalanceWithStakedA - balanceA)
573- let uncountableB = (accountBalanceWithStakedB - balanceB)
574- let amountEnrollA = (uncountableA - (if ((assetIdA == unit))
539+ let uncountableAmountEnrollAssetA = (accountBalanceWithStakedA - balanceA)
540+ let uncountableAmountEnrollAssetB = (accountBalanceWithStakedB - balanceB)
541+ let amountEnrollA = (uncountableAmountEnrollAssetA - (if ((assetIdA == unit))
575542 then amountLeave
576543 else 0))
577- let amountEnrollB = (uncountableB - (if ((assetIdB == unit))
544+ let amountEnrollB = (uncountableAmountEnrollAssetB - (if ((assetIdB == unit))
578545 then amountLeave
579546 else 0))
580- let invariantNew = invariantCalc((balanceA + amountEnrollA), (balanceB + amountEnrollB))
581547 if (!(isActive))
582- then throwIsInactive()
548+ then throw("DApp is inactive at this moment")
583549 else if ((i.caller != this))
584- then throwOnlyAdmin()
550+ then throw("Only the DApp itself can call this function")
585551 else if ((0 > amountLeave))
586552 then throw(("Argument 'amountLeave' cannot be negative. Actual: " + toString(amountLeave)))
587- else if (if ((0 > uncountableA))
553+ else if (if ((0 > uncountableAmountEnrollAssetA))
588554 then true
589- else (0 > uncountableB))
555+ else (0 > uncountableAmountEnrollAssetB))
590556 then suspend("Enroll amount negative")
591557 else if (if ((0 > amountEnrollA))
592558 then true
593559 else (0 > amountEnrollB))
594560 then throw("Too large amountLeave")
595- else [IntegerEntry(kInvariant, invariantNew), IntegerEntry(kBalanceA, (balanceA + amountEnrollA)), IntegerEntry(kBalanceB, (balanceB + amountEnrollB)), IntegerEntry(("last_income_" + strAssetIdA), amountEnrollA), IntegerEntry(("last_income_" + strAssetIdB), amountEnrollB)]
561+ else [IntegerEntry(keyBalanceA, (balanceA + amountEnrollA)), IntegerEntry(keyBalanceB, (balanceB + amountEnrollB)), IntegerEntry(("last_income_" + strAssetIdA), amountEnrollA), IntegerEntry(("last_income_" + strAssetIdB), amountEnrollB)]
596562 }
597-
598-
599-
600-@Callable(i)
601-func keepLimitForFirstHarvest (shareLimit) = if (!(isActive))
602- then throw("DApp is inactive at this moment")
603- else if (!(containsElement([adminPubKey1, adminPubKey2, adminPubKey3, admStaking], i.callerPublicKey)))
604- then throw("Only admin can call this function")
605- else [IntegerEntry(kShareLimit, shareLimit)]
606563
607564
608565 @Verifier(tx)
609566 func verify () = {
610567 let multiSignedByAdmins = {
611568 let adminPubKey1Signed = if (sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKey1))
612569 then 1
613570 else 0
614571 let adminPubKey2Signed = if (sigVerify(tx.bodyBytes, tx.proofs[1], adminPubKey2))
615572 then 1
616573 else 0
617574 let adminPubKey3Signed = if (sigVerify(tx.bodyBytes, tx.proofs[2], adminPubKey3))
618575 then 1
619576 else 0
620577 (((adminPubKey1Signed + adminPubKey2Signed) + adminPubKey3Signed) >= 2)
621578 }
622579 match tx {
623580 case inv: InvokeScriptTransaction =>
624581 let callTakeIntoAccount = if ((inv.dApp == this))
625582 then (inv.function == "takeIntoAccountExtraFunds")
626583 else false
627- let callStaking = if ((inv.dApp == stakingAddress))
628- then if (if (if ((inv.function == "lockNeutrino"))
584+ let callStaking = if (if ((inv.dApp == stakingUSDNNSBTAddress))
585+ then if (if (if (containsElement(["lockNeutrino", "lockNsbt"], inv.function))
629586 then (size(inv.payments) == 1)
630587 else false)
631- then (inv.payments[0].assetId == USDN)
588+ then if ((inv.payments[0].assetId == USDN))
589+ then true
590+ else (inv.payments[0].assetId == NSBT)
632591 else false)
633592 then true
634- else if ((inv.function == "unlockNeutrino"))
593+ else if (containsElement(["unlockNeutrino", "unlockNsbt"], inv.function))
635594 then (size(inv.payments) == 0)
636595 else false
637- else false
596+ else false)
597+ then true
598+ else if ((inv.dApp == stakingEURNAddress))
599+ then if (if (if ((inv.function == "startStaking"))
600+ then (size(inv.payments) == 1)
601+ else false)
602+ then (inv.payments[0].assetId == EURN)
603+ else false)
604+ then true
605+ else if ((inv.function == "stopStaking"))
606+ then (size(inv.payments) == 0)
607+ else false
608+ else false
638609 let exchangeToWaves = if (if (if ((inv.dApp == USDNToWavesExchanger))
639610 then (inv.function == "exchange")
640611 else false)
641612 then (assetIdA == USDN)
642613 else false)
643614 then true
644615 else if (if ((assetIdB == USDN))
645616 then (size(inv.payments) == 1)
646617 else false)
647618 then (inv.payments[0].assetId == USDN)
648619 else false
620+ let exchangeToNSBTs = if (if (if ((inv.dApp == USDNToNSBTExchanger))
621+ then (inv.function == "exchange")
622+ else false)
623+ then (assetIdA == NSBT)
624+ else false)
625+ then true
626+ else if (if ((assetIdB == NSBT))
627+ then (size(inv.payments) == 1)
628+ else false)
629+ then (inv.payments[0].assetId == USDN)
630+ else false
649631 let signedByAdmin = if (if (if (sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKey1))
650632 then true
651633 else sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKey2))
652634 then true
653635 else sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKey3))
654636 then true
655- else sigVerify(tx.bodyBytes, tx.proofs[0], admStaking)
656- if (if (if (if (callTakeIntoAccount)
637+ else sigVerify(tx.bodyBytes, tx.proofs[0], adminPubKeyStaking)
638+ if (if (if (if (if (callTakeIntoAccount)
657639 then true
658640 else callStaking)
659641 then true
660642 else exchangeToWaves)
643+ then true
644+ else exchangeToNSBTs)
661645 then signedByAdmin
662646 else false)
663647 then true
664648 else multiSignedByAdmins
665649 case _ =>
666650 multiSignedByAdmins
667651 }
668652 }
669653

github/deemru/w8io/786bc32 
133.81 ms