tx · 6QSZ8tuWBu3ux4tWRxSGi3fZ6ajv3wR8tuE8fkF56ArW 3MuGfNhF98CNBCfthhoJEo6SYUv7zTgkK4J: -0.01400000 Waves 2022.03.16 11:21 [1966279] smart account 3MuGfNhF98CNBCfthhoJEo6SYUv7zTgkK4J > SELF 0.00000000 Waves
{ "type": 13, "id": "6QSZ8tuWBu3ux4tWRxSGi3fZ6ajv3wR8tuE8fkF56ArW", "fee": 1400000, "feeAssetId": null, "timestamp": 1647418922456, "version": 1, "sender": "3MuGfNhF98CNBCfthhoJEo6SYUv7zTgkK4J", "senderPublicKey": "4DthuG3xjZV9WtZ34Y66AummdAr67wRzwWsVQL4y2bob", "proofs": [ "5UoQrt2x2WkAR91UiSHWk8NrvENYRvUJfYb6mDLQsVEAA6jea4WuES4Ap8z2MtiYvRdAnC5E9r4Sn4YR4WJFuv21" ], "script": "base64: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AgkAAaQAAAABBQAAAAluZXdBbW91bnQJAARMAAAAAgkAAaQAAAABBQAAAAhuZXdTdGFydAUAAAADbmlsBQAAAAlzZXBhcmF0b3IBAAAAEkhpc3RvcnlSZWNvcmRFbnRyeQAAAAcAAAAEdHlwZQAAAAt1c2VyQWRkcmVzcwAAAAR0eElkAAAACW9sZEFtb3VudAAAAAhvbGRTdGFydAAAAAluZXdBbW91bnQAAAAIbmV3U3RhcnQJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABBrZXlIaXN0b3J5UmVjb3JkAAAAAwUAAAAEdHlwZQUAAAALdXNlckFkZHJlc3MFAAAABHR4SWQJAQAAABNmb3JtYXRIaXN0b3J5UmVjb3JkAAAABAUAAAAJb2xkQW1vdW50BQAAAAhvbGRTdGFydAUAAAAJbmV3QW1vdW50BQAAAAhuZXdTdGFydAEAAAALU3RhdHNSZXN1bHQAAAADAAAADnRvdGFsTG9ja2VkSW5jAAAADGxvY2tDb3VudEluYwAAAA11c2Vyc0NvdW50SW5jBAAAAApsb2Nrc0NvdW50CQEAAAAMZ2V0SW50T3JaZXJvAAAAAQkBAAAAEmtleVN0YXRzTG9ja3NDb3VudAAAAAAEAAAACnVzZXJzQ291bnQJAQAAAAxnZXRJbnRPclplcm8AAAABCQEAAAASa2V5U3RhdHNVc2Vyc0NvdW50AAAAAAQAAAALdG90YWxBbW91bnQJAQAAAAxnZXRJbnRPclplcm8AAAABCQEAAAAXa2V5TG9ja1BhcmFtVG90YWxBbW91bnQAAAAABAAAAA50b3RhbEFtb3VudE5ldwkAAGQAAAACBQAAAAt0b3RhbEFtb3VudAUAAAAOdG90YWxMb2NrZWRJbmMJAAUVAAAAAwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEmtleVN0YXRzTG9ja3NDb3VudAAAAAAJAABkAAAAAgUAAAAKbG9ja3NDb3VudAUAAAAMbG9ja0NvdW50SW5jCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAASa2V5U3RhdHNVc2Vyc0NvdW50AAAAAAkAAGQAAAACBQAAAAp1c2Vyc0NvdW50BQAAAA11c2Vyc0NvdW50SW5jCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAXa2V5TG9ja1BhcmFtVG90YWxBbW91bnQAAAAABQAAAA50b3RhbEFtb3VudE5ldwUAAAADbmlsBQAAAAt0b3RhbEFtb3VudAUAAAAOdG90YWxBbW91bnROZXcBAAAAD0xvY2tQYXJhbXNFbnRyeQAAAAMAAAALdXNlckFkZHJlc3MAAAAGYW1vdW50AAAABXN0YXJ0CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAWa2V5TG9ja1BhcmFtVXNlckFtb3VudAAAAAEFAAAAC3VzZXJBZGRyZXNzBQAAAAZhbW91bnQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABZrZXlMb2NrUGFyYW1TdGFydEJsb2NrAAAAAQUAAAALdXNlckFkZHJlc3MFAAAABXN0YXJ0BQAAAANuaWwBAAAAD2dldFBhcmFtc09yRmFpbAAAAAAEAAAAEG5ldXRyaW5vQ29udHJhY3QJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEJAQAAAA9nZXRTdHJpbmdPckZhaWwAAAABCQEAAAAaa2V5TmV1dHJpbm9Db250cmFjdEFkZHJlc3MAAAAACQAFFgAAAAQJAAJZAAAAAQkBAAAAEUBleHRyTmF0aXZlKDEwNTMpAAAAAgUAAAAQbmV1dHJpbm9Db250cmFjdAkBAAAAGWtleUF1Y3Rpb25Db250cmFjdEFkZHJlc3MAAAAACQACWQAAAAEJAQAAABFAZXh0ck5hdGl2ZSgxMDUzKQAAAAIFAAAAEG5ldXRyaW5vQ29udHJhY3QJAQAAAAxrZXlCb25kQXNzZXQAAAAACQEAAAAMZ2V0SW50T3JGYWlsAAAAAQkBAAAAEGtleU1pbkxvY2tBbW91bnQAAAAACQEAAAAMZ2V0SW50T3JGYWlsAAAAAQkBAAAAC2tleUhhbGZMaWZlAAAAAAEAAAAMaXNBY3RpdmVVc2VyAAAAAQAAAAt1c2VyQWRkcmVzcwkAAGYAAAACCQEAAAAMZ2V0SW50T3JFbHNlAAAAAgkBAAAAFmtleUxvY2tQYXJhbVVzZXJBbW91bnQAAAABBQAAAAt1c2VyQWRkcmVzcwAAAAAAAAAAAAAAAAAAAAAAAAEAAAATZ2V0VXNlclBhcmFtc09yVW5pdAAAAAEAAAALdXNlckFkZHJlc3MDCQEAAAAMaXNBY3RpdmVVc2VyAAAAAQUAAAALdXNlckFkZHJlc3MJAAUVAAAAAwcJAQAAAAxnZXRJbnRPckZhaWwAAAABCQEAAAAWa2V5TG9ja1BhcmFtVXNlckFtb3VudAAAAAEFAAAAC3VzZXJBZGRyZXNzCQEAAAAMZ2V0SW50T3JGYWlsAAAAAQkBAAAAFmtleUxvY2tQYXJhbVN0YXJ0QmxvY2sAAAABBQAAAAt1c2VyQWRkcmVzcwUAAAAEdW5pdAEAAAATZ2V0VXNlclBhcmFtc09yRmFpbAAAAAEAAAALdXNlckFkZHJlc3MJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkBAAAAE2dldFVzZXJQYXJhbXNPclVuaXQAAAABBQAAAAt1c2VyQWRkcmVzcwkAASwAAAACCQABLAAAAAICAAAABVVzZXIgCQAEJQAAAAEFAAAAC3VzZXJBZGRyZXNzAgAAAA8gaXMgbm90IGRlZmluZWQAAAAAEnN1cHBvcnRlZEFzc2V0c1N0cgkBAAAADGdldFN0ck9yRWxzZQAAAAIJAQAAABhrZXlTdXBwb3J0ZWRSZXdhcmRBc3NldHMAAAAAAgAAAAAAAAAAE3N1cHBvcnRlZEFzc2V0c0xpc3QJAAS1AAAAAgUAAAASc3VwcG9ydGVkQXNzZXRzU3RyAgAAAAFfAQAAAApjYWxjUmV3YXJkAAAABQAAAAt1c2VyQWRkcmVzcwAAAAdhc3NldElkAAAADXN0YWtlZEFtb3VudFgAAAAOZGVwb3NpdE51bVVzZXIAAAAOZGVwb3NpdE51bUxhc3QEAAAAF3Jld2FyZFBlck5zYnRTdW1MYXN0S0VZCQEAAAAVa2V5UmV3YXJkUGVyTnNidFN1bUF0AAAAAgUAAAAOZGVwb3NpdE51bUxhc3QFAAAAB2Fzc2V0SWQEAAAACnN1bUxhc3RYMTgJAAGnAAAAAQkBAAAADGdldFN0ck9yRWxzZQAAAAIJAQAAABVrZXlSZXdhcmRQZXJOc2J0U3VtQXQAAAACBQAAAA5kZXBvc2l0TnVtTGFzdAUAAAAHYXNzZXRJZAIAAAABMAQAAAAKc3VtVXNlclgxOAkAAacAAAABCQEAAAAMZ2V0U3RyT3JFbHNlAAAAAgkBAAAAFWtleVJld2FyZFBlck5zYnRTdW1BdAAAAAIFAAAADmRlcG9zaXROdW1Vc2VyBQAAAAdhc3NldElkAgAAAAEwBAAAABFyZXdhcmREeW5hbWljUGFydAkAAaAAAAABCQABPAAAAAMJAAE4AAAAAgUAAAAKc3VtTGFzdFgxOAUAAAAKc3VtVXNlclgxOAUAAAANc3Rha2VkQW1vdW50WAUAAAAHTVVMVFgxOAQAAAATcmV3YXJkQ2FjaGVkUGFydEtFWQkBAAAACWtleVJld2FyZAAAAAIFAAAAC3VzZXJBZGRyZXNzBQAAAAdhc3NldElkBAAAABByZXdhcmRDYWNoZWRQYXJ0CQEAAAAMZ2V0SW50T3JFbHNlAAAAAgUAAAATcmV3YXJkQ2FjaGVkUGFydEtFWQAAAAAAAAAAAAkABRYAAAAECQAAZAAAAAIFAAAAEHJld2FyZENhY2hlZFBhcnQFAAAAEXJld2FyZER5bmFtaWNQYXJ0BQAAABByZXdhcmRDYWNoZWRQYXJ0BQAAABFyZXdhcmREeW5hbWljUGFydAUAAAATcmV3YXJkQ2FjaGVkUGFydEtFWQEAAAANUmV3YXJkRW50cmllcwAAAAMAAAAJaXNOZXdVc2VyAAAAC3VzZXJBZGRyZXNzAAAADHN0YWtlZEFtb3VudAQAAAANc3Rha2VkQW1vdW50WAkAATYAAAABBQAAAAxzdGFrZWRBbW91bnQEAAAAG3VzZXJSZXdhcmRGcm9tRGVwb3NpdE51bUtFWQkBAAAAG2tleVVzZXJSZXdhcmRGcm9tRGVwb3NpdE51bQAAAAEFAAAAC3VzZXJBZGRyZXNzBAAAAA5kZXBvc2l0TnVtVXNlcgkBAAAADGdldEludE9yRWxzZQAAAAIFAAAAG3VzZXJSZXdhcmRGcm9tRGVwb3NpdE51bUtFWQD//////////wQAAAAOZGVwb3NpdE51bUxhc3QJAQAAAAxnZXRJbnRPckVsc2UAAAACCQEAAAARa2V5RGVwb3NpdE51bUxhc3QAAAAAAP//////////CgEAAAAbZm9yRWFjaEFzc2V0Q2FjaGVVc2VyUmV3YXJkAAAAAgAAAAVhY2N1bQAAAAVhc3NldAQAAAALJHQwNjc5ODY5MzMJAQAAAApjYWxjUmV3YXJkAAAABQUAAAAL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AAEFAAAADmRlcG9zaXROdW1Vc2VyAQAAACJJbmNyZW1lbnROb3REaXN0cmlidXRlZFJld2FyZEVudHJ5AAAAAgAAAAN0a24AAAAJYW1vdW50SW5jBAAAABdub3REaXN0cmlidXRlZFJld2FyZEtFWQkBAAAAF2tleU5vdERpc3RyaWJ1dGVkUmV3YXJkAAAAAQUAAAADdGtuBAAAABRub3REaXN0cmlidXRlZFJld2FyZAkBAAAADGdldEludE9yRWxzZQAAAAIFAAAAF25vdERpc3RyaWJ1dGVkUmV3YXJkS0VZAAAAAAAAAAAACQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAABdub3REaXN0cmlidXRlZFJld2FyZEtFWQkAAGQAAAACBQAAABRub3REaXN0cmlidXRlZFJld2FyZAUAAAAJYW1vdW50SW5jBQAAAANuaWwAAAAIAAAAAWkBAAAAC2NvbnN0cnVjdG9yAAAABQAAABduZXV0cmlub0NvbnRyYWN0QWRkcmVzcwAAABNtYXRoQ29udHJhY3RBZGRyZXNzAAAADW1pbkxvY2tBbW91bnQAAAAIaGFsZkxpZmUAAAAVc3VwcG9ydGVkUmV3YXJkQXNzZXRzAwkBAAAAAiE9AAAAAggFAAAAAWkAAAAGY2FsbGVyBQAAAAR0aGlzCQAAAgAAAAECAAAAEVBlcm1pc3Npb24gZGVuaWVkCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABprZXlOZXV0cmlub0NvbnRyYWN0QWRkcmVzcwAAAAAFAAAAF25ldXRyaW5vQ29udHJhY3RBZGRyZXNzCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABZrZXlNYXRoQ29udHJhY3RBZGRyZXNzAAAAAAUAAAATbWF0aENvbnRyYWN0QWRkcmVzcwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEGtleU1pbkxvY2tBbW91bnQAAAAABQAAAA1taW5Mb2NrQW1vdW50CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAALa2V5SGFsZkxpZmUAAAAABQAAAAhoYWxmTGlmZQkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACCQEAAAAYa2V5U3VwcG9ydGVkUmV3YXJkQXNzZXRzAAAAAAUAAAAVc3VwcG9ydGVkUmV3YXJkQXNzZXRzBQAAAANuaWwAAAABaQEAAAAFc3Rha2UAAAAABAAAAA0kdDAxMDgwMzEwODgyCQEAAAAPZ2V0UGFyYW1zT3JGYWlsAAAAAAQAAAAPYXVjdGlvbkNvbnRyYWN0CAUAAAANJHQwMTA4MDMxMDg4MgAAAAJfMQQAAAALYm9uZEFzc2V0SWQIBQAAAA0kdDAxMDgwMzEwODgyAAAAAl8yBAAAAA1taW5Mb2NrQW1vdW50CAUAAAANJHQwMTA4MDMxMDg4MgAAAAJfMwQAAAAIaGFsZkxpZmUIBQAAAA0kdDAxMDgwMzEwODgyAAAAAl80AwkBAAAAAiE9AAAAAgkAAZAAAAABCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAQkAAAIAAAABAgAAABVJbnZhbGlkIHBheW1lbnRzIHNpemUEAAAAB3BheW1lbnQJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAEAAAABmFtb3VudAgFAAAAB3BheW1lbnQAAAAGYW1vdW50BAAAABNpbnZhbGlkQXNzZXRNZXNzYWdlCQABLAAAAAIJAAEsAAAAAgIAAAAPSW52YWxpZCBhc3NldC4gCQACWAAAAAEFAAAAC2JvbmRBc3NldElkAgAAAAwgaXMgZXhwZWN0ZWQEAAAAB2Fzc2V0SWQJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAggFAAAAB3BheW1lbnQAAAAHYXNzZXRJZAUAAAATaW52YWxpZEFzc2V0TWVzc2FnZQMJAQAAAAIhPQAAAAIFAAAAB2Fzc2V0SWQFAAAAC2JvbmRBc3NldElkCQAAAgAAAAEFAAAAE2ludmFsaWRBc3NldE1lc3NhZ2UEAAAAC3VzZXJBZGRyZXNzCAUAAAABaQAAAAZjYWxsZXIEAAAADnVzZXJBZGRyZXNzU3RyCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgQAAAANJHQwMTE0MjQxMTUzMQkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkBAAAAE2dldFVzZXJQYXJhbXNPclVuaXQAAAABBQAAAAt1c2VyQWRkcmVzcwkABRUAAAADBgAAAAAAAAAAAAD//////////wQAAAAJaXNOZXdVc2VyCAUAAAANJHQwMTE0MjQxMTUzMQAAAAJfMQQAAAAKbG9ja0Ftb3VudAgFAAAADSR0MDExNDI0MTE1MzEAAAACXzIEAAAAD2xvY2tTdGFydEhlaWdodAgFAAAADSR0MDExNDI0MTE1MzEAAAACXzMEAAAADG1lcmdlZEFtb3VudAMFAAAACWlzTmV3VXNlcgUAAAAGYW1vdW50CQAAZAAAAAIFAAAABmFtb3VudAUAAAAKbG9ja0Ftb3VudAQAAAARbWVyZ2VkU3RhcnRIZWlnaHQDBQAAAAlpc05ld1VzZXIFAAAABmhlaWdodAQAAAAMbWF0aENvbnRyYWN0CQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABCQEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAQkBAAAAFmtleU1hdGhDb250cmFjdEFkZHJlc3MAAAAACQEAAAAFYXNJbnQAAAABCQAD/AAAAAQFAAAADG1hdGhDb250cmFjdAIAAAATbWVyZ2VTdGFrZXNSRUFET05MWQkABEwAAAACBQAAAAZhbW91bnQJAARMAAAAAgUAAAAGaGVpZ2h0CQAETAAAAAIFAAAACmxvY2tBbW91bnQJAARMAAAAAgUAAAAPbG9ja1N0YXJ0SGVpZ2h0CQAETAAAAAIFAAAACGhhbGZMaWZlBQAAAANuaWwFAAAAA25pbAMJAABmAAAAAgUAAAANbWluTG9ja0Ftb3VudAUAAAAMbWVyZ2VkQW1vdW50CQAAAgAAAAEJAAEsAAAAAgIAAAATTWluIGxvY2sgYW1vdW50IGlzIAkAAaQAAAABBQAAAA1taW5Mb2NrQW1vdW50BAAAAA0kdDAxMTk4MTEyMDgzCQEAAAALU3RhdHNSZXN1bHQAAAADBQAAAAZhbW91bnQAAAAAAAAAAAEDBQAAAAlpc05ld1VzZXIAAAAAAAAAAAEAAAAAAAAAAAAEAAAADHN0YXRzRW50cmllcwgFAAAADSR0MDExOTgxMTIwODMAAAACXzEEAAAAC3RvdGFsU3Rha2VkCAUAAAANJHQwMTE5ODExMjA4MwAAAAJfMgQAAAAOdG90YWxTdGFrZWROZXcIBQAAAA0kdDAxMTk4MTEyMDgzAAAAAl8zBAAAAA5kZXBvc2l0TnVtTGFzdAkBAAAADGdldEludE9yRWxzZQAAAAIJAQAAABFrZXlEZXBvc2l0TnVtTGFzdAAAAAAA//////////8JAARNAAAAAgkABE4AAAACCQAETgAAAAIJAARMAAAAAgkBAAAAEkhpc3RvcnlSZWNvcmRFbnRyeQAAAAcCAAAABXN0YWtlBQAAAAt1c2VyQWRkcmVzcwgFAAAAAWkAAAANdHJhbnNhY3Rpb25JZAUAAAAKbG9ja0Ftb3VudAUAAAAPbG9ja1N0YXJ0SGVpZ2h0BQAAAAxtZXJnZWRBbW91bnQFAAAAEW1lcmdlZFN0YXJ0SGVpZ2h0BQAAAANuaWwJAQAAAA9Mb2NrUGFyYW1zRW50cnkAAAADBQAAAAt1c2VyQWRkcmVzcwUAAAAMbWVyZ2VkQW1vdW50BQAAABFtZXJnZWRTdGFydEhlaWdodAUAAAAMc3RhdHNFbnRyaWVzCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAG2tleVVzZXJSZXdhcmRGcm9tRGVwb3NpdE51bQAAAAEFAAAADnVzZXJBZGRyZXNzU3RyCQEAAAAMZ2V0SW50T3JFbHNlAAAAAgkBAAAAEWtleURlcG9zaXROdW1MYXN0AAAAAAD//////////wAAAAFpAQAAAAd1bnN0YWtlAAAAAQAAAAZhbW91bnQEAAAAC3VzZXJBZGRyZXNzCAUAAAABaQAAAAZjYWxsZXIEAAAADnVzZXJBZGRyZXNzU3RyCQAEJQAAAAEFAAAAC3VzZXJBZGRyZXNzBAAAAA0kdDAxMjU4ODEyNjY2CQEAAAAPZ2V0UGFyYW1zT3JGYWlsAAAAAAQAAAAOYXVjdGlvbkFkZHJlc3MIBQAAAA0kdDAxMjU4ODEyNjY2AAAAAl8xBAAAAAtib25kQXNzZXRJZAgFAAAADSR0MDEyNTg4MTI2NjYAAAACXzIEAAAADW1pbkxvY2tBbW91bnQIBQAAAA0kdDAxMjU4ODEyNjY2AAAAAl8zBAAAAAhoYWxmTGlmZQgFAAAADSR0MDEyNTg4MTI2NjYAAAACXzQEAAAADSR0MDEyNjY5MTI3NDMJAQAAABNnZXRVc2VyUGFyYW1zT3JGYWlsAAAAAQUAAAALdXNlckFkZHJlc3MEAAAACWlzTmV3VXNlcggFAAAADSR0MDEyNjY5MTI3NDMAAAACXzEEAAAACmxvY2tBbW91bnQIBQAAAA0kdDAxMjY2OTEyNzQzAAAAAl8yBAAAAAlsb2NrU3RhcnQIBQAAAA0kdDAxMjY2OTEyNzQzAAAAAl8zAwkAAGcAAAACAAAAAAAAAAAABQAAAApsb2NrQW1vdW50CQAAAgAAAAECAAAAEk5vdGhpbmcgdG8gdW5zdGFrZQMJAABmAAAAAgUAAAAGYW1vdW50BQAAAApsb2NrQW1vdW50CQAAAgAAAAEJAAEsAAAAAgkAASwAAAACCQABLAAAAAICAAAAClJlcXVlc3RlZCAJAAGkAAAAAQUAAAAGYW1vdW50AgAAABIsIGJ1dCBzdGFrZWQgb25seSAJAAGkAAAAAQUAAAAKbG9ja0Ftb3VudAQAAAAMbWF0aENvbnRyYWN0CQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABCQEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAQkBAAAAFmtleU1hdGhDb250cmFjdEFkZHJlc3MAAAAABAAAAA9jb21pc3Npb25BbW91bnQJAQAAAAVhc0ludAAAAAEJAAP8AAAABAUAAAAMbWF0aENvbnRyYWN0AgAAACFnZXRVbnN0YWtlQ29taXNzaW9uQW1vdW50UkVBRE9OTFkJAARMAAAAAgUAAAAGYW1vdW50CQAETAAAAAIFAAAACWxvY2tTdGFydAkABEwAAAACBQAAAAhoYWxmTGlmZQUAAAADbmlsBQAAAANuaWwEAAAADSR0MDEzMTQ0MTMyOTgJAQAAAAtTdGF0c1Jlc3VsdAAAAAMJAQAAAAEtAAAAAQUAAAAGYW1vdW50AwkAAAAAAAACBQAAAAZhbW91bnQFAAAACmxvY2tBbW91bnQA//////////8AAAAAAAAAAAADCQAAAAAAAAIFAAAABmFtb3VudAUAAAAKbG9ja0Ftb3VudAD//////////wAAAAAAAAAAAAQAAAAMc3RhdHNFbnRyaWVzCAUAAAANJHQwMTMxNDQxMzI5OAAAAAJfMQQAAAALdG90YWxTdGFrZWQIBQAAAA0kdDAxMzE0NDEzMjk4AAAAAl8yBAAAAA50b3RhbFN0YWtlZE5ldwgFAAAADSR0MDEzMTQ0MTMyOTgAAAACXzMJAAROAAAAAgkABE4AAAACCQAETgAAAAIJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAALdXNlckFkZHJlc3MJAABlAAAAAgUAAAAGYW1vdW50BQAAAA9jb21pc3Npb25BbW91bnQFAAAAC2JvbmRBc3NldElkCQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMJAQAAAAdBZGRyZXNzAAAAAQUAAAAOYXVjdGlvbkFkZHJlc3MFAAAAD2NvbWlzc2lvbkFtb3VudAUAAAALYm9uZEFzc2V0SWQJAARMAAAAAgkBAAAAEkhpc3RvcnlSZWNvcmRFbnRyeQAAAAcCAAAAB3Vuc3Rha2UFAAAAC3VzZXJBZGRyZXNzCAUAAAABaQAAAA10cmFuc2FjdGlvbklkBQAAAApsb2NrQW1vdW50BQAAAAlsb2NrU3RhcnQJAABlAAAAAgUAAAAKbG9ja0Ftb3VudAUAAAAGYW1vdW50BQAAAAlsb2NrU3RhcnQFAAAAA25pbAkBAAAADVJld2FyZEVudHJpZXMAAAADBwUAAAAOdXNlckFkZHJlc3NTdHIFAAAACmxvY2tBbW91bnQJAQAAAA9Mb2NrUGFyYW1zRW50cnkAAAADBQAAAAt1c2VyQWRkcmVzcwkAAGUAAAACBQAAAApsb2NrQW1vdW50BQAAAAZhbW91bnQFAAAACWxvY2tTdGFydAUAAAAMc3RhdHNFbnRyaWVzAAAAAWkBAAAAB2RlcG9zaXQAAAAAAwkBAAAAAiE9AAAAAgkAAZAAAAABCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAQkAAAIAAAABAgAAAB9leGFjdCAxIHBheW1lbnQgaXMgYWxsb3dlZCBvbmx5BAAAAANwbXQJAAGRAAAAAggFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAEAAAABmFtb3VudAgFAAAAA3BtdAAAAAZhbW91bnQEAAAACnBtdEFzc2V0SWQJAQAAAAt2YWx1ZU9yRWxzZQAAAAIIBQAAAANwbXQAAAAHYXNzZXRJZAUAAAAHV0FWRVNJRAQAAAANcG10QXNzZXRJZFN0cgkAAlgAAAABBQAAAApwbXRBc3NldElkBAAAAAhwbXRNdWx0WAMJAAAAAAAAAgUAAAAKcG10QXNzZXRJZAUAAAAHV0FWRVNJRAUAAAAGTVVMVFg4BQAAAAZNVUxUWDYEAAAAB2Ftb3VudFgJAAE2AAAAAQUAAAAGYW1vdW50BAAAAAt0b3RhbFN0YWtlZAkBAAAADGdldEludE9yRWxzZQAAAAIJAQAAABdrZXlMb2NrUGFyYW1Ub3RhbEFtb3VudAAAAAAAAAAAAAAAAAAEAAAADHRvdGFsU3Rha2VkWAkAATYAAAABBQAAAAt0b3RhbFN0YWtlZAMJAABmAAAAAgAAAAAAAAAAAAUAAAALdG90YWxTdGFrZWQJAAACAAAAAQIAAAAbVE9ETzogY2FzZSBpcyBub3Qgc3VwcG9ydGVkAwkAAAAAAAACBQAAAAt0b3RhbFN0YWtlZAAAAAAAAAAAAAkBAAAAIkluY3JlbWVudE5vdERpc3RyaWJ1dGVkUmV3YXJkRW50cnkAAAACBQAAAA1wbXRBc3NldElkU3RyBQAAAAZhbW91bnQEAAAAEHJld2FyZFBlck5zYnRYMTgJAAE8AAAAAwUAAAAHYW1vdW50WAUAAAAHTVVMVFgxOAUAAAAMdG90YWxTdGFrZWRYBAAAABFkZXBvc2l0TnVtTGFzdEtFWQkBAAAAEWtleURlcG9zaXROdW1MYXN0AAAAAAQAAAAOZGVwb3NpdE51bUxhc3QJAQAAAAxnZXRJbnRPckVsc2UAAAACBQAAABFkZXBvc2l0TnVtTGFzdEtFWQD//////////wQAAAANZGVwb3NpdE51bU5ldwkAAGQAAAACBQAAAA5kZXBvc2l0TnVtTGFzdAAAAAAAAAAAAQMJAQAAAAEhAAAAAQkBAAAACGNvbnRhaW5zAAAAAgUAAAASc3VwcG9ydGVkQXNzZXRzU3RyBQAAAA1wbXRBc3NldElkU3RyCQAAAgAAAAEJAAEsAAAAAgkAASwAAAACBQAAABJzdXBwb3J0ZWRBc3NldHNTdHICAAAAESBkb2Vzbid0IGNvbnRhaW4gBQAAAA1wbXRBc3NldElkU3RyCgEAAAAXcmVmcmVzaFJld2FyZFBlck5zYnRTVU0AAAACAAAABWFjY3VtAAAACW5leHRBc3NldAQAAAAWcmV3YXJkUGVyTnNidFN1bU5ld0tFWQkBAAAAFWtleVJld2FyZFBlck5zYnRTdW1BdAAAAAIFAAAADWRlcG9zaXROdW1OZXcFAAAACW5leHRBc3NldAQAAAAKc3VtTGFzdFN0cgkBAAAADGdldFN0ck9yRWxzZQAAAAIJAQAAABVrZXlSZXdhcmRQZXJOc2J0U3VtQXQAAAACBQAAAA5kZXBvc2l0TnVtTGFzdAUAAAAJbmV4dEFzc2V0AgAAAAEwCQAETQAAAAIFAAAABWFjY3VtAwkAAAAAAAACBQAAAAluZXh0QXNzZXQFAAAADXBtdEFzc2V0SWRTdHIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAFnJld2FyZFBlck5zYnRTdW1OZXdLRVkJAAGmAAAAAQkAATcAAAACCQABpwAAAAEFAAAACnN1bUxhc3RTdHIFAAAAEHJld2FyZFBlck5zYnRYMTgJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAFnJld2FyZFBlck5zYnRTdW1OZXdLRVkFAAAACnN1bUxhc3RTdHIJAARNAAAAAgoAAAAAAiRsBQAAABNzdXBwb3J0ZWRBc3NldHNMaXN0CgAAAAACJHMJAAGQAAAAAQUAAAACJGwKAAAAAAUkYWNjMAUAAAADbmlsCgEAAAAFJGYwXzEAAAACAAAAAiRhAAAAAiRpAwkAAGcAAAACBQAAAAIkaQUAAAACJHMFAAAAAiRhCQEAAAAXcmVmcmVzaFJld2FyZFBlck5zYnRTVU0AAAACBQAAAAIkYQkAAZEAAAACBQAAAAIkbAUAAAACJGkKAQAAAAUkZjBfMgAAAAIAAAACJGEAAAACJGkDCQAAZwAAAAIFAAAAAiRpBQAAAAIkcwUAAAACJGEJAAACAAAAAQIAAAAUTGlzdCBzaXplIGV4Y2VlZHMgMTAJAQAAAAUkZjBfMgAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIJAQAAAAUkZjBfMQAAAAIFAAAABSRhY2MwAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAACAAAAAAAAAAADAAAAAAAAAAAEAAAAAAAAAAAFAAAAAAAAAAAGAAAAAAAAAAAHAAAAAAAAAAAIAAAAAAAAAAAJAAAAAAAAAAAKCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAARZGVwb3NpdE51bUxhc3RLRVkFAAAADWRlcG9zaXROdW1OZXcAAAABaQEAAAAMY2xhaW1SZXdhcmRzAAAAAAQAAAALdXNlckFkZHJlc3MIBQAAAAFpAAAABmNhbGxlcgQAAAAOdXNlckFkZHJlc3NTdHIJAAQlAAAAAQUAAAALdXNlckFkZHJlc3MEAAAADSR0MDE1NDgwMTU1ODUJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAQAAABNnZXRVc2VyUGFyYW1zT3JVbml0AAAAAQUAAAALdXNlckFkZHJlc3MJAAUVAAAAAwYAAAAAAAAAAAAAAAAAAAAAAAAEAAAACWlzTmV3VXNlcggFAAAADSR0MDE1NDgwMTU1ODUAAAACXzEEAAAADHN0YWtlZEFtb3VudAgFAAAADSR0MDE1NDgwMTU1ODUAAAACXzIEAAAADHN0YWtpbmdTdGFydAgFAAAADSR0MDE1NDgwMTU1ODUAAAACXzMEAAAADXN0YWtlZEFtb3VudFgJAAE2AAAAAQUAAAAMc3Rha2VkQW1vdW50BAAAABt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkJAQAAABtrZXlVc2VyUmV3YXJkRnJvbURlcG9zaXROdW0AAAABBQAAAA51c2VyQWRkcmVzc1N0cgQAAAAOZGVwb3NpdE51bVVzZXIJAQAAAAxnZXRJbnRPckVsc2UAAAACBQAAABt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkA//////////8EAAAADmRlcG9zaXROdW1MYXN0CQEAAAAMZ2V0SW50T3JFbHNlAAAAAgkBAAAAEWtleURlcG9zaXROdW1MYXN0AAAAAAD//////////woBAAAAH2ZvckVhY2hBc3NldENhbGNVbmNsYWltZWRSZXdhcmQAAAACAAAABWFjY3VtAAAABWFzc2V0BAAAAA0kdDAxNTk0NjE2MDg0CQEAAAAKY2FsY1Jld2FyZAAAAAUFAAAADnVzZXJBZGRyZXNzU3RyBQAAAAVhc3NldAUAAAANc3Rha2VkQW1vdW50WAUAAAAOZGVwb3NpdE51bVVzZXIFAAAADmRlcG9zaXROdW1MYXN0BAAAAAtyZXdhcmRUb3RhbAgFAAAADSR0MDE1OTQ2MTYwODQAAAACXzEEAAAABmNhY2hl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CgQAAAALdXNlckFkZHJlc3MJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEFAAAADnVzZXJBZGRyZXNzU3RyBAAAAA0kdDAxNjg0ODE2OTUzCQEAAAALdmFsdWVPckVsc2UAAAACCQEAAAATZ2V0VXNlclBhcmFtc09yVW5pdAAAAAEFAAAAC3VzZXJBZGRyZXNzCQAFFQAAAAMGAAAAAAAAAAAAAAAAAAAAAAAABAAAAAlpc05ld1VzZXIIBQAAAA0kdDAxNjg0ODE2OTUzAAAAAl8xBAAAAAxzdGFrZWRBbW91bnQIBQAAAA0kdDAxNjg0ODE2OTUzAAAAAl8yBAAAAAxzdGFraW5nU3RhcnQIBQAAAA0kdDAxNjg0ODE2OTUzAAAAAl8zBAAAAA1zdGFrZWRBbW91bnRYCQABNgAAAAEFAAAADHN0YWtlZEFtb3VudAQAAAAbdXNlclJld2FyZEZyb21EZXBvc2l0TnVtS0VZCQEAAAAba2V5VXNlclJld2FyZEZyb21EZXBvc2l0TnVtAAAAAQUAAAAOdXNlckFkZHJlc3NTdHIEAAAADmRlcG9zaXROdW1Vc2VyCQEAAAAMZ2V0SW50T3JFbHNlAAAAAgUAAAAbdXNlclJld2FyZEZyb21EZXBvc2l0TnVtS0VZAP//////////BAAAAA5kZXBvc2l0TnVtTGFzdAkBAAAADGdldEludE9yRWxzZQAAAAIJAQAAABFrZXlEZXBvc2l0TnVtTGFzdAAAAAAA//////////8KAQAAAB9mb3JFYWNoQXNzZXRDYWxjVW5jbGFpbWVkUmV3YXJkAAAAAgAAAAVhY2N1bQAAAAVhc3NldAQAAAANJHQwMTcyOTkxNzQzNwkBAAAACmNhbGNSZXdhcmQAAAAFBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAFYXNzZXQFAAAADXN0YWtlZEFtb3VudFgFAAAADmRlcG9zaXROdW1Vc2VyBQAAAA5kZXBvc2l0TnVtTGFzdAQAAAALcmV3YXJkVG90YWwIBQAAAA0kdDAxNzI5OTE3NDM3AAAAAl8xBAAAAAZjYWNoZWQIBQAAAA0kdDAxNzI5OTE3NDM3AAAAAl8yBAAAAAdkeW5hbWljCAUAAAANJHQwMTcyOTkxNzQzNwAAAAJfMwQAAAATcmV3YXJkQ2FjaGVk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", "chainId": 84, "height": 1966279, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 2gVDhZ8weEKXjsrpqPRbLJn4y7eYuRoaJZCE9TAb6gLA Next: 4SajAxuPevgLaVq1n46WFcN2jw5jxd6ew1AEQWtWtyTS Diff:
Old | New | Differences | |
---|---|---|---|
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let separator = "__" | |
5 | 5 | ||
6 | + | let MULT6 = 1000000 | |
7 | + | ||
6 | 8 | let MULT8 = 100000000 | |
9 | + | ||
10 | + | let MULTX6 = toBigInt(MULT6) | |
11 | + | ||
12 | + | let MULTX8 = toBigInt(MULT8) | |
13 | + | ||
14 | + | let MULTX18 = toBigInt(1000000000000000000) | |
15 | + | ||
16 | + | let WAVESIDSTR = "WAVES" | |
17 | + | ||
18 | + | let WAVESID = fromBase58String(WAVESIDSTR) | |
7 | 19 | ||
8 | 20 | func keyBondAsset () = "bond_asset_id" | |
9 | 21 | ||
44 | 56 | func keyNextPeriod () = "%s__nextPeriod" | |
45 | 57 | ||
46 | 58 | ||
59 | + | func keySupportedRewardAssets () = "supportedRewardAssets" | |
60 | + | ||
61 | + | ||
62 | + | func keyDepositNumLast () = makeString(["%s%s%s", "dep", "lastNum"], separator) | |
63 | + | ||
64 | + | ||
65 | + | func keyUserRewardFromDepositNum (userAddress) = makeString(["%s%s%s", "userRwdFromDepNum", userAddress], separator) | |
66 | + | ||
67 | + | ||
68 | + | func keyRewardPerNsbtSumAt (depositNum,tkn) = makeString(["%s%d", "rwdPerNsbtSumByDepNum", toString(depositNum), tkn], separator) | |
69 | + | ||
70 | + | ||
71 | + | func keyReward (userAddress,tkn) = makeString(["%s%s%s", "rwd", userAddress, tkn], separator) | |
72 | + | ||
73 | + | ||
74 | + | func keyNotDistributedReward (tkn) = makeString(["%s%s", "notDistributed", tkn], separator) | |
75 | + | ||
76 | + | ||
77 | + | func toX18 (origVal,origMult) = fraction(toBigInt(origVal), MULTX18, origMult) | |
78 | + | ||
79 | + | ||
47 | 80 | func getIntOrZero (key) = valueOrElse(getInteger(this, key), 0) | |
81 | + | ||
82 | + | ||
83 | + | func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal) | |
48 | 84 | ||
49 | 85 | ||
50 | 86 | func getIntOrFail (key) = valueOrErrorMessage(getInteger(this, key), (("Mandatory this." + key) + " is not defined")) | |
51 | 87 | ||
52 | 88 | ||
89 | + | func getStrOrElse (key,defaultVal) = valueOrElse(getString(this, key), defaultVal) | |
90 | + | ||
91 | + | ||
53 | 92 | func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), (("Mandatory this." + key) + " is not defined")) | |
93 | + | ||
94 | + | ||
95 | + | func toAddressOrFail (addressStr) = valueOrErrorMessage(addressFromString(addressStr), ("couldn't parse passed addressStr=" + addressStr)) | |
96 | + | ||
97 | + | ||
98 | + | func toAssetVect (assetStr) = if ((assetStr == WAVESIDSTR)) | |
99 | + | then unit | |
100 | + | else fromBase58String(assetStr) | |
54 | 101 | ||
55 | 102 | ||
56 | 103 | func asInt (val) = match val { | |
67 | 114 | func HistoryRecordEntry (type,userAddress,txId,oldAmount,oldStart,newAmount,newStart) = StringEntry(keyHistoryRecord(type, userAddress, txId), formatHistoryRecord(oldAmount, oldStart, newAmount, newStart)) | |
68 | 115 | ||
69 | 116 | ||
70 | - | func | |
117 | + | func StatsResult (totalLockedInc,lockCountInc,usersCountInc) = { | |
71 | 118 | let locksCount = getIntOrZero(keyStatsLocksCount()) | |
72 | 119 | let usersCount = getIntOrZero(keyStatsUsersCount()) | |
73 | 120 | let totalAmount = getIntOrZero(keyLockParamTotalAmount()) | |
74 | - | [IntegerEntry(keyStatsLocksCount(), (locksCount + lockCountInc)), IntegerEntry(keyStatsUsersCount(), (usersCount + usersCountInc)), IntegerEntry(keyLockParamTotalAmount(), (totalAmount + totalLockedInc))] | |
121 | + | let totalAmountNew = (totalAmount + totalLockedInc) | |
122 | + | $Tuple3([IntegerEntry(keyStatsLocksCount(), (locksCount + lockCountInc)), IntegerEntry(keyStatsUsersCount(), (usersCount + usersCountInc)), IntegerEntry(keyLockParamTotalAmount(), totalAmountNew)], totalAmount, totalAmountNew) | |
75 | 123 | } | |
76 | 124 | ||
77 | 125 | ||
84 | 132 | } | |
85 | 133 | ||
86 | 134 | ||
87 | - | func | |
135 | + | func isActiveUser (userAddress) = (getIntOrElse(keyLockParamUserAmount(userAddress), 0) > 0) | |
88 | 136 | ||
89 | 137 | ||
90 | - | func getUserParamsOrUnit (userAddress) = if ( | |
91 | - | then $ | |
138 | + | func getUserParamsOrUnit (userAddress) = if (isActiveUser(userAddress)) | |
139 | + | then $Tuple3(false, getIntOrFail(keyLockParamUserAmount(userAddress)), getIntOrFail(keyLockParamStartBlock(userAddress))) | |
92 | 140 | else unit | |
93 | 141 | ||
94 | 142 | ||
95 | 143 | func getUserParamsOrFail (userAddress) = valueOrErrorMessage(getUserParamsOrUnit(userAddress), (("User " + toString(userAddress)) + " is not defined")) | |
96 | 144 | ||
97 | 145 | ||
146 | + | let supportedAssetsStr = getStrOrElse(keySupportedRewardAssets(), "") | |
147 | + | ||
148 | + | let supportedAssetsList = split(supportedAssetsStr, "_") | |
149 | + | ||
150 | + | func calcReward (userAddress,assetId,stakedAmountX,depositNumUser,depositNumLast) = { | |
151 | + | let rewardPerNsbtSumLastKEY = keyRewardPerNsbtSumAt(depositNumLast, assetId) | |
152 | + | let sumLastX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, assetId), "0")) | |
153 | + | let sumUserX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumUser, assetId), "0")) | |
154 | + | let rewardDynamicPart = toInt(fraction((sumLastX18 - sumUserX18), stakedAmountX, MULTX18)) | |
155 | + | let rewardCachedPartKEY = keyReward(userAddress, assetId) | |
156 | + | let rewardCachedPart = getIntOrElse(rewardCachedPartKEY, 0) | |
157 | + | $Tuple4((rewardCachedPart + rewardDynamicPart), rewardCachedPart, rewardDynamicPart, rewardCachedPartKEY) | |
158 | + | } | |
159 | + | ||
160 | + | ||
161 | + | func RewardEntries (isNewUser,userAddress,stakedAmount) = { | |
162 | + | let stakedAmountX = toBigInt(stakedAmount) | |
163 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddress) | |
164 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
165 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
166 | + | func forEachAssetCacheUserReward (accum,asset) = { | |
167 | + | let $t067986933 = calcReward(userAddress, asset, stakedAmountX, depositNumUser, depositNumLast) | |
168 | + | let rewardTotal = $t067986933._1 | |
169 | + | let cached = $t067986933._2 | |
170 | + | let dynamic = $t067986933._3 | |
171 | + | let rewardCachedPartKEY = $t067986933._4 | |
172 | + | (accum :+ IntegerEntry(rewardCachedPartKEY, rewardTotal)) | |
173 | + | } | |
174 | + | ||
175 | + | if (if ((depositNumLast == -1)) | |
176 | + | then (depositNumUser == -1) | |
177 | + | else false) | |
178 | + | then nil | |
179 | + | else if (if ((depositNumLast == -1)) | |
180 | + | then (depositNumUser > -1) | |
181 | + | else false) | |
182 | + | then throw("invalid depositNumLast and depositNumUser state") | |
183 | + | else if (if ((depositNumLast > -1)) | |
184 | + | then (depositNumUser == -1) | |
185 | + | else false) | |
186 | + | then if (isNewUser) | |
187 | + | then [IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)] | |
188 | + | else throw("isNewUser must not be false in 5 + 6 cases") | |
189 | + | else if (if ((depositNumLast > -1)) | |
190 | + | then (depositNumUser > -1) | |
191 | + | else false) | |
192 | + | then if (isNewUser) | |
193 | + | then throw((((("invalid management for isNewUser=" + toString(isNewUser)) + " and depositNumUser=") + toString(depositNumUser)) + " during full unstake")) | |
194 | + | else ({ | |
195 | + | let $l = supportedAssetsList | |
196 | + | let $s = size($l) | |
197 | + | let $acc0 = nil | |
198 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
199 | + | then $a | |
200 | + | else forEachAssetCacheUserReward($a, $l[$i]) | |
201 | + | ||
202 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
203 | + | then $a | |
204 | + | else throw("List size exceeds 10") | |
205 | + | ||
206 | + | $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) | |
207 | + | } :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) | |
208 | + | else throw(((("uncovered condition: depositNumLast=" + toString(depositNumLast)) + " depositNumUser=") + toString(depositNumUser))) | |
209 | + | } | |
210 | + | ||
211 | + | ||
212 | + | func IncrementNotDistributedRewardEntry (tkn,amountInc) = { | |
213 | + | let notDistributedRewardKEY = keyNotDistributedReward(tkn) | |
214 | + | let notDistributedReward = getIntOrElse(notDistributedRewardKEY, 0) | |
215 | + | [IntegerEntry(notDistributedRewardKEY, (notDistributedReward + amountInc))] | |
216 | + | } | |
217 | + | ||
218 | + | ||
98 | 219 | @Callable(i) | |
99 | - | func constructor (neutrinoContractAddress,mathContractAddress,minLockAmount,halfLife) = if ((i.caller != this)) | |
220 | + | func constructor (neutrinoContractAddress,mathContractAddress,minLockAmount,halfLife,supportedRewardAssets) = if ((i.caller != this)) | |
100 | 221 | then throw("Permission denied") | |
101 | - | else [StringEntry(keyNeutrinoContractAddress(), neutrinoContractAddress), StringEntry(keyMathContractAddress(), mathContractAddress), IntegerEntry(keyMinLockAmount(), minLockAmount), IntegerEntry(keyHalfLife(), halfLife)] | |
222 | + | else [StringEntry(keyNeutrinoContractAddress(), neutrinoContractAddress), StringEntry(keyMathContractAddress(), mathContractAddress), IntegerEntry(keyMinLockAmount(), minLockAmount), IntegerEntry(keyHalfLife(), halfLife), StringEntry(keySupportedRewardAssets(), supportedRewardAssets)] | |
102 | 223 | ||
103 | 224 | ||
104 | 225 | ||
105 | 226 | @Callable(i) | |
106 | 227 | func stake () = { | |
107 | - | let $ | |
108 | - | let auctionContract = $ | |
109 | - | let bondAssetId = $ | |
110 | - | let minLockAmount = $ | |
111 | - | let halfLife = $ | |
228 | + | let $t01080310882 = getParamsOrFail() | |
229 | + | let auctionContract = $t01080310882._1 | |
230 | + | let bondAssetId = $t01080310882._2 | |
231 | + | let minLockAmount = $t01080310882._3 | |
232 | + | let halfLife = $t01080310882._4 | |
112 | 233 | if ((size(i.payments) != 1)) | |
113 | 234 | then throw("Invalid payments size") | |
114 | 235 | else { | |
120 | 241 | then throw(invalidAssetMessage) | |
121 | 242 | else { | |
122 | 243 | let userAddress = i.caller | |
123 | - | let $t050205192 = match getUserParamsOrUnit(userAddress) { | |
124 | - | case p: (Int, Int) => | |
125 | - | $Tuple3(false, p._1, p._2) | |
126 | - | case _: Unit => | |
127 | - | $Tuple3(true, 0, -1) | |
128 | - | case _ => | |
129 | - | throw("Match error") | |
130 | - | } | |
131 | - | let isNewUser = $t050205192._1 | |
132 | - | let lockAmount = $t050205192._2 | |
133 | - | let lockStartHeight = $t050205192._3 | |
244 | + | let userAddressStr = toString(i.caller) | |
245 | + | let $t01142411531 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, -1)) | |
246 | + | let isNewUser = $t01142411531._1 | |
247 | + | let lockAmount = $t01142411531._2 | |
248 | + | let lockStartHeight = $t01142411531._3 | |
134 | 249 | let mergedAmount = if (isNewUser) | |
135 | 250 | then amount | |
136 | 251 | else (amount + lockAmount) | |
138 | 253 | then height | |
139 | 254 | else { | |
140 | 255 | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
141 | - | asInt(invoke(mathContract, " | |
256 | + | asInt(invoke(mathContract, "mergeStakesREADONLY", [amount, height, lockAmount, lockStartHeight, halfLife], nil)) | |
142 | 257 | } | |
143 | 258 | if ((minLockAmount > mergedAmount)) | |
144 | 259 | then throw(("Min lock amount is " + toString(minLockAmount))) | |
145 | - | else (([HistoryRecordEntry("stake", userAddress, i.transactionId, lockAmount, lockStartHeight, mergedAmount, mergedStartHeight)] ++ LockParamsEntry(userAddress, mergedAmount, mergedStartHeight)) ++ StatsEntry(amount, 1, if (isNewUser) | |
146 | - | then 1 | |
147 | - | else 0)) | |
260 | + | else { | |
261 | + | let $t01198112083 = StatsResult(amount, 1, if (isNewUser) | |
262 | + | then 1 | |
263 | + | else 0) | |
264 | + | let statsEntries = $t01198112083._1 | |
265 | + | let totalStaked = $t01198112083._2 | |
266 | + | let totalStakedNew = $t01198112083._3 | |
267 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
268 | + | ((([HistoryRecordEntry("stake", userAddress, i.transactionId, lockAmount, lockStartHeight, mergedAmount, mergedStartHeight)] ++ LockParamsEntry(userAddress, mergedAmount, mergedStartHeight)) ++ statsEntries) :+ IntegerEntry(keyUserRewardFromDepositNum(userAddressStr), getIntOrElse(keyDepositNumLast(), -1))) | |
269 | + | } | |
148 | 270 | } | |
149 | 271 | } | |
150 | 272 | } | |
154 | 276 | @Callable(i) | |
155 | 277 | func unstake (amount) = { | |
156 | 278 | let userAddress = i.caller | |
157 | - | let $t059606038 = getParamsOrFail() | |
158 | - | let auctionAddress = $t059606038._1 | |
159 | - | let bondAssetId = $t059606038._2 | |
160 | - | let minLockAmount = $t059606038._3 | |
161 | - | let halfLife = $t059606038._4 | |
162 | - | let $t060416104 = getUserParamsOrFail(userAddress) | |
163 | - | let lockAmount = $t060416104._1 | |
164 | - | let lockStart = $t060416104._2 | |
279 | + | let userAddressStr = toString(userAddress) | |
280 | + | let $t01258812666 = getParamsOrFail() | |
281 | + | let auctionAddress = $t01258812666._1 | |
282 | + | let bondAssetId = $t01258812666._2 | |
283 | + | let minLockAmount = $t01258812666._3 | |
284 | + | let halfLife = $t01258812666._4 | |
285 | + | let $t01266912743 = getUserParamsOrFail(userAddress) | |
286 | + | let isNewUser = $t01266912743._1 | |
287 | + | let lockAmount = $t01266912743._2 | |
288 | + | let lockStart = $t01266912743._3 | |
165 | 289 | if ((0 >= lockAmount)) | |
166 | 290 | then throw("Nothing to unstake") | |
167 | 291 | else if ((amount > lockAmount)) | |
168 | 292 | then throw(((("Requested " + toString(amount)) + ", but staked only ") + toString(lockAmount))) | |
169 | 293 | else { | |
170 | 294 | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
171 | - | let comissionAmount = asInt(invoke(mathContract, " | |
172 | - | | |
295 | + | let comissionAmount = asInt(invoke(mathContract, "getUnstakeComissionAmountREADONLY", [amount, lockStart, halfLife], nil)) | |
296 | + | let $t01314413298 = StatsResult(-(amount), if ((amount == lockAmount)) | |
173 | 297 | then -1 | |
174 | 298 | else 0, if ((amount == lockAmount)) | |
175 | 299 | then -1 | |
176 | - | else 0)) | |
300 | + | else 0) | |
301 | + | let statsEntries = $t01314413298._1 | |
302 | + | let totalStaked = $t01314413298._2 | |
303 | + | let totalStakedNew = $t01314413298._3 | |
304 | + | ((([ScriptTransfer(userAddress, (amount - comissionAmount), bondAssetId), ScriptTransfer(Address(auctionAddress), comissionAmount, bondAssetId), HistoryRecordEntry("unstake", userAddress, i.transactionId, lockAmount, lockStart, (lockAmount - amount), lockStart)] ++ RewardEntries(false, userAddressStr, lockAmount)) ++ LockParamsEntry(userAddress, (lockAmount - amount), lockStart)) ++ statsEntries) | |
177 | 305 | } | |
178 | 306 | } | |
179 | 307 | ||
180 | 308 | ||
181 | 309 | ||
182 | 310 | @Callable(i) | |
183 | - | func gNsbtAmountREADONLY (userAddressStr) = { | |
184 | - | let userAddress = addressFromStringValue(userAddressStr) | |
185 | - | $Tuple2(nil, if (isUserExists(userAddress)) | |
186 | - | then getUserParamsOrFail(userAddress)._1 | |
187 | - | else 0) | |
311 | + | func deposit () = if ((size(i.payments) != 1)) | |
312 | + | then throw("exact 1 payment is allowed only") | |
313 | + | else { | |
314 | + | let pmt = i.payments[0] | |
315 | + | let amount = pmt.amount | |
316 | + | let pmtAssetId = valueOrElse(pmt.assetId, WAVESID) | |
317 | + | let pmtAssetIdStr = toBase58String(pmtAssetId) | |
318 | + | let pmtMultX = if ((pmtAssetId == WAVESID)) | |
319 | + | then MULTX8 | |
320 | + | else MULTX6 | |
321 | + | let amountX = toBigInt(amount) | |
322 | + | let totalStaked = getIntOrElse(keyLockParamTotalAmount(), 0) | |
323 | + | let totalStakedX = toBigInt(totalStaked) | |
324 | + | if ((0 > totalStaked)) | |
325 | + | then throw("TODO: case is not supported") | |
326 | + | else if ((totalStaked == 0)) | |
327 | + | then IncrementNotDistributedRewardEntry(pmtAssetIdStr, amount) | |
328 | + | else { | |
329 | + | let rewardPerNsbtX18 = fraction(amountX, MULTX18, totalStakedX) | |
330 | + | let depositNumLastKEY = keyDepositNumLast() | |
331 | + | let depositNumLast = getIntOrElse(depositNumLastKEY, -1) | |
332 | + | let depositNumNew = (depositNumLast + 1) | |
333 | + | if (!(contains(supportedAssetsStr, pmtAssetIdStr))) | |
334 | + | then throw(((supportedAssetsStr + " doesn't contain ") + pmtAssetIdStr)) | |
335 | + | else { | |
336 | + | func refreshRewardPerNsbtSUM (accum,nextAsset) = { | |
337 | + | let rewardPerNsbtSumNewKEY = keyRewardPerNsbtSumAt(depositNumNew, nextAsset) | |
338 | + | let sumLastStr = getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, nextAsset), "0") | |
339 | + | (accum :+ (if ((nextAsset == pmtAssetIdStr)) | |
340 | + | then StringEntry(rewardPerNsbtSumNewKEY, toString((parseBigIntValue(sumLastStr) + rewardPerNsbtX18))) | |
341 | + | else StringEntry(rewardPerNsbtSumNewKEY, sumLastStr))) | |
342 | + | } | |
343 | + | ||
344 | + | ({ | |
345 | + | let $l = supportedAssetsList | |
346 | + | let $s = size($l) | |
347 | + | let $acc0 = nil | |
348 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
349 | + | then $a | |
350 | + | else refreshRewardPerNsbtSUM($a, $l[$i]) | |
351 | + | ||
352 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
353 | + | then $a | |
354 | + | else throw("List size exceeds 10") | |
355 | + | ||
356 | + | $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) | |
357 | + | } :+ IntegerEntry(depositNumLastKEY, depositNumNew)) | |
358 | + | } | |
359 | + | } | |
360 | + | } | |
361 | + | ||
362 | + | ||
363 | + | ||
364 | + | @Callable(i) | |
365 | + | func claimRewards () = { | |
366 | + | let userAddress = i.caller | |
367 | + | let userAddressStr = toString(userAddress) | |
368 | + | let $t01548015585 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
369 | + | let isNewUser = $t01548015585._1 | |
370 | + | let stakedAmount = $t01548015585._2 | |
371 | + | let stakingStart = $t01548015585._3 | |
372 | + | let stakedAmountX = toBigInt(stakedAmount) | |
373 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
374 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
375 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
376 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
377 | + | let $t01594616084 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
378 | + | let rewardTotal = $t01594616084._1 | |
379 | + | let cached = $t01594616084._2 | |
380 | + | let dynamic = $t01594616084._3 | |
381 | + | let rewardCachedPartKEY = $t01594616084._4 | |
382 | + | if ((0 >= rewardTotal)) | |
383 | + | then accum | |
384 | + | else ((accum :+ ScriptTransfer(userAddress, rewardTotal, toAssetVect(asset))) :+ IntegerEntry(rewardCachedPartKEY, 0)) | |
385 | + | } | |
386 | + | ||
387 | + | let transfers = { | |
388 | + | let $l = supportedAssetsList | |
389 | + | let $s = size($l) | |
390 | + | let $acc0 = nil | |
391 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
392 | + | then $a | |
393 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
394 | + | ||
395 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
396 | + | then $a | |
397 | + | else throw("List size exceeds 10") | |
398 | + | ||
399 | + | $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) | |
400 | + | } | |
401 | + | if ((0 >= size(transfers))) | |
402 | + | then throw("nothing to claim") | |
403 | + | else transfers | |
188 | 404 | } | |
189 | 405 | ||
190 | 406 | ||
191 | 407 | ||
192 | 408 | @Callable(i) | |
193 | - | func nsbtStakingInfoWrapperREADONLY (userAddressStr) = { | |
194 | - | let $t073267626 = if ((userAddressStr == "")) | |
195 | - | then $Tuple2(0, 0) | |
409 | + | func unclaimedRewardsREADONLY (userAddressStr) = { | |
410 | + | func forEachAssetZeroReward (accum,asset) = ((accum + makeString([asset, "0", "0"], ":")) + "_") | |
411 | + | ||
412 | + | let unclaimedRewardStr = if ((userAddressStr == "")) | |
413 | + | then { | |
414 | + | let $l = supportedAssetsList | |
415 | + | let $s = size($l) | |
416 | + | let $acc0 = "" | |
417 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
418 | + | then $a | |
419 | + | else forEachAssetZeroReward($a, $l[$i]) | |
420 | + | ||
421 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
422 | + | then $a | |
423 | + | else throw("List size exceeds 10") | |
424 | + | ||
425 | + | $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) | |
426 | + | } | |
196 | 427 | else { | |
197 | 428 | let userAddress = addressFromStringValue(userAddressStr) | |
198 | - | if (isUserExists(userAddress)) | |
199 | - | then { | |
200 | - | let $t075157570 = getUserParamsOrFail(userAddress) | |
201 | - | let amount = $t075157570._1 | |
202 | - | let start = $t075157570._2 | |
203 | - | $Tuple2(nil, $Tuple2(amount, start)) | |
204 | - | } | |
205 | - | else $Tuple2(nil, $Tuple2(0, 0)) | |
429 | + | let $t01684816953 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
430 | + | let isNewUser = $t01684816953._1 | |
431 | + | let stakedAmount = $t01684816953._2 | |
432 | + | let stakingStart = $t01684816953._3 | |
433 | + | let stakedAmountX = toBigInt(stakedAmount) | |
434 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
435 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
436 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
437 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
438 | + | let $t01729917437 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
439 | + | let rewardTotal = $t01729917437._1 | |
440 | + | let cached = $t01729917437._2 | |
441 | + | let dynamic = $t01729917437._3 | |
442 | + | let rewardCachedPartKEY = $t01729917437._4 | |
443 | + | ((accum + makeString([asset, toString(rewardTotal), "0"], ":")) + "_") | |
444 | + | } | |
445 | + | ||
446 | + | let $l = supportedAssetsList | |
447 | + | let $s = size($l) | |
448 | + | let $acc0 = "" | |
449 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
450 | + | then $a | |
451 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
452 | + | ||
453 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
454 | + | then $a | |
455 | + | else throw("List size exceeds 10") | |
456 | + | ||
457 | + | $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) | |
206 | 458 | } | |
207 | - | let nsbtAmt = $t073267626._1 | |
208 | - | let stakingStart = $t073267626._2 | |
209 | - | $Tuple2(nil, $Tuple2(nsbtAmt, stakingStart)) | |
459 | + | $Tuple2(nil, dropRight(unclaimedRewardStr, 1)) | |
210 | 460 | } | |
461 | + | ||
462 | + | ||
463 | + | ||
464 | + | @Callable(i) | |
465 | + | func gNsbtAmountREADONLY (userAddressStr) = if ((userAddressStr == "")) | |
466 | + | then $Tuple2(nil, 0) | |
467 | + | else { | |
468 | + | let userAddress = toAddressOrFail(userAddressStr) | |
469 | + | let $t01782917955 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
470 | + | let isNewUser = $t01782917955._1 | |
471 | + | let nsbtAmt = $t01782917955._2 | |
472 | + | let stakingStart = $t01782917955._3 | |
473 | + | $Tuple2(nil, nsbtAmt) | |
474 | + | } | |
475 | + | ||
476 | + | ||
477 | + | ||
478 | + | @Callable(i) | |
479 | + | func nsbtStakingInfoWrapperREADONLY (userAddressStr) = if ((userAddressStr == "")) | |
480 | + | then $Tuple2(nil, $Tuple2(0, 0)) | |
481 | + | else { | |
482 | + | let userAddress = toAddressOrFail(userAddressStr) | |
483 | + | let $t01821118311 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
484 | + | let isNewUser = $t01821118311._1 | |
485 | + | let nsbtAmt = $t01821118311._2 | |
486 | + | let stakingStart = $t01821118311._3 | |
487 | + | $Tuple2(nil, $Tuple2(nsbtAmt, stakingStart)) | |
488 | + | } | |
211 | 489 | ||
212 | 490 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let separator = "__" | |
5 | 5 | ||
6 | + | let MULT6 = 1000000 | |
7 | + | ||
6 | 8 | let MULT8 = 100000000 | |
9 | + | ||
10 | + | let MULTX6 = toBigInt(MULT6) | |
11 | + | ||
12 | + | let MULTX8 = toBigInt(MULT8) | |
13 | + | ||
14 | + | let MULTX18 = toBigInt(1000000000000000000) | |
15 | + | ||
16 | + | let WAVESIDSTR = "WAVES" | |
17 | + | ||
18 | + | let WAVESID = fromBase58String(WAVESIDSTR) | |
7 | 19 | ||
8 | 20 | func keyBondAsset () = "bond_asset_id" | |
9 | 21 | ||
10 | 22 | ||
11 | 23 | func keyAuctionContractAddress () = "auction_contract" | |
12 | 24 | ||
13 | 25 | ||
14 | 26 | func keyNeutrinoContractAddress () = "%s__neutrinoContractAddress" | |
15 | 27 | ||
16 | 28 | ||
17 | 29 | func keyMathContractAddress () = "%s__mathContract" | |
18 | 30 | ||
19 | 31 | ||
20 | 32 | func keyMinLockAmount () = "%s__minLockAmount" | |
21 | 33 | ||
22 | 34 | ||
23 | 35 | func keyHalfLife () = "%s__halfLife" | |
24 | 36 | ||
25 | 37 | ||
26 | 38 | func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", toString(userAddress), "amount"], separator) | |
27 | 39 | ||
28 | 40 | ||
29 | 41 | func keyLockParamStartBlock (userAddress) = makeString(["%s%s%s", "paramByUser", toString(userAddress), "start"], separator) | |
30 | 42 | ||
31 | 43 | ||
32 | 44 | func keyHistoryRecord (type,userAddress,txId) = makeString(["%s%s%s%s", "history", type, toString(userAddress), toBase58String(txId)], separator) | |
33 | 45 | ||
34 | 46 | ||
35 | 47 | func keyLockParamTotalAmount () = makeString(["%s%s", "stats", "activeTotalLocked"], separator) | |
36 | 48 | ||
37 | 49 | ||
38 | 50 | func keyStatsLocksCount () = makeString(["%s%s", "stats", "locksCount"], separator) | |
39 | 51 | ||
40 | 52 | ||
41 | 53 | func keyStatsUsersCount () = makeString(["%s%s", "stats", "activeUsersCount"], separator) | |
42 | 54 | ||
43 | 55 | ||
44 | 56 | func keyNextPeriod () = "%s__nextPeriod" | |
45 | 57 | ||
46 | 58 | ||
59 | + | func keySupportedRewardAssets () = "supportedRewardAssets" | |
60 | + | ||
61 | + | ||
62 | + | func keyDepositNumLast () = makeString(["%s%s%s", "dep", "lastNum"], separator) | |
63 | + | ||
64 | + | ||
65 | + | func keyUserRewardFromDepositNum (userAddress) = makeString(["%s%s%s", "userRwdFromDepNum", userAddress], separator) | |
66 | + | ||
67 | + | ||
68 | + | func keyRewardPerNsbtSumAt (depositNum,tkn) = makeString(["%s%d", "rwdPerNsbtSumByDepNum", toString(depositNum), tkn], separator) | |
69 | + | ||
70 | + | ||
71 | + | func keyReward (userAddress,tkn) = makeString(["%s%s%s", "rwd", userAddress, tkn], separator) | |
72 | + | ||
73 | + | ||
74 | + | func keyNotDistributedReward (tkn) = makeString(["%s%s", "notDistributed", tkn], separator) | |
75 | + | ||
76 | + | ||
77 | + | func toX18 (origVal,origMult) = fraction(toBigInt(origVal), MULTX18, origMult) | |
78 | + | ||
79 | + | ||
47 | 80 | func getIntOrZero (key) = valueOrElse(getInteger(this, key), 0) | |
81 | + | ||
82 | + | ||
83 | + | func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal) | |
48 | 84 | ||
49 | 85 | ||
50 | 86 | func getIntOrFail (key) = valueOrErrorMessage(getInteger(this, key), (("Mandatory this." + key) + " is not defined")) | |
51 | 87 | ||
52 | 88 | ||
89 | + | func getStrOrElse (key,defaultVal) = valueOrElse(getString(this, key), defaultVal) | |
90 | + | ||
91 | + | ||
53 | 92 | func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), (("Mandatory this." + key) + " is not defined")) | |
93 | + | ||
94 | + | ||
95 | + | func toAddressOrFail (addressStr) = valueOrErrorMessage(addressFromString(addressStr), ("couldn't parse passed addressStr=" + addressStr)) | |
96 | + | ||
97 | + | ||
98 | + | func toAssetVect (assetStr) = if ((assetStr == WAVESIDSTR)) | |
99 | + | then unit | |
100 | + | else fromBase58String(assetStr) | |
54 | 101 | ||
55 | 102 | ||
56 | 103 | func asInt (val) = match val { | |
57 | 104 | case valInt: Int => | |
58 | 105 | valInt | |
59 | 106 | case _ => | |
60 | 107 | throw("fail to cast into Int") | |
61 | 108 | } | |
62 | 109 | ||
63 | 110 | ||
64 | 111 | func formatHistoryRecord (oldAmount,oldStart,newAmount,newStart) = makeString(["%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(oldAmount), toString(oldStart), toString(newAmount), toString(newStart)], separator) | |
65 | 112 | ||
66 | 113 | ||
67 | 114 | func HistoryRecordEntry (type,userAddress,txId,oldAmount,oldStart,newAmount,newStart) = StringEntry(keyHistoryRecord(type, userAddress, txId), formatHistoryRecord(oldAmount, oldStart, newAmount, newStart)) | |
68 | 115 | ||
69 | 116 | ||
70 | - | func | |
117 | + | func StatsResult (totalLockedInc,lockCountInc,usersCountInc) = { | |
71 | 118 | let locksCount = getIntOrZero(keyStatsLocksCount()) | |
72 | 119 | let usersCount = getIntOrZero(keyStatsUsersCount()) | |
73 | 120 | let totalAmount = getIntOrZero(keyLockParamTotalAmount()) | |
74 | - | [IntegerEntry(keyStatsLocksCount(), (locksCount + lockCountInc)), IntegerEntry(keyStatsUsersCount(), (usersCount + usersCountInc)), IntegerEntry(keyLockParamTotalAmount(), (totalAmount + totalLockedInc))] | |
121 | + | let totalAmountNew = (totalAmount + totalLockedInc) | |
122 | + | $Tuple3([IntegerEntry(keyStatsLocksCount(), (locksCount + lockCountInc)), IntegerEntry(keyStatsUsersCount(), (usersCount + usersCountInc)), IntegerEntry(keyLockParamTotalAmount(), totalAmountNew)], totalAmount, totalAmountNew) | |
75 | 123 | } | |
76 | 124 | ||
77 | 125 | ||
78 | 126 | func LockParamsEntry (userAddress,amount,start) = [IntegerEntry(keyLockParamUserAmount(userAddress), amount), IntegerEntry(keyLockParamStartBlock(userAddress), start)] | |
79 | 127 | ||
80 | 128 | ||
81 | 129 | func getParamsOrFail () = { | |
82 | 130 | let neutrinoContract = addressFromStringValue(getStringOrFail(keyNeutrinoContractAddress())) | |
83 | 131 | $Tuple4(fromBase58String(getStringValue(neutrinoContract, keyAuctionContractAddress())), fromBase58String(getStringValue(neutrinoContract, keyBondAsset())), getIntOrFail(keyMinLockAmount()), getIntOrFail(keyHalfLife())) | |
84 | 132 | } | |
85 | 133 | ||
86 | 134 | ||
87 | - | func | |
135 | + | func isActiveUser (userAddress) = (getIntOrElse(keyLockParamUserAmount(userAddress), 0) > 0) | |
88 | 136 | ||
89 | 137 | ||
90 | - | func getUserParamsOrUnit (userAddress) = if ( | |
91 | - | then $ | |
138 | + | func getUserParamsOrUnit (userAddress) = if (isActiveUser(userAddress)) | |
139 | + | then $Tuple3(false, getIntOrFail(keyLockParamUserAmount(userAddress)), getIntOrFail(keyLockParamStartBlock(userAddress))) | |
92 | 140 | else unit | |
93 | 141 | ||
94 | 142 | ||
95 | 143 | func getUserParamsOrFail (userAddress) = valueOrErrorMessage(getUserParamsOrUnit(userAddress), (("User " + toString(userAddress)) + " is not defined")) | |
96 | 144 | ||
97 | 145 | ||
146 | + | let supportedAssetsStr = getStrOrElse(keySupportedRewardAssets(), "") | |
147 | + | ||
148 | + | let supportedAssetsList = split(supportedAssetsStr, "_") | |
149 | + | ||
150 | + | func calcReward (userAddress,assetId,stakedAmountX,depositNumUser,depositNumLast) = { | |
151 | + | let rewardPerNsbtSumLastKEY = keyRewardPerNsbtSumAt(depositNumLast, assetId) | |
152 | + | let sumLastX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, assetId), "0")) | |
153 | + | let sumUserX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumUser, assetId), "0")) | |
154 | + | let rewardDynamicPart = toInt(fraction((sumLastX18 - sumUserX18), stakedAmountX, MULTX18)) | |
155 | + | let rewardCachedPartKEY = keyReward(userAddress, assetId) | |
156 | + | let rewardCachedPart = getIntOrElse(rewardCachedPartKEY, 0) | |
157 | + | $Tuple4((rewardCachedPart + rewardDynamicPart), rewardCachedPart, rewardDynamicPart, rewardCachedPartKEY) | |
158 | + | } | |
159 | + | ||
160 | + | ||
161 | + | func RewardEntries (isNewUser,userAddress,stakedAmount) = { | |
162 | + | let stakedAmountX = toBigInt(stakedAmount) | |
163 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddress) | |
164 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
165 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
166 | + | func forEachAssetCacheUserReward (accum,asset) = { | |
167 | + | let $t067986933 = calcReward(userAddress, asset, stakedAmountX, depositNumUser, depositNumLast) | |
168 | + | let rewardTotal = $t067986933._1 | |
169 | + | let cached = $t067986933._2 | |
170 | + | let dynamic = $t067986933._3 | |
171 | + | let rewardCachedPartKEY = $t067986933._4 | |
172 | + | (accum :+ IntegerEntry(rewardCachedPartKEY, rewardTotal)) | |
173 | + | } | |
174 | + | ||
175 | + | if (if ((depositNumLast == -1)) | |
176 | + | then (depositNumUser == -1) | |
177 | + | else false) | |
178 | + | then nil | |
179 | + | else if (if ((depositNumLast == -1)) | |
180 | + | then (depositNumUser > -1) | |
181 | + | else false) | |
182 | + | then throw("invalid depositNumLast and depositNumUser state") | |
183 | + | else if (if ((depositNumLast > -1)) | |
184 | + | then (depositNumUser == -1) | |
185 | + | else false) | |
186 | + | then if (isNewUser) | |
187 | + | then [IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)] | |
188 | + | else throw("isNewUser must not be false in 5 + 6 cases") | |
189 | + | else if (if ((depositNumLast > -1)) | |
190 | + | then (depositNumUser > -1) | |
191 | + | else false) | |
192 | + | then if (isNewUser) | |
193 | + | then throw((((("invalid management for isNewUser=" + toString(isNewUser)) + " and depositNumUser=") + toString(depositNumUser)) + " during full unstake")) | |
194 | + | else ({ | |
195 | + | let $l = supportedAssetsList | |
196 | + | let $s = size($l) | |
197 | + | let $acc0 = nil | |
198 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
199 | + | then $a | |
200 | + | else forEachAssetCacheUserReward($a, $l[$i]) | |
201 | + | ||
202 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
203 | + | then $a | |
204 | + | else throw("List size exceeds 10") | |
205 | + | ||
206 | + | $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) | |
207 | + | } :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) | |
208 | + | else throw(((("uncovered condition: depositNumLast=" + toString(depositNumLast)) + " depositNumUser=") + toString(depositNumUser))) | |
209 | + | } | |
210 | + | ||
211 | + | ||
212 | + | func IncrementNotDistributedRewardEntry (tkn,amountInc) = { | |
213 | + | let notDistributedRewardKEY = keyNotDistributedReward(tkn) | |
214 | + | let notDistributedReward = getIntOrElse(notDistributedRewardKEY, 0) | |
215 | + | [IntegerEntry(notDistributedRewardKEY, (notDistributedReward + amountInc))] | |
216 | + | } | |
217 | + | ||
218 | + | ||
98 | 219 | @Callable(i) | |
99 | - | func constructor (neutrinoContractAddress,mathContractAddress,minLockAmount,halfLife) = if ((i.caller != this)) | |
220 | + | func constructor (neutrinoContractAddress,mathContractAddress,minLockAmount,halfLife,supportedRewardAssets) = if ((i.caller != this)) | |
100 | 221 | then throw("Permission denied") | |
101 | - | else [StringEntry(keyNeutrinoContractAddress(), neutrinoContractAddress), StringEntry(keyMathContractAddress(), mathContractAddress), IntegerEntry(keyMinLockAmount(), minLockAmount), IntegerEntry(keyHalfLife(), halfLife)] | |
222 | + | else [StringEntry(keyNeutrinoContractAddress(), neutrinoContractAddress), StringEntry(keyMathContractAddress(), mathContractAddress), IntegerEntry(keyMinLockAmount(), minLockAmount), IntegerEntry(keyHalfLife(), halfLife), StringEntry(keySupportedRewardAssets(), supportedRewardAssets)] | |
102 | 223 | ||
103 | 224 | ||
104 | 225 | ||
105 | 226 | @Callable(i) | |
106 | 227 | func stake () = { | |
107 | - | let $ | |
108 | - | let auctionContract = $ | |
109 | - | let bondAssetId = $ | |
110 | - | let minLockAmount = $ | |
111 | - | let halfLife = $ | |
228 | + | let $t01080310882 = getParamsOrFail() | |
229 | + | let auctionContract = $t01080310882._1 | |
230 | + | let bondAssetId = $t01080310882._2 | |
231 | + | let minLockAmount = $t01080310882._3 | |
232 | + | let halfLife = $t01080310882._4 | |
112 | 233 | if ((size(i.payments) != 1)) | |
113 | 234 | then throw("Invalid payments size") | |
114 | 235 | else { | |
115 | 236 | let payment = i.payments[0] | |
116 | 237 | let amount = payment.amount | |
117 | 238 | let invalidAssetMessage = (("Invalid asset. " + toBase58String(bondAssetId)) + " is expected") | |
118 | 239 | let assetId = valueOrErrorMessage(payment.assetId, invalidAssetMessage) | |
119 | 240 | if ((assetId != bondAssetId)) | |
120 | 241 | then throw(invalidAssetMessage) | |
121 | 242 | else { | |
122 | 243 | let userAddress = i.caller | |
123 | - | let $t050205192 = match getUserParamsOrUnit(userAddress) { | |
124 | - | case p: (Int, Int) => | |
125 | - | $Tuple3(false, p._1, p._2) | |
126 | - | case _: Unit => | |
127 | - | $Tuple3(true, 0, -1) | |
128 | - | case _ => | |
129 | - | throw("Match error") | |
130 | - | } | |
131 | - | let isNewUser = $t050205192._1 | |
132 | - | let lockAmount = $t050205192._2 | |
133 | - | let lockStartHeight = $t050205192._3 | |
244 | + | let userAddressStr = toString(i.caller) | |
245 | + | let $t01142411531 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, -1)) | |
246 | + | let isNewUser = $t01142411531._1 | |
247 | + | let lockAmount = $t01142411531._2 | |
248 | + | let lockStartHeight = $t01142411531._3 | |
134 | 249 | let mergedAmount = if (isNewUser) | |
135 | 250 | then amount | |
136 | 251 | else (amount + lockAmount) | |
137 | 252 | let mergedStartHeight = if (isNewUser) | |
138 | 253 | then height | |
139 | 254 | else { | |
140 | 255 | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
141 | - | asInt(invoke(mathContract, " | |
256 | + | asInt(invoke(mathContract, "mergeStakesREADONLY", [amount, height, lockAmount, lockStartHeight, halfLife], nil)) | |
142 | 257 | } | |
143 | 258 | if ((minLockAmount > mergedAmount)) | |
144 | 259 | then throw(("Min lock amount is " + toString(minLockAmount))) | |
145 | - | else (([HistoryRecordEntry("stake", userAddress, i.transactionId, lockAmount, lockStartHeight, mergedAmount, mergedStartHeight)] ++ LockParamsEntry(userAddress, mergedAmount, mergedStartHeight)) ++ StatsEntry(amount, 1, if (isNewUser) | |
146 | - | then 1 | |
147 | - | else 0)) | |
260 | + | else { | |
261 | + | let $t01198112083 = StatsResult(amount, 1, if (isNewUser) | |
262 | + | then 1 | |
263 | + | else 0) | |
264 | + | let statsEntries = $t01198112083._1 | |
265 | + | let totalStaked = $t01198112083._2 | |
266 | + | let totalStakedNew = $t01198112083._3 | |
267 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
268 | + | ((([HistoryRecordEntry("stake", userAddress, i.transactionId, lockAmount, lockStartHeight, mergedAmount, mergedStartHeight)] ++ LockParamsEntry(userAddress, mergedAmount, mergedStartHeight)) ++ statsEntries) :+ IntegerEntry(keyUserRewardFromDepositNum(userAddressStr), getIntOrElse(keyDepositNumLast(), -1))) | |
269 | + | } | |
148 | 270 | } | |
149 | 271 | } | |
150 | 272 | } | |
151 | 273 | ||
152 | 274 | ||
153 | 275 | ||
154 | 276 | @Callable(i) | |
155 | 277 | func unstake (amount) = { | |
156 | 278 | let userAddress = i.caller | |
157 | - | let $t059606038 = getParamsOrFail() | |
158 | - | let auctionAddress = $t059606038._1 | |
159 | - | let bondAssetId = $t059606038._2 | |
160 | - | let minLockAmount = $t059606038._3 | |
161 | - | let halfLife = $t059606038._4 | |
162 | - | let $t060416104 = getUserParamsOrFail(userAddress) | |
163 | - | let lockAmount = $t060416104._1 | |
164 | - | let lockStart = $t060416104._2 | |
279 | + | let userAddressStr = toString(userAddress) | |
280 | + | let $t01258812666 = getParamsOrFail() | |
281 | + | let auctionAddress = $t01258812666._1 | |
282 | + | let bondAssetId = $t01258812666._2 | |
283 | + | let minLockAmount = $t01258812666._3 | |
284 | + | let halfLife = $t01258812666._4 | |
285 | + | let $t01266912743 = getUserParamsOrFail(userAddress) | |
286 | + | let isNewUser = $t01266912743._1 | |
287 | + | let lockAmount = $t01266912743._2 | |
288 | + | let lockStart = $t01266912743._3 | |
165 | 289 | if ((0 >= lockAmount)) | |
166 | 290 | then throw("Nothing to unstake") | |
167 | 291 | else if ((amount > lockAmount)) | |
168 | 292 | then throw(((("Requested " + toString(amount)) + ", but staked only ") + toString(lockAmount))) | |
169 | 293 | else { | |
170 | 294 | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
171 | - | let comissionAmount = asInt(invoke(mathContract, " | |
172 | - | | |
295 | + | let comissionAmount = asInt(invoke(mathContract, "getUnstakeComissionAmountREADONLY", [amount, lockStart, halfLife], nil)) | |
296 | + | let $t01314413298 = StatsResult(-(amount), if ((amount == lockAmount)) | |
173 | 297 | then -1 | |
174 | 298 | else 0, if ((amount == lockAmount)) | |
175 | 299 | then -1 | |
176 | - | else 0)) | |
300 | + | else 0) | |
301 | + | let statsEntries = $t01314413298._1 | |
302 | + | let totalStaked = $t01314413298._2 | |
303 | + | let totalStakedNew = $t01314413298._3 | |
304 | + | ((([ScriptTransfer(userAddress, (amount - comissionAmount), bondAssetId), ScriptTransfer(Address(auctionAddress), comissionAmount, bondAssetId), HistoryRecordEntry("unstake", userAddress, i.transactionId, lockAmount, lockStart, (lockAmount - amount), lockStart)] ++ RewardEntries(false, userAddressStr, lockAmount)) ++ LockParamsEntry(userAddress, (lockAmount - amount), lockStart)) ++ statsEntries) | |
177 | 305 | } | |
178 | 306 | } | |
179 | 307 | ||
180 | 308 | ||
181 | 309 | ||
182 | 310 | @Callable(i) | |
183 | - | func gNsbtAmountREADONLY (userAddressStr) = { | |
184 | - | let userAddress = addressFromStringValue(userAddressStr) | |
185 | - | $Tuple2(nil, if (isUserExists(userAddress)) | |
186 | - | then getUserParamsOrFail(userAddress)._1 | |
187 | - | else 0) | |
311 | + | func deposit () = if ((size(i.payments) != 1)) | |
312 | + | then throw("exact 1 payment is allowed only") | |
313 | + | else { | |
314 | + | let pmt = i.payments[0] | |
315 | + | let amount = pmt.amount | |
316 | + | let pmtAssetId = valueOrElse(pmt.assetId, WAVESID) | |
317 | + | let pmtAssetIdStr = toBase58String(pmtAssetId) | |
318 | + | let pmtMultX = if ((pmtAssetId == WAVESID)) | |
319 | + | then MULTX8 | |
320 | + | else MULTX6 | |
321 | + | let amountX = toBigInt(amount) | |
322 | + | let totalStaked = getIntOrElse(keyLockParamTotalAmount(), 0) | |
323 | + | let totalStakedX = toBigInt(totalStaked) | |
324 | + | if ((0 > totalStaked)) | |
325 | + | then throw("TODO: case is not supported") | |
326 | + | else if ((totalStaked == 0)) | |
327 | + | then IncrementNotDistributedRewardEntry(pmtAssetIdStr, amount) | |
328 | + | else { | |
329 | + | let rewardPerNsbtX18 = fraction(amountX, MULTX18, totalStakedX) | |
330 | + | let depositNumLastKEY = keyDepositNumLast() | |
331 | + | let depositNumLast = getIntOrElse(depositNumLastKEY, -1) | |
332 | + | let depositNumNew = (depositNumLast + 1) | |
333 | + | if (!(contains(supportedAssetsStr, pmtAssetIdStr))) | |
334 | + | then throw(((supportedAssetsStr + " doesn't contain ") + pmtAssetIdStr)) | |
335 | + | else { | |
336 | + | func refreshRewardPerNsbtSUM (accum,nextAsset) = { | |
337 | + | let rewardPerNsbtSumNewKEY = keyRewardPerNsbtSumAt(depositNumNew, nextAsset) | |
338 | + | let sumLastStr = getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, nextAsset), "0") | |
339 | + | (accum :+ (if ((nextAsset == pmtAssetIdStr)) | |
340 | + | then StringEntry(rewardPerNsbtSumNewKEY, toString((parseBigIntValue(sumLastStr) + rewardPerNsbtX18))) | |
341 | + | else StringEntry(rewardPerNsbtSumNewKEY, sumLastStr))) | |
342 | + | } | |
343 | + | ||
344 | + | ({ | |
345 | + | let $l = supportedAssetsList | |
346 | + | let $s = size($l) | |
347 | + | let $acc0 = nil | |
348 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
349 | + | then $a | |
350 | + | else refreshRewardPerNsbtSUM($a, $l[$i]) | |
351 | + | ||
352 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
353 | + | then $a | |
354 | + | else throw("List size exceeds 10") | |
355 | + | ||
356 | + | $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) | |
357 | + | } :+ IntegerEntry(depositNumLastKEY, depositNumNew)) | |
358 | + | } | |
359 | + | } | |
360 | + | } | |
361 | + | ||
362 | + | ||
363 | + | ||
364 | + | @Callable(i) | |
365 | + | func claimRewards () = { | |
366 | + | let userAddress = i.caller | |
367 | + | let userAddressStr = toString(userAddress) | |
368 | + | let $t01548015585 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
369 | + | let isNewUser = $t01548015585._1 | |
370 | + | let stakedAmount = $t01548015585._2 | |
371 | + | let stakingStart = $t01548015585._3 | |
372 | + | let stakedAmountX = toBigInt(stakedAmount) | |
373 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
374 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
375 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
376 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
377 | + | let $t01594616084 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
378 | + | let rewardTotal = $t01594616084._1 | |
379 | + | let cached = $t01594616084._2 | |
380 | + | let dynamic = $t01594616084._3 | |
381 | + | let rewardCachedPartKEY = $t01594616084._4 | |
382 | + | if ((0 >= rewardTotal)) | |
383 | + | then accum | |
384 | + | else ((accum :+ ScriptTransfer(userAddress, rewardTotal, toAssetVect(asset))) :+ IntegerEntry(rewardCachedPartKEY, 0)) | |
385 | + | } | |
386 | + | ||
387 | + | let transfers = { | |
388 | + | let $l = supportedAssetsList | |
389 | + | let $s = size($l) | |
390 | + | let $acc0 = nil | |
391 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
392 | + | then $a | |
393 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
394 | + | ||
395 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
396 | + | then $a | |
397 | + | else throw("List size exceeds 10") | |
398 | + | ||
399 | + | $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) | |
400 | + | } | |
401 | + | if ((0 >= size(transfers))) | |
402 | + | then throw("nothing to claim") | |
403 | + | else transfers | |
188 | 404 | } | |
189 | 405 | ||
190 | 406 | ||
191 | 407 | ||
192 | 408 | @Callable(i) | |
193 | - | func nsbtStakingInfoWrapperREADONLY (userAddressStr) = { | |
194 | - | let $t073267626 = if ((userAddressStr == "")) | |
195 | - | then $Tuple2(0, 0) | |
409 | + | func unclaimedRewardsREADONLY (userAddressStr) = { | |
410 | + | func forEachAssetZeroReward (accum,asset) = ((accum + makeString([asset, "0", "0"], ":")) + "_") | |
411 | + | ||
412 | + | let unclaimedRewardStr = if ((userAddressStr == "")) | |
413 | + | then { | |
414 | + | let $l = supportedAssetsList | |
415 | + | let $s = size($l) | |
416 | + | let $acc0 = "" | |
417 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
418 | + | then $a | |
419 | + | else forEachAssetZeroReward($a, $l[$i]) | |
420 | + | ||
421 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
422 | + | then $a | |
423 | + | else throw("List size exceeds 10") | |
424 | + | ||
425 | + | $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) | |
426 | + | } | |
196 | 427 | else { | |
197 | 428 | let userAddress = addressFromStringValue(userAddressStr) | |
198 | - | if (isUserExists(userAddress)) | |
199 | - | then { | |
200 | - | let $t075157570 = getUserParamsOrFail(userAddress) | |
201 | - | let amount = $t075157570._1 | |
202 | - | let start = $t075157570._2 | |
203 | - | $Tuple2(nil, $Tuple2(amount, start)) | |
204 | - | } | |
205 | - | else $Tuple2(nil, $Tuple2(0, 0)) | |
429 | + | let $t01684816953 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
430 | + | let isNewUser = $t01684816953._1 | |
431 | + | let stakedAmount = $t01684816953._2 | |
432 | + | let stakingStart = $t01684816953._3 | |
433 | + | let stakedAmountX = toBigInt(stakedAmount) | |
434 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
435 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
436 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
437 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
438 | + | let $t01729917437 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
439 | + | let rewardTotal = $t01729917437._1 | |
440 | + | let cached = $t01729917437._2 | |
441 | + | let dynamic = $t01729917437._3 | |
442 | + | let rewardCachedPartKEY = $t01729917437._4 | |
443 | + | ((accum + makeString([asset, toString(rewardTotal), "0"], ":")) + "_") | |
444 | + | } | |
445 | + | ||
446 | + | let $l = supportedAssetsList | |
447 | + | let $s = size($l) | |
448 | + | let $acc0 = "" | |
449 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
450 | + | then $a | |
451 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
452 | + | ||
453 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
454 | + | then $a | |
455 | + | else throw("List size exceeds 10") | |
456 | + | ||
457 | + | $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) | |
206 | 458 | } | |
207 | - | let nsbtAmt = $t073267626._1 | |
208 | - | let stakingStart = $t073267626._2 | |
209 | - | $Tuple2(nil, $Tuple2(nsbtAmt, stakingStart)) | |
459 | + | $Tuple2(nil, dropRight(unclaimedRewardStr, 1)) | |
210 | 460 | } | |
461 | + | ||
462 | + | ||
463 | + | ||
464 | + | @Callable(i) | |
465 | + | func gNsbtAmountREADONLY (userAddressStr) = if ((userAddressStr == "")) | |
466 | + | then $Tuple2(nil, 0) | |
467 | + | else { | |
468 | + | let userAddress = toAddressOrFail(userAddressStr) | |
469 | + | let $t01782917955 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
470 | + | let isNewUser = $t01782917955._1 | |
471 | + | let nsbtAmt = $t01782917955._2 | |
472 | + | let stakingStart = $t01782917955._3 | |
473 | + | $Tuple2(nil, nsbtAmt) | |
474 | + | } | |
475 | + | ||
476 | + | ||
477 | + | ||
478 | + | @Callable(i) | |
479 | + | func nsbtStakingInfoWrapperREADONLY (userAddressStr) = if ((userAddressStr == "")) | |
480 | + | then $Tuple2(nil, $Tuple2(0, 0)) | |
481 | + | else { | |
482 | + | let userAddress = toAddressOrFail(userAddressStr) | |
483 | + | let $t01821118311 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
484 | + | let isNewUser = $t01821118311._1 | |
485 | + | let nsbtAmt = $t01821118311._2 | |
486 | + | let stakingStart = $t01821118311._3 | |
487 | + | $Tuple2(nil, $Tuple2(nsbtAmt, stakingStart)) | |
488 | + | } | |
211 | 489 | ||
212 | 490 |
github/deemru/w8io/169f3d6 108.57 ms ◑