tx · 6yAo28f4tA5JpJof7PCMZ2ipYSe24GhZLhVwkZnvPN9k 3N3PoX8z2Mvu5YbaqZmtyF3dRFjqvhRkB3M: -0.01400000 Waves 2022.03.10 17:45 [1957987] smart account 3N3PoX8z2Mvu5YbaqZmtyF3dRFjqvhRkB3M > SELF 0.00000000 Waves
{ "type": 13, "id": "6yAo28f4tA5JpJof7PCMZ2ipYSe24GhZLhVwkZnvPN9k", "fee": 1400000, "feeAssetId": null, "timestamp": 1646923546105, "version": 2, "chainId": 84, "sender": "3N3PoX8z2Mvu5YbaqZmtyF3dRFjqvhRkB3M", "senderPublicKey": "FWZMxrtn6KRrWMPXmQPqDg5eRzwB2YvHhMjMJpwnLmBi", "proofs": [ "4bFMWsyHifo2mC3drhyR1DSZnH7L8npJLGKMAAVPyv1D29fXkHBsZ6RtDyGZBTMfRNxozrn5C6CDdJjRsMt1YBys" ], "script": "base64:AAIFAAAAAAAAFnoIAhIDCgEIEgMKAQgSBAoCCAgSAwoBCBIHCgUBAQEICBIAEgMKAQgSBAoCCAESBAoCCAESBAoCCAESAwoBCBIDCgEIEgAaDwoBQRIKdmFsQW55THlzdBoKCgFCEgVhc0ludBoLCgFDEgZ2YWxJbnQaDQoBRBIIYXNTdHJpbmcaCwoBRRIGdmFsU3RyGhYKAUYSEWtleUZhY3RvcnlBZGRyZXNzGhgKAUcSE2tleU1hbmFnZXJQdWJsaWNLZXkaHwoBSBIaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkaHQoBSRIYSWR4RmFjdG9yeUNmZ1N0YWtpbmdEYXBwGh4KAUoSGUlkeEZhY3RvcnlDZmdCb29zdGluZ0RhcHAaGQoBSxIUSWR4RmFjdG9yeUNmZ0lkb0RhcHAaGgoBTBIVSWR4RmFjdG9yeUNmZ1RlYW1EYXBwGh4KAU0SGUlkeEZhY3RvcnlDZmdFbWlzc2lvbkRhcHAaGgoBThIVSWR4RmFjdG9yeUNmZ1Jlc3REYXBwGh4KAU8SGUlkeEZhY3RvcnlDZmdTbGlwcGFnZURhcHAaHwoBUBIaSWR4RmFjdG9yeUNmZ0d3eFJld2FyZERhcHAaEgoBURINa2V5RmFjdG9yeUNmZxofCgFSEhprZXlGYWN0b3J5THAyQXNzZXRzTWFwcGluZxoPCgFTEgpscEFzc2V0U3RyGhUKAVQSEGtleUZhY3RvcnlMcExpc3QaKwoBVRIma2V5RmFjdG9yeUxwQXNzZXRUb1Bvb2xDb250cmFjdEFkZHJlc3MaGQoBVhIUa2V5RmFjdG9yeVBvb2xXZWlnaHQaFAoBVxIPY29udHJhY3RBZGRyZXNzGh0KAVgSGHJlYWRGYWN0b3J5QWRkcmVzc09yRmFpbBoPCgFZEgpyZWFkTHBMaXN0GhkKAVoSFHJlYWRGYWN0b3J5Q2ZnT3JGYWlsGgsKAWESBlNDQUxFOBoeCgJhQRIYa2V5VG90YWxNYXhCb29zdElOVEVHUkFMGicKAmFCEiFrZXlVc2VyQm9vc3RBdmFsYWlibGVUb0NsYWltVG90YWwaGQoCYUMSE2tleVVzZXJCb29zdENsYWltZWQaFwoCYUQSEWtleVRvdGFsQ2FjaGVkR3d4GhUKAmFFEg9rZXlTdGFrZWRCeVVzZXIaFAoCYUYSDnVzZXJBZGRyZXNzU3RyGhIKAmFHEgxscEFzc2V0SWRTdHIaFAoCYUgSDmtleVN0YWtlZFRvdGFsGhYKAmFJEhBrZXlDbGFpbWVkQnlVc2VyGh8KAmFKEhlrZXlDbGFpbWVkQnlVc2VyTWluUmV3YXJkGiEKAmFLEhtrZXlDbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmQaEAoCYUwSCnJlYWRTdGFrZWQaEQoCYU0SC3N0YWtpbmdEYXBwGiQKAmFOEh5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQaJwoCYU8SIWtleUVtaXNzaW9uUmF0ZVBlckJsb2NrTWF4Q3VycmVudBobCgJhUBIVa2V5RW1pc3Npb25TdGFydEJsb2NrGiEKAmFREhtrZXlFbWlzc2lvbkR1cmF0aW9uSW5CbG9ja3MaGQoCYVISE2tleUVtaXNzaW9uRW5kQmxvY2saEQoCYVMSC2ZhY3RvcnlEYXBwGhAKAmFUEgpmYWN0b3J5Q2ZnGhIKAmFVEgxlbWlzc2lvbkRhcHAaEwoCYVYSDWd3eFJld2FyZERhcHAaEgoCYVcSDGJvb3N0aW5nRGFwcBofCgJhWBIZaW50ZXJuYWxDdXJyZW50UmV3YXJkUmF0ZRoPCgJhWRIJbHBBc3NldElkGhQKAmFaEg5wb29sQWRkcmVzc1N0choNCgJhYRIHZmFjdG9yeRoeCgJhYhIYZ2V0Qm9vc3RpbmdBZGRyZXNzT3JGYWlsGgoKAmFjEgRmQ2ZnGh4KAmFkEhhnZXRFbWlzc2lvbkFkZHJlc3NPckZhaWwaHQoCYWUSF2dldFN0YWtpbmdBZGRyZXNzT3JGYWlsGh8KAmFmEhlnZXRHd3hSZXdhcmRBZGRyZXNzT3JGYWlsGhEKAmFnEgtrZXlCb29zdENmZxolCgJhaBIfa2V5Qm9vc3RpbmdMb2NrUGFyYW1Ub3RhbEFtb3VudBouCgJhaRIoa2V5Qm9vc3RpbmdTdGF0c0xvY2tzRHVyYXRpb25TdW1JbkJsb2NrcxogCgJhahIaa2V5Qm9vc3RpbmdTdGF0c0xvY2tzQ291bnQaIAoCYWsSGmtleUJvb3N0aW5nU3RhdHNVc2Vyc0NvdW50GhgKAmFsEhJrZXlVc2VyMk51bU1hcHBpbmcaEQoCYW0SC3VzZXJBZGRyZXNzGhgKAmFuEhJrZXlOdW0yVXNlck1hcHBpbmcaCQoCYW8SA251bRocCgJhcBIWa2V5TG9ja1BhcmFtVXNlckFtb3VudBoNCgJhcRIHdXNlck51bRocCgJhchIWa2V5TG9ja1BhcmFtU3RhcnRCbG9jaxoaCgJhcxIUa2V5TG9ja1BhcmFtRHVyYXRpb24aEwoCYXQSDWtleUxvY2tQYXJhbUsaEwoCYXUSDWtleUxvY2tQYXJhbUIaGwoCYXYSFWtleUxvY2tQYXJhbUJ5UGVyaW9kSxoMCgJhdxIGcGVyaW9kGhsKAmF4EhVrZXlMb2NrUGFyYW1CeVBlcmlvZEIaJgoCYXkSIGtleVVzZXJCb29zdEVtaXNzaW9uTGFzdElOVEVHUkFMGh0KAmF6EhdrZXlVc2VyTWF4Qm9vc3RJTlRFR1JBTBoKCgFiEgVNVUxUOBoTCgJiQRINbWluUmV3YXJkUGFydBoVCgJiQhIPYm9vc3RSZXdhcmRQYXJ0GgsKAmJDEgVkZWJ1ZxoTCgJiRBINYm9vc3RpbmdQb3dlchoMCgJiRRIGbHBMaXN0GgwKAmJGEgZwcmVmaXgaIQoCYkcSG2NsYWltZWRSZXdhcmRCeUxwQWdncmVnYXRvchoPCgJiSBIJcmVzdWx0U3RyGgwKAmJJEgZuZXh0THAaHwoCYkoSGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkaIQoCYksSG2NsYWltZWRCeVVzZXJCb29zdFJld2FyZEtFWRoWCgJiTBIQbWluUmV3YXJkQ2xhaW1lZBoYCgJiTRISYm9vc3RSZXdhcmRDbGFpbWVkGhEKAmJOEgtnRmVlQ2xhaW1lZBoMCgJiTxIGcmVzdWx0GggKAmJQEgIkbBoICgJiURICJHMaCwoCYlISBSRhY2MwGgsKAmJTEgUkZjBfMRoICgJiVBICJGEaCAoCYlUSAiRpGgsKAmJWEgUkZjBfMhoTCgJiVxINZGVsdGFXeEFtb3VudBodCgJiWBIXZGVsdGFMb2NrUGVyaW9kSW5CbG9ja3MaEwoCYlkSDWRlbHRhTHBBbW91bnQaEgoCYloSDGxwQXNzZXRJZE9wdBoUCgJiYRIOcG9vbFdlaWdodE11bHQaEAoCYmISCnBvb2xXZWlnaHQaGAoCYmMSEnd4RW1pc3Npb25QZXJCbG9jaxobCgJiZBIVd3hFbWlzc2lvblBlckJsb2NrTWF4GhMKAmJlEg1ib29zdE1heENvZWZmGhwKAmJmEhZwb29sV3hFbWlzc2lvblBlckJsb2NrGh8KAmJnEhlwb29sV3hFbWlzc2lvblBlckJsb2NrTWF4Gg8KAmJoEgltYXhGYWN0b3IaEwoCYmkSDXRvdGFsTHBTdGFrZWQaIAoCYmoSGmNhbGNHd3hBbW91bnRTdGFydFJFQURPTkxZGhAKAmJrEgpsb2NrQW1vdW50GhIKAmJsEgxsb2NrRHVyYXRpb24aFQoCYm0SD21heExvY2tEdXJhdGlvbhoNCgJibhIHY29lZmZYOBoUCgJibxIOZ1d4QW1vdW50U3RhcnQaHAoCYnASFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQaBwoCYnESAXMaIwoCYnISHXBlbmRpbmdNYW5hZ2VyUHVibGljS2V5T3JVbml0GhEKAmJzEgttdXN0TWFuYWdlchoHCgJidBIBaRoICgJidRICcGQaCAoCYnYSAnBrGhQKAmJ3Eg5mYWN0b3J5QWRkcmVzcxoQCgJieBIKcmV3YXJkRGF0YRoUCgJieRIObHBTdGFrZWRCeVVzZXIaEwoCYnoSDXVzZXJDbGFpbUluZm8aDAoBYxIHU0NBTEUxOBoSCgJjQRIMc3Rha2VkQnlVc2VyGhEKAmNCEgtzdGFrZWRUb3RhbBoVCgJjQxIPc3Rha2VkQnlVc2VyTmV3GhQKAmNEEg5zdGFrZWRUb3RhbE5ldxoeCgJjRRIYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzGg8KAmNGEgl3eFBlckxwWDMaFgoCY0cSEHVzZXJXeFBlckJsb2NrWDMaHQoCY0gSF2Jvb3N0RW1pc3Npb25QZXJCbG9ja1gzGhwKAmNJEhZ0bXBVc2VyQm9vc3RQZXJCbG9ja1gzGhkKAmNKEhN1c2VyQm9vc3RQZXJCbG9ja1gzGhAKAmNLEgpib29zdENvZWZmGg0KAmNMEgdPTkVNVUxUGgkKAmNNEgNPTkUaGAoCY04SEmVtaXNzaW9uU3RhcnRCbG9jaxoSCgJjTxIMcGFzc2VkQmxvY2tzGhQKAmNQEg50ZWFtRW1EdXJhdGlvbhoPCgJjURIJdGVhbUVtTWF4GgwKAmNSEgZ0ZWFtRW0aFQoCY1MSD3RvdGFsV3hSZWxlYXNlZBoTCgJjVBINdG90YWxXeExvY2tlZBoeCgJjVRIYbG9ja3NEdXJhdGlvblN1bUluQmxvY2tzGhAKAmNWEgpsb2Nrc0NvdW50Gg0KAmNXEgdscEFzc2V0GhEKAmNYEgtwb29sQWRkcmVzcxoJCgJjWRIDY2ZnGhAKAmNaEgphbXRBc3NldElkGhQKAmNhEg51c2VyQWRkcmVzc09wdBoOCgJjYhIIbWF0aERhcHAaDgoCY2MSCEVNUFRZU1RSGh0KAmNkEhdtYXhMb2NrRHVyYXRpb25JbkJsb2NrcxoQCgJjZRIKdXNlck51bVN0choQCgJjZhIKdXNlckFtb3VudBoPCgJjZxIJbG9ja1N0YXJ0Gg0KAmNoEgdsb2NrRW5kGhcKAmNpEhFyZW1haW5pbmdEdXJhdGlvbhoTCgJjahINdXNlckFtb3VudE5ldxoVCgJjaxIPbG9ja0R1cmF0aW9uTmV3GhcKAmNsEhF1c2VyQ3VycmdXeEFtb3VudBoXCgJjbRIRZ1d4QW1vdW50U3RhcnROZXcaGQoCY24SE2dXeFBhcmFtc1Jlc3VsdExpc3QaEwoCY28SDWdXeEFtb3VudERpZmYaBwoCY3ASAWsaBwoCY3ESAWIaHgoCY3ISGHRvdGFsTWF4Qm9vc3RJbnRlZ3JhbEtFWRoXCgJjcxIRdG90YWxDYWNoZWRHd3hLRVkaGAoCY3QSEnVzZXJNYXhCb29zdEludE5ldxoWCgJjdRIQdG90YWxNYXhCb29zdEludBoUCgJjdhIOdG90YWxDYWNoZWRHd3gaCwoCY3cSBU1VTFQzGhoKAmN4EhR3eEVtaXNzaW9uUGVyQmxvY2tYMxoVCgJjeRIPc3Rha2VkQnlVc2VyS0VZGhQKAmN6Eg5zdGFrZWRUb3RhbEtFWRoLCgFkEgZNVUxUMTgaDwoCZEESCWNhbGNMcEFtdBoSCgJkQhIMY3VyUHJpY2VDYWxjGg8KAmRDEglhbUJhbGFuY2UaDwoCZEQSCXByQmFsYW5jZRoQCgJkRRIKbHBFbWlzc2lvbhoSCgJkRhIMYW1CYWxhbmNlUmF3GhIKAmRHEgxwckJhbGFuY2VSYXcaFQoCZEgSD2FtQmFsYW5jZVJhd1gxOBoVCgJkSRIPcHJCYWxhbmNlUmF3WDE4GhMKAmRKEg0kdDAyNTc0NzI2MTAwGhYKAmRLEhBwYXltZW50THBBc3NldElkGhIKAmRMEgxwYXltZW50THBBbXQaEwoCZE0SDSR0MDI2Nzk1MjcyMTIaDgoCZE4SCG91dEFtQW10Gg4KAmRPEghvdXRQckFtdBoVCgJkUBIPZ3d4VXNlckluZm9MSVNUGg8KAmRREglnd3hBbW91bnQaHQoCZFISF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5GhEKAmRTEgtjaGVja0NhbGxlchobCgJkVBIVY2hlY2tNYW5hZ2VyUHVibGljS2V5GggKAmRVEgJwbRoLCgJkVhIFaGFzUE0aDQoCZFcSB2NoZWNrUE0aCAoCZFgSAnR4GgwKAmRZEgZ2ZXJpZnkaFQoCZFoSD3RhcmdldFB1YmxpY0tleRoSCgJkYRIMcHJpY2VBc3NldElkGhEKAmRiEgtpQW10QXNzZXRJZBoTCgJkYxINaVByaWNlQXNzZXRJZBoRCgJkZBILYW10QXNzZXREY20aEwoCZGUSDXByaWNlQXNzZXREY20aEwoCZGYSDXBvb2xMUEJhbGFuY2UaGAoCZGcSEmFjY0FtdEFzc2V0QmFsYW5jZRoaCgJkaBIUYWNjUHJpY2VBc3NldEJhbGFuY2UaEAoCZGkSCnByaWNlc0xpc3QaDgoCZGoSCGN1clByaWNlGhUKAmRrEg9scEFtdEFzc2V0U2hhcmUaFwoCZGwSEWxwUHJpY2VBc3NldFNoYXJlGhIKAmRtEgxpbkFtQXNzZXRBbXQaEgoCZG4SDGFtQXNzZXRJZFN0choPCgJkbxIJYW1Bc3NldElkGhIKAmRwEgxwckFzc2V0SWRTdHIaDwoCZHESCXByQXNzZXRJZBoQCgJkchIKcG9vbFN0YXR1cxoUCgJkcxIOYW10QXNzZXRBbXRYMTgaFgoCZHQSEHByaWNlQXNzZXRBbXRYMTgaEQoCZHUSC2N1clByaWNlWDE4GhUKAmR2Eg9pbkFtQXNzZXRBbXRYMTgaFQoCZHcSD2luUHJBc3NldEFtdFgxOBoSCgJkeBIMaW5QckFzc2V0QW10GgkKAmR5EgNyZXMaEwoCZHoSDSR0MDIyODIxMjMxNzQaCAoBZRIDU0VQGhMKAWYSDlBPT0xXRUlHSFRNVUxUGg8KAWcSCnplcm9CaWdJbnQaEwoB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", "height": 1957987, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 3agbDC377kX4quSvwhKBdkGyNhmoELSL3e5RKm5SXGcd Next: Dw5HPqqhBvepzspaCV3PuvhK4BHpbVxt84H7oiRYqVi8 Diff:
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let SCALE8 = 8 | |
5 | + | ||
6 | + | let MULT8 = 100000000 | |
7 | + | ||
8 | + | let SCALE18 = 18 | |
9 | + | ||
10 | + | let MULT18 = toBigInt(1000000000000000000) | |
11 | + | ||
12 | + | let SEP = "__" | |
13 | + | ||
14 | + | let POOLWEIGHTMULT = MULT8 | |
15 | + | ||
16 | + | let zeroBigInt = toBigInt(0) | |
17 | + | ||
18 | + | let idxPoolAddress = 1 | |
19 | + | ||
20 | + | let idxPoolStatus = 2 | |
21 | + | ||
22 | + | let idxPoolLPAssetId = 3 | |
23 | + | ||
24 | + | let idxAmtAssetId = 4 | |
25 | + | ||
26 | + | let idxPriceAssetId = 5 | |
27 | + | ||
28 | + | let idxAmtAssetDcm = 6 | |
29 | + | ||
30 | + | let idxPriceAssetDcm = 7 | |
31 | + | ||
32 | + | let idxIAmtAssetId = 8 | |
33 | + | ||
34 | + | let idxIPriceAssetId = 9 | |
35 | + | ||
36 | + | let idxLPAssetDcm = 10 | |
37 | + | ||
4 | 38 | func getStringOrFail (key) = valueOrErrorMessage(getString(key), (("mandatory this." + key) + " is not defined")) | |
5 | 39 | ||
6 | 40 | ||
7 | - | let SEP = "__" | |
8 | - | ||
9 | - | let BUFSCALE = toBigInt(1000000000000000000) | |
10 | - | ||
11 | - | func convertPriceAssetIntoIdoAsset (priceAssetAmount,priceAssetMULT,price,priceMULT,idoAssetMULT) = { | |
12 | - | let bPriceAssetMULT = toBigInt(priceAssetMULT) | |
13 | - | let bIdoAssetMULT = toBigInt(idoAssetMULT) | |
14 | - | let bPriceAssetBUF = fraction(toBigInt(priceAssetAmount), BUFSCALE, bPriceAssetMULT) | |
15 | - | let bAmountAssetBUF = fraction(bPriceAssetBUF, toBigInt(priceMULT), toBigInt(price)) | |
16 | - | toInt(fraction(bAmountAssetBUF, toBigInt(idoAssetMULT), BUFSCALE)) | |
17 | - | } | |
41 | + | func getStringByAddressOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined")) | |
18 | 42 | ||
19 | 43 | ||
20 | - | let IdxCfgIdoStart = 1 | |
21 | - | ||
22 | - | let IdxCfgIdoDuration = 2 | |
23 | - | ||
24 | - | let IdxCfgClaimStart = 3 | |
25 | - | ||
26 | - | let IdxCfgClaimDuration = 4 | |
27 | - | ||
28 | - | let IdxCfgPrice = 5 | |
29 | - | ||
30 | - | let IdxCfgPriceMult = 6 | |
31 | - | ||
32 | - | let IdxCfgIdoAssetId = 7 | |
33 | - | ||
34 | - | let IdxCfgIdoAssetMult = 8 | |
35 | - | ||
36 | - | let IdxCfgPriceAssetId = 9 | |
37 | - | ||
38 | - | let IdxCfgPriceAssetMult = 10 | |
39 | - | ||
40 | - | let IdxCfgMinInvestAmount = 11 | |
41 | - | ||
42 | - | func fromatConfigS (idoStart,idoDuration,claimStart,claimDuration,price,priceMult,idoAssetId58,idoAssetMult,priceAssetId58,priceAssetMult,minInvestAmount,totalIdoAssetToSell) = makeString(["%d%d%d%d%d%d%s%d%s%d%d%d", idoStart, idoDuration, claimStart, claimDuration, price, priceMult, idoAssetId58, idoAssetMult, priceAssetId58, priceAssetMult, minInvestAmount, totalIdoAssetToSell], SEP) | |
44 | + | func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0) | |
43 | 45 | ||
44 | 46 | ||
45 | - | func | |
47 | + | func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined")) | |
46 | 48 | ||
47 | 49 | ||
48 | - | let IdxInvTotalAmount = 1 | |
49 | - | ||
50 | - | let IdxInvRemainingAmount = 2 | |
51 | - | ||
52 | - | let IdxInvClaimedPriceAssetAmount = 3 | |
53 | - | ||
54 | - | let IdxInvClaimedIdoAssetAmount = 4 | |
55 | - | ||
56 | - | let IdxInvLastClaimedHeight = 5 | |
57 | - | ||
58 | - | func formatInvestorS (totalAmount,remainingAmount,claimedPriceAssetAmount,claimedIdoAssetAmount,lastClaimedHeight) = makeString(["%d%d%d%d%d", totalAmount, remainingAmount, claimedPriceAssetAmount, claimedIdoAssetAmount, lastClaimedHeight], SEP) | |
50 | + | func asAnyList (val) = match val { | |
51 | + | case valAnyLyst: List[Any] => | |
52 | + | valAnyLyst | |
53 | + | case _ => | |
54 | + | throw("fail to cast into List[Any]") | |
55 | + | } | |
59 | 56 | ||
60 | 57 | ||
61 | - | func formatInvestor (totalAmount,remainingAmount,claimedPriceAssetAmount,claimedIdoAssetAmount,lastClaimedHeight) = formatInvestorS(toString(totalAmount), toString(remainingAmount), toString(claimedPriceAssetAmount), toString(claimedIdoAssetAmount), toString(lastClaimedHeight)) | |
58 | + | func asInt (val) = match val { | |
59 | + | case valInt: Int => | |
60 | + | valInt | |
61 | + | case _ => | |
62 | + | throw("fail to cast into Int") | |
63 | + | } | |
62 | 64 | ||
63 | 65 | ||
64 | - | func formatHistoryRecord (priceAssetAmount,idoAssetAmount) = makeString(["%d%d%d%d", toString(height), toString(lastBlock.timestamp), toString(priceAssetAmount), toString(idoAssetAmount)], SEP) | |
66 | + | func asString (val) = match val { | |
67 | + | case valStr: String => | |
68 | + | valStr | |
69 | + | case _ => | |
70 | + | throw("fail to cast into String") | |
71 | + | } | |
65 | 72 | ||
66 | 73 | ||
67 | - | func keyConfig () = "%s__config" | |
68 | - | ||
69 | - | ||
70 | - | func keyInvestor (userAddress) = ("%s__" + userAddress) | |
71 | - | ||
72 | - | ||
73 | - | func keyTotals () = "%s__totals" | |
74 | - | ||
75 | - | ||
76 | - | func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP) | |
74 | + | func keyFactoryAddress () = "%s%s__config__factoryAddress" | |
77 | 75 | ||
78 | 76 | ||
79 | 77 | func keyManagerPublicKey () = "%s__managerPublicKey" | |
82 | 80 | func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey" | |
83 | 81 | ||
84 | 82 | ||
85 | - | func readConfigArray () = split(getStringOrFail(keyConfig()), SEP) | |
83 | + | let IdxFactoryCfgStakingDapp = 1 | |
84 | + | ||
85 | + | let IdxFactoryCfgBoostingDapp = 2 | |
86 | + | ||
87 | + | let IdxFactoryCfgIdoDapp = 3 | |
88 | + | ||
89 | + | let IdxFactoryCfgTeamDapp = 4 | |
90 | + | ||
91 | + | let IdxFactoryCfgEmissionDapp = 5 | |
92 | + | ||
93 | + | let IdxFactoryCfgRestDapp = 6 | |
94 | + | ||
95 | + | let IdxFactoryCfgSlippageDapp = 7 | |
96 | + | ||
97 | + | let IdxFactoryCfgGwxRewardDapp = 8 | |
98 | + | ||
99 | + | func keyFactoryCfg () = "%s__factoryConfig" | |
86 | 100 | ||
87 | 101 | ||
88 | - | func | |
102 | + | func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP) | |
89 | 103 | ||
90 | 104 | ||
91 | - | func | |
105 | + | func keyFactoryLpList () = "%s__lpTokensList" | |
92 | 106 | ||
93 | 107 | ||
94 | - | func | |
108 | + | func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP) | |
95 | 109 | ||
96 | 110 | ||
97 | - | func | |
111 | + | func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP) | |
98 | 112 | ||
99 | 113 | ||
100 | - | ||
114 | + | func readFactoryAddressOrFail () = addressFromStringValue(getStringOrFail(keyFactoryAddress())) | |
101 | 115 | ||
102 | - | let IdxDiffRemainingPriceAmountIncrement = 1 | |
103 | 116 | ||
104 | - | ||
117 | + | func readLpList () = split(valueOrElse(getString(readFactoryAddressOrFail(), keyFactoryLpList()), ""), SEP) | |
105 | 118 | ||
106 | - | let IdxDiffClaimedIdoAssetAmountIncrement = 3 | |
107 | 119 | ||
108 | - | func TotalsEntry (key,origArray,incrementDiff,newLastClaimedHeight) = { | |
109 | - | let totalAmount = parseIntValue(origArray[IdxInvTotalAmount]) | |
110 | - | let remainingAmount = parseIntValue(origArray[IdxInvRemainingAmount]) | |
111 | - | let claimedPriceAssetAmount = parseIntValue(origArray[IdxInvClaimedPriceAssetAmount]) | |
112 | - | let claimedIdoAssetAmount = parseIntValue(origArray[IdxInvClaimedIdoAssetAmount]) | |
113 | - | let lastClaimedHeight = parseIntValue(origArray[IdxInvLastClaimedHeight]) | |
114 | - | let newTotalAmount = (totalAmount + incrementDiff[IdxDiffTotalIncrement]) | |
115 | - | let newRemainingAmount = (remainingAmount + incrementDiff[IdxDiffRemainingPriceAmountIncrement]) | |
116 | - | let newClaimedPriceAssetAmount = (claimedPriceAssetAmount + incrementDiff[IdxDiffClaimedPriceAmountIncrement]) | |
117 | - | let newClaimedIdoAssetAmount = (claimedIdoAssetAmount + incrementDiff[IdxDiffClaimedIdoAssetAmountIncrement]) | |
118 | - | if ((0 > newRemainingAmount)) | |
119 | - | then throw("invalid math") | |
120 | - | else StringEntry(key, formatInvestor(newTotalAmount, newRemainingAmount, newClaimedPriceAssetAmount, newClaimedIdoAssetAmount, newLastClaimedHeight)) | |
120 | + | func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP) | |
121 | + | ||
122 | + | ||
123 | + | func getBoostingAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgBoostingDapp]) | |
124 | + | ||
125 | + | ||
126 | + | func getEmissionAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgEmissionDapp]) | |
127 | + | ||
128 | + | ||
129 | + | func getStakingAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgStakingDapp]) | |
130 | + | ||
131 | + | ||
132 | + | func getGwxRewardAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgGwxRewardDapp]) | |
133 | + | ||
134 | + | ||
135 | + | func keyBoostCfg () = "%s__config" | |
136 | + | ||
137 | + | ||
138 | + | func keyBoostingLockParamTotalAmount () = "%s%s__stats__activeTotalLocked" | |
139 | + | ||
140 | + | ||
141 | + | func keyBoostingStatsLocksDurationSumInBlocks () = "%s%s__stats__locksDurationSumInBlocks" | |
142 | + | ||
143 | + | ||
144 | + | func keyBoostingStatsLocksCount () = "%s%s__stats__locksCount" | |
145 | + | ||
146 | + | ||
147 | + | func keyBoostingStatsUsersCount () = "%s%s__stats__activeUsersCount" | |
148 | + | ||
149 | + | ||
150 | + | func keyUser2NumMapping (userAddress) = makeString(["%s%s%s__mapping__user2num", userAddress], SEP) | |
151 | + | ||
152 | + | ||
153 | + | func keyNum2UserMapping (num) = makeString(["%s%s%s__mapping__num2user", num], SEP) | |
154 | + | ||
155 | + | ||
156 | + | func keyLockParamUserAmount (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "amount"], SEP) | |
157 | + | ||
158 | + | ||
159 | + | func keyLockParamStartBlock (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "start"], SEP) | |
160 | + | ||
161 | + | ||
162 | + | func keyLockParamDuration (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "duration"], SEP) | |
163 | + | ||
164 | + | ||
165 | + | func keyLockParamK (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "k"], SEP) | |
166 | + | ||
167 | + | ||
168 | + | func keyLockParamB (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "b"], SEP) | |
169 | + | ||
170 | + | ||
171 | + | func keyLockParamByPeriodK (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "k", period], SEP) | |
172 | + | ||
173 | + | ||
174 | + | func keyLockParamByPeriodB (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "b", period], SEP) | |
175 | + | ||
176 | + | ||
177 | + | func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastInt", userNum], SEP) | |
178 | + | ||
179 | + | ||
180 | + | func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", userNum], SEP) | |
181 | + | ||
182 | + | ||
183 | + | func keyTotalMaxBoostINTEGRAL () = "%s%s__maxBoostInt__total" | |
184 | + | ||
185 | + | ||
186 | + | func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", userNum], SEP) | |
187 | + | ||
188 | + | ||
189 | + | func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", userNum], SEP) | |
190 | + | ||
191 | + | ||
192 | + | func keyTotalCachedGwx () = "%s%s__gwxCached__total" | |
193 | + | ||
194 | + | ||
195 | + | func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP) | |
196 | + | ||
197 | + | ||
198 | + | func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr) | |
199 | + | ||
200 | + | ||
201 | + | func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP) | |
202 | + | ||
203 | + | ||
204 | + | func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP) | |
205 | + | ||
206 | + | ||
207 | + | func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP) | |
208 | + | ||
209 | + | ||
210 | + | func readStaked (stakingDapp,key) = valueOrElse(getInteger(stakingDapp, key), 0) | |
211 | + | ||
212 | + | ||
213 | + | func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current" | |
214 | + | ||
215 | + | ||
216 | + | func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current" | |
217 | + | ||
218 | + | ||
219 | + | func keyEmissionStartBlock () = "%s%s__emission__startBlock" | |
220 | + | ||
221 | + | ||
222 | + | func keyEmissionDurationInBlocks () = "%s%s__emission__duration" | |
223 | + | ||
224 | + | ||
225 | + | func keyEmissionEndBlock () = "%s%s__emission__endBlock" | |
226 | + | ||
227 | + | ||
228 | + | let factoryDapp = readFactoryAddressOrFail() | |
229 | + | ||
230 | + | let factoryCfg = readFactoryCfgOrFail(factoryDapp) | |
231 | + | ||
232 | + | let emissionDapp = getEmissionAddressOrFail(factoryCfg) | |
233 | + | ||
234 | + | let stakingDapp = getStakingAddressOrFail(factoryCfg) | |
235 | + | ||
236 | + | let gwxRewardDapp = getGwxRewardAddressOrFail(factoryCfg) | |
237 | + | ||
238 | + | let boostingDapp = getBoostingAddressOrFail(factoryCfg) | |
239 | + | ||
240 | + | func internalCurrentRewardRate (lpAssetId) = { | |
241 | + | let poolAddressStr = getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAssetId)) | |
242 | + | let poolWeightMult = MULT8 | |
243 | + | let poolWeight = getIntegerValue(factoryDapp, keyFactoryPoolWeight(poolAddressStr)) | |
244 | + | let wxEmissionPerBlock = getIntOrFail(emissionDapp, keyEmissionRatePerBlockCurrent()) | |
245 | + | let wxEmissionPerBlockMax = getIntOrFail(emissionDapp, keyEmissionRatePerBlockMaxCurrent()) | |
246 | + | let boostMaxCoeff = 3 | |
247 | + | let poolWxEmissionPerBlock = (fraction(wxEmissionPerBlock, poolWeight, poolWeightMult) / boostMaxCoeff) | |
248 | + | let poolWxEmissionPerBlockMax = fraction(wxEmissionPerBlockMax, poolWeight, poolWeightMult) | |
249 | + | let maxFactor = (boostMaxCoeff * MULT8) | |
250 | + | let totalLpStaked = getIntOrZero(stakingDapp, keyStakedTotal(lpAssetId)) | |
251 | + | [poolWxEmissionPerBlock, maxFactor, totalLpStaked] | |
121 | 252 | } | |
122 | 253 | ||
123 | 254 | ||
124 | - | func InvestOperationHistoryEntry (userAddress,priceAssetAmount,idoAssetAmount,txId) = StringEntry(keyOperationHistoryRecord("invest", userAddress, toBase58String(txId)), formatHistoryRecord(priceAssetAmount, idoAssetAmount)) | |
125 | - | ||
126 | - | ||
127 | - | func ClaimOperationHistoryEntry (userAddress,priceAssetAmount,idoAssetAmount,txId) = StringEntry(keyOperationHistoryRecord("claim", userAddress, toBase58String(txId)), formatHistoryRecord(priceAssetAmount, idoAssetAmount)) | |
128 | - | ||
129 | - | ||
130 | - | func internalClaim (claimedAssetId58,userAddress,txId) = { | |
131 | - | let cfgArray = readConfigArray() | |
132 | - | let claimStart = parseIntValue(cfgArray[IdxCfgClaimStart]) | |
133 | - | let claimDuration = parseIntValue(cfgArray[IdxCfgClaimDuration]) | |
134 | - | let claimEnd = (claimStart + claimDuration) | |
135 | - | let price = parseIntValue(cfgArray[IdxCfgPrice]) | |
136 | - | let priceMult = parseIntValue(cfgArray[IdxCfgPriceMult]) | |
137 | - | let idoAssetId58 = cfgArray[IdxCfgIdoAssetId] | |
138 | - | let idoAssetId = fromBase58String(idoAssetId58) | |
139 | - | let idoAssetMult = parseIntValue(cfgArray[IdxCfgIdoAssetMult]) | |
140 | - | let priceAssetId58 = cfgArray[IdxCfgPriceAssetId] | |
141 | - | let priceAssetId = fromBase58String(priceAssetId58) | |
142 | - | let priceAssetMult = parseIntValue(cfgArray[IdxCfgPriceAssetMult]) | |
143 | - | let userAddress58 = toString(userAddress) | |
144 | - | let origInvestArray = readInvestorArrayOrFail(userAddress58) | |
145 | - | let investTotalAmount = parseIntValue(origInvestArray[IdxInvTotalAmount]) | |
146 | - | let investLastClaimedHeightTMP = parseIntValue(origInvestArray[IdxInvLastClaimedHeight]) | |
147 | - | let investLastClaimedHeight = if ((claimStart >= investLastClaimedHeightTMP)) | |
148 | - | then claimStart | |
149 | - | else investLastClaimedHeightTMP | |
150 | - | let newClaimPeriodHeight = if ((height > claimEnd)) | |
151 | - | then claimEnd | |
152 | - | else if ((claimStart > height)) | |
153 | - | then claimStart | |
154 | - | else height | |
155 | - | let claimingBlocks = (newClaimPeriodHeight - investLastClaimedHeight) | |
156 | - | let claimingPriceAssetAmount = fraction(investTotalAmount, claimingBlocks, claimDuration) | |
157 | - | let claimingIdoAssetAmount = convertPriceAssetIntoIdoAsset(claimingPriceAssetAmount, priceAssetMult, price, priceMult, idoAssetMult) | |
158 | - | if ((claimedAssetId58 == priceAssetId58)) | |
159 | - | then $Tuple6([0, -(claimingPriceAssetAmount), claimingPriceAssetAmount, 0], claimingPriceAssetAmount, priceAssetId, origInvestArray, newClaimPeriodHeight, [claimingPriceAssetAmount, claimingIdoAssetAmount]) | |
160 | - | else if ((claimedAssetId58 == idoAssetId58)) | |
161 | - | then $Tuple6([0, -(claimingPriceAssetAmount), 0, claimingIdoAssetAmount], claimingIdoAssetAmount, idoAssetId, origInvestArray, newClaimPeriodHeight, [claimingPriceAssetAmount, claimingIdoAssetAmount]) | |
162 | - | else throw(("unsupported assetId: " + claimedAssetId58)) | |
255 | + | func calcGwxAmountStartREADONLY (lockAmount,lockDuration,maxLockDuration) = { | |
256 | + | let coeffX8 = fraction(lockDuration, MULT8, maxLockDuration) | |
257 | + | let gWxAmountStart = fraction(lockAmount, coeffX8, MULT8) | |
258 | + | [gWxAmountStart] | |
163 | 259 | } | |
164 | 260 | ||
165 | 261 | ||
201 | 297 | ||
202 | 298 | ||
203 | 299 | @Callable(i) | |
204 | - | func constructor (idoStart,idoDuration,claimStart,claimDuration,price,priceAssetId58,minInvestAmount) = { | |
205 | - | let priceMult = ((100 * 1000) * 1000) | |
206 | - | let idoEnd = (idoStart + idoDuration) | |
207 | - | if (isDefined(getString(keyConfig()))) | |
208 | - | then throw("already initialized") | |
209 | - | else if (("3PMEHLx1j6zerarZTYfsGqDeeZqQoMpxq5S" != toString(i.caller))) | |
210 | - | then throw("not authorized") | |
211 | - | else if ((size(i.payments) != 1)) | |
212 | - | then throw("exactly 1 payment must be attached") | |
213 | - | else if ((idoEnd >= claimStart)) | |
214 | - | then throw("claimStart must be greater than idoEnd") | |
215 | - | else { | |
216 | - | let pmt = value(i.payments[0]) | |
217 | - | let idoAssetId = value(pmt.assetId) | |
218 | - | let idoAssetInfo = valueOrErrorMessage(assetInfo(idoAssetId), "fail to load ido asset info") | |
219 | - | let idoAssetId58 = toBase58String(idoAssetId) | |
220 | - | let idoAssetMult = pow(10, 0, idoAssetInfo.decimals, 0, 0, DOWN) | |
221 | - | let priceAssetId = fromBase58String(priceAssetId58) | |
222 | - | let priceAssetInfo = valueOrErrorMessage(assetInfo(priceAssetId), "fail to load price asset info") | |
223 | - | let priceAssetMult = pow(10, 0, priceAssetInfo.decimals, 0, 0, DOWN) | |
224 | - | let origTotalsArray = readTotalsArrayOrDefault() | |
225 | - | let totalsDiff = [0, 0, 0, 0] | |
226 | - | [StringEntry(keyConfig(), fromatConfig(idoStart, idoDuration, claimStart, claimDuration, price, priceMult, idoAssetId58, idoAssetMult, priceAssetId58, priceAssetMult, minInvestAmount, pmt.amount)), TotalsEntry(keyTotals(), origTotalsArray, totalsDiff, claimStart)] | |
227 | - | } | |
300 | + | func constructor (factoryAddress) = if ((i.caller != this)) | |
301 | + | then throw("not authorized") | |
302 | + | else [StringEntry(keyFactoryAddress(), factoryAddress)] | |
303 | + | ||
304 | + | ||
305 | + | ||
306 | + | @Callable(i) | |
307 | + | func currentRewardRateREADONLY (lpAssetId) = { | |
308 | + | let rewardData = internalCurrentRewardRate(lpAssetId) | |
309 | + | let wxEmissionPerBlock = rewardData[0] | |
310 | + | let maxFactor = rewardData[1] | |
311 | + | let totalLpStaked = rewardData[2] | |
312 | + | $Tuple2(nil, makeString(["%d%d%d", toString(wxEmissionPerBlock), toString(maxFactor), toString(totalLpStaked)], SEP)) | |
228 | 313 | } | |
229 | 314 | ||
230 | 315 | ||
231 | 316 | ||
232 | 317 | @Callable(i) | |
233 | - | func invest () = { | |
234 | - | let cfgArray = readConfigArray() | |
235 | - | let idoStart = parseIntValue(cfgArray[IdxCfgIdoStart]) | |
236 | - | let idoDuration = parseIntValue(cfgArray[IdxCfgIdoDuration]) | |
237 | - | let idoEnd = (idoStart + idoDuration) | |
238 | - | let claimStart = parseIntValue(cfgArray[IdxCfgClaimStart]) | |
239 | - | let claimDuration = parseIntValue(cfgArray[IdxCfgClaimDuration]) | |
240 | - | let price = parseIntValue(cfgArray[IdxCfgPrice]) | |
241 | - | let priceMult = parseIntValue(cfgArray[IdxCfgPriceMult]) | |
242 | - | let idoAssetId58 = cfgArray[IdxCfgIdoAssetId] | |
243 | - | let idoAssetId = fromBase58String(idoAssetId58) | |
244 | - | let idoAssetMult = parseIntValue(cfgArray[IdxCfgIdoAssetMult]) | |
245 | - | let priceAssetId58 = cfgArray[IdxCfgPriceAssetId] | |
246 | - | let priceAssetId = fromBase58String(priceAssetId58) | |
247 | - | let priceAssetMult = parseIntValue(cfgArray[IdxCfgPriceAssetMult]) | |
248 | - | let minIvestAmount = parseIntValue(cfgArray[IdxCfgMinInvestAmount]) | |
249 | - | let userAddress = toString(i.caller) | |
250 | - | if ((idoStart > height)) | |
251 | - | then throw("ido has not been started yet") | |
252 | - | else if ((height > idoEnd)) | |
253 | - | then throw("ido has been already ended") | |
254 | - | else if ((size(i.payments) != 1)) | |
255 | - | then throw("exactly 1 payment is expected") | |
256 | - | else { | |
257 | - | let pmt = value(i.payments[0]) | |
258 | - | let pmtAssetId = value(pmt.assetId) | |
259 | - | let pmtAmount = pmt.amount | |
260 | - | if ((pmtAssetId != priceAssetId)) | |
261 | - | then throw((("invalid payment asset id: " + toBase58String(pmtAssetId)) + " is expected")) | |
262 | - | else { | |
263 | - | let origInvestorArray = readInvestorArrayOrDefault(userAddress) | |
264 | - | let origTotalsArray = readTotalsArrayOrDefault() | |
265 | - | let newPriceTotalAmount = (parseIntValue(origTotalsArray[IdxInvTotalAmount]) + pmtAmount) | |
266 | - | let requiredIdoAssetAmount = (newPriceTotalAmount * 100) | |
267 | - | if ((requiredIdoAssetAmount > assetBalance(this, idoAssetId))) | |
268 | - | then throw("IDO asset has been - sold consider to use smaller payment") | |
269 | - | else { | |
270 | - | let totalsDiff = [pmtAmount, pmtAmount, 0, 0] | |
271 | - | [TotalsEntry(keyInvestor(userAddress), origInvestorArray, totalsDiff, claimStart), TotalsEntry(keyTotals(), origTotalsArray, totalsDiff, claimStart), InvestOperationHistoryEntry(userAddress, pmtAmount, 0, i.transactionId)] | |
272 | - | } | |
273 | - | } | |
274 | - | } | |
318 | + | func currentUserRewardRateREADONLY (lpAssetId,userAddress) = { | |
319 | + | let rewardData = internalCurrentRewardRate(lpAssetId) | |
320 | + | let wxEmissionPerBlock = rewardData[0] | |
321 | + | let maxFactor = rewardData[1] | |
322 | + | let totalLpStaked = rewardData[2] | |
323 | + | let lpStakedByUser = getIntOrZero(stakingDapp, keyStakedByUser(userAddress, lpAssetId)) | |
324 | + | let userClaimInfo = split(asString(invoke(stakingDapp, "claimWxREADONLY", [lpAssetId, userAddress], nil)), SEP) | |
325 | + | let minRewardPart = valueOrErrorMessage(parseInt(userClaimInfo[5]), "couldn't parse minRewardPart") | |
326 | + | let boostRewardPart = valueOrErrorMessage(parseInt(userClaimInfo[6]), "couldn't parse boostRewardPart") | |
327 | + | let debug = userClaimInfo[7] | |
328 | + | let boostingPower = if ((boostRewardPart == 0)) | |
329 | + | then (1 * MULT8) | |
330 | + | else fraction((minRewardPart + boostRewardPart), MULT8, minRewardPart) | |
331 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%s", toString(wxEmissionPerBlock), toString(maxFactor), toString(totalLpStaked), toString(lpStakedByUser), toString(boostingPower), debug], SEP)) | |
275 | 332 | } | |
276 | 333 | ||
277 | 334 | ||
278 | 335 | ||
279 | 336 | @Callable(i) | |
280 | - | func claim (claimedAssetId58,userAddress58) = { | |
281 | - | let callerAddress58 = toString(i.caller) | |
282 | - | if ((userAddress58 != callerAddress58)) | |
283 | - | then throw("not authorized") | |
284 | - | else { | |
285 | - | let claimResultTuple = internalClaim(claimedAssetId58, i.caller, i.transactionId) | |
286 | - | let totalsDiff = claimResultTuple._1 | |
287 | - | let outAmount = claimResultTuple._2 | |
288 | - | let outAssetId = claimResultTuple._3 | |
289 | - | let origInvestArray = claimResultTuple._4 | |
290 | - | let newClaimPeriodHeight = claimResultTuple._5 | |
291 | - | let claimedPriceAmountFromDiff = totalsDiff[IdxDiffClaimedPriceAmountIncrement] | |
292 | - | let claimedIdoAssetAmountFromDiff = totalsDiff[IdxDiffClaimedIdoAssetAmountIncrement] | |
293 | - | $Tuple2([ScriptTransfer(i.caller, outAmount, outAssetId), TotalsEntry(keyInvestor(userAddress58), origInvestArray, totalsDiff, newClaimPeriodHeight), TotalsEntry(keyTotals(), readTotalsArrayOrDefault(), totalsDiff, newClaimPeriodHeight), ClaimOperationHistoryEntry(userAddress58, claimedPriceAmountFromDiff, claimedIdoAssetAmountFromDiff, i.transactionId)], unit) | |
294 | - | } | |
337 | + | func claimedRewardREADONLY (userAddress) = { | |
338 | + | let lpList = readLpList() | |
339 | + | let prefix = "%s%d%d%d%s" | |
340 | + | func claimedRewardByLpAggregator (resultStr,nextLp) = { | |
341 | + | let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(nextLp, userAddress) | |
342 | + | let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(nextLp, userAddress) | |
343 | + | let minRewardClaimed = valueOrElse(getInteger(stakingDapp, claimedByUserMinRewardKEY), 0) | |
344 | + | let boostRewardClaimed = valueOrElse(getInteger(stakingDapp, claimedByUserBoostRewardKEY), 0) | |
345 | + | let gFeeClaimed = 0 | |
346 | + | makeString([(prefix + resultStr), nextLp, toString(minRewardClaimed), toString(boostRewardClaimed), toString(gFeeClaimed), "end"], SEP) | |
347 | + | } | |
348 | + | ||
349 | + | let result = { | |
350 | + | let $l = lpList | |
351 | + | let $s = size($l) | |
352 | + | let $acc0 = "%s" | |
353 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
354 | + | then $a | |
355 | + | else claimedRewardByLpAggregator($a, $l[$i]) | |
356 | + | ||
357 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
358 | + | then $a | |
359 | + | else throw("List size exceeds 10") | |
360 | + | ||
361 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
362 | + | } | |
363 | + | $Tuple2(nil, ((result + SEP) + userAddress)) | |
295 | 364 | } | |
296 | 365 | ||
297 | 366 | ||
298 | 367 | ||
299 | 368 | @Callable(i) | |
300 | - | func claimREADONLY (claimedAssetId58,userAddress58) = { | |
301 | - | let claimResultTuple = internalClaim(claimedAssetId58, addressFromStringValue(userAddress58), fromBase58String("")) | |
302 | - | let totalsDiff = claimResultTuple._1 | |
303 | - | let outAmount = claimResultTuple._2 | |
304 | - | let outAssetId = claimResultTuple._3 | |
305 | - | let origInvestArray = claimResultTuple._4 | |
306 | - | let newClaimPeriodHeight = claimResultTuple._5 | |
307 | - | let availableToClaimArray = claimResultTuple._6 | |
308 | - | let availablePriceAmountToClaim = availableToClaimArray[0] | |
309 | - | let availableIdoAmountToClaim = availableToClaimArray[1] | |
310 | - | $Tuple2(nil, makeString(["%s%d%d", userAddress58, toString(availablePriceAmountToClaim), toString(availableIdoAmountToClaim)], SEP)) | |
369 | + | func calcBoostREADONLY (deltaWxAmount,deltaLockPeriodInBlocks,deltaLpAmount,lpAssetIdOpt,userAddressOpt) = { | |
370 | + | let mathDapp = gwxRewardDapp | |
371 | + | let EMPTYSTR = "empty" | |
372 | + | let maxLockDurationInBlocks = parseIntValue(split(getStringByAddressOrFail(boostingDapp, keyBoostCfg()), SEP)[4]) | |
373 | + | let lpAssetIdStr = if ((lpAssetIdOpt == "")) | |
374 | + | then EMPTYSTR | |
375 | + | else lpAssetIdOpt | |
376 | + | let userAddressStr = if ((userAddressOpt == "")) | |
377 | + | then EMPTYSTR | |
378 | + | else userAddressOpt | |
379 | + | let userNumStr = valueOrElse(getString(boostingDapp, keyUser2NumMapping(userAddressOpt)), EMPTYSTR) | |
380 | + | let userAmount = valueOrElse(getInteger(boostingDapp, keyLockParamUserAmount(userNumStr)), 0) | |
381 | + | let lockStart = valueOrElse(getInteger(boostingDapp, keyLockParamStartBlock(userNumStr)), height) | |
382 | + | let lockDuration = valueOrElse(getInteger(boostingDapp, keyLockParamDuration(userNumStr)), 0) | |
383 | + | let lockEnd = (lockStart + lockDuration) | |
384 | + | let remainingDuration = max([(lockEnd - height), 0]) | |
385 | + | let userAmountNew = (userAmount + deltaWxAmount) | |
386 | + | let lockDurationNew = min([(remainingDuration + deltaLockPeriodInBlocks), maxLockDurationInBlocks]) | |
387 | + | let userCurrgWxAmount = asInt(asAnyList(invoke(boostingDapp, "gwxUserInfoREADONLY", [userAddressStr], nil))[0]) | |
388 | + | let gWxAmountStartNew = calcGwxAmountStartREADONLY(userAmountNew, lockDurationNew, maxLockDurationInBlocks)[0] | |
389 | + | let gWxParamsResultList = asAnyList(invoke(mathDapp, "calcGwxParamsREADONLY", [gWxAmountStartNew, height, lockDurationNew], nil)) | |
390 | + | let gWxAmountDiff = (gWxAmountStartNew - userCurrgWxAmount) | |
391 | + | let k = asInt(gWxParamsResultList[0]) | |
392 | + | let b = asInt(gWxParamsResultList[1]) | |
393 | + | let period = toString(asInt(gWxParamsResultList[2])) | |
394 | + | let totalMaxBoostIntegralKEY = keyTotalMaxBoostINTEGRAL() | |
395 | + | let totalCachedGwxKEY = keyTotalCachedGwx() | |
396 | + | let userMaxBoostIntNew = ((gWxAmountStartNew * lockDurationNew) / 2) | |
397 | + | let totalMaxBoostInt = getIntOrZero(boostingDapp, totalMaxBoostIntegralKEY) | |
398 | + | let totalCachedGwx = valueOrElse(getInteger(boostingDapp, totalCachedGwxKEY), 0) | |
399 | + | let MULT3 = 1000 | |
400 | + | let wxEmissionPerBlockX3 = (getIntOrFail(emissionDapp, keyEmissionRatePerBlockCurrent()) * MULT3) | |
401 | + | let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr) | |
402 | + | let stakedTotalKEY = keyStakedTotal(lpAssetIdStr) | |
403 | + | let stakedByUser = readStaked(stakingDapp, stakedByUserKEY) | |
404 | + | let stakedTotal = readStaked(stakingDapp, stakedTotalKEY) | |
405 | + | let stakedByUserNew = (stakedByUser + deltaLpAmount) | |
406 | + | let stakedTotalNew = (stakedTotal + deltaLpAmount) | |
407 | + | let poolWeight = if ((lpAssetIdStr != EMPTYSTR)) | |
408 | + | then { | |
409 | + | let poolAddressStr = valueOrErrorMessage(getString(factoryDapp, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr)) | |
410 | + | getIntegerValue(factoryDapp, keyFactoryPoolWeight(poolAddressStr)) | |
411 | + | } | |
412 | + | else 0 | |
413 | + | let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3)) | |
414 | + | let wxPerLpX3 = if ((stakedTotalNew != 0)) | |
415 | + | then fraction(poolWxEmissionPerBlockX3, MULT8, stakedTotalNew) | |
416 | + | else 0 | |
417 | + | let userWxPerBlockX3 = fraction(wxPerLpX3, stakedByUserNew, MULT8) | |
418 | + | let boostEmissionPerBlockX3 = (poolWxEmissionPerBlockX3 * 2) | |
419 | + | let tmpUserBoostPerBlockX3 = fraction(gWxAmountStartNew, boostEmissionPerBlockX3, (totalCachedGwx + gWxAmountDiff)) | |
420 | + | let userBoostPerBlockX3 = min([tmpUserBoostPerBlockX3, (userWxPerBlockX3 * 2)]) | |
421 | + | let boostCoeff = if ((userWxPerBlockX3 == 0)) | |
422 | + | then (1 * MULT8) | |
423 | + | else fraction((userBoostPerBlockX3 + userWxPerBlockX3), MULT8, userWxPerBlockX3) | |
424 | + | let debug = makeString([("lpAssetIdStr=" + lpAssetIdStr), ("userAddressStr=" + userAddressStr), ("userNumStr=" + userNumStr), ("userAmount=" + toString(userAmount)), ("userAmountNew=" + toString(userAmountNew)), ("lockDurationNew=" + toString(lockDurationNew)), ("gWxAmountStart=" + toString(gWxAmountStartNew)), ("tmpUserBoostPerBlockX3=" + toString(tmpUserBoostPerBlockX3)), ("stakedByUserNew=" + toString(stakedByUserNew)), ("stakedTotalNew=" + toString(stakedTotalNew)), ("poolWeight=" + toString(poolWeight)), ("wxPerLpX3=" + toString(wxPerLpX3)), ("poolWxEmissionPerBlockX3=" + toString(poolWxEmissionPerBlockX3)), ("userWxPerBlockX3=" + toString(userWxPerBlockX3)), ("gWxAmountDiff=" + toString(gWxAmountDiff)), ("totalCachedGwx=" + toString(totalCachedGwx)), ("userCurrgWxAmount=" + toString(userCurrgWxAmount))], "::") | |
425 | + | $Tuple2(nil, makeString(["%d%d%s", toString(gWxAmountStartNew), toString(boostCoeff), debug], SEP)) | |
426 | + | } | |
427 | + | ||
428 | + | ||
429 | + | ||
430 | + | @Callable(i) | |
431 | + | func wxEmissionStatsREADONLY () = { | |
432 | + | let ONEMULT = toString(MULT8) | |
433 | + | let ONE = "1" | |
434 | + | let wxEmissionPerBlock = getIntOrFail(emissionDapp, keyEmissionRatePerBlockCurrent()) | |
435 | + | let emissionStartBlock = getIntOrFail(emissionDapp, keyEmissionStartBlock()) | |
436 | + | let passedBlocks = if ((emissionStartBlock > height)) | |
437 | + | then 0 | |
438 | + | else (height - emissionStartBlock) | |
439 | + | let teamEmDuration = (1440 * 365) | |
440 | + | let teamEmMax = (201000000 * MULT8) | |
441 | + | let teamEm = if ((passedBlocks > teamEmDuration)) | |
442 | + | then teamEmMax | |
443 | + | else fraction(teamEmMax, passedBlocks, teamEmDuration) | |
444 | + | let totalWxReleased = ((wxEmissionPerBlock * passedBlocks) + teamEm) | |
445 | + | let totalWxLocked = getIntOrZero(boostingDapp, keyBoostingLockParamTotalAmount()) | |
446 | + | let locksDurationSumInBlocks = getIntOrZero(boostingDapp, keyBoostingStatsLocksDurationSumInBlocks()) | |
447 | + | let locksCount = getIntOrZero(boostingDapp, keyBoostingStatsLocksCount()) | |
448 | + | $Tuple2(nil, makeString(["%d%d%d%d", toString(totalWxReleased), toString(totalWxLocked), toString(locksDurationSumInBlocks), toString(locksCount)], SEP)) | |
449 | + | } | |
450 | + | ||
451 | + | ||
452 | + | ||
453 | + | @Callable(i) | |
454 | + | func poolStatsREADONLY (lpAsset) = { | |
455 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAsset))) | |
456 | + | let cfg = asAnyList(invoke(poolAddress, "getPoolConfigWrapperREADONLY", nil, nil)) | |
457 | + | let lpAssetId = fromBase58String(asString(cfg[idxPoolLPAssetId])) | |
458 | + | let amtAssetId = asString(cfg[idxAmtAssetId]) | |
459 | + | let priceAssetId = asString(cfg[idxPriceAssetId]) | |
460 | + | let iAmtAssetId = asString(cfg[idxIAmtAssetId]) | |
461 | + | let iPriceAssetId = asString(cfg[idxIPriceAssetId]) | |
462 | + | let amtAssetDcm = parseIntValue(asString(cfg[idxAmtAssetDcm])) | |
463 | + | let priceAssetDcm = parseIntValue(asString(cfg[idxPriceAssetDcm])) | |
464 | + | let poolLPBalance = valueOrErrorMessage(assetInfo(lpAssetId), (("Asset " + toBase58String(lpAssetId)) + " doesn't exist")).quantity | |
465 | + | let accAmtAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [amtAssetId], nil)) | |
466 | + | let accPriceAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [priceAssetId], nil)) | |
467 | + | let pricesList = if ((poolLPBalance == 0)) | |
468 | + | then [toString(zeroBigInt), toString(zeroBigInt), toString(zeroBigInt)] | |
469 | + | else asAnyList(invoke(poolAddress, "calcPricesWrapperREADONLY", [accAmtAssetBalance, accPriceAssetBalance, poolLPBalance], nil)) | |
470 | + | let curPrice = 0 | |
471 | + | let lpAmtAssetShare = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [pricesList[1], MULT8], nil)) | |
472 | + | let lpPriceAssetShare = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [pricesList[2], MULT8], nil)) | |
473 | + | let poolWeight = getIntegerValue(factoryDapp, keyFactoryPoolWeight(toString(poolAddress))) | |
474 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d", toString(accAmtAssetBalance), toString(accPriceAssetBalance), toString(poolLPBalance), toString(curPrice), toString(lpAmtAssetShare), toString(lpPriceAssetShare), toString(poolWeight)], SEP)) | |
475 | + | } | |
476 | + | ||
477 | + | ||
478 | + | ||
479 | + | @Callable(i) | |
480 | + | func poolEvaluatePutByAmountAssetREADONLY (lpAsset,inAmAssetAmt) = { | |
481 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAsset))) | |
482 | + | let cfg = asAnyList(invoke(poolAddress, "getPoolConfigWrapperREADONLY", nil, nil)) | |
483 | + | let lpAssetId = fromBase58String(asString(cfg[idxPoolLPAssetId])) | |
484 | + | let amAssetIdStr = asString(cfg[idxAmtAssetId]) | |
485 | + | let amAssetId = fromBase58String(amAssetIdStr) | |
486 | + | let prAssetIdStr = asString(cfg[idxPriceAssetId]) | |
487 | + | let prAssetId = fromBase58String(prAssetIdStr) | |
488 | + | let amtAssetDcm = parseIntValue(asString(cfg[idxAmtAssetDcm])) | |
489 | + | let priceAssetDcm = parseIntValue(asString(cfg[idxPriceAssetDcm])) | |
490 | + | let poolStatus = asString(cfg[idxPoolStatus]) | |
491 | + | let poolLPBalance = valueOrErrorMessage(assetInfo(lpAssetId), (("Asset " + toBase58String(lpAssetId)) + " doesn't exist")).quantity | |
492 | + | let accAmtAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [amAssetIdStr], nil)) | |
493 | + | let accPriceAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [prAssetIdStr], nil)) | |
494 | + | let amtAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [accAmtAssetBalance, amtAssetDcm], nil))) | |
495 | + | let priceAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [accPriceAssetBalance, priceAssetDcm], nil))) | |
496 | + | let curPriceX18 = if ((poolLPBalance == 0)) | |
497 | + | then zeroBigInt | |
498 | + | else parseBigIntValue(asString(invoke(poolAddress, "calcPriceBigIntWrapperREADONLY", [toString(priceAssetAmtX18), toString(amtAssetAmtX18)], nil))) | |
499 | + | let curPrice = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(curPriceX18), MULT8], nil)) | |
500 | + | let inAmAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [inAmAssetAmt, amtAssetDcm], nil))) | |
501 | + | let inPrAssetAmtX18 = fraction(inAmAssetAmtX18, curPriceX18, MULT18) | |
502 | + | let inPrAssetAmt = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(inPrAssetAmtX18), priceAssetDcm], nil)) | |
503 | + | let res = invoke(poolAddress, "estimatePutOperationWrapperREADONLY", ["", 500000, inAmAssetAmt, amAssetId, inPrAssetAmt, prAssetId, "", true, false], nil) | |
504 | + | let $t02282123174 = match res { | |
505 | + | case _ => | |
506 | + | if (if ($isInstanceOf($match0._1, "Int")) | |
507 | + | then if ($isInstanceOf($match0._3, "Int")) | |
508 | + | then if ($isInstanceOf($match0._4, "Int")) | |
509 | + | then if ($isInstanceOf($match0._5, "Int")) | |
510 | + | then $isInstanceOf($match0._6, "Int") | |
511 | + | else false | |
512 | + | else false | |
513 | + | else false | |
514 | + | else false) | |
515 | + | then { | |
516 | + | let calcLpAmt = $match0._1 | |
517 | + | let curPriceCalc = $match0._3 | |
518 | + | let amBalance = $match0._4 | |
519 | + | let prBalance = $match0._5 | |
520 | + | let lpEmission = $match0._6 | |
521 | + | $Tuple5(calcLpAmt, curPriceCalc, amBalance, prBalance, lpEmission) | |
522 | + | } | |
523 | + | else throw("Couldn't cast types") | |
524 | + | } | |
525 | + | let calcLpAmt = $t02282123174._1 | |
526 | + | let curPriceCalc = $t02282123174._2 | |
527 | + | let amBalance = $t02282123174._3 | |
528 | + | let prBalance = $t02282123174._4 | |
529 | + | let lpEmission = $t02282123174._5 | |
530 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d%d", toString(calcLpAmt), toString(curPrice), toString(amBalance), toString(prBalance), toString(lpEmission), poolStatus, toString(inAmAssetAmt), toString(inPrAssetAmt)], SEP)) | |
531 | + | } | |
532 | + | ||
533 | + | ||
534 | + | ||
535 | + | @Callable(i) | |
536 | + | func poolEvaluatePutByPriceAssetREADONLY (lpAsset,inPrAssetAmt) = { | |
537 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAsset))) | |
538 | + | let cfg = asAnyList(invoke(poolAddress, "getPoolConfigWrapperREADONLY", nil, nil)) | |
539 | + | let lpAssetId = fromBase58String(asString(cfg[idxPoolLPAssetId])) | |
540 | + | let amAssetIdStr = asString(cfg[idxAmtAssetId]) | |
541 | + | let amAssetId = fromBase58String(amAssetIdStr) | |
542 | + | let prAssetIdStr = asString(cfg[idxPriceAssetId]) | |
543 | + | let prAssetId = fromBase58String(prAssetIdStr) | |
544 | + | let amtAssetDcm = parseIntValue(asString(cfg[idxAmtAssetDcm])) | |
545 | + | let priceAssetDcm = parseIntValue(asString(cfg[idxPriceAssetDcm])) | |
546 | + | let poolStatus = asString(cfg[idxPoolStatus]) | |
547 | + | let poolLPBalance = valueOrErrorMessage(assetInfo(lpAssetId), (("Asset " + toBase58String(lpAssetId)) + " doesn't exist")).quantity | |
548 | + | let amBalanceRaw = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [amAssetIdStr], nil)) | |
549 | + | let prBalanceRaw = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [prAssetIdStr], nil)) | |
550 | + | let amBalanceRawX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [amBalanceRaw, amtAssetDcm], nil))) | |
551 | + | let prBalanceRawX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [prBalanceRaw, priceAssetDcm], nil))) | |
552 | + | let curPriceX18 = if ((poolLPBalance == 0)) | |
553 | + | then zeroBigInt | |
554 | + | else parseBigIntValue(asString(invoke(poolAddress, "calcPriceBigIntWrapperREADONLY", [toString(prBalanceRawX18), toString(amBalanceRawX18)], nil))) | |
555 | + | let curPrice = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(curPriceX18), MULT8], nil)) | |
556 | + | let inPrAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [inPrAssetAmt, priceAssetDcm], nil))) | |
557 | + | let inAmAssetAmtX18 = fraction(inPrAssetAmtX18, MULT18, curPriceX18) | |
558 | + | let inAmAssetAmt = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(inAmAssetAmtX18), amtAssetDcm], nil)) | |
559 | + | let res = invoke(poolAddress, "estimatePutOperationWrapperREADONLY", ["", 500000, inAmAssetAmt, amAssetId, inPrAssetAmt, prAssetId, "", true, false], nil) | |
560 | + | let $t02574726100 = match res { | |
561 | + | case _ => | |
562 | + | if (if ($isInstanceOf($match0._1, "Int")) | |
563 | + | then if ($isInstanceOf($match0._3, "Int")) | |
564 | + | then if ($isInstanceOf($match0._4, "Int")) | |
565 | + | then if ($isInstanceOf($match0._5, "Int")) | |
566 | + | then $isInstanceOf($match0._6, "Int") | |
567 | + | else false | |
568 | + | else false | |
569 | + | else false | |
570 | + | else false) | |
571 | + | then { | |
572 | + | let calcLpAmt = $match0._1 | |
573 | + | let curPriceCalc = $match0._3 | |
574 | + | let amBalance = $match0._4 | |
575 | + | let prBalance = $match0._5 | |
576 | + | let lpEmission = $match0._6 | |
577 | + | $Tuple5(calcLpAmt, curPriceCalc, amBalance, prBalance, lpEmission) | |
578 | + | } | |
579 | + | else throw("Couldn't cast types") | |
580 | + | } | |
581 | + | let calcLpAmt = $t02574726100._1 | |
582 | + | let curPriceCalc = $t02574726100._2 | |
583 | + | let amBalance = $t02574726100._3 | |
584 | + | let prBalance = $t02574726100._4 | |
585 | + | let lpEmission = $t02574726100._5 | |
586 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d%d", toString(calcLpAmt), toString(curPrice), toString(amBalance), toString(prBalance), toString(lpEmission), poolStatus, toString(inAmAssetAmt), toString(inPrAssetAmt)], SEP)) | |
587 | + | } | |
588 | + | ||
589 | + | ||
590 | + | ||
591 | + | @Callable(i) | |
592 | + | func poolEvaluateGetREADONLY (paymentLpAssetId,paymentLpAmt) = { | |
593 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(paymentLpAssetId))) | |
594 | + | let res = invoke(poolAddress, "estimateGetOperationWrapperREADONLY", ["", paymentLpAssetId, paymentLpAmt, toString(poolAddress)], nil) | |
595 | + | let $t02679527212 = match res { | |
596 | + | case _ => | |
597 | + | if (if ($isInstanceOf($match0._1, "Int")) | |
598 | + | then if ($isInstanceOf($match0._2, "Int")) | |
599 | + | then if ($isInstanceOf($match0._5, "Int")) | |
600 | + | then if ($isInstanceOf($match0._6, "Int")) | |
601 | + | then if ($isInstanceOf($match0._7, "Int")) | |
602 | + | then if ($isInstanceOf($match0._8, "String")) | |
603 | + | then $isInstanceOf($match0._9, "String") | |
604 | + | else false | |
605 | + | else false | |
606 | + | else false | |
607 | + | else false | |
608 | + | else false | |
609 | + | else false) | |
610 | + | then { | |
611 | + | let outAmAmt = $match0._1 | |
612 | + | let outPrAmt = $match0._2 | |
613 | + | let amBalance = $match0._5 | |
614 | + | let prBalance = $match0._6 | |
615 | + | let lpEmission = $match0._7 | |
616 | + | let curPrice = $match0._8 | |
617 | + | let poolStatus = $match0._9 | |
618 | + | $Tuple7(outAmAmt, outPrAmt, amBalance, prBalance, lpEmission, curPrice, poolStatus) | |
619 | + | } | |
620 | + | else throw("Couldn't cast types") | |
621 | + | } | |
622 | + | let outAmAmt = $t02679527212._1 | |
623 | + | let outPrAmt = $t02679527212._2 | |
624 | + | let amBalance = $t02679527212._3 | |
625 | + | let prBalance = $t02679527212._4 | |
626 | + | let lpEmission = $t02679527212._5 | |
627 | + | let curPrice = $t02679527212._6 | |
628 | + | let poolStatus = $t02679527212._7 | |
629 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d", toString(outAmAmt), toString(outPrAmt), toString(amBalance), toString(prBalance), toString(lpEmission), curPrice, poolStatus], SEP)) | |
630 | + | } | |
631 | + | ||
632 | + | ||
633 | + | ||
634 | + | @Callable(i) | |
635 | + | func gwxUserInfoREADONLY (userAddress) = { | |
636 | + | let gwxUserInfoLIST = asAnyList(invoke(boostingDapp, "gwxUserInfoREADONLY", [userAddress], nil)) | |
637 | + | let gwxAmount = asInt(gwxUserInfoLIST[0]) | |
638 | + | $Tuple2(nil, makeString(["%d", toString(gwxAmount)], SEP)) | |
311 | 639 | } | |
312 | 640 | ||
313 | 641 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let SCALE8 = 8 | |
5 | + | ||
6 | + | let MULT8 = 100000000 | |
7 | + | ||
8 | + | let SCALE18 = 18 | |
9 | + | ||
10 | + | let MULT18 = toBigInt(1000000000000000000) | |
11 | + | ||
12 | + | let SEP = "__" | |
13 | + | ||
14 | + | let POOLWEIGHTMULT = MULT8 | |
15 | + | ||
16 | + | let zeroBigInt = toBigInt(0) | |
17 | + | ||
18 | + | let idxPoolAddress = 1 | |
19 | + | ||
20 | + | let idxPoolStatus = 2 | |
21 | + | ||
22 | + | let idxPoolLPAssetId = 3 | |
23 | + | ||
24 | + | let idxAmtAssetId = 4 | |
25 | + | ||
26 | + | let idxPriceAssetId = 5 | |
27 | + | ||
28 | + | let idxAmtAssetDcm = 6 | |
29 | + | ||
30 | + | let idxPriceAssetDcm = 7 | |
31 | + | ||
32 | + | let idxIAmtAssetId = 8 | |
33 | + | ||
34 | + | let idxIPriceAssetId = 9 | |
35 | + | ||
36 | + | let idxLPAssetDcm = 10 | |
37 | + | ||
4 | 38 | func getStringOrFail (key) = valueOrErrorMessage(getString(key), (("mandatory this." + key) + " is not defined")) | |
5 | 39 | ||
6 | 40 | ||
7 | - | let SEP = "__" | |
8 | - | ||
9 | - | let BUFSCALE = toBigInt(1000000000000000000) | |
10 | - | ||
11 | - | func convertPriceAssetIntoIdoAsset (priceAssetAmount,priceAssetMULT,price,priceMULT,idoAssetMULT) = { | |
12 | - | let bPriceAssetMULT = toBigInt(priceAssetMULT) | |
13 | - | let bIdoAssetMULT = toBigInt(idoAssetMULT) | |
14 | - | let bPriceAssetBUF = fraction(toBigInt(priceAssetAmount), BUFSCALE, bPriceAssetMULT) | |
15 | - | let bAmountAssetBUF = fraction(bPriceAssetBUF, toBigInt(priceMULT), toBigInt(price)) | |
16 | - | toInt(fraction(bAmountAssetBUF, toBigInt(idoAssetMULT), BUFSCALE)) | |
17 | - | } | |
41 | + | func getStringByAddressOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined")) | |
18 | 42 | ||
19 | 43 | ||
20 | - | let IdxCfgIdoStart = 1 | |
21 | - | ||
22 | - | let IdxCfgIdoDuration = 2 | |
23 | - | ||
24 | - | let IdxCfgClaimStart = 3 | |
25 | - | ||
26 | - | let IdxCfgClaimDuration = 4 | |
27 | - | ||
28 | - | let IdxCfgPrice = 5 | |
29 | - | ||
30 | - | let IdxCfgPriceMult = 6 | |
31 | - | ||
32 | - | let IdxCfgIdoAssetId = 7 | |
33 | - | ||
34 | - | let IdxCfgIdoAssetMult = 8 | |
35 | - | ||
36 | - | let IdxCfgPriceAssetId = 9 | |
37 | - | ||
38 | - | let IdxCfgPriceAssetMult = 10 | |
39 | - | ||
40 | - | let IdxCfgMinInvestAmount = 11 | |
41 | - | ||
42 | - | func fromatConfigS (idoStart,idoDuration,claimStart,claimDuration,price,priceMult,idoAssetId58,idoAssetMult,priceAssetId58,priceAssetMult,minInvestAmount,totalIdoAssetToSell) = makeString(["%d%d%d%d%d%d%s%d%s%d%d%d", idoStart, idoDuration, claimStart, claimDuration, price, priceMult, idoAssetId58, idoAssetMult, priceAssetId58, priceAssetMult, minInvestAmount, totalIdoAssetToSell], SEP) | |
44 | + | func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0) | |
43 | 45 | ||
44 | 46 | ||
45 | - | func | |
47 | + | func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined")) | |
46 | 48 | ||
47 | 49 | ||
48 | - | let IdxInvTotalAmount = 1 | |
49 | - | ||
50 | - | let IdxInvRemainingAmount = 2 | |
51 | - | ||
52 | - | let IdxInvClaimedPriceAssetAmount = 3 | |
53 | - | ||
54 | - | let IdxInvClaimedIdoAssetAmount = 4 | |
55 | - | ||
56 | - | let IdxInvLastClaimedHeight = 5 | |
57 | - | ||
58 | - | func formatInvestorS (totalAmount,remainingAmount,claimedPriceAssetAmount,claimedIdoAssetAmount,lastClaimedHeight) = makeString(["%d%d%d%d%d", totalAmount, remainingAmount, claimedPriceAssetAmount, claimedIdoAssetAmount, lastClaimedHeight], SEP) | |
50 | + | func asAnyList (val) = match val { | |
51 | + | case valAnyLyst: List[Any] => | |
52 | + | valAnyLyst | |
53 | + | case _ => | |
54 | + | throw("fail to cast into List[Any]") | |
55 | + | } | |
59 | 56 | ||
60 | 57 | ||
61 | - | func formatInvestor (totalAmount,remainingAmount,claimedPriceAssetAmount,claimedIdoAssetAmount,lastClaimedHeight) = formatInvestorS(toString(totalAmount), toString(remainingAmount), toString(claimedPriceAssetAmount), toString(claimedIdoAssetAmount), toString(lastClaimedHeight)) | |
58 | + | func asInt (val) = match val { | |
59 | + | case valInt: Int => | |
60 | + | valInt | |
61 | + | case _ => | |
62 | + | throw("fail to cast into Int") | |
63 | + | } | |
62 | 64 | ||
63 | 65 | ||
64 | - | func formatHistoryRecord (priceAssetAmount,idoAssetAmount) = makeString(["%d%d%d%d", toString(height), toString(lastBlock.timestamp), toString(priceAssetAmount), toString(idoAssetAmount)], SEP) | |
66 | + | func asString (val) = match val { | |
67 | + | case valStr: String => | |
68 | + | valStr | |
69 | + | case _ => | |
70 | + | throw("fail to cast into String") | |
71 | + | } | |
65 | 72 | ||
66 | 73 | ||
67 | - | func keyConfig () = "%s__config" | |
68 | - | ||
69 | - | ||
70 | - | func keyInvestor (userAddress) = ("%s__" + userAddress) | |
71 | - | ||
72 | - | ||
73 | - | func keyTotals () = "%s__totals" | |
74 | - | ||
75 | - | ||
76 | - | func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP) | |
74 | + | func keyFactoryAddress () = "%s%s__config__factoryAddress" | |
77 | 75 | ||
78 | 76 | ||
79 | 77 | func keyManagerPublicKey () = "%s__managerPublicKey" | |
80 | 78 | ||
81 | 79 | ||
82 | 80 | func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey" | |
83 | 81 | ||
84 | 82 | ||
85 | - | func readConfigArray () = split(getStringOrFail(keyConfig()), SEP) | |
83 | + | let IdxFactoryCfgStakingDapp = 1 | |
84 | + | ||
85 | + | let IdxFactoryCfgBoostingDapp = 2 | |
86 | + | ||
87 | + | let IdxFactoryCfgIdoDapp = 3 | |
88 | + | ||
89 | + | let IdxFactoryCfgTeamDapp = 4 | |
90 | + | ||
91 | + | let IdxFactoryCfgEmissionDapp = 5 | |
92 | + | ||
93 | + | let IdxFactoryCfgRestDapp = 6 | |
94 | + | ||
95 | + | let IdxFactoryCfgSlippageDapp = 7 | |
96 | + | ||
97 | + | let IdxFactoryCfgGwxRewardDapp = 8 | |
98 | + | ||
99 | + | func keyFactoryCfg () = "%s__factoryConfig" | |
86 | 100 | ||
87 | 101 | ||
88 | - | func | |
102 | + | func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP) | |
89 | 103 | ||
90 | 104 | ||
91 | - | func | |
105 | + | func keyFactoryLpList () = "%s__lpTokensList" | |
92 | 106 | ||
93 | 107 | ||
94 | - | func | |
108 | + | func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP) | |
95 | 109 | ||
96 | 110 | ||
97 | - | func | |
111 | + | func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP) | |
98 | 112 | ||
99 | 113 | ||
100 | - | ||
114 | + | func readFactoryAddressOrFail () = addressFromStringValue(getStringOrFail(keyFactoryAddress())) | |
101 | 115 | ||
102 | - | let IdxDiffRemainingPriceAmountIncrement = 1 | |
103 | 116 | ||
104 | - | ||
117 | + | func readLpList () = split(valueOrElse(getString(readFactoryAddressOrFail(), keyFactoryLpList()), ""), SEP) | |
105 | 118 | ||
106 | - | let IdxDiffClaimedIdoAssetAmountIncrement = 3 | |
107 | 119 | ||
108 | - | func TotalsEntry (key,origArray,incrementDiff,newLastClaimedHeight) = { | |
109 | - | let totalAmount = parseIntValue(origArray[IdxInvTotalAmount]) | |
110 | - | let remainingAmount = parseIntValue(origArray[IdxInvRemainingAmount]) | |
111 | - | let claimedPriceAssetAmount = parseIntValue(origArray[IdxInvClaimedPriceAssetAmount]) | |
112 | - | let claimedIdoAssetAmount = parseIntValue(origArray[IdxInvClaimedIdoAssetAmount]) | |
113 | - | let lastClaimedHeight = parseIntValue(origArray[IdxInvLastClaimedHeight]) | |
114 | - | let newTotalAmount = (totalAmount + incrementDiff[IdxDiffTotalIncrement]) | |
115 | - | let newRemainingAmount = (remainingAmount + incrementDiff[IdxDiffRemainingPriceAmountIncrement]) | |
116 | - | let newClaimedPriceAssetAmount = (claimedPriceAssetAmount + incrementDiff[IdxDiffClaimedPriceAmountIncrement]) | |
117 | - | let newClaimedIdoAssetAmount = (claimedIdoAssetAmount + incrementDiff[IdxDiffClaimedIdoAssetAmountIncrement]) | |
118 | - | if ((0 > newRemainingAmount)) | |
119 | - | then throw("invalid math") | |
120 | - | else StringEntry(key, formatInvestor(newTotalAmount, newRemainingAmount, newClaimedPriceAssetAmount, newClaimedIdoAssetAmount, newLastClaimedHeight)) | |
120 | + | func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP) | |
121 | + | ||
122 | + | ||
123 | + | func getBoostingAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgBoostingDapp]) | |
124 | + | ||
125 | + | ||
126 | + | func getEmissionAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgEmissionDapp]) | |
127 | + | ||
128 | + | ||
129 | + | func getStakingAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgStakingDapp]) | |
130 | + | ||
131 | + | ||
132 | + | func getGwxRewardAddressOrFail (fCfg) = addressFromStringValue(fCfg[IdxFactoryCfgGwxRewardDapp]) | |
133 | + | ||
134 | + | ||
135 | + | func keyBoostCfg () = "%s__config" | |
136 | + | ||
137 | + | ||
138 | + | func keyBoostingLockParamTotalAmount () = "%s%s__stats__activeTotalLocked" | |
139 | + | ||
140 | + | ||
141 | + | func keyBoostingStatsLocksDurationSumInBlocks () = "%s%s__stats__locksDurationSumInBlocks" | |
142 | + | ||
143 | + | ||
144 | + | func keyBoostingStatsLocksCount () = "%s%s__stats__locksCount" | |
145 | + | ||
146 | + | ||
147 | + | func keyBoostingStatsUsersCount () = "%s%s__stats__activeUsersCount" | |
148 | + | ||
149 | + | ||
150 | + | func keyUser2NumMapping (userAddress) = makeString(["%s%s%s__mapping__user2num", userAddress], SEP) | |
151 | + | ||
152 | + | ||
153 | + | func keyNum2UserMapping (num) = makeString(["%s%s%s__mapping__num2user", num], SEP) | |
154 | + | ||
155 | + | ||
156 | + | func keyLockParamUserAmount (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "amount"], SEP) | |
157 | + | ||
158 | + | ||
159 | + | func keyLockParamStartBlock (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "start"], SEP) | |
160 | + | ||
161 | + | ||
162 | + | func keyLockParamDuration (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "duration"], SEP) | |
163 | + | ||
164 | + | ||
165 | + | func keyLockParamK (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "k"], SEP) | |
166 | + | ||
167 | + | ||
168 | + | func keyLockParamB (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "b"], SEP) | |
169 | + | ||
170 | + | ||
171 | + | func keyLockParamByPeriodK (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "k", period], SEP) | |
172 | + | ||
173 | + | ||
174 | + | func keyLockParamByPeriodB (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "b", period], SEP) | |
175 | + | ||
176 | + | ||
177 | + | func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastInt", userNum], SEP) | |
178 | + | ||
179 | + | ||
180 | + | func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", userNum], SEP) | |
181 | + | ||
182 | + | ||
183 | + | func keyTotalMaxBoostINTEGRAL () = "%s%s__maxBoostInt__total" | |
184 | + | ||
185 | + | ||
186 | + | func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", userNum], SEP) | |
187 | + | ||
188 | + | ||
189 | + | func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", userNum], SEP) | |
190 | + | ||
191 | + | ||
192 | + | func keyTotalCachedGwx () = "%s%s__gwxCached__total" | |
193 | + | ||
194 | + | ||
195 | + | func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP) | |
196 | + | ||
197 | + | ||
198 | + | func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr) | |
199 | + | ||
200 | + | ||
201 | + | func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP) | |
202 | + | ||
203 | + | ||
204 | + | func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP) | |
205 | + | ||
206 | + | ||
207 | + | func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP) | |
208 | + | ||
209 | + | ||
210 | + | func readStaked (stakingDapp,key) = valueOrElse(getInteger(stakingDapp, key), 0) | |
211 | + | ||
212 | + | ||
213 | + | func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current" | |
214 | + | ||
215 | + | ||
216 | + | func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current" | |
217 | + | ||
218 | + | ||
219 | + | func keyEmissionStartBlock () = "%s%s__emission__startBlock" | |
220 | + | ||
221 | + | ||
222 | + | func keyEmissionDurationInBlocks () = "%s%s__emission__duration" | |
223 | + | ||
224 | + | ||
225 | + | func keyEmissionEndBlock () = "%s%s__emission__endBlock" | |
226 | + | ||
227 | + | ||
228 | + | let factoryDapp = readFactoryAddressOrFail() | |
229 | + | ||
230 | + | let factoryCfg = readFactoryCfgOrFail(factoryDapp) | |
231 | + | ||
232 | + | let emissionDapp = getEmissionAddressOrFail(factoryCfg) | |
233 | + | ||
234 | + | let stakingDapp = getStakingAddressOrFail(factoryCfg) | |
235 | + | ||
236 | + | let gwxRewardDapp = getGwxRewardAddressOrFail(factoryCfg) | |
237 | + | ||
238 | + | let boostingDapp = getBoostingAddressOrFail(factoryCfg) | |
239 | + | ||
240 | + | func internalCurrentRewardRate (lpAssetId) = { | |
241 | + | let poolAddressStr = getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAssetId)) | |
242 | + | let poolWeightMult = MULT8 | |
243 | + | let poolWeight = getIntegerValue(factoryDapp, keyFactoryPoolWeight(poolAddressStr)) | |
244 | + | let wxEmissionPerBlock = getIntOrFail(emissionDapp, keyEmissionRatePerBlockCurrent()) | |
245 | + | let wxEmissionPerBlockMax = getIntOrFail(emissionDapp, keyEmissionRatePerBlockMaxCurrent()) | |
246 | + | let boostMaxCoeff = 3 | |
247 | + | let poolWxEmissionPerBlock = (fraction(wxEmissionPerBlock, poolWeight, poolWeightMult) / boostMaxCoeff) | |
248 | + | let poolWxEmissionPerBlockMax = fraction(wxEmissionPerBlockMax, poolWeight, poolWeightMult) | |
249 | + | let maxFactor = (boostMaxCoeff * MULT8) | |
250 | + | let totalLpStaked = getIntOrZero(stakingDapp, keyStakedTotal(lpAssetId)) | |
251 | + | [poolWxEmissionPerBlock, maxFactor, totalLpStaked] | |
121 | 252 | } | |
122 | 253 | ||
123 | 254 | ||
124 | - | func InvestOperationHistoryEntry (userAddress,priceAssetAmount,idoAssetAmount,txId) = StringEntry(keyOperationHistoryRecord("invest", userAddress, toBase58String(txId)), formatHistoryRecord(priceAssetAmount, idoAssetAmount)) | |
125 | - | ||
126 | - | ||
127 | - | func ClaimOperationHistoryEntry (userAddress,priceAssetAmount,idoAssetAmount,txId) = StringEntry(keyOperationHistoryRecord("claim", userAddress, toBase58String(txId)), formatHistoryRecord(priceAssetAmount, idoAssetAmount)) | |
128 | - | ||
129 | - | ||
130 | - | func internalClaim (claimedAssetId58,userAddress,txId) = { | |
131 | - | let cfgArray = readConfigArray() | |
132 | - | let claimStart = parseIntValue(cfgArray[IdxCfgClaimStart]) | |
133 | - | let claimDuration = parseIntValue(cfgArray[IdxCfgClaimDuration]) | |
134 | - | let claimEnd = (claimStart + claimDuration) | |
135 | - | let price = parseIntValue(cfgArray[IdxCfgPrice]) | |
136 | - | let priceMult = parseIntValue(cfgArray[IdxCfgPriceMult]) | |
137 | - | let idoAssetId58 = cfgArray[IdxCfgIdoAssetId] | |
138 | - | let idoAssetId = fromBase58String(idoAssetId58) | |
139 | - | let idoAssetMult = parseIntValue(cfgArray[IdxCfgIdoAssetMult]) | |
140 | - | let priceAssetId58 = cfgArray[IdxCfgPriceAssetId] | |
141 | - | let priceAssetId = fromBase58String(priceAssetId58) | |
142 | - | let priceAssetMult = parseIntValue(cfgArray[IdxCfgPriceAssetMult]) | |
143 | - | let userAddress58 = toString(userAddress) | |
144 | - | let origInvestArray = readInvestorArrayOrFail(userAddress58) | |
145 | - | let investTotalAmount = parseIntValue(origInvestArray[IdxInvTotalAmount]) | |
146 | - | let investLastClaimedHeightTMP = parseIntValue(origInvestArray[IdxInvLastClaimedHeight]) | |
147 | - | let investLastClaimedHeight = if ((claimStart >= investLastClaimedHeightTMP)) | |
148 | - | then claimStart | |
149 | - | else investLastClaimedHeightTMP | |
150 | - | let newClaimPeriodHeight = if ((height > claimEnd)) | |
151 | - | then claimEnd | |
152 | - | else if ((claimStart > height)) | |
153 | - | then claimStart | |
154 | - | else height | |
155 | - | let claimingBlocks = (newClaimPeriodHeight - investLastClaimedHeight) | |
156 | - | let claimingPriceAssetAmount = fraction(investTotalAmount, claimingBlocks, claimDuration) | |
157 | - | let claimingIdoAssetAmount = convertPriceAssetIntoIdoAsset(claimingPriceAssetAmount, priceAssetMult, price, priceMult, idoAssetMult) | |
158 | - | if ((claimedAssetId58 == priceAssetId58)) | |
159 | - | then $Tuple6([0, -(claimingPriceAssetAmount), claimingPriceAssetAmount, 0], claimingPriceAssetAmount, priceAssetId, origInvestArray, newClaimPeriodHeight, [claimingPriceAssetAmount, claimingIdoAssetAmount]) | |
160 | - | else if ((claimedAssetId58 == idoAssetId58)) | |
161 | - | then $Tuple6([0, -(claimingPriceAssetAmount), 0, claimingIdoAssetAmount], claimingIdoAssetAmount, idoAssetId, origInvestArray, newClaimPeriodHeight, [claimingPriceAssetAmount, claimingIdoAssetAmount]) | |
162 | - | else throw(("unsupported assetId: " + claimedAssetId58)) | |
255 | + | func calcGwxAmountStartREADONLY (lockAmount,lockDuration,maxLockDuration) = { | |
256 | + | let coeffX8 = fraction(lockDuration, MULT8, maxLockDuration) | |
257 | + | let gWxAmountStart = fraction(lockAmount, coeffX8, MULT8) | |
258 | + | [gWxAmountStart] | |
163 | 259 | } | |
164 | 260 | ||
165 | 261 | ||
166 | 262 | func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) { | |
167 | 263 | case s: String => | |
168 | 264 | fromBase58String(s) | |
169 | 265 | case _: Unit => | |
170 | 266 | unit | |
171 | 267 | case _ => | |
172 | 268 | throw("Match error") | |
173 | 269 | } | |
174 | 270 | ||
175 | 271 | ||
176 | 272 | func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) { | |
177 | 273 | case s: String => | |
178 | 274 | fromBase58String(s) | |
179 | 275 | case _: Unit => | |
180 | 276 | unit | |
181 | 277 | case _ => | |
182 | 278 | throw("Match error") | |
183 | 279 | } | |
184 | 280 | ||
185 | 281 | ||
186 | 282 | func mustManager (i) = { | |
187 | 283 | let pd = throw("Permission denied") | |
188 | 284 | match managerPublicKeyOrUnit() { | |
189 | 285 | case pk: ByteVector => | |
190 | 286 | if ((i.callerPublicKey == pk)) | |
191 | 287 | then true | |
192 | 288 | else pd | |
193 | 289 | case _: Unit => | |
194 | 290 | if ((i.caller == this)) | |
195 | 291 | then true | |
196 | 292 | else pd | |
197 | 293 | case _ => | |
198 | 294 | throw("Match error") | |
199 | 295 | } | |
200 | 296 | } | |
201 | 297 | ||
202 | 298 | ||
203 | 299 | @Callable(i) | |
204 | - | func constructor (idoStart,idoDuration,claimStart,claimDuration,price,priceAssetId58,minInvestAmount) = { | |
205 | - | let priceMult = ((100 * 1000) * 1000) | |
206 | - | let idoEnd = (idoStart + idoDuration) | |
207 | - | if (isDefined(getString(keyConfig()))) | |
208 | - | then throw("already initialized") | |
209 | - | else if (("3PMEHLx1j6zerarZTYfsGqDeeZqQoMpxq5S" != toString(i.caller))) | |
210 | - | then throw("not authorized") | |
211 | - | else if ((size(i.payments) != 1)) | |
212 | - | then throw("exactly 1 payment must be attached") | |
213 | - | else if ((idoEnd >= claimStart)) | |
214 | - | then throw("claimStart must be greater than idoEnd") | |
215 | - | else { | |
216 | - | let pmt = value(i.payments[0]) | |
217 | - | let idoAssetId = value(pmt.assetId) | |
218 | - | let idoAssetInfo = valueOrErrorMessage(assetInfo(idoAssetId), "fail to load ido asset info") | |
219 | - | let idoAssetId58 = toBase58String(idoAssetId) | |
220 | - | let idoAssetMult = pow(10, 0, idoAssetInfo.decimals, 0, 0, DOWN) | |
221 | - | let priceAssetId = fromBase58String(priceAssetId58) | |
222 | - | let priceAssetInfo = valueOrErrorMessage(assetInfo(priceAssetId), "fail to load price asset info") | |
223 | - | let priceAssetMult = pow(10, 0, priceAssetInfo.decimals, 0, 0, DOWN) | |
224 | - | let origTotalsArray = readTotalsArrayOrDefault() | |
225 | - | let totalsDiff = [0, 0, 0, 0] | |
226 | - | [StringEntry(keyConfig(), fromatConfig(idoStart, idoDuration, claimStart, claimDuration, price, priceMult, idoAssetId58, idoAssetMult, priceAssetId58, priceAssetMult, minInvestAmount, pmt.amount)), TotalsEntry(keyTotals(), origTotalsArray, totalsDiff, claimStart)] | |
227 | - | } | |
300 | + | func constructor (factoryAddress) = if ((i.caller != this)) | |
301 | + | then throw("not authorized") | |
302 | + | else [StringEntry(keyFactoryAddress(), factoryAddress)] | |
303 | + | ||
304 | + | ||
305 | + | ||
306 | + | @Callable(i) | |
307 | + | func currentRewardRateREADONLY (lpAssetId) = { | |
308 | + | let rewardData = internalCurrentRewardRate(lpAssetId) | |
309 | + | let wxEmissionPerBlock = rewardData[0] | |
310 | + | let maxFactor = rewardData[1] | |
311 | + | let totalLpStaked = rewardData[2] | |
312 | + | $Tuple2(nil, makeString(["%d%d%d", toString(wxEmissionPerBlock), toString(maxFactor), toString(totalLpStaked)], SEP)) | |
228 | 313 | } | |
229 | 314 | ||
230 | 315 | ||
231 | 316 | ||
232 | 317 | @Callable(i) | |
233 | - | func invest () = { | |
234 | - | let cfgArray = readConfigArray() | |
235 | - | let idoStart = parseIntValue(cfgArray[IdxCfgIdoStart]) | |
236 | - | let idoDuration = parseIntValue(cfgArray[IdxCfgIdoDuration]) | |
237 | - | let idoEnd = (idoStart + idoDuration) | |
238 | - | let claimStart = parseIntValue(cfgArray[IdxCfgClaimStart]) | |
239 | - | let claimDuration = parseIntValue(cfgArray[IdxCfgClaimDuration]) | |
240 | - | let price = parseIntValue(cfgArray[IdxCfgPrice]) | |
241 | - | let priceMult = parseIntValue(cfgArray[IdxCfgPriceMult]) | |
242 | - | let idoAssetId58 = cfgArray[IdxCfgIdoAssetId] | |
243 | - | let idoAssetId = fromBase58String(idoAssetId58) | |
244 | - | let idoAssetMult = parseIntValue(cfgArray[IdxCfgIdoAssetMult]) | |
245 | - | let priceAssetId58 = cfgArray[IdxCfgPriceAssetId] | |
246 | - | let priceAssetId = fromBase58String(priceAssetId58) | |
247 | - | let priceAssetMult = parseIntValue(cfgArray[IdxCfgPriceAssetMult]) | |
248 | - | let minIvestAmount = parseIntValue(cfgArray[IdxCfgMinInvestAmount]) | |
249 | - | let userAddress = toString(i.caller) | |
250 | - | if ((idoStart > height)) | |
251 | - | then throw("ido has not been started yet") | |
252 | - | else if ((height > idoEnd)) | |
253 | - | then throw("ido has been already ended") | |
254 | - | else if ((size(i.payments) != 1)) | |
255 | - | then throw("exactly 1 payment is expected") | |
256 | - | else { | |
257 | - | let pmt = value(i.payments[0]) | |
258 | - | let pmtAssetId = value(pmt.assetId) | |
259 | - | let pmtAmount = pmt.amount | |
260 | - | if ((pmtAssetId != priceAssetId)) | |
261 | - | then throw((("invalid payment asset id: " + toBase58String(pmtAssetId)) + " is expected")) | |
262 | - | else { | |
263 | - | let origInvestorArray = readInvestorArrayOrDefault(userAddress) | |
264 | - | let origTotalsArray = readTotalsArrayOrDefault() | |
265 | - | let newPriceTotalAmount = (parseIntValue(origTotalsArray[IdxInvTotalAmount]) + pmtAmount) | |
266 | - | let requiredIdoAssetAmount = (newPriceTotalAmount * 100) | |
267 | - | if ((requiredIdoAssetAmount > assetBalance(this, idoAssetId))) | |
268 | - | then throw("IDO asset has been - sold consider to use smaller payment") | |
269 | - | else { | |
270 | - | let totalsDiff = [pmtAmount, pmtAmount, 0, 0] | |
271 | - | [TotalsEntry(keyInvestor(userAddress), origInvestorArray, totalsDiff, claimStart), TotalsEntry(keyTotals(), origTotalsArray, totalsDiff, claimStart), InvestOperationHistoryEntry(userAddress, pmtAmount, 0, i.transactionId)] | |
272 | - | } | |
273 | - | } | |
274 | - | } | |
318 | + | func currentUserRewardRateREADONLY (lpAssetId,userAddress) = { | |
319 | + | let rewardData = internalCurrentRewardRate(lpAssetId) | |
320 | + | let wxEmissionPerBlock = rewardData[0] | |
321 | + | let maxFactor = rewardData[1] | |
322 | + | let totalLpStaked = rewardData[2] | |
323 | + | let lpStakedByUser = getIntOrZero(stakingDapp, keyStakedByUser(userAddress, lpAssetId)) | |
324 | + | let userClaimInfo = split(asString(invoke(stakingDapp, "claimWxREADONLY", [lpAssetId, userAddress], nil)), SEP) | |
325 | + | let minRewardPart = valueOrErrorMessage(parseInt(userClaimInfo[5]), "couldn't parse minRewardPart") | |
326 | + | let boostRewardPart = valueOrErrorMessage(parseInt(userClaimInfo[6]), "couldn't parse boostRewardPart") | |
327 | + | let debug = userClaimInfo[7] | |
328 | + | let boostingPower = if ((boostRewardPart == 0)) | |
329 | + | then (1 * MULT8) | |
330 | + | else fraction((minRewardPart + boostRewardPart), MULT8, minRewardPart) | |
331 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%s", toString(wxEmissionPerBlock), toString(maxFactor), toString(totalLpStaked), toString(lpStakedByUser), toString(boostingPower), debug], SEP)) | |
275 | 332 | } | |
276 | 333 | ||
277 | 334 | ||
278 | 335 | ||
279 | 336 | @Callable(i) | |
280 | - | func claim (claimedAssetId58,userAddress58) = { | |
281 | - | let callerAddress58 = toString(i.caller) | |
282 | - | if ((userAddress58 != callerAddress58)) | |
283 | - | then throw("not authorized") | |
284 | - | else { | |
285 | - | let claimResultTuple = internalClaim(claimedAssetId58, i.caller, i.transactionId) | |
286 | - | let totalsDiff = claimResultTuple._1 | |
287 | - | let outAmount = claimResultTuple._2 | |
288 | - | let outAssetId = claimResultTuple._3 | |
289 | - | let origInvestArray = claimResultTuple._4 | |
290 | - | let newClaimPeriodHeight = claimResultTuple._5 | |
291 | - | let claimedPriceAmountFromDiff = totalsDiff[IdxDiffClaimedPriceAmountIncrement] | |
292 | - | let claimedIdoAssetAmountFromDiff = totalsDiff[IdxDiffClaimedIdoAssetAmountIncrement] | |
293 | - | $Tuple2([ScriptTransfer(i.caller, outAmount, outAssetId), TotalsEntry(keyInvestor(userAddress58), origInvestArray, totalsDiff, newClaimPeriodHeight), TotalsEntry(keyTotals(), readTotalsArrayOrDefault(), totalsDiff, newClaimPeriodHeight), ClaimOperationHistoryEntry(userAddress58, claimedPriceAmountFromDiff, claimedIdoAssetAmountFromDiff, i.transactionId)], unit) | |
294 | - | } | |
337 | + | func claimedRewardREADONLY (userAddress) = { | |
338 | + | let lpList = readLpList() | |
339 | + | let prefix = "%s%d%d%d%s" | |
340 | + | func claimedRewardByLpAggregator (resultStr,nextLp) = { | |
341 | + | let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(nextLp, userAddress) | |
342 | + | let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(nextLp, userAddress) | |
343 | + | let minRewardClaimed = valueOrElse(getInteger(stakingDapp, claimedByUserMinRewardKEY), 0) | |
344 | + | let boostRewardClaimed = valueOrElse(getInteger(stakingDapp, claimedByUserBoostRewardKEY), 0) | |
345 | + | let gFeeClaimed = 0 | |
346 | + | makeString([(prefix + resultStr), nextLp, toString(minRewardClaimed), toString(boostRewardClaimed), toString(gFeeClaimed), "end"], SEP) | |
347 | + | } | |
348 | + | ||
349 | + | let result = { | |
350 | + | let $l = lpList | |
351 | + | let $s = size($l) | |
352 | + | let $acc0 = "%s" | |
353 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
354 | + | then $a | |
355 | + | else claimedRewardByLpAggregator($a, $l[$i]) | |
356 | + | ||
357 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
358 | + | then $a | |
359 | + | else throw("List size exceeds 10") | |
360 | + | ||
361 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10) | |
362 | + | } | |
363 | + | $Tuple2(nil, ((result + SEP) + userAddress)) | |
295 | 364 | } | |
296 | 365 | ||
297 | 366 | ||
298 | 367 | ||
299 | 368 | @Callable(i) | |
300 | - | func claimREADONLY (claimedAssetId58,userAddress58) = { | |
301 | - | let claimResultTuple = internalClaim(claimedAssetId58, addressFromStringValue(userAddress58), fromBase58String("")) | |
302 | - | let totalsDiff = claimResultTuple._1 | |
303 | - | let outAmount = claimResultTuple._2 | |
304 | - | let outAssetId = claimResultTuple._3 | |
305 | - | let origInvestArray = claimResultTuple._4 | |
306 | - | let newClaimPeriodHeight = claimResultTuple._5 | |
307 | - | let availableToClaimArray = claimResultTuple._6 | |
308 | - | let availablePriceAmountToClaim = availableToClaimArray[0] | |
309 | - | let availableIdoAmountToClaim = availableToClaimArray[1] | |
310 | - | $Tuple2(nil, makeString(["%s%d%d", userAddress58, toString(availablePriceAmountToClaim), toString(availableIdoAmountToClaim)], SEP)) | |
369 | + | func calcBoostREADONLY (deltaWxAmount,deltaLockPeriodInBlocks,deltaLpAmount,lpAssetIdOpt,userAddressOpt) = { | |
370 | + | let mathDapp = gwxRewardDapp | |
371 | + | let EMPTYSTR = "empty" | |
372 | + | let maxLockDurationInBlocks = parseIntValue(split(getStringByAddressOrFail(boostingDapp, keyBoostCfg()), SEP)[4]) | |
373 | + | let lpAssetIdStr = if ((lpAssetIdOpt == "")) | |
374 | + | then EMPTYSTR | |
375 | + | else lpAssetIdOpt | |
376 | + | let userAddressStr = if ((userAddressOpt == "")) | |
377 | + | then EMPTYSTR | |
378 | + | else userAddressOpt | |
379 | + | let userNumStr = valueOrElse(getString(boostingDapp, keyUser2NumMapping(userAddressOpt)), EMPTYSTR) | |
380 | + | let userAmount = valueOrElse(getInteger(boostingDapp, keyLockParamUserAmount(userNumStr)), 0) | |
381 | + | let lockStart = valueOrElse(getInteger(boostingDapp, keyLockParamStartBlock(userNumStr)), height) | |
382 | + | let lockDuration = valueOrElse(getInteger(boostingDapp, keyLockParamDuration(userNumStr)), 0) | |
383 | + | let lockEnd = (lockStart + lockDuration) | |
384 | + | let remainingDuration = max([(lockEnd - height), 0]) | |
385 | + | let userAmountNew = (userAmount + deltaWxAmount) | |
386 | + | let lockDurationNew = min([(remainingDuration + deltaLockPeriodInBlocks), maxLockDurationInBlocks]) | |
387 | + | let userCurrgWxAmount = asInt(asAnyList(invoke(boostingDapp, "gwxUserInfoREADONLY", [userAddressStr], nil))[0]) | |
388 | + | let gWxAmountStartNew = calcGwxAmountStartREADONLY(userAmountNew, lockDurationNew, maxLockDurationInBlocks)[0] | |
389 | + | let gWxParamsResultList = asAnyList(invoke(mathDapp, "calcGwxParamsREADONLY", [gWxAmountStartNew, height, lockDurationNew], nil)) | |
390 | + | let gWxAmountDiff = (gWxAmountStartNew - userCurrgWxAmount) | |
391 | + | let k = asInt(gWxParamsResultList[0]) | |
392 | + | let b = asInt(gWxParamsResultList[1]) | |
393 | + | let period = toString(asInt(gWxParamsResultList[2])) | |
394 | + | let totalMaxBoostIntegralKEY = keyTotalMaxBoostINTEGRAL() | |
395 | + | let totalCachedGwxKEY = keyTotalCachedGwx() | |
396 | + | let userMaxBoostIntNew = ((gWxAmountStartNew * lockDurationNew) / 2) | |
397 | + | let totalMaxBoostInt = getIntOrZero(boostingDapp, totalMaxBoostIntegralKEY) | |
398 | + | let totalCachedGwx = valueOrElse(getInteger(boostingDapp, totalCachedGwxKEY), 0) | |
399 | + | let MULT3 = 1000 | |
400 | + | let wxEmissionPerBlockX3 = (getIntOrFail(emissionDapp, keyEmissionRatePerBlockCurrent()) * MULT3) | |
401 | + | let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr) | |
402 | + | let stakedTotalKEY = keyStakedTotal(lpAssetIdStr) | |
403 | + | let stakedByUser = readStaked(stakingDapp, stakedByUserKEY) | |
404 | + | let stakedTotal = readStaked(stakingDapp, stakedTotalKEY) | |
405 | + | let stakedByUserNew = (stakedByUser + deltaLpAmount) | |
406 | + | let stakedTotalNew = (stakedTotal + deltaLpAmount) | |
407 | + | let poolWeight = if ((lpAssetIdStr != EMPTYSTR)) | |
408 | + | then { | |
409 | + | let poolAddressStr = valueOrErrorMessage(getString(factoryDapp, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr)) | |
410 | + | getIntegerValue(factoryDapp, keyFactoryPoolWeight(poolAddressStr)) | |
411 | + | } | |
412 | + | else 0 | |
413 | + | let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3)) | |
414 | + | let wxPerLpX3 = if ((stakedTotalNew != 0)) | |
415 | + | then fraction(poolWxEmissionPerBlockX3, MULT8, stakedTotalNew) | |
416 | + | else 0 | |
417 | + | let userWxPerBlockX3 = fraction(wxPerLpX3, stakedByUserNew, MULT8) | |
418 | + | let boostEmissionPerBlockX3 = (poolWxEmissionPerBlockX3 * 2) | |
419 | + | let tmpUserBoostPerBlockX3 = fraction(gWxAmountStartNew, boostEmissionPerBlockX3, (totalCachedGwx + gWxAmountDiff)) | |
420 | + | let userBoostPerBlockX3 = min([tmpUserBoostPerBlockX3, (userWxPerBlockX3 * 2)]) | |
421 | + | let boostCoeff = if ((userWxPerBlockX3 == 0)) | |
422 | + | then (1 * MULT8) | |
423 | + | else fraction((userBoostPerBlockX3 + userWxPerBlockX3), MULT8, userWxPerBlockX3) | |
424 | + | let debug = makeString([("lpAssetIdStr=" + lpAssetIdStr), ("userAddressStr=" + userAddressStr), ("userNumStr=" + userNumStr), ("userAmount=" + toString(userAmount)), ("userAmountNew=" + toString(userAmountNew)), ("lockDurationNew=" + toString(lockDurationNew)), ("gWxAmountStart=" + toString(gWxAmountStartNew)), ("tmpUserBoostPerBlockX3=" + toString(tmpUserBoostPerBlockX3)), ("stakedByUserNew=" + toString(stakedByUserNew)), ("stakedTotalNew=" + toString(stakedTotalNew)), ("poolWeight=" + toString(poolWeight)), ("wxPerLpX3=" + toString(wxPerLpX3)), ("poolWxEmissionPerBlockX3=" + toString(poolWxEmissionPerBlockX3)), ("userWxPerBlockX3=" + toString(userWxPerBlockX3)), ("gWxAmountDiff=" + toString(gWxAmountDiff)), ("totalCachedGwx=" + toString(totalCachedGwx)), ("userCurrgWxAmount=" + toString(userCurrgWxAmount))], "::") | |
425 | + | $Tuple2(nil, makeString(["%d%d%s", toString(gWxAmountStartNew), toString(boostCoeff), debug], SEP)) | |
426 | + | } | |
427 | + | ||
428 | + | ||
429 | + | ||
430 | + | @Callable(i) | |
431 | + | func wxEmissionStatsREADONLY () = { | |
432 | + | let ONEMULT = toString(MULT8) | |
433 | + | let ONE = "1" | |
434 | + | let wxEmissionPerBlock = getIntOrFail(emissionDapp, keyEmissionRatePerBlockCurrent()) | |
435 | + | let emissionStartBlock = getIntOrFail(emissionDapp, keyEmissionStartBlock()) | |
436 | + | let passedBlocks = if ((emissionStartBlock > height)) | |
437 | + | then 0 | |
438 | + | else (height - emissionStartBlock) | |
439 | + | let teamEmDuration = (1440 * 365) | |
440 | + | let teamEmMax = (201000000 * MULT8) | |
441 | + | let teamEm = if ((passedBlocks > teamEmDuration)) | |
442 | + | then teamEmMax | |
443 | + | else fraction(teamEmMax, passedBlocks, teamEmDuration) | |
444 | + | let totalWxReleased = ((wxEmissionPerBlock * passedBlocks) + teamEm) | |
445 | + | let totalWxLocked = getIntOrZero(boostingDapp, keyBoostingLockParamTotalAmount()) | |
446 | + | let locksDurationSumInBlocks = getIntOrZero(boostingDapp, keyBoostingStatsLocksDurationSumInBlocks()) | |
447 | + | let locksCount = getIntOrZero(boostingDapp, keyBoostingStatsLocksCount()) | |
448 | + | $Tuple2(nil, makeString(["%d%d%d%d", toString(totalWxReleased), toString(totalWxLocked), toString(locksDurationSumInBlocks), toString(locksCount)], SEP)) | |
449 | + | } | |
450 | + | ||
451 | + | ||
452 | + | ||
453 | + | @Callable(i) | |
454 | + | func poolStatsREADONLY (lpAsset) = { | |
455 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAsset))) | |
456 | + | let cfg = asAnyList(invoke(poolAddress, "getPoolConfigWrapperREADONLY", nil, nil)) | |
457 | + | let lpAssetId = fromBase58String(asString(cfg[idxPoolLPAssetId])) | |
458 | + | let amtAssetId = asString(cfg[idxAmtAssetId]) | |
459 | + | let priceAssetId = asString(cfg[idxPriceAssetId]) | |
460 | + | let iAmtAssetId = asString(cfg[idxIAmtAssetId]) | |
461 | + | let iPriceAssetId = asString(cfg[idxIPriceAssetId]) | |
462 | + | let amtAssetDcm = parseIntValue(asString(cfg[idxAmtAssetDcm])) | |
463 | + | let priceAssetDcm = parseIntValue(asString(cfg[idxPriceAssetDcm])) | |
464 | + | let poolLPBalance = valueOrErrorMessage(assetInfo(lpAssetId), (("Asset " + toBase58String(lpAssetId)) + " doesn't exist")).quantity | |
465 | + | let accAmtAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [amtAssetId], nil)) | |
466 | + | let accPriceAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [priceAssetId], nil)) | |
467 | + | let pricesList = if ((poolLPBalance == 0)) | |
468 | + | then [toString(zeroBigInt), toString(zeroBigInt), toString(zeroBigInt)] | |
469 | + | else asAnyList(invoke(poolAddress, "calcPricesWrapperREADONLY", [accAmtAssetBalance, accPriceAssetBalance, poolLPBalance], nil)) | |
470 | + | let curPrice = 0 | |
471 | + | let lpAmtAssetShare = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [pricesList[1], MULT8], nil)) | |
472 | + | let lpPriceAssetShare = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [pricesList[2], MULT8], nil)) | |
473 | + | let poolWeight = getIntegerValue(factoryDapp, keyFactoryPoolWeight(toString(poolAddress))) | |
474 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d", toString(accAmtAssetBalance), toString(accPriceAssetBalance), toString(poolLPBalance), toString(curPrice), toString(lpAmtAssetShare), toString(lpPriceAssetShare), toString(poolWeight)], SEP)) | |
475 | + | } | |
476 | + | ||
477 | + | ||
478 | + | ||
479 | + | @Callable(i) | |
480 | + | func poolEvaluatePutByAmountAssetREADONLY (lpAsset,inAmAssetAmt) = { | |
481 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAsset))) | |
482 | + | let cfg = asAnyList(invoke(poolAddress, "getPoolConfigWrapperREADONLY", nil, nil)) | |
483 | + | let lpAssetId = fromBase58String(asString(cfg[idxPoolLPAssetId])) | |
484 | + | let amAssetIdStr = asString(cfg[idxAmtAssetId]) | |
485 | + | let amAssetId = fromBase58String(amAssetIdStr) | |
486 | + | let prAssetIdStr = asString(cfg[idxPriceAssetId]) | |
487 | + | let prAssetId = fromBase58String(prAssetIdStr) | |
488 | + | let amtAssetDcm = parseIntValue(asString(cfg[idxAmtAssetDcm])) | |
489 | + | let priceAssetDcm = parseIntValue(asString(cfg[idxPriceAssetDcm])) | |
490 | + | let poolStatus = asString(cfg[idxPoolStatus]) | |
491 | + | let poolLPBalance = valueOrErrorMessage(assetInfo(lpAssetId), (("Asset " + toBase58String(lpAssetId)) + " doesn't exist")).quantity | |
492 | + | let accAmtAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [amAssetIdStr], nil)) | |
493 | + | let accPriceAssetBalance = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [prAssetIdStr], nil)) | |
494 | + | let amtAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [accAmtAssetBalance, amtAssetDcm], nil))) | |
495 | + | let priceAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [accPriceAssetBalance, priceAssetDcm], nil))) | |
496 | + | let curPriceX18 = if ((poolLPBalance == 0)) | |
497 | + | then zeroBigInt | |
498 | + | else parseBigIntValue(asString(invoke(poolAddress, "calcPriceBigIntWrapperREADONLY", [toString(priceAssetAmtX18), toString(amtAssetAmtX18)], nil))) | |
499 | + | let curPrice = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(curPriceX18), MULT8], nil)) | |
500 | + | let inAmAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [inAmAssetAmt, amtAssetDcm], nil))) | |
501 | + | let inPrAssetAmtX18 = fraction(inAmAssetAmtX18, curPriceX18, MULT18) | |
502 | + | let inPrAssetAmt = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(inPrAssetAmtX18), priceAssetDcm], nil)) | |
503 | + | let res = invoke(poolAddress, "estimatePutOperationWrapperREADONLY", ["", 500000, inAmAssetAmt, amAssetId, inPrAssetAmt, prAssetId, "", true, false], nil) | |
504 | + | let $t02282123174 = match res { | |
505 | + | case _ => | |
506 | + | if (if ($isInstanceOf($match0._1, "Int")) | |
507 | + | then if ($isInstanceOf($match0._3, "Int")) | |
508 | + | then if ($isInstanceOf($match0._4, "Int")) | |
509 | + | then if ($isInstanceOf($match0._5, "Int")) | |
510 | + | then $isInstanceOf($match0._6, "Int") | |
511 | + | else false | |
512 | + | else false | |
513 | + | else false | |
514 | + | else false) | |
515 | + | then { | |
516 | + | let calcLpAmt = $match0._1 | |
517 | + | let curPriceCalc = $match0._3 | |
518 | + | let amBalance = $match0._4 | |
519 | + | let prBalance = $match0._5 | |
520 | + | let lpEmission = $match0._6 | |
521 | + | $Tuple5(calcLpAmt, curPriceCalc, amBalance, prBalance, lpEmission) | |
522 | + | } | |
523 | + | else throw("Couldn't cast types") | |
524 | + | } | |
525 | + | let calcLpAmt = $t02282123174._1 | |
526 | + | let curPriceCalc = $t02282123174._2 | |
527 | + | let amBalance = $t02282123174._3 | |
528 | + | let prBalance = $t02282123174._4 | |
529 | + | let lpEmission = $t02282123174._5 | |
530 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d%d", toString(calcLpAmt), toString(curPrice), toString(amBalance), toString(prBalance), toString(lpEmission), poolStatus, toString(inAmAssetAmt), toString(inPrAssetAmt)], SEP)) | |
531 | + | } | |
532 | + | ||
533 | + | ||
534 | + | ||
535 | + | @Callable(i) | |
536 | + | func poolEvaluatePutByPriceAssetREADONLY (lpAsset,inPrAssetAmt) = { | |
537 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(lpAsset))) | |
538 | + | let cfg = asAnyList(invoke(poolAddress, "getPoolConfigWrapperREADONLY", nil, nil)) | |
539 | + | let lpAssetId = fromBase58String(asString(cfg[idxPoolLPAssetId])) | |
540 | + | let amAssetIdStr = asString(cfg[idxAmtAssetId]) | |
541 | + | let amAssetId = fromBase58String(amAssetIdStr) | |
542 | + | let prAssetIdStr = asString(cfg[idxPriceAssetId]) | |
543 | + | let prAssetId = fromBase58String(prAssetIdStr) | |
544 | + | let amtAssetDcm = parseIntValue(asString(cfg[idxAmtAssetDcm])) | |
545 | + | let priceAssetDcm = parseIntValue(asString(cfg[idxPriceAssetDcm])) | |
546 | + | let poolStatus = asString(cfg[idxPoolStatus]) | |
547 | + | let poolLPBalance = valueOrErrorMessage(assetInfo(lpAssetId), (("Asset " + toBase58String(lpAssetId)) + " doesn't exist")).quantity | |
548 | + | let amBalanceRaw = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [amAssetIdStr], nil)) | |
549 | + | let prBalanceRaw = asInt(invoke(poolAddress, "getAccBalanceWrapperREADONLY", [prAssetIdStr], nil)) | |
550 | + | let amBalanceRawX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [amBalanceRaw, amtAssetDcm], nil))) | |
551 | + | let prBalanceRawX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [prBalanceRaw, priceAssetDcm], nil))) | |
552 | + | let curPriceX18 = if ((poolLPBalance == 0)) | |
553 | + | then zeroBigInt | |
554 | + | else parseBigIntValue(asString(invoke(poolAddress, "calcPriceBigIntWrapperREADONLY", [toString(prBalanceRawX18), toString(amBalanceRawX18)], nil))) | |
555 | + | let curPrice = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(curPriceX18), MULT8], nil)) | |
556 | + | let inPrAssetAmtX18 = parseBigIntValue(asString(invoke(poolAddress, "toX18WrapperREADONLY", [inPrAssetAmt, priceAssetDcm], nil))) | |
557 | + | let inAmAssetAmtX18 = fraction(inPrAssetAmtX18, MULT18, curPriceX18) | |
558 | + | let inAmAssetAmt = asInt(invoke(poolAddress, "fromX18WrapperREADONLY", [toString(inAmAssetAmtX18), amtAssetDcm], nil)) | |
559 | + | let res = invoke(poolAddress, "estimatePutOperationWrapperREADONLY", ["", 500000, inAmAssetAmt, amAssetId, inPrAssetAmt, prAssetId, "", true, false], nil) | |
560 | + | let $t02574726100 = match res { | |
561 | + | case _ => | |
562 | + | if (if ($isInstanceOf($match0._1, "Int")) | |
563 | + | then if ($isInstanceOf($match0._3, "Int")) | |
564 | + | then if ($isInstanceOf($match0._4, "Int")) | |
565 | + | then if ($isInstanceOf($match0._5, "Int")) | |
566 | + | then $isInstanceOf($match0._6, "Int") | |
567 | + | else false | |
568 | + | else false | |
569 | + | else false | |
570 | + | else false) | |
571 | + | then { | |
572 | + | let calcLpAmt = $match0._1 | |
573 | + | let curPriceCalc = $match0._3 | |
574 | + | let amBalance = $match0._4 | |
575 | + | let prBalance = $match0._5 | |
576 | + | let lpEmission = $match0._6 | |
577 | + | $Tuple5(calcLpAmt, curPriceCalc, amBalance, prBalance, lpEmission) | |
578 | + | } | |
579 | + | else throw("Couldn't cast types") | |
580 | + | } | |
581 | + | let calcLpAmt = $t02574726100._1 | |
582 | + | let curPriceCalc = $t02574726100._2 | |
583 | + | let amBalance = $t02574726100._3 | |
584 | + | let prBalance = $t02574726100._4 | |
585 | + | let lpEmission = $t02574726100._5 | |
586 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d%d", toString(calcLpAmt), toString(curPrice), toString(amBalance), toString(prBalance), toString(lpEmission), poolStatus, toString(inAmAssetAmt), toString(inPrAssetAmt)], SEP)) | |
587 | + | } | |
588 | + | ||
589 | + | ||
590 | + | ||
591 | + | @Callable(i) | |
592 | + | func poolEvaluateGetREADONLY (paymentLpAssetId,paymentLpAmt) = { | |
593 | + | let poolAddress = addressFromStringValue(getStringByAddressOrFail(factoryDapp, keyFactoryLpAssetToPoolContractAddress(paymentLpAssetId))) | |
594 | + | let res = invoke(poolAddress, "estimateGetOperationWrapperREADONLY", ["", paymentLpAssetId, paymentLpAmt, toString(poolAddress)], nil) | |
595 | + | let $t02679527212 = match res { | |
596 | + | case _ => | |
597 | + | if (if ($isInstanceOf($match0._1, "Int")) | |
598 | + | then if ($isInstanceOf($match0._2, "Int")) | |
599 | + | then if ($isInstanceOf($match0._5, "Int")) | |
600 | + | then if ($isInstanceOf($match0._6, "Int")) | |
601 | + | then if ($isInstanceOf($match0._7, "Int")) | |
602 | + | then if ($isInstanceOf($match0._8, "String")) | |
603 | + | then $isInstanceOf($match0._9, "String") | |
604 | + | else false | |
605 | + | else false | |
606 | + | else false | |
607 | + | else false | |
608 | + | else false | |
609 | + | else false) | |
610 | + | then { | |
611 | + | let outAmAmt = $match0._1 | |
612 | + | let outPrAmt = $match0._2 | |
613 | + | let amBalance = $match0._5 | |
614 | + | let prBalance = $match0._6 | |
615 | + | let lpEmission = $match0._7 | |
616 | + | let curPrice = $match0._8 | |
617 | + | let poolStatus = $match0._9 | |
618 | + | $Tuple7(outAmAmt, outPrAmt, amBalance, prBalance, lpEmission, curPrice, poolStatus) | |
619 | + | } | |
620 | + | else throw("Couldn't cast types") | |
621 | + | } | |
622 | + | let outAmAmt = $t02679527212._1 | |
623 | + | let outPrAmt = $t02679527212._2 | |
624 | + | let amBalance = $t02679527212._3 | |
625 | + | let prBalance = $t02679527212._4 | |
626 | + | let lpEmission = $t02679527212._5 | |
627 | + | let curPrice = $t02679527212._6 | |
628 | + | let poolStatus = $t02679527212._7 | |
629 | + | $Tuple2(nil, makeString(["%d%d%d%d%d%d%d", toString(outAmAmt), toString(outPrAmt), toString(amBalance), toString(prBalance), toString(lpEmission), curPrice, poolStatus], SEP)) | |
630 | + | } | |
631 | + | ||
632 | + | ||
633 | + | ||
634 | + | @Callable(i) | |
635 | + | func gwxUserInfoREADONLY (userAddress) = { | |
636 | + | let gwxUserInfoLIST = asAnyList(invoke(boostingDapp, "gwxUserInfoREADONLY", [userAddress], nil)) | |
637 | + | let gwxAmount = asInt(gwxUserInfoLIST[0]) | |
638 | + | $Tuple2(nil, makeString(["%d", toString(gwxAmount)], SEP)) | |
311 | 639 | } | |
312 | 640 | ||
313 | 641 | ||
314 | 642 | ||
315 | 643 | @Callable(i) | |
316 | 644 | func setManager (pendingManagerPublicKey) = { | |
317 | 645 | let checkCaller = mustManager(i) | |
318 | 646 | if ((checkCaller == checkCaller)) | |
319 | 647 | then { | |
320 | 648 | let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey) | |
321 | 649 | if ((checkManagerPublicKey == checkManagerPublicKey)) | |
322 | 650 | then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)] | |
323 | 651 | else throw("Strict value is not equal to itself.") | |
324 | 652 | } | |
325 | 653 | else throw("Strict value is not equal to itself.") | |
326 | 654 | } | |
327 | 655 | ||
328 | 656 | ||
329 | 657 | ||
330 | 658 | @Callable(i) | |
331 | 659 | func confirmManager () = { | |
332 | 660 | let pm = pendingManagerPublicKeyOrUnit() | |
333 | 661 | let hasPM = if (isDefined(pm)) | |
334 | 662 | then true | |
335 | 663 | else throw("No pending manager") | |
336 | 664 | if ((hasPM == hasPM)) | |
337 | 665 | then { | |
338 | 666 | let checkPM = if ((i.callerPublicKey == value(pm))) | |
339 | 667 | then true | |
340 | 668 | else throw("You are not pending manager") | |
341 | 669 | if ((checkPM == checkPM)) | |
342 | 670 | then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())] | |
343 | 671 | else throw("Strict value is not equal to itself.") | |
344 | 672 | } | |
345 | 673 | else throw("Strict value is not equal to itself.") | |
346 | 674 | } | |
347 | 675 | ||
348 | 676 | ||
349 | 677 | @Verifier(tx) | |
350 | 678 | func verify () = { | |
351 | 679 | let targetPublicKey = match managerPublicKeyOrUnit() { | |
352 | 680 | case pk: ByteVector => | |
353 | 681 | pk | |
354 | 682 | case _: Unit => | |
355 | 683 | tx.senderPublicKey | |
356 | 684 | case _ => | |
357 | 685 | throw("Match error") | |
358 | 686 | } | |
359 | 687 | sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey) | |
360 | 688 | } | |
361 | 689 |
github/deemru/w8io/026f985 93.55 ms ◑