2022.08.08 11:05 [3240724] smart account 3P8w8NXZUtYdCA13tHbDY5sW4mC27ZFJgG3 > SELF 0.00000000 Waves
{ "type": 13, "id": "24XWyrzVBWBFbvMCBpUzntzxhT7R5zqdh2HJ47vNwbY4", "fee": 3100000, "feeAssetId": null, "timestamp": 1659947840872, "version": 1, "sender": "3P8w8NXZUtYdCA13tHbDY5sW4mC27ZFJgG3", "senderPublicKey": "6uKJV5r5qjqG9uVK4Q24W7zG5KZtGtKXz3NWRMwfZbB7", "proofs": [ "", "4wrRczJMTYP2AN7wjM5S5sRA3HPsRbaWX3dG8uFVeLTvGqxFfjMRCHq5jEuLsfCkxpQ1zq36D1q2uubcijVysVFM", "", "2qXSgvFyEunu3g4XgFJ8PwG6z9ksT12YZNBErReHaWKvKXUFdHMbRvbeo4YSV6xz2z3c2rCNPHgBRRFkskzUNeun" ], "script": "base64:AAIFAAAAAAAAACkIAhIHCgUICAEBCBIAEgMKAQESABIAEgASAwoBCBIECgIIARIECgIIAQAAAEgAAAAAC3JldmlzaW9uTnVtAgAAAChjYmQwYmRjOGJiYmE5MWRiNjQwNjZiMTZhODQ5MTNhNGM5NjVlMjNlAAAAAAlzZXBhcmF0b3ICAAAAAl9fAAAAAANTRVACAAAAAl9fAAAAAAVNVUxUNgAAAAAAAA9CQAAAAAAFTVVMVDgAAAAAAAX14QAAAAAABk1VTFRYNgkAATYAAAABBQAAAAVNVUxUNgAAAAAGTVVMVFg4CQABNgAAAAEFAAAABU1VTFQ4AAAAAAdNVUxUWDE4CQABNgAAAAEADeC2s6dkAAAAAAAACldBVkVTSURTVFICAAAABVdBVkVTAAAAAAdXQVZFU0lECQACWQAAAAEFAAAACldBVkVTSURTVFIAAAAAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAAAAAAAAAAEAAAAAGElkeENvbnRyb2xDZmdBdWN0aW9uRGFwcAAAAAAAAAAAAgAAAAAUSWR4Q29udHJvbENmZ1JwZERhcHAAAAAAAAAAAAMAAAAAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAAAAAAAAAABAAAAAAcSWR4Q29udHJvbENmZ0xpcXVpZGF0aW9uRGFwcAAAAAAAAAAABQAAAAAVSWR4Q29udHJvbENmZ1Jlc3REYXBwAAAAAAAAAAAGAAAAAB1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAAAAAAAAAAABwAAAAAcSWR4Q29udHJvbENmZ05zYnRTdGFraW5nRGFwcAAAAAAAAAAACAAAAAAZSWR4Q29udHJvbENmZ01lZGlhdG9yRGFwcAAAAAAAAAAACQEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAgAAAAdhZGRyZXNzAAAAA2tleQkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAAB2FkZHJlc3MFAAAAA2tleQkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAAAptYW5kYXRvcnkgCQAEJQAAAAEFAAAAB2FkZHJlc3MCAAAAAS4FAAAAA2tleQIAAAAPIGlzIG5vdCBkZWZpbmVkAQAAABFrZXlDb250cm9sQWRkcmVzcwAAAAACAAAAHCVzJXNfX2NvbmZpZ19fY29udHJvbEFkZHJlc3MBAAAADWtleUNvbnRyb2xDZmcAAAAAAgAAABElc19fY29udHJvbENvbmZpZwEAAAAUcmVhZENvbnRyb2xDZmdPckZhaWwAAAABAAAAB2NvbnRyb2wJAAS1AAAAAgkBAAAAD2dldFN0cmluZ09yRmFpbAAAAAIFAAAAB2NvbnRyb2wJAQAAAA1rZXlDb250cm9sQ2ZnAAAAAAUAAAADU0VQAQAAABhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwAAAACAAAACmNvbnRyb2xDZmcAAAADaWR4CQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQmAAAAAQkAAZEAAAACBQAAAApjb250cm9sQ2ZnBQAAAANpZHgJAAEsAAAAAgIAAAAtQ29udHJvbCBjZmcgZG9lc24ndCBjb250YWluIGFkZHJlc3MgYXQgaW5kZXggCQABpAAAAAEFAAAAA2lkeAAAAAAPY29udHJvbENvbnRyYWN0CQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABCQEAAAALdmFsdWVPckVsc2UAAAACCQAEHQAAAAIFAAAABHRoaXMJAQAAABFrZXlDb250cm9sQWRkcmVzcwAAAAACAAAAIzNQNUJmZDU4UFBmTnZCTTJIeThRZmJjRHFNZU50emc3S2ZQAAAAAApjb250cm9sQ2ZnCQEAAAAUcmVhZENvbnRyb2xDZmdPckZhaWwAAAABBQAAAA9jb250cm9sQ29udHJhY3QAAAAADG1hdGhDb250cmFjdAkBAAAAGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAAAAAIFAAAACmNvbnRyb2xDZmcFAAAAFUlkeENvbnRyb2xDZmdNYXRoRGFwcAAAAAAQbmV1dHJpbm9Db250cmFjdAkBAAAAGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAAAAAIFAAAACmNvbnRyb2xDZmcFAAAAGUlkeENvbnRyb2xDZmdOZXV0cmlub0RhcHAAAAAAD2F1Y3Rpb25Db250cmFjdAkBAAAAGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAAAAAIFAAAACmNvbnRyb2xDZmcFAAAAGElkeENvbnRyb2xDZmdBdWN0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YXRvcgEAAAASSGlzdG9yeVJlY29yZEVudHJ5AAAABwAAAAR0eXBlAAAAC3VzZXJBZGRyZXNzAAAABHR4SWQAAAAJb2xkQW1vdW50AAAACG9sZFN0YXJ0AAAACW5ld0Ftb3VudAAAAAhuZXdTdGFydAkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAEGtleUhpc3RvcnlSZWNvcmQAAAADBQAAAAR0eXBlBQAAAAt1c2VyQWRkcmVzcwUAAAAEdHhJZAkBAAAAE2Zvcm1hdEhpc3RvcnlSZWNvcmQAAAAEBQAAAAlvbGRBbW91bnQFAAAACG9sZFN0YXJ0BQAAAAluZXdBbW91bnQFAAAACG5ld1N0YXJ0AQAAABFDbGFpbUhpc3RvcnlFbnRyeQAAAAMAAAALdXNlckFkZHJlc3MAAAAEdHhJZAAAAA5jbGFpbWVkUmV3YXJkcwkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAEGtleUhpc3RvcnlSZWNvcmQAAAADAgAAAAVjbGFpbQUAAAALdXNlckFkZHJlc3MFAAAABHR4SWQJAQAAABhmb3JtYXRDbGFpbUhpc3RvcnlSZWNvcmQAAAACCQAEJQAAAAEFAAAAC3VzZXJBZGRyZXNzBQAAAA5jbGFpbWVkUmV3YXJkcwEAAAALU3RhdHNSZXN1bHQAAAADAAAADnRvdGFsTG9ja2VkSW5jAAAADGxvY2tDb3VudEluYwAAAA11c2Vyc0NvdW50SW5jBAAAAApsb2Nrc0NvdW50CQEAAAAMZ2V0SW50T3JaZXJvAAAAAQkBAAAAEmtleVN0YXRzTG9ja3NDb3VudAAAAAAEAAAACnVzZXJzQ291bnQJAQAAAAxnZXRJbnRPclplcm8AAAABCQEAAAASa2V5U3RhdHNVc2Vyc0NvdW50AAAAAAQAAAALdG90YWxBbW91bnQJAQAAAAxnZXRJbnRPclplcm8AAAABCQEAAAAXa2V5TG9ja1BhcmFtVG90YWxBbW91bnQAAAAABAAAAA50b3RhbEFtb3VudE5ldwkAAGQAAAACBQAAAAt0b3RhbEFtb3VudAUAAAAOdG90YWxMb2NrZWRJbmMJAAUVAAAAAwkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgkBAAAAEmtleVN0YXRzTG9ja3NDb3VudAAAAAAJAABkAAAAAgUAAAAKbG9ja3NDb3VudAUAAAAMbG9ja0NvdW50SW5jCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAASa2V5U3RhdHNVc2Vyc0NvdW50AAAAAAkAAGQAAAACBQAAAAp1c2Vyc0NvdW50BQAAAA11c2Vyc0NvdW50SW5jCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAXa2V5TG9ja1BhcmFtVG90YWxBbW91bnQAAAAABQAAAA50b3RhbEFtb3VudE5ldwUAAAADbmlsBQAAAAt0b3RhbEFtb3VudAUAAAAOdG90YWxBbW91bnROZXcBAAAAD0xvY2tQYXJhbXNFbnRyeQAAAAMAAAALdXNlckFkZHJlc3MAAAAGYW1vdW50AAAABXN0YXJ0CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAWa2V5TG9ja1BhcmFtVXNlckFtb3VudAAAAAEFAAAAC3VzZXJBZGRyZXNzBQAAAAZhbW91bnQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAABZrZXlMb2NrUGFyYW1TdGFydEJsb2NrAAAAAQUAAAALdXNlckFkZHJlc3MFAAAABXN0YXJ0BQAAAANuaWwBAAAAD2dldFBhcmFtc09yRmFpbAAAAAAJAAUVAAAAAwkAAlkAAAABCQEAAAARQGV4dHJOYXRpdmUoMTA1MykAAAACBQAAABBuZXV0cmlub0NvbnRyYWN0CQEAAAAMa2V5Qm9uZEFzc2V0AAAAAAkBAAAADGdldEludE9yRmFpbAAAAAEJAQAAABBrZXlNaW5Mb2NrQW1vdW50AAAAAAkBAAAADGdldEludE9yRmFpbAAAAAEJAQAAAAtrZXlIYWxmTGlmZQAAAAABAAAADGlzQWN0aXZlVXNlcgAAAAEAAAALdXNlckFkZHJlc3MJAABmAAAAAgkBAAAADGdldEludE9yRWxzZQAAAAIJAQAAABZrZXlMb2NrUGFyYW1Vc2VyQW1vdW50AAAAAQUAAAALdXNlckFkZHJlc3MAAAAAAAAAAAAAAAAAAAAAAAABAAAAE2dldFVzZXJQYXJhbXNPclVuaXQAAAABAAAAC3VzZXJBZGRyZXNzAwkBAAAADGlzQWN0aXZlVXNlcgAAAAEFAAAAC3VzZXJBZGRyZXNzCQAFFQAAAAMHCQEAAAAMZ2V0SW50T3JGYWlsAAAAAQkBAAAAFmtleUxvY2tQYXJhbVVzZXJBbW91bnQAAAABBQAAAAt1c2VyQWRkcmVzcwkBAAAADGdldEludE9yRmFpbAAAAAEJAQAAABZrZXlMb2NrUGFyYW1TdGFydEJsb2NrAAAAAQUAAAALdXNlckFkZHJlc3MFAAAABHVuaXQBAAAAE2dldFVzZXJQYXJhbXNPckZhaWwAAAABAAAAC3VzZXJBZGRyZXNzCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAQAAABNnZXRVc2VyUGFyYW1zT3JVbml0AAAAAQUAAAALdXNlckFkZHJlc3MJAAEsAAAAAgkAASwAAAACAgAAAAVVc2VyIAkABCUAAAABBQAAAAt1c2VyQWRkcmVzcwIAAAAPIGlzIG5vdCBkZWZpbmVkAAAAABJzdXBwb3J0ZWRBc3NldHNTdHIJAQAAAAxnZXRTdHJPckVsc2UAAAACCQEAAAAYa2V5U3VwcG9ydGVkUmV3YXJkQXNzZXRzAAAAAAIAAAAAAAAAABNzdXBwb3J0ZWRBc3NldHNMaXN0CQAEtQAAAAIFAAAAEnN1cHBvcnRlZEFzc2V0c1N0cgIAAAABXwEAAAAKY2FsY1Jld2FyZAAAAAUAAAALdXNlckFkZHJlc3MAAAAHYXNzZXRJZAAAAA1zdGFrZWRBbW91bnRYAAAADmRlcG9zaXROdW1Vc2VyAAAADmRlcG9zaXROdW1MYXN0BAAAABdyZXdhcmRQZXJOc2J0U3VtTGFzdEtFWQkBAAAAFWtleVJld2FyZFBlck5zYnRTdW1BdAAAAAIFAAAADmRlcG9zaXROdW1MYXN0BQAAAAdhc3NldElkBAAAAApzdW1MYXN0WDE4CQABpwAAAAEJAQAAAAxnZXRTdHJPckVsc2UAAAACCQEAAAAVa2V5UmV3YXJkUGVyTnNidFN1bUF0AAAAAgUAAAAOZGVwb3NpdE51bUxhc3QFAAAAB2Fzc2V0SWQCAAAAATAEAAAACnN1bVVzZXJYMTgJAAGnAAAAAQkBAAAADGdldFN0ck9yRWxzZQAAAAIJAQAAABVrZXlSZXdhcmRQZXJOc2J0U3VtQXQAAAACBQAAAA5kZXBvc2l0TnVtVXNlcgUAAAAHYXNzZXRJZAIAAAABMAQAAAARcmV3YXJkRHluYW1pY1BhcnQJAAGgAAAAAQkAATwAAAADCQABOAAAAAIFAAAACnN1bUxhc3RYMTgFAAAACnN1bVVzZXJYMTgFAAAADXN0YWtlZEFtb3VudFgFAAAAB01VTFRYMTgEAAAAE3Jld2FyZENhY2hlZFBhcnRLRVkJAQAAAAlrZXlSZXdhcmQAAAACBQAAAAt1c2VyQWRkcmVzcwUAAAAHYXNzZXRJZAQAAAAQcmV3YXJkQ2FjaGVkUGFydAkBAAAADGdldEludE9yRWxzZQAAAAIFAAAAE3Jld2FyZENhY2hlZFBhcnRLRVkAAAAAAAAAAAAJAAUWAAAABAkAAGQAAAACBQAAABByZXdhcmRDYWNoZWRQYXJ0BQAAABFyZXdhcmREeW5hbWljUGFydAUAAAAQcmV3YXJkQ2FjaGVkUGFydAUAAAARcmV3YXJkRHluYW1pY1BhcnQFAAAAE3Jld2FyZENhY2hlZFBhcnRLRVkBAAAADVJld2FyZEVudHJpZXMAAAADAAAACWlzTmV3VXNlcgAAAAt1c2VyQWRkcmVzcwAAAAxzdGFrZWRBbW91bnQEAAAADXN0YWtlZEFtb3VudFgJAAE2AAAAAQUAAAAMc3Rha2VkQW1vdW50BAAAABt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkJAQAAABtrZXlVc2VyUmV3YXJkRnJvbURlcG9zaXROdW0AAAABBQAAAAt1c2VyQWRkcmVzcwQAAAAOZGVwb3NpdE51bVVzZXIJAQAAAAxnZXRJbnRPckVsc2UAAAACBQAAABt1c2VyUmV3YXJkRnJvbURlcG9zaXROdW1LRVkA//////////8EAAAADmRlcG9zaXROdW1MYXN0CQEAAAAMZ2V0SW50T3JFbHNlAAAAAgkBAAAAEWtleURlcG9zaXROdW1MYXN0AAAAAAD//////////woBAAAAG2ZvckVhY2hBc3NldENhY2hlVXNlclJld2FyZAAAAAIAAAAFYWNjdW0AAAAFYXNzZXQEAAAACyR0MDg0NTA4NTg1CQEAAAAKY2FsY1Jld2FyZAAAAAUFAAAAC3VzZXJBZGRyZXNzBQAAAAVhc3NldAUAAAANc3Rha2VkQW1vdW50WAUAAAAO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AAAAAgAAAAt1c2VyQWRkcmVzcwAAAAFpBAAAAA51c2VyQWRkcmVzc1N0cgkABCUAAAABBQAAAAt1c2VyQWRkcmVzcwMJAABmAAAAAgkAAZAAAAABCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAkAAAIAAAABAgAAABlwYXltZW50cyBhcmUgbm90IGFjY2VwdGVkBAAAAA0kdDAxMTUyOTExNjM0CQEAAAALdmFsdWVPckVsc2UAAAACCQEAAAATZ2V0VXNlclBhcmFtc09yVW5pdAAAAAEFAAAAC3VzZXJBZGRyZXNzCQAFFQAAAAMGAAAAAAAAAAAAAAAAAAAAAAAABAAAAAlpc05ld1VzZXIIBQAAAA0kdDAxMTUyOTExNjM0AAAAAl8xBAAAAAxzdGFrZWRBbW91bnQIBQAAAA0kdDAxMTUyOTExNjM0AAAAAl8yBAAAAAxzdGFraW5nU3RhcnQIBQAAAA0kdDAxMTUyOTExNjM0AAAAAl8zBAAAAA1zdGFrZWRBbW91bnRYCQABNgAAAAEFAAAADHN0YWtlZEFtb3VudAQAAAAbdXNlclJld2FyZEZyb21EZXBvc2l0TnVtS0VZCQEAAAAba2V5VXNlclJld2FyZEZyb21EZXBvc2l0TnVtAAAAAQUAAAAOdXNlckFkZHJlc3NTdHIEAAAADmRlcG9zaXROdW1Vc2VyCQEAAAAMZ2V0SW50T3JFbHNlAAAAAgUAAAAbdXNlclJld2FyZEZyb21EZXBvc2l0TnVtS0VZAP//////////BAAAAA5kZXBvc2l0TnVtTGFzdAkBAAAADGdldEludE9yRWxzZQAAAAIJAQAAABFrZXlEZXBvc2l0TnVtTGFzdAAAAAAA//////////8KAQAAAB9mb3JFYWNoQXNzZXRDYWxjVW5jbGFpbWVkUmV3YXJkAAAAAgAAAAVhY2N1bQAAAAVhc3NldAQAAAANJHQwMTIwMDUxMjE0MwkBAAAACmNhbGNSZXdhcmQAAAAFBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAFYXNzZXQFAAAADXN0YWtlZEFtb3VudFgFAAAADmRlcG9zaXROdW1Vc2VyBQAAAA5kZXBvc2l0TnVtTGFzdAQAAAALcmV3YXJkVG90YWwIBQAAAA0kdDAxMjAwNTEyMTQzAAAAAl8xBAAA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QnlBc3NldFJlc3VsdAAAAAAAAAAAAQAAAAkAAAABaQEAAAALY29uc3RydWN0b3IAAAAFAAAAF25ldXRyaW5vQ29udHJhY3RBZGRyZXNzAAAAE21hdGhDb250cmFjdEFkZHJlc3MAAAANbWluTG9ja0Ftb3VudAAAAAhoYWxmTGlmZQAAABVzdXBwb3J0ZWRSZXdhcmRBc3NldHMDCQEAAAACIT0AAAACCAUAAAABaQAAAAZjYWxsZXIFAAAABHRoaXMJAAACAAAAAQIAAAARUGVybWlzc2lvbiBkZW5pZWQJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAGmtleU5ldXRyaW5vQ29udHJhY3RBZGRyZXNzAAAAAAUAAAAXbmV1dHJpbm9Db250cmFjdEFkZHJlc3MJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgkBAAAAFmtleU1hdGhDb250cmFjdEFkZHJlc3MAAAAABQAAABNtYXRoQ29udHJhY3RBZGRyZXNzCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACCQEAAAAQa2V5TWluTG9ja0Ftb3VudAAAAAAFAAAADW1pbkxvY2tBbW91bnQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIJAQAAAAtrZXlIYWxmTGlmZQAAAAAFAAAACGhhbGZMaWZlCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABhrZXlTdXBwb3J0ZWRSZXdhcmRBc3NldHMAAAAABQAAABVzdXBwb3J0ZWRSZXdhcmRBc3NldHMFAAAAA25pbAAAAAFpAQAAAAVzdGFrZQAAAAAEAAAADSR0MDEzNjM4MTM3MDAJAQAAAA9nZXRQYXJhbXNPckZhaWwAAAAABAAAAAtib25kQXNzZXRJZAgFAAAADSR0MDEzNjM4MTM3MDAAAAACXzEEAAAADW1pbkxvY2tBbW91bnQIBQAAAA0kdDAxMzYzODEzNzAwAAAAAl8yBAAAAAhoYWxmTGlmZQgFAAAADSR0MDEzNjM4MTM3MDAAAAACXzMDCQEAAAACIT0AAAACCQABkAAAAAEIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAABCQAAAgAAAAECAAAAFUludmFsaWQgcGF5bWVudHMgc2l6ZQQAAAAHcGF5bWVudAkAAZEAAAACCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAQAAAAGYW1vdW50CAUAAAAHcGF5bWVudAAAAAZhbW91bnQEAAAAE2ludmFsaWRBc3NldE1lc3NhZ2UJAAEsAAAAAgkAASwAAAACAgAAAA9JbnZhbGlkIGFzc2V0LiAJAAJYAAAAAQUAAAALYm9uZEFzc2V0SWQCAAAADCBpcyBleHBlY3RlZAQAAAAHYXNzZXRJZAkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCAUAAAAHcGF5bWVudAAAAAdhc3NldElkBQAAABNpbnZhbGlkQXNzZXRNZXNzYWdlAwkBAAAAAiE9AAAAAgUAAAAHYXNzZXRJZAUAAAALYm9uZEFzc2V0SWQJAAACAAAAAQUAAAATaW52YWxpZEFzc2V0TWVzc2FnZQQAAAALdXNlckFkZHJlc3MIBQAAAAFpAAAABmNhbGxlcgQAAAAOdXNlckFkZHJlc3NTdHIJAAQlAAAAAQgFAAAAAWkAAAAGY2FsbGVyBAAAAA0kdDAxNDI0MjE0MzQ5CQEAAAALdmFsdWVPckVsc2UAAAACCQEAAAATZ2V0VXNlclBhcmFtc09yVW5pdAAAAAEFAAAAC3VzZXJBZGRyZXNzCQAFFQAAAAMGAAAAAAAAAAAAAP//////////BAAAAAlpc05ld1VzZXIIBQAAAA0kdDAxNDI0MjE0MzQ5AAAAAl8xBAAAAApsb2NrQW1vdW50CAUAAAANJHQwMTQyNDIxNDM0OQAAAAJfMgQAAAAPbG9ja1N0YXJ0SGVpZ2h0CAUAAAANJHQwMTQyNDIxNDM0OQAAAAJfMwQAAAAMbWVyZ2VkQW1vdW50AwUAAAAJaXNOZXdVc2VyBQAAAAZhbW91bnQJAABkAAAAAgUAAAAGYW1vdW50BQAAAApsb2NrQW1vdW50BAAAABFtZXJnZWRTdGFydEhlaWdodAMFAAAACWlzTmV3VXNlcgUAAAAGaGVpZ2h0CQEAAAAFYXNJbnQAAAABCQAD/AAAAAQFAAAADG1hdGhDb250cmFjdAIAAAATbWVyZ2VTdGFrZXNSRUFET05MWQkABEwAAAACBQAAAAZhbW91bnQJAARMAAAAAgUAAAAGaGVpZ2h0CQAETAAAAAIFAAAACmxvY2tBbW91bnQJAARMAAAAAgUAAAAPbG9ja1N0YXJ0SGVpZ2h0CQAETAAAAAIFAAAACGhhbGZMaWZlBQAAAANuaWwFAAAAA25pbAMJAABmAAAAAgUAAAANbWluTG9ja0Ftb3VudAUAAAAMbWVyZ2VkQW1vdW50CQAAAgAAAAEJAAEsAAAAAgIAAAATTWluIGxvY2sgYW1vdW50IGlzIAkAAaQAAAABBQAAAA1taW5Mb2NrQW1vdW50BAAAAA0kdDAxNDcxMDE0ODEyCQEAAAALU3RhdHNSZXN1bHQAAAADBQAAAAZhbW91bnQAAAAAAAAAAAEDBQAAAAlpc05ld1VzZXIAAAAAAAAAAAEAAAAAAAAAAAAEAAAADHN0YXRzRW50cmllcwgFAAAADSR0MDE0NzEwMTQ4MTIAAAACXzEEAAAAC3RvdGFsU3Rha2VkCAUAAAANJHQwMTQ3MTAxNDgxMgAAAAJfMgQAAAAOdG90YWxTdGFrZWROZXcIBQAAAA0kdDAxNDcxMDE0ODEyAAAAAl8zCQAETgAAAAIJAAROAAAAAgkABE4AAAACCQAETAAAAAIJAQAAABJIaXN0b3J5UmVjb3JkRW50cnkAAAAHAgAAAAVzdGFrZQUAAAALdXNlckFkZHJlc3MIBQAAAAFpAAAADXRyYW5zYWN0aW9uSWQFAAAACmxvY2tBbW91bnQFAAAAD2xvY2tTdGFydEhlaWdodAUAAAAMbWVyZ2VkQW1vdW50BQAAABFtZXJnZWRTdGFydEhlaWdodAUAAAADbmlsCQEAAAANUmV3YXJkRW50cmllcwAAAAMFAAAACWlzTmV3VXNlcgUAAAAOdXNlckFkZHJlc3NTdHIFAAAACmxvY2tBbW91bnQJAQAAAA9Mb2NrUGFyYW1zRW50cnkAAAADBQAAAAt1c2VyQWRkcmVzcwUAAAAMbWVyZ2VkQW1vdW50BQAAABFtZXJnZWRTdGFydEhlaWdodAUAAAAMc3RhdHNFbnRyaWVzAAAAAWkBAAAAB3Vuc3Rha2UAAAABAAAABmFtb3VudAMJAQAAAAIhPQAAAAIJAAGQAAAAAQgFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAAJAAACAAAAAQIAAAAjdW5zdGFrZSBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnQEAAAAC3VzZXJBZGRyZXNzCAUAAAABaQAAAAZjYWxsZXIEAAAADnVzZXJBZGRyZXNzU3RyCQAEJQAAAAEFAAAAC3VzZXJBZGRyZXNzBAAAAA0kdDAxNTI5ODE1MzYwCQEAAAAPZ2V0UGFyYW1zT3JGYWlsAAAAAAQAAAALYm9uZEFzc2V0SWQIBQAAAA0kdDAxNTI5ODE1MzYwAAAAAl8xBAAAAA1taW5Mb2NrQW1vdW50CAUAAAANJHQwMTUyOTgxNTM2MAAAAAJfMgQAAAAIaGFsZkxpZmUIBQAAAA0kdDAxNTI5ODE1MzYwAAAAAl8zBAAAAA0kdDAxNTM2MzE1NDM3CQEAAAATZ2V0VXNlclBhcmFtc09yRmFpbAAAAAEFAAAAC3VzZXJBZGRyZXNzBAAAAAlpc05ld1VzZXIIBQAAAA0kdDAxNTM2MzE1NDM3AAAAAl8xBAAAAApsb2NrQW1vdW50CAUAAAANJHQwMTUzNjMxNTQzNwAAAAJfMgQAAAAJbG9ja1N0YXJ0CAUAAAANJHQwMTUzNjMxNTQzNwAAAAJfMwMJAABnAAAAAgAAAAAAAAAAAAUAAAAKbG9ja0Ftb3VudAkAAAIAAAABAgAAABJOb3RoaW5nIHRvIHVuc3Rha2UDCQAAZgAAAAIFAAAABmFtb3VudAUAAAAKbG9ja0Ftb3VudAkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgkAASwAAAACAgAAAApSZXF1ZXN0ZWQgCQABpAAAAAEFAAAABmFtb3VudAIAAAASLCBidXQgc3Rha2VkIG9ubHkgCQABpAAAAAEFAAAACmxvY2tBbW91bnQEAAAAD2NvbWlzc2lvbkFtb3VudAkBAAAABWFzSW50AAAAAQkAA/wAAAAEBQAAAAxtYXRoQ29udHJhY3QCAAAAIWdldFVuc3Rha2VDb21pc3Npb25BbW91bnRSRUFET05MWQkABEwAAAACBQAAAAZhbW91bnQJAARMAAAAAgUAAAAJbG9ja1N0YXJ0CQAETAAAAAIFAAAACGhhbGZMaWZlBQAAAANuaWwFAAAAA25pbAQAAAANJHQwMTU3NTExNTkwNQkBAAAAC1N0YXRzUmVzdWx0AAAAAwkBAAAAAS0AAAABBQAAAAZhbW91bnQDCQAAAAAAAAIFAAAABmFtb3VudAUAAAAKbG9ja0Ftb3VudAD//////////wAAAAAAAAAAAAMJAAAAAAAAAgUAAAAGYW1vdW50BQAAAApsb2NrQW1vdW50AP//////////AAAAAAAAAAAABAAAAAxzdGF0c0VudHJpZXMIBQAAAA0kdDAxNTc1MTE1OTA1AAAAAl8xBAAAAAt0b3RhbFN0YWtlZAgFAAAADSR0MDE1NzUxMTU5MDUAAAACXzIEAAAADnRvdGFsU3Rha2VkTmV3CAUAAAANJHQwMTU3NTExNTkwNQAAAAJfMwkABE4AAAACCQAETgAAAAIJAAROAAAAAgkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAAAt1c2VyQWRkcmVzcwkAAGUAAAACBQAAAAZhbW91bnQFAAAAD2NvbWlzc2lvbkFtb3VudAUAAAALYm9uZEFzc2V0SWQJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAAPYXVjdGlvbkNvbnRyYWN0BQAAAA9jb21pc3Npb25BbW91bnQFAAAAC2JvbmRBc3NldElkCQAETAAAAAIJAQAAABJIaXN0b3J5UmVjb3JkRW50cnkAAAAHAgAAAAd1bnN0YWtlBQAAAAt1c2VyQWRkcmVzcwgFAAAAAWkAAAANdHJhbnNhY3Rpb25JZAUAAAAKbG9ja0Ftb3VudAUAAAAJbG9ja1N0YXJ0CQAAZQAAAAIFAAAACmxvY2tBbW91bnQFAAAABmFtb3VudAUAAAAJbG9ja1N0YXJ0BQAAAANuaWwJAQAAAA1SZXdhcmRFbnRyaWVzAAAAAwcFAAAADnVzZXJBZGRyZXNzU3RyBQAAAApsb2NrQW1vdW50CQEAAAAPTG9ja1BhcmFtc0VudHJ5AAAAAwUAAAALdXNlckFkZHJlc3MJAABlAAAAAgUAAAAKbG9ja0Ftb3VudAUAAAAGYW1vdW50BQAAAAlsb2NrU3RhcnQFAAAADHN0YXRzRW50cmllcwAAAAFpAQAAAAdkZXBvc2l0AAAAAAMJAQAAAAIhPQAAAAIJAAGQAAAAAQgFAAAAAWkAAAAIcGF5bWVudHMAAAAAAAAAAAEJAAACAAAAAQIAAAAfZXhhY3QgMSBwYXltZW50IGlzIGFsbG93ZWQgb25seQQAAAADcG10CQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAABAAAAAZhbW91bnQIBQAAAANwbXQAAAAGYW1vdW50BAAAAApwbXRBc3NldElkCQEAAAALdmFsdWVPckVsc2UAAAACCAUAAAADcG10AAAAB2Fzc2V0SWQFAAAAB1dBVkVTSUQEAAAADXBtdEFzc2V0SWRTdHIJAAJYAAAAAQUAAAAKcG10QXNzZXRJZAQAAAAIcG10TXVsdFgDCQAAAAAAAAIFAAAACnBtdEFzc2V0SWQFAAAAB1dBVkVTSUQFAAAABk1VTFRYOAUAAAAGTVVMVFg2BAAAAAdhbW91bnRYCQABNgAAAAEFAAAABmFtb3VudAQAAAALdG90YWxTdGFrZWQJAQAAAAxnZXRJbnRPckVsc2UAAAACCQEAAAAXa2V5TG9ja1BhcmFtVG90YWxBbW91bnQAAAAAAAAAAAAAAAAABAAAAAx0b3RhbFN0YWtlZFgJAAE2AAAAAQUAAAALdG90YWxTdGFrZWQDCQAAZgAAAAIAAAAAAAAAAAAFAAAAC3RvdGFsU3Rha2VkCQAAAgAAAAECAAAAG1RPRE86IGNhc2UgaXMgbm90IHN1cHBvcnRlZAMJAAAAAAAAAgUAAAALdG90YWxTdGFrZWQAAAAAAAAAAAAJAQAAACJJbmNyZW1lbnROb3REaXN0cmlidXRlZFJld2FyZEVudHJ5AAAAAgUAAAANcG10QXNzZXRJZFN0cgUAAAAGYW1vdW50BAAAABByZXdhcmRQZXJOc2J0WDE4CQABPAAAAAMFAAAAB2Ftb3VudFgFAAAAB01VTFRYMTgFAAAADHRvdGFsU3Rha2VkWAQAAAARZGVwb3NpdE51bUxhc3RLRVkJAQAAABFrZXlEZXBvc2l0TnVtTGFzdAAAAAAEAAAADmRlcG9zaXROdW1MYXN0CQEAAAAMZ2V0SW50T3JFbHNlAAAAAgUAAAARZGVwb3NpdE51bUxhc3RLRVkA//////////8EAAAADWRlcG9zaXROdW1OZXcJAABkAAAAAgUAAAAOZGVwb3NpdE51bUxhc3QAAAAAAAAAAAEDCQEAAAABIQAAAAEJAQAAAAhjb250YWlucwAAAAIFAAAAEnN1cHBvcnRlZEFzc2V0c1N0cgUAAAANcG10QXNzZXRJZFN0cgkAAAIAAAABCQABLAAAAAIJAAEsAAAAAgUAAAASc3VwcG9y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bAQAAAALdXNlckFkZHJlc3MJAQAAAA90b0FkZHJlc3NPckZhaWwAAAABBQAAAA51c2VyQWRkcmVzc1N0cgQAAAANJHQwMjA4NDkyMDk1MwkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkBAAAAE2dldFVzZXJQYXJhbXNPclVuaXQAAAABBQAAAAt1c2VyQWRkcmVzcwkABRUAAAADBgAAAAAAAAAAAAAAAAAAAAAAAAQAAAAJaXNOZXdVc2VyCAUAAAANJHQwMjA4NDkyMDk1MwAAAAJfMQQAAAALdXNlck5zYnRBbXQIBQAAAA0kdDAyMDg0OTIwOTUzAAAAAl8yBAAAAAxzdGFraW5nU3RhcnQIBQAAAA0kdDAyMDg0OTIwOTUzAAAAAl8zCQAFFAAAAAIFAAAAA25pbAkABEwAAAACBQAAAAt1c2VyTnNidEFtdAkABEwAAAACBQAAAAx0b3RhbE5zYnRBbXQJAARMAAAAAgUAAAAMc3Rha2luZ1N0YXJ0BQAAAANuaWwAAAABAAAAAnR4AQAAAAZ2ZXJpZnkAAAAABAAAABNwdWJLZXlBZG1pbnNMaXN0U3RyCQAEuQAAAAIJAARMAAAAAgIAAAAsR0pkTFNhTGl2NUs3eHVlamFjOG1jUmNIb3lvM2RQckVTcnZrdEczYTZNQVIJAARMAAAAAgIAAAAsRVl3Wm1VUmQ1S0thUVJCanNWYTZnOERQaXNGb1M2U292Ukp0RmlMNWdNSFUJAARMAAAAAgIAAAAsRHRtQWZ1RGRDckhLOHNwZEFlQVl6cTZNc1plZ2VEOWduc3JwdVRSa0NiVkEJAARMAAAAAgIAAAAsNVdSWEZTandjVGJOZktjSnM4WnFYbVNTV1lzU1ZKVXRNdk1xWmo1aEg0TmMFAAAAA25pbAUAAAADU0VQBAAAABBwdWJLZXlBZG1pbnNMaXN0CQAEtQAAAAIJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQdAAAAAgUAAAAPY29udHJvbENvbnRyYWN0AgAAAAwlc19fbXVsdGlzaWcFAAAAE3B1YktleUFkbWluc0xpc3RTdHIFAAAAA1NFUAQAAAAFY291bnQJAABkAAAAAgkAAGQAAAACCQAAZAAAAAIDCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAAkAAlkAAAABCQABkQAAAAIFAAAAEHB1YktleUFkbWluc0xpc3QAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAADCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAQkAAlkAAAABCQABkQAAAAIFAAAAEHB1YktleUFkbWluc0xpc3QAAAAAAAAAAAEAAAAAAAAAAAEAAAAAAAAAAAADCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAgkAAlkAAAABCQABkQAAAAIFAAAAEHB1YktleUFkbWluc0xpc3QAAAAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAADCQAB9AAAAAMIBQAAAAJ0eAAAAAlib2R5Qnl0ZXMJAAGRAAAAAggFAAAAAnR4AAAABnByb29mcwAAAAAAAAAAAwkAAlkAAAABCQABkQAAAAIFAAAAEHB1YktleUFkbWluc0xpc3QAAAAAAAAAAAMAAAAAAAAAAAIAAAAAAAAAAAAJAABnAAAAAgUAAAAFY291bnQAAAAAAAAAAAM0bKA6", "chainId": 87, "height": 3240724, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 7NDg2qJaEmtDnrgaqnPDCZd9D97yrsXjbkeT1jhpUbDr Next: G4ZV5HPmVK7hK96j9CKhNKREiKJVQ3oRkVAhxAs6q2tV Diff:
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | - | let revisionNum = " | |
4 | + | let revisionNum = "cbd0bdc8bbba91db64066b16a84913a4c965e23e" | |
5 | 5 | ||
6 | 6 | let separator = "__" | |
7 | 7 | ||
21 | 21 | ||
22 | 22 | let WAVESID = fromBase58String(WAVESIDSTR) | |
23 | 23 | ||
24 | - | func keyBondAsset () = "bond_asset_id" | |
24 | + | let IdxControlCfgNeutrinoDapp = 1 | |
25 | + | ||
26 | + | let IdxControlCfgAuctionDapp = 2 | |
27 | + | ||
28 | + | let IdxControlCfgRpdDapp = 3 | |
29 | + | ||
30 | + | let IdxControlCfgMathDapp = 4 | |
31 | + | ||
32 | + | let IdxControlCfgLiquidationDapp = 5 | |
33 | + | ||
34 | + | let IdxControlCfgRestDapp = 6 | |
35 | + | ||
36 | + | let IdxControlCfgNodeRegistryDapp = 7 | |
37 | + | ||
38 | + | let IdxControlCfgNsbtStakingDapp = 8 | |
39 | + | ||
40 | + | let IdxControlCfgMediatorDapp = 9 | |
41 | + | ||
42 | + | func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined")) | |
25 | 43 | ||
26 | 44 | ||
27 | - | func keyAuctionContractAddress () = "auction_contract" | |
45 | + | func keyControlAddress () = "%s%s__config__controlAddress" | |
46 | + | ||
47 | + | ||
48 | + | func keyControlCfg () = "%s__controlConfig" | |
49 | + | ||
50 | + | ||
51 | + | func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP) | |
52 | + | ||
53 | + | ||
54 | + | func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx))) | |
55 | + | ||
56 | + | ||
57 | + | let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP")) | |
58 | + | ||
59 | + | let controlCfg = readControlCfgOrFail(controlContract) | |
60 | + | ||
61 | + | let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp) | |
62 | + | ||
63 | + | let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp) | |
64 | + | ||
65 | + | let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp) | |
66 | + | ||
67 | + | func keyBondAsset () = "bond_asset_id" | |
28 | 68 | ||
29 | 69 | ||
30 | 70 | func keyNeutrinoContractAddress () = "%s__neutrinoContractAddress" | |
96 | 136 | func getStrOrElse (key,defaultVal) = valueOrElse(getString(this, key), defaultVal) | |
97 | 137 | ||
98 | 138 | ||
99 | - | func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), (("Mandatory this." + key) + " is not defined")) | |
100 | - | ||
101 | - | ||
102 | 139 | func toAddressOrFail (addressStr) = valueOrErrorMessage(addressFromString(addressStr), ("couldn't parse passed addressStr=" + addressStr)) | |
103 | 140 | ||
104 | 141 | ||
139 | 176 | func LockParamsEntry (userAddress,amount,start) = [IntegerEntry(keyLockParamUserAmount(userAddress), amount), IntegerEntry(keyLockParamStartBlock(userAddress), start)] | |
140 | 177 | ||
141 | 178 | ||
142 | - | func getParamsOrFail () = { | |
143 | - | let neutrinoContract = addressFromStringValue(getStringOrFail(keyNeutrinoContractAddress())) | |
144 | - | $Tuple4(fromBase58String(getStringValue(neutrinoContract, keyAuctionContractAddress())), fromBase58String(getStringValue(neutrinoContract, keyBondAsset())), getIntOrFail(keyMinLockAmount()), getIntOrFail(keyHalfLife())) | |
145 | - | } | |
179 | + | func getParamsOrFail () = $Tuple3(fromBase58String(getStringValue(neutrinoContract, keyBondAsset())), getIntOrFail(keyMinLockAmount()), getIntOrFail(keyHalfLife())) | |
146 | 180 | ||
147 | 181 | ||
148 | 182 | func isActiveUser (userAddress) = (getIntOrElse(keyLockParamUserAmount(userAddress), 0) > 0) | |
177 | 211 | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
178 | 212 | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
179 | 213 | func forEachAssetCacheUserReward (accum,asset) = { | |
180 | - | let $ | |
181 | - | let rewardTotal = $ | |
182 | - | let cached = $ | |
183 | - | let dynamic = $ | |
184 | - | let rewardCachedPartKEY = $ | |
214 | + | let $t084508585 = calcReward(userAddress, asset, stakedAmountX, depositNumUser, depositNumLast) | |
215 | + | let rewardTotal = $t084508585._1 | |
216 | + | let cached = $t084508585._2 | |
217 | + | let dynamic = $t084508585._3 | |
218 | + | let rewardCachedPartKEY = $t084508585._4 | |
185 | 219 | (accum :+ IntegerEntry(rewardCachedPartKEY, rewardTotal)) | |
186 | 220 | } | |
187 | 221 | ||
194 | 228 | else false) | |
195 | 229 | then throw("invalid depositNumLast and depositNumUser state") | |
196 | 230 | else if (if ((depositNumLast > -1)) | |
197 | - | then (depositNumUser | |
231 | + | then (depositNumUser >= -1) | |
198 | 232 | else false) | |
199 | 233 | then if (isNewUser) | |
200 | 234 | then [IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)] | |
212 | 246 | ||
213 | 247 | $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) | |
214 | 248 | } :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) | |
215 | - | else if (if ((depositNumLast > -1)) | |
216 | - | then (depositNumUser > -1) | |
217 | - | else false) | |
218 | - | then if (isNewUser) | |
219 | - | then [IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)] | |
220 | - | else ({ | |
221 | - | let $l = supportedAssetsList | |
222 | - | let $s = size($l) | |
223 | - | let $acc0 = nil | |
224 | - | func $f0_1 ($a,$i) = if (($i >= $s)) | |
225 | - | then $a | |
226 | - | else forEachAssetCacheUserReward($a, $l[$i]) | |
227 | - | ||
228 | - | func $f0_2 ($a,$i) = if (($i >= $s)) | |
229 | - | then $a | |
230 | - | else throw("List size exceeds 10") | |
231 | - | ||
232 | - | $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) | |
233 | - | } :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) | |
234 | - | else throw(((("uncovered condition: depositNumLast=" + toString(depositNumLast)) + " depositNumUser=") + toString(depositNumUser))) | |
249 | + | else throw(((("uncovered condition: depositNumLast=" + toString(depositNumLast)) + " depositNumUser=") + toString(depositNumUser))) | |
235 | 250 | } | |
236 | 251 | ||
237 | 252 | ||
242 | 257 | } | |
243 | 258 | ||
244 | 259 | ||
245 | - | let ContolContractKey = "control_contract" | |
260 | + | func commonClaim (userAddress,i) = { | |
261 | + | let userAddressStr = toString(userAddress) | |
262 | + | if ((size(i.payments) > 0)) | |
263 | + | then throw("payments are not accepted") | |
264 | + | else { | |
265 | + | let $t01152911634 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
266 | + | let isNewUser = $t01152911634._1 | |
267 | + | let stakedAmount = $t01152911634._2 | |
268 | + | let stakingStart = $t01152911634._3 | |
269 | + | let stakedAmountX = toBigInt(stakedAmount) | |
270 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
271 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
272 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
273 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
274 | + | let $t01200512143 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
275 | + | let rewardTotal = $t01200512143._1 | |
276 | + | let cached = $t01200512143._2 | |
277 | + | let dynamic = $t01200512143._3 | |
278 | + | let rewardCachedPartKEY = $t01200512143._4 | |
279 | + | let claimedKEY = keyClaimed(userAddressStr, asset) | |
280 | + | let $t01220312240 = accum | |
281 | + | let data = $t01220312240._1 | |
282 | + | let claimedAmtByAsset = $t01220312240._2 | |
283 | + | let newPart = makeString([asset, toString(rewardTotal)], ":") | |
284 | + | let claimedAmtByAssetNew = makeString([claimedAmtByAsset, newPart], "_") | |
285 | + | if ((0 >= rewardTotal)) | |
286 | + | then $Tuple2(data, claimedAmtByAssetNew) | |
287 | + | else $Tuple2((((data :+ ScriptTransfer(userAddress, rewardTotal, toAssetVect(asset))) :+ IntegerEntry(claimedKEY, (valueOrElse(getInteger(claimedKEY), 0) + rewardTotal))) :+ IntegerEntry(rewardCachedPartKEY, 0)), claimedAmtByAssetNew) | |
288 | + | } | |
246 | 289 | ||
247 | - | let neutrinoContract = addressFromStringValue(getStringOrFail(keyNeutrinoContractAddress())) | |
290 | + | let $t01270012814 = { | |
291 | + | let $l = supportedAssetsList | |
292 | + | let $s = size($l) | |
293 | + | let $acc0 = $Tuple2(nil, "") | |
294 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
295 | + | then $a | |
296 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
248 | 297 | ||
249 | - | let controlContract = addressFromStringValue(getStringValue(neutrinoContract, ContolContractKey)) | |
298 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
299 | + | then $a | |
300 | + | else throw("List size exceeds 10") | |
301 | + | ||
302 | + | $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) | |
303 | + | } | |
304 | + | let transfers = $t01270012814._1 | |
305 | + | let claimedAmtByAssetResult = $t01270012814._2 | |
306 | + | if ((0 >= size(transfers))) | |
307 | + | then nil | |
308 | + | else ((transfers :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) :+ ClaimHistoryEntry(userAddress, i.transactionId, drop(claimedAmtByAssetResult, 1))) | |
309 | + | } | |
310 | + | } | |
311 | + | ||
250 | 312 | ||
251 | 313 | @Callable(i) | |
252 | 314 | func constructor (neutrinoContractAddress,mathContractAddress,minLockAmount,halfLife,supportedRewardAssets) = if ((i.caller != this)) | |
257 | 319 | ||
258 | 320 | @Callable(i) | |
259 | 321 | func stake () = { | |
260 | - | let $t01144211521 = getParamsOrFail() | |
261 | - | let auctionContract = $t01144211521._1 | |
262 | - | let bondAssetId = $t01144211521._2 | |
263 | - | let minLockAmount = $t01144211521._3 | |
264 | - | let halfLife = $t01144211521._4 | |
322 | + | let $t01363813700 = getParamsOrFail() | |
323 | + | let bondAssetId = $t01363813700._1 | |
324 | + | let minLockAmount = $t01363813700._2 | |
325 | + | let halfLife = $t01363813700._3 | |
265 | 326 | if ((size(i.payments) != 1)) | |
266 | 327 | then throw("Invalid payments size") | |
267 | 328 | else { | |
274 | 335 | else { | |
275 | 336 | let userAddress = i.caller | |
276 | 337 | let userAddressStr = toString(i.caller) | |
277 | - | let $ | |
278 | - | let isNewUser = $ | |
279 | - | let lockAmount = $ | |
280 | - | let lockStartHeight = $ | |
338 | + | let $t01424214349 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, -1)) | |
339 | + | let isNewUser = $t01424214349._1 | |
340 | + | let lockAmount = $t01424214349._2 | |
341 | + | let lockStartHeight = $t01424214349._3 | |
281 | 342 | let mergedAmount = if (isNewUser) | |
282 | 343 | then amount | |
283 | 344 | else (amount + lockAmount) | |
284 | 345 | let mergedStartHeight = if (isNewUser) | |
285 | 346 | then height | |
286 | - | else { | |
287 | - | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
288 | - | asInt(invoke(mathContract, "mergeStakesREADONLY", [amount, height, lockAmount, lockStartHeight, halfLife], nil)) | |
289 | - | } | |
347 | + | else asInt(invoke(mathContract, "mergeStakesREADONLY", [amount, height, lockAmount, lockStartHeight, halfLife], nil)) | |
290 | 348 | if ((minLockAmount > mergedAmount)) | |
291 | 349 | then throw(("Min lock amount is " + toString(minLockAmount))) | |
292 | 350 | else { | |
293 | - | let $ | |
351 | + | let $t01471014812 = StatsResult(amount, 1, if (isNewUser) | |
294 | 352 | then 1 | |
295 | 353 | else 0) | |
296 | - | let statsEntries = $ | |
297 | - | let totalStaked = $ | |
298 | - | let totalStakedNew = $ | |
354 | + | let statsEntries = $t01471014812._1 | |
355 | + | let totalStaked = $t01471014812._2 | |
356 | + | let totalStakedNew = $t01471014812._3 | |
299 | 357 | ((([HistoryRecordEntry("stake", userAddress, i.transactionId, lockAmount, lockStartHeight, mergedAmount, mergedStartHeight)] ++ RewardEntries(isNewUser, userAddressStr, lockAmount)) ++ LockParamsEntry(userAddress, mergedAmount, mergedStartHeight)) ++ statsEntries) | |
300 | 358 | } | |
301 | 359 | } | |
310 | 368 | else { | |
311 | 369 | let userAddress = i.caller | |
312 | 370 | let userAddressStr = toString(userAddress) | |
313 | - | let $t01320813286 = getParamsOrFail() | |
314 | - | let auctionAddress = $t01320813286._1 | |
315 | - | let bondAssetId = $t01320813286._2 | |
316 | - | let minLockAmount = $t01320813286._3 | |
317 | - | let halfLife = $t01320813286._4 | |
318 | - | let $t01328913363 = getUserParamsOrFail(userAddress) | |
319 | - | let isNewUser = $t01328913363._1 | |
320 | - | let lockAmount = $t01328913363._2 | |
321 | - | let lockStart = $t01328913363._3 | |
371 | + | let $t01529815360 = getParamsOrFail() | |
372 | + | let bondAssetId = $t01529815360._1 | |
373 | + | let minLockAmount = $t01529815360._2 | |
374 | + | let halfLife = $t01529815360._3 | |
375 | + | let $t01536315437 = getUserParamsOrFail(userAddress) | |
376 | + | let isNewUser = $t01536315437._1 | |
377 | + | let lockAmount = $t01536315437._2 | |
378 | + | let lockStart = $t01536315437._3 | |
322 | 379 | if ((0 >= lockAmount)) | |
323 | 380 | then throw("Nothing to unstake") | |
324 | 381 | else if ((amount > lockAmount)) | |
325 | 382 | then throw(((("Requested " + toString(amount)) + ", but staked only ") + toString(lockAmount))) | |
326 | 383 | else { | |
327 | - | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
328 | 384 | let comissionAmount = asInt(invoke(mathContract, "getUnstakeComissionAmountREADONLY", [amount, lockStart, halfLife], nil)) | |
329 | - | let $ | |
385 | + | let $t01575115905 = StatsResult(-(amount), if ((amount == lockAmount)) | |
330 | 386 | then -1 | |
331 | 387 | else 0, if ((amount == lockAmount)) | |
332 | 388 | then -1 | |
333 | 389 | else 0) | |
334 | - | let statsEntries = $ | |
335 | - | let totalStaked = $ | |
336 | - | let totalStakedNew = $ | |
337 | - | ((([ScriptTransfer(userAddress, (amount - comissionAmount), bondAssetId), ScriptTransfer( | |
390 | + | let statsEntries = $t01575115905._1 | |
391 | + | let totalStaked = $t01575115905._2 | |
392 | + | let totalStakedNew = $t01575115905._3 | |
393 | + | ((([ScriptTransfer(userAddress, (amount - comissionAmount), bondAssetId), ScriptTransfer(auctionContract, comissionAmount, bondAssetId), HistoryRecordEntry("unstake", userAddress, i.transactionId, lockAmount, lockStart, (lockAmount - amount), lockStart)] ++ RewardEntries(false, userAddressStr, lockAmount)) ++ LockParamsEntry(userAddress, (lockAmount - amount), lockStart)) ++ statsEntries) | |
338 | 394 | } | |
339 | 395 | } | |
340 | 396 | ||
395 | 451 | ||
396 | 452 | ||
397 | 453 | @Callable(i) | |
398 | - | func claimRewards () = { | |
399 | - | let userAddress = i.caller | |
400 | - | let userAddressStr = toString(userAddress) | |
401 | - | if ((size(i.payments) > 0)) | |
402 | - | then throw("payments are not accepted") | |
403 | - | else { | |
404 | - | let $t01617416279 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
405 | - | let isNewUser = $t01617416279._1 | |
406 | - | let stakedAmount = $t01617416279._2 | |
407 | - | let stakingStart = $t01617416279._3 | |
408 | - | let stakedAmountX = toBigInt(stakedAmount) | |
409 | - | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
410 | - | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
411 | - | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
412 | - | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
413 | - | let $t01665016788 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
414 | - | let rewardTotal = $t01665016788._1 | |
415 | - | let cached = $t01665016788._2 | |
416 | - | let dynamic = $t01665016788._3 | |
417 | - | let rewardCachedPartKEY = $t01665016788._4 | |
418 | - | let claimedKEY = keyClaimed(userAddressStr, asset) | |
419 | - | let $t01684816885 = accum | |
420 | - | let data = $t01684816885._1 | |
421 | - | let claimedAmtByAsset = $t01684816885._2 | |
422 | - | let newPart = makeString([asset, toString(rewardTotal)], ":") | |
423 | - | let claimedAmtByAssetNew = makeString([claimedAmtByAsset, newPart], "_") | |
424 | - | if ((0 >= rewardTotal)) | |
425 | - | then $Tuple2(data, claimedAmtByAssetNew) | |
426 | - | else $Tuple2((((data :+ ScriptTransfer(userAddress, rewardTotal, toAssetVect(asset))) :+ IntegerEntry(claimedKEY, (valueOrElse(getInteger(claimedKEY), 0) + rewardTotal))) :+ IntegerEntry(rewardCachedPartKEY, 0)), claimedAmtByAssetNew) | |
427 | - | } | |
454 | + | func claimRewards () = commonClaim(i.caller, i) | |
428 | 455 | ||
429 | - | let $t01734517459 = { | |
430 | - | let $l = supportedAssetsList | |
431 | - | let $s = size($l) | |
432 | - | let $acc0 = $Tuple2(nil, "") | |
433 | - | func $f0_1 ($a,$i) = if (($i >= $s)) | |
434 | - | then $a | |
435 | - | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
436 | 456 | ||
437 | - | func $f0_2 ($a,$i) = if (($i >= $s)) | |
438 | - | then $a | |
439 | - | else throw("List size exceeds 10") | |
440 | 457 | ||
441 | - | $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) | |
442 | - | } | |
443 | - | let transfers = $t01734517459._1 | |
444 | - | let claimedAmtByAssetResult = $t01734517459._2 | |
445 | - | if ((0 >= size(transfers))) | |
446 | - | then throw("nothing to claim") | |
447 | - | else ((transfers :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) :+ ClaimHistoryEntry(userAddress, i.transactionId, drop(claimedAmtByAssetResult, 1))) | |
448 | - | } | |
449 | - | } | |
458 | + | @Callable(i) | |
459 | + | func claimRewardsByOriginCaller () = commonClaim(i.originCaller, i) | |
450 | 460 | ||
451 | 461 | ||
452 | 462 | ||
471 | 481 | } | |
472 | 482 | else { | |
473 | 483 | let userAddress = addressFromStringValue(userAddressStr) | |
474 | - | let $ | |
475 | - | let isNewUser = $ | |
476 | - | let stakedAmount = $ | |
477 | - | let stakingStart = $ | |
484 | + | let $t01858118686 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
485 | + | let isNewUser = $t01858118686._1 | |
486 | + | let stakedAmount = $t01858118686._2 | |
487 | + | let stakingStart = $t01858118686._3 | |
478 | 488 | let stakedAmountX = toBigInt(stakedAmount) | |
479 | 489 | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
480 | 490 | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
481 | 491 | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
482 | 492 | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
483 | - | let $ | |
484 | - | let rewardTotal = $ | |
485 | - | let cached = $ | |
486 | - | let dynamic = $ | |
487 | - | let rewardCachedPartKEY = $ | |
493 | + | let $t01903219170 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
494 | + | let rewardTotal = $t01903219170._1 | |
495 | + | let cached = $t01903219170._2 | |
496 | + | let dynamic = $t01903219170._3 | |
497 | + | let rewardCachedPartKEY = $t01903219170._4 | |
488 | 498 | let claimed = valueOrElse(getInteger(keyClaimed(userAddressStr, asset)), 0) | |
489 | 499 | ((accum + makeString([asset, toString(rewardTotal), toString(claimed)], ":")) + "_") | |
490 | 500 | } | |
508 | 518 | ||
509 | 519 | ||
510 | 520 | @Callable(i) | |
511 | - | func nsbtStakingSYSREADONLY (userAddressStr) = { | |
521 | + | func nsbtUnstakingSYSREADONLY (userAddressStrOrEmpty,unstakeAmtP) = { | |
522 | + | let resultArray = if ((userAddressStrOrEmpty == "")) | |
523 | + | then [0, 0, 0, 0] | |
524 | + | else { | |
525 | + | let userAddress = addressFromStringValue(userAddressStrOrEmpty) | |
526 | + | let cfgDATA = getParamsOrFail() | |
527 | + | let nsbtAssetId = cfgDATA._1 | |
528 | + | let minLockAmount = cfgDATA._2 | |
529 | + | let halfLife = cfgDATA._3 | |
530 | + | let userDATA = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
531 | + | let isNewUser = userDATA._1 | |
532 | + | let stakedAmount = userDATA._2 | |
533 | + | let lockStart = userDATA._3 | |
534 | + | let unstakeAmt = if ((unstakeAmtP > stakedAmount)) | |
535 | + | then stakedAmount | |
536 | + | else unstakeAmtP | |
537 | + | let stakedAmountNEW = (stakedAmount - unstakeAmt) | |
538 | + | let comissionAmount = if ((unstakeAmt == 0)) | |
539 | + | then 0 | |
540 | + | else asInt(invoke(mathContract, "getUnstakeComissionAmountREADONLY", [unstakeAmt, lockStart, halfLife], nil)) | |
541 | + | let receiveAmount = (unstakeAmt - comissionAmount) | |
542 | + | [stakedAmount, stakedAmountNEW, receiveAmount, comissionAmount] | |
543 | + | } | |
544 | + | $Tuple2(nil, resultArray) | |
545 | + | } | |
546 | + | ||
547 | + | ||
548 | + | ||
549 | + | @Callable(i) | |
550 | + | func nsbtStakingSYSREADONLY (userAddressStr,nsbtDiff) = { | |
512 | 551 | let totalNsbtAmt = getIntOrElse(keyLockParamTotalAmount(), 0) | |
513 | 552 | if ((userAddressStr == "")) | |
514 | 553 | then $Tuple2(nil, [0, totalNsbtAmt, 0]) | |
515 | 554 | else { | |
516 | 555 | let userAddress = toAddressOrFail(userAddressStr) | |
517 | - | let $ | |
518 | - | let isNewUser = $ | |
519 | - | let userNsbtAmt = $ | |
520 | - | let stakingStart = $ | |
556 | + | let $t02084920953 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
557 | + | let isNewUser = $t02084920953._1 | |
558 | + | let userNsbtAmt = $t02084920953._2 | |
559 | + | let stakingStart = $t02084920953._3 | |
521 | 560 | $Tuple2(nil, [userNsbtAmt, totalNsbtAmt, stakingStart]) | |
522 | 561 | } | |
523 | 562 | } |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 5 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | - | let revisionNum = " | |
4 | + | let revisionNum = "cbd0bdc8bbba91db64066b16a84913a4c965e23e" | |
5 | 5 | ||
6 | 6 | let separator = "__" | |
7 | 7 | ||
8 | 8 | let SEP = "__" | |
9 | 9 | ||
10 | 10 | let MULT6 = 1000000 | |
11 | 11 | ||
12 | 12 | let MULT8 = 100000000 | |
13 | 13 | ||
14 | 14 | let MULTX6 = toBigInt(MULT6) | |
15 | 15 | ||
16 | 16 | let MULTX8 = toBigInt(MULT8) | |
17 | 17 | ||
18 | 18 | let MULTX18 = toBigInt(1000000000000000000) | |
19 | 19 | ||
20 | 20 | let WAVESIDSTR = "WAVES" | |
21 | 21 | ||
22 | 22 | let WAVESID = fromBase58String(WAVESIDSTR) | |
23 | 23 | ||
24 | - | func keyBondAsset () = "bond_asset_id" | |
24 | + | let IdxControlCfgNeutrinoDapp = 1 | |
25 | + | ||
26 | + | let IdxControlCfgAuctionDapp = 2 | |
27 | + | ||
28 | + | let IdxControlCfgRpdDapp = 3 | |
29 | + | ||
30 | + | let IdxControlCfgMathDapp = 4 | |
31 | + | ||
32 | + | let IdxControlCfgLiquidationDapp = 5 | |
33 | + | ||
34 | + | let IdxControlCfgRestDapp = 6 | |
35 | + | ||
36 | + | let IdxControlCfgNodeRegistryDapp = 7 | |
37 | + | ||
38 | + | let IdxControlCfgNsbtStakingDapp = 8 | |
39 | + | ||
40 | + | let IdxControlCfgMediatorDapp = 9 | |
41 | + | ||
42 | + | func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined")) | |
25 | 43 | ||
26 | 44 | ||
27 | - | func keyAuctionContractAddress () = "auction_contract" | |
45 | + | func keyControlAddress () = "%s%s__config__controlAddress" | |
46 | + | ||
47 | + | ||
48 | + | func keyControlCfg () = "%s__controlConfig" | |
49 | + | ||
50 | + | ||
51 | + | func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP) | |
52 | + | ||
53 | + | ||
54 | + | func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx))) | |
55 | + | ||
56 | + | ||
57 | + | let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3P5Bfd58PPfNvBM2Hy8QfbcDqMeNtzg7KfP")) | |
58 | + | ||
59 | + | let controlCfg = readControlCfgOrFail(controlContract) | |
60 | + | ||
61 | + | let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp) | |
62 | + | ||
63 | + | let neutrinoContract = getContractAddressOrFail(controlCfg, IdxControlCfgNeutrinoDapp) | |
64 | + | ||
65 | + | let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp) | |
66 | + | ||
67 | + | func keyBondAsset () = "bond_asset_id" | |
28 | 68 | ||
29 | 69 | ||
30 | 70 | func keyNeutrinoContractAddress () = "%s__neutrinoContractAddress" | |
31 | 71 | ||
32 | 72 | ||
33 | 73 | func keyMathContractAddress () = "%s__mathContract" | |
34 | 74 | ||
35 | 75 | ||
36 | 76 | func keyMinLockAmount () = "%s__minLockAmount" | |
37 | 77 | ||
38 | 78 | ||
39 | 79 | func keyHalfLife () = "%s__halfLife" | |
40 | 80 | ||
41 | 81 | ||
42 | 82 | func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", toString(userAddress), "amount"], separator) | |
43 | 83 | ||
44 | 84 | ||
45 | 85 | func keyLockParamStartBlock (userAddress) = makeString(["%s%s%s", "paramByUser", toString(userAddress), "start"], separator) | |
46 | 86 | ||
47 | 87 | ||
48 | 88 | func keyHistoryRecord (type,userAddress,txId) = makeString(["%s%s%s%s", "history", type, toString(userAddress), toBase58String(txId)], separator) | |
49 | 89 | ||
50 | 90 | ||
51 | 91 | func keyLockParamTotalAmount () = makeString(["%s%s", "stats", "activeTotalLocked"], separator) | |
52 | 92 | ||
53 | 93 | ||
54 | 94 | func keyStatsLocksCount () = makeString(["%s%s", "stats", "locksCount"], separator) | |
55 | 95 | ||
56 | 96 | ||
57 | 97 | func keyStatsUsersCount () = makeString(["%s%s", "stats", "activeUsersCount"], separator) | |
58 | 98 | ||
59 | 99 | ||
60 | 100 | func keyNextPeriod () = "%s__nextPeriod" | |
61 | 101 | ||
62 | 102 | ||
63 | 103 | func keySupportedRewardAssets () = "supportedRewardAssets" | |
64 | 104 | ||
65 | 105 | ||
66 | 106 | func keyDepositNumLast () = makeString(["%s%s%s", "dep", "lastNum"], separator) | |
67 | 107 | ||
68 | 108 | ||
69 | 109 | func keyUserRewardFromDepositNum (userAddress) = makeString(["%s%s%s", "userRwdFromDepNum", userAddress], separator) | |
70 | 110 | ||
71 | 111 | ||
72 | 112 | func keyRewardPerNsbtSumAt (depositNum,tkn) = makeString(["%s%d", "rwdPerNsbtSumByDepNum", toString(depositNum), tkn], separator) | |
73 | 113 | ||
74 | 114 | ||
75 | 115 | func keyReward (userAddress,tkn) = makeString(["%s%s%s", "rwd", userAddress, tkn], separator) | |
76 | 116 | ||
77 | 117 | ||
78 | 118 | func keyClaimed (userAddress,tkn) = makeString(["%s%s%s", "clm", userAddress, tkn], separator) | |
79 | 119 | ||
80 | 120 | ||
81 | 121 | func keyNotDistributedReward (tkn) = makeString(["%s%s", "notDistributed", tkn], separator) | |
82 | 122 | ||
83 | 123 | ||
84 | 124 | func toX18 (origVal,origMult) = fraction(toBigInt(origVal), MULTX18, origMult) | |
85 | 125 | ||
86 | 126 | ||
87 | 127 | func getIntOrZero (key) = valueOrElse(getInteger(this, key), 0) | |
88 | 128 | ||
89 | 129 | ||
90 | 130 | func getIntOrElse (key,defaultVal) = valueOrElse(getInteger(this, key), defaultVal) | |
91 | 131 | ||
92 | 132 | ||
93 | 133 | func getIntOrFail (key) = valueOrErrorMessage(getInteger(this, key), (("Mandatory this." + key) + " is not defined")) | |
94 | 134 | ||
95 | 135 | ||
96 | 136 | func getStrOrElse (key,defaultVal) = valueOrElse(getString(this, key), defaultVal) | |
97 | 137 | ||
98 | 138 | ||
99 | - | func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), (("Mandatory this." + key) + " is not defined")) | |
100 | - | ||
101 | - | ||
102 | 139 | func toAddressOrFail (addressStr) = valueOrErrorMessage(addressFromString(addressStr), ("couldn't parse passed addressStr=" + addressStr)) | |
103 | 140 | ||
104 | 141 | ||
105 | 142 | func toAssetVect (assetStr) = if ((assetStr == WAVESIDSTR)) | |
106 | 143 | then unit | |
107 | 144 | else fromBase58String(assetStr) | |
108 | 145 | ||
109 | 146 | ||
110 | 147 | func asInt (val) = match val { | |
111 | 148 | case valInt: Int => | |
112 | 149 | valInt | |
113 | 150 | case _ => | |
114 | 151 | throw("fail to cast into Int") | |
115 | 152 | } | |
116 | 153 | ||
117 | 154 | ||
118 | 155 | 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) | |
119 | 156 | ||
120 | 157 | ||
121 | 158 | func formatClaimHistoryRecord (user,claimedRewards) = makeString(["%s%d%d%s", user, toString(lastBlock.height), toString(lastBlock.timestamp), claimedRewards], separator) | |
122 | 159 | ||
123 | 160 | ||
124 | 161 | func HistoryRecordEntry (type,userAddress,txId,oldAmount,oldStart,newAmount,newStart) = StringEntry(keyHistoryRecord(type, userAddress, txId), formatHistoryRecord(oldAmount, oldStart, newAmount, newStart)) | |
125 | 162 | ||
126 | 163 | ||
127 | 164 | func ClaimHistoryEntry (userAddress,txId,claimedRewards) = StringEntry(keyHistoryRecord("claim", userAddress, txId), formatClaimHistoryRecord(toString(userAddress), claimedRewards)) | |
128 | 165 | ||
129 | 166 | ||
130 | 167 | func StatsResult (totalLockedInc,lockCountInc,usersCountInc) = { | |
131 | 168 | let locksCount = getIntOrZero(keyStatsLocksCount()) | |
132 | 169 | let usersCount = getIntOrZero(keyStatsUsersCount()) | |
133 | 170 | let totalAmount = getIntOrZero(keyLockParamTotalAmount()) | |
134 | 171 | let totalAmountNew = (totalAmount + totalLockedInc) | |
135 | 172 | $Tuple3([IntegerEntry(keyStatsLocksCount(), (locksCount + lockCountInc)), IntegerEntry(keyStatsUsersCount(), (usersCount + usersCountInc)), IntegerEntry(keyLockParamTotalAmount(), totalAmountNew)], totalAmount, totalAmountNew) | |
136 | 173 | } | |
137 | 174 | ||
138 | 175 | ||
139 | 176 | func LockParamsEntry (userAddress,amount,start) = [IntegerEntry(keyLockParamUserAmount(userAddress), amount), IntegerEntry(keyLockParamStartBlock(userAddress), start)] | |
140 | 177 | ||
141 | 178 | ||
142 | - | func getParamsOrFail () = { | |
143 | - | let neutrinoContract = addressFromStringValue(getStringOrFail(keyNeutrinoContractAddress())) | |
144 | - | $Tuple4(fromBase58String(getStringValue(neutrinoContract, keyAuctionContractAddress())), fromBase58String(getStringValue(neutrinoContract, keyBondAsset())), getIntOrFail(keyMinLockAmount()), getIntOrFail(keyHalfLife())) | |
145 | - | } | |
179 | + | func getParamsOrFail () = $Tuple3(fromBase58String(getStringValue(neutrinoContract, keyBondAsset())), getIntOrFail(keyMinLockAmount()), getIntOrFail(keyHalfLife())) | |
146 | 180 | ||
147 | 181 | ||
148 | 182 | func isActiveUser (userAddress) = (getIntOrElse(keyLockParamUserAmount(userAddress), 0) > 0) | |
149 | 183 | ||
150 | 184 | ||
151 | 185 | func getUserParamsOrUnit (userAddress) = if (isActiveUser(userAddress)) | |
152 | 186 | then $Tuple3(false, getIntOrFail(keyLockParamUserAmount(userAddress)), getIntOrFail(keyLockParamStartBlock(userAddress))) | |
153 | 187 | else unit | |
154 | 188 | ||
155 | 189 | ||
156 | 190 | func getUserParamsOrFail (userAddress) = valueOrErrorMessage(getUserParamsOrUnit(userAddress), (("User " + toString(userAddress)) + " is not defined")) | |
157 | 191 | ||
158 | 192 | ||
159 | 193 | let supportedAssetsStr = getStrOrElse(keySupportedRewardAssets(), "") | |
160 | 194 | ||
161 | 195 | let supportedAssetsList = split(supportedAssetsStr, "_") | |
162 | 196 | ||
163 | 197 | func calcReward (userAddress,assetId,stakedAmountX,depositNumUser,depositNumLast) = { | |
164 | 198 | let rewardPerNsbtSumLastKEY = keyRewardPerNsbtSumAt(depositNumLast, assetId) | |
165 | 199 | let sumLastX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, assetId), "0")) | |
166 | 200 | let sumUserX18 = parseBigIntValue(getStrOrElse(keyRewardPerNsbtSumAt(depositNumUser, assetId), "0")) | |
167 | 201 | let rewardDynamicPart = toInt(fraction((sumLastX18 - sumUserX18), stakedAmountX, MULTX18)) | |
168 | 202 | let rewardCachedPartKEY = keyReward(userAddress, assetId) | |
169 | 203 | let rewardCachedPart = getIntOrElse(rewardCachedPartKEY, 0) | |
170 | 204 | $Tuple4((rewardCachedPart + rewardDynamicPart), rewardCachedPart, rewardDynamicPart, rewardCachedPartKEY) | |
171 | 205 | } | |
172 | 206 | ||
173 | 207 | ||
174 | 208 | func RewardEntries (isNewUser,userAddress,stakedAmount) = { | |
175 | 209 | let stakedAmountX = toBigInt(stakedAmount) | |
176 | 210 | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddress) | |
177 | 211 | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
178 | 212 | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
179 | 213 | func forEachAssetCacheUserReward (accum,asset) = { | |
180 | - | let $ | |
181 | - | let rewardTotal = $ | |
182 | - | let cached = $ | |
183 | - | let dynamic = $ | |
184 | - | let rewardCachedPartKEY = $ | |
214 | + | let $t084508585 = calcReward(userAddress, asset, stakedAmountX, depositNumUser, depositNumLast) | |
215 | + | let rewardTotal = $t084508585._1 | |
216 | + | let cached = $t084508585._2 | |
217 | + | let dynamic = $t084508585._3 | |
218 | + | let rewardCachedPartKEY = $t084508585._4 | |
185 | 219 | (accum :+ IntegerEntry(rewardCachedPartKEY, rewardTotal)) | |
186 | 220 | } | |
187 | 221 | ||
188 | 222 | if (if ((depositNumLast == -1)) | |
189 | 223 | then (depositNumUser == -1) | |
190 | 224 | else false) | |
191 | 225 | then nil | |
192 | 226 | else if (if ((depositNumLast == -1)) | |
193 | 227 | then (depositNumUser > -1) | |
194 | 228 | else false) | |
195 | 229 | then throw("invalid depositNumLast and depositNumUser state") | |
196 | 230 | else if (if ((depositNumLast > -1)) | |
197 | - | then (depositNumUser | |
231 | + | then (depositNumUser >= -1) | |
198 | 232 | else false) | |
199 | 233 | then if (isNewUser) | |
200 | 234 | then [IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)] | |
201 | 235 | else ({ | |
202 | 236 | let $l = supportedAssetsList | |
203 | 237 | let $s = size($l) | |
204 | 238 | let $acc0 = nil | |
205 | 239 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
206 | 240 | then $a | |
207 | 241 | else forEachAssetCacheUserReward($a, $l[$i]) | |
208 | 242 | ||
209 | 243 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
210 | 244 | then $a | |
211 | 245 | else throw("List size exceeds 10") | |
212 | 246 | ||
213 | 247 | $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) | |
214 | 248 | } :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) | |
215 | - | else if (if ((depositNumLast > -1)) | |
216 | - | then (depositNumUser > -1) | |
217 | - | else false) | |
218 | - | then if (isNewUser) | |
219 | - | then [IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)] | |
220 | - | else ({ | |
221 | - | let $l = supportedAssetsList | |
222 | - | let $s = size($l) | |
223 | - | let $acc0 = nil | |
224 | - | func $f0_1 ($a,$i) = if (($i >= $s)) | |
225 | - | then $a | |
226 | - | else forEachAssetCacheUserReward($a, $l[$i]) | |
227 | - | ||
228 | - | func $f0_2 ($a,$i) = if (($i >= $s)) | |
229 | - | then $a | |
230 | - | else throw("List size exceeds 10") | |
231 | - | ||
232 | - | $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) | |
233 | - | } :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) | |
234 | - | else throw(((("uncovered condition: depositNumLast=" + toString(depositNumLast)) + " depositNumUser=") + toString(depositNumUser))) | |
249 | + | else throw(((("uncovered condition: depositNumLast=" + toString(depositNumLast)) + " depositNumUser=") + toString(depositNumUser))) | |
235 | 250 | } | |
236 | 251 | ||
237 | 252 | ||
238 | 253 | func IncrementNotDistributedRewardEntry (tkn,amountInc) = { | |
239 | 254 | let notDistributedRewardKEY = keyNotDistributedReward(tkn) | |
240 | 255 | let notDistributedReward = getIntOrElse(notDistributedRewardKEY, 0) | |
241 | 256 | [IntegerEntry(notDistributedRewardKEY, (notDistributedReward + amountInc))] | |
242 | 257 | } | |
243 | 258 | ||
244 | 259 | ||
245 | - | let ContolContractKey = "control_contract" | |
260 | + | func commonClaim (userAddress,i) = { | |
261 | + | let userAddressStr = toString(userAddress) | |
262 | + | if ((size(i.payments) > 0)) | |
263 | + | then throw("payments are not accepted") | |
264 | + | else { | |
265 | + | let $t01152911634 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
266 | + | let isNewUser = $t01152911634._1 | |
267 | + | let stakedAmount = $t01152911634._2 | |
268 | + | let stakingStart = $t01152911634._3 | |
269 | + | let stakedAmountX = toBigInt(stakedAmount) | |
270 | + | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
271 | + | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
272 | + | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
273 | + | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
274 | + | let $t01200512143 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
275 | + | let rewardTotal = $t01200512143._1 | |
276 | + | let cached = $t01200512143._2 | |
277 | + | let dynamic = $t01200512143._3 | |
278 | + | let rewardCachedPartKEY = $t01200512143._4 | |
279 | + | let claimedKEY = keyClaimed(userAddressStr, asset) | |
280 | + | let $t01220312240 = accum | |
281 | + | let data = $t01220312240._1 | |
282 | + | let claimedAmtByAsset = $t01220312240._2 | |
283 | + | let newPart = makeString([asset, toString(rewardTotal)], ":") | |
284 | + | let claimedAmtByAssetNew = makeString([claimedAmtByAsset, newPart], "_") | |
285 | + | if ((0 >= rewardTotal)) | |
286 | + | then $Tuple2(data, claimedAmtByAssetNew) | |
287 | + | else $Tuple2((((data :+ ScriptTransfer(userAddress, rewardTotal, toAssetVect(asset))) :+ IntegerEntry(claimedKEY, (valueOrElse(getInteger(claimedKEY), 0) + rewardTotal))) :+ IntegerEntry(rewardCachedPartKEY, 0)), claimedAmtByAssetNew) | |
288 | + | } | |
246 | 289 | ||
247 | - | let neutrinoContract = addressFromStringValue(getStringOrFail(keyNeutrinoContractAddress())) | |
290 | + | let $t01270012814 = { | |
291 | + | let $l = supportedAssetsList | |
292 | + | let $s = size($l) | |
293 | + | let $acc0 = $Tuple2(nil, "") | |
294 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
295 | + | then $a | |
296 | + | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
248 | 297 | ||
249 | - | let controlContract = addressFromStringValue(getStringValue(neutrinoContract, ContolContractKey)) | |
298 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
299 | + | then $a | |
300 | + | else throw("List size exceeds 10") | |
301 | + | ||
302 | + | $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) | |
303 | + | } | |
304 | + | let transfers = $t01270012814._1 | |
305 | + | let claimedAmtByAssetResult = $t01270012814._2 | |
306 | + | if ((0 >= size(transfers))) | |
307 | + | then nil | |
308 | + | else ((transfers :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) :+ ClaimHistoryEntry(userAddress, i.transactionId, drop(claimedAmtByAssetResult, 1))) | |
309 | + | } | |
310 | + | } | |
311 | + | ||
250 | 312 | ||
251 | 313 | @Callable(i) | |
252 | 314 | func constructor (neutrinoContractAddress,mathContractAddress,minLockAmount,halfLife,supportedRewardAssets) = if ((i.caller != this)) | |
253 | 315 | then throw("Permission denied") | |
254 | 316 | else [StringEntry(keyNeutrinoContractAddress(), neutrinoContractAddress), StringEntry(keyMathContractAddress(), mathContractAddress), IntegerEntry(keyMinLockAmount(), minLockAmount), IntegerEntry(keyHalfLife(), halfLife), StringEntry(keySupportedRewardAssets(), supportedRewardAssets)] | |
255 | 317 | ||
256 | 318 | ||
257 | 319 | ||
258 | 320 | @Callable(i) | |
259 | 321 | func stake () = { | |
260 | - | let $t01144211521 = getParamsOrFail() | |
261 | - | let auctionContract = $t01144211521._1 | |
262 | - | let bondAssetId = $t01144211521._2 | |
263 | - | let minLockAmount = $t01144211521._3 | |
264 | - | let halfLife = $t01144211521._4 | |
322 | + | let $t01363813700 = getParamsOrFail() | |
323 | + | let bondAssetId = $t01363813700._1 | |
324 | + | let minLockAmount = $t01363813700._2 | |
325 | + | let halfLife = $t01363813700._3 | |
265 | 326 | if ((size(i.payments) != 1)) | |
266 | 327 | then throw("Invalid payments size") | |
267 | 328 | else { | |
268 | 329 | let payment = i.payments[0] | |
269 | 330 | let amount = payment.amount | |
270 | 331 | let invalidAssetMessage = (("Invalid asset. " + toBase58String(bondAssetId)) + " is expected") | |
271 | 332 | let assetId = valueOrErrorMessage(payment.assetId, invalidAssetMessage) | |
272 | 333 | if ((assetId != bondAssetId)) | |
273 | 334 | then throw(invalidAssetMessage) | |
274 | 335 | else { | |
275 | 336 | let userAddress = i.caller | |
276 | 337 | let userAddressStr = toString(i.caller) | |
277 | - | let $ | |
278 | - | let isNewUser = $ | |
279 | - | let lockAmount = $ | |
280 | - | let lockStartHeight = $ | |
338 | + | let $t01424214349 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, -1)) | |
339 | + | let isNewUser = $t01424214349._1 | |
340 | + | let lockAmount = $t01424214349._2 | |
341 | + | let lockStartHeight = $t01424214349._3 | |
281 | 342 | let mergedAmount = if (isNewUser) | |
282 | 343 | then amount | |
283 | 344 | else (amount + lockAmount) | |
284 | 345 | let mergedStartHeight = if (isNewUser) | |
285 | 346 | then height | |
286 | - | else { | |
287 | - | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
288 | - | asInt(invoke(mathContract, "mergeStakesREADONLY", [amount, height, lockAmount, lockStartHeight, halfLife], nil)) | |
289 | - | } | |
347 | + | else asInt(invoke(mathContract, "mergeStakesREADONLY", [amount, height, lockAmount, lockStartHeight, halfLife], nil)) | |
290 | 348 | if ((minLockAmount > mergedAmount)) | |
291 | 349 | then throw(("Min lock amount is " + toString(minLockAmount))) | |
292 | 350 | else { | |
293 | - | let $ | |
351 | + | let $t01471014812 = StatsResult(amount, 1, if (isNewUser) | |
294 | 352 | then 1 | |
295 | 353 | else 0) | |
296 | - | let statsEntries = $ | |
297 | - | let totalStaked = $ | |
298 | - | let totalStakedNew = $ | |
354 | + | let statsEntries = $t01471014812._1 | |
355 | + | let totalStaked = $t01471014812._2 | |
356 | + | let totalStakedNew = $t01471014812._3 | |
299 | 357 | ((([HistoryRecordEntry("stake", userAddress, i.transactionId, lockAmount, lockStartHeight, mergedAmount, mergedStartHeight)] ++ RewardEntries(isNewUser, userAddressStr, lockAmount)) ++ LockParamsEntry(userAddress, mergedAmount, mergedStartHeight)) ++ statsEntries) | |
300 | 358 | } | |
301 | 359 | } | |
302 | 360 | } | |
303 | 361 | } | |
304 | 362 | ||
305 | 363 | ||
306 | 364 | ||
307 | 365 | @Callable(i) | |
308 | 366 | func unstake (amount) = if ((size(i.payments) != 0)) | |
309 | 367 | then throw("unstake doesn't require any payment") | |
310 | 368 | else { | |
311 | 369 | let userAddress = i.caller | |
312 | 370 | let userAddressStr = toString(userAddress) | |
313 | - | let $t01320813286 = getParamsOrFail() | |
314 | - | let auctionAddress = $t01320813286._1 | |
315 | - | let bondAssetId = $t01320813286._2 | |
316 | - | let minLockAmount = $t01320813286._3 | |
317 | - | let halfLife = $t01320813286._4 | |
318 | - | let $t01328913363 = getUserParamsOrFail(userAddress) | |
319 | - | let isNewUser = $t01328913363._1 | |
320 | - | let lockAmount = $t01328913363._2 | |
321 | - | let lockStart = $t01328913363._3 | |
371 | + | let $t01529815360 = getParamsOrFail() | |
372 | + | let bondAssetId = $t01529815360._1 | |
373 | + | let minLockAmount = $t01529815360._2 | |
374 | + | let halfLife = $t01529815360._3 | |
375 | + | let $t01536315437 = getUserParamsOrFail(userAddress) | |
376 | + | let isNewUser = $t01536315437._1 | |
377 | + | let lockAmount = $t01536315437._2 | |
378 | + | let lockStart = $t01536315437._3 | |
322 | 379 | if ((0 >= lockAmount)) | |
323 | 380 | then throw("Nothing to unstake") | |
324 | 381 | else if ((amount > lockAmount)) | |
325 | 382 | then throw(((("Requested " + toString(amount)) + ", but staked only ") + toString(lockAmount))) | |
326 | 383 | else { | |
327 | - | let mathContract = addressFromStringValue(getStringOrFail(keyMathContractAddress())) | |
328 | 384 | let comissionAmount = asInt(invoke(mathContract, "getUnstakeComissionAmountREADONLY", [amount, lockStart, halfLife], nil)) | |
329 | - | let $ | |
385 | + | let $t01575115905 = StatsResult(-(amount), if ((amount == lockAmount)) | |
330 | 386 | then -1 | |
331 | 387 | else 0, if ((amount == lockAmount)) | |
332 | 388 | then -1 | |
333 | 389 | else 0) | |
334 | - | let statsEntries = $ | |
335 | - | let totalStaked = $ | |
336 | - | let totalStakedNew = $ | |
337 | - | ((([ScriptTransfer(userAddress, (amount - comissionAmount), bondAssetId), ScriptTransfer( | |
390 | + | let statsEntries = $t01575115905._1 | |
391 | + | let totalStaked = $t01575115905._2 | |
392 | + | let totalStakedNew = $t01575115905._3 | |
393 | + | ((([ScriptTransfer(userAddress, (amount - comissionAmount), bondAssetId), ScriptTransfer(auctionContract, comissionAmount, bondAssetId), HistoryRecordEntry("unstake", userAddress, i.transactionId, lockAmount, lockStart, (lockAmount - amount), lockStart)] ++ RewardEntries(false, userAddressStr, lockAmount)) ++ LockParamsEntry(userAddress, (lockAmount - amount), lockStart)) ++ statsEntries) | |
338 | 394 | } | |
339 | 395 | } | |
340 | 396 | ||
341 | 397 | ||
342 | 398 | ||
343 | 399 | @Callable(i) | |
344 | 400 | func deposit () = if ((size(i.payments) != 1)) | |
345 | 401 | then throw("exact 1 payment is allowed only") | |
346 | 402 | else { | |
347 | 403 | let pmt = i.payments[0] | |
348 | 404 | let amount = pmt.amount | |
349 | 405 | let pmtAssetId = valueOrElse(pmt.assetId, WAVESID) | |
350 | 406 | let pmtAssetIdStr = toBase58String(pmtAssetId) | |
351 | 407 | let pmtMultX = if ((pmtAssetId == WAVESID)) | |
352 | 408 | then MULTX8 | |
353 | 409 | else MULTX6 | |
354 | 410 | let amountX = toBigInt(amount) | |
355 | 411 | let totalStaked = getIntOrElse(keyLockParamTotalAmount(), 0) | |
356 | 412 | let totalStakedX = toBigInt(totalStaked) | |
357 | 413 | if ((0 > totalStaked)) | |
358 | 414 | then throw("TODO: case is not supported") | |
359 | 415 | else if ((totalStaked == 0)) | |
360 | 416 | then IncrementNotDistributedRewardEntry(pmtAssetIdStr, amount) | |
361 | 417 | else { | |
362 | 418 | let rewardPerNsbtX18 = fraction(amountX, MULTX18, totalStakedX) | |
363 | 419 | let depositNumLastKEY = keyDepositNumLast() | |
364 | 420 | let depositNumLast = getIntOrElse(depositNumLastKEY, -1) | |
365 | 421 | let depositNumNew = (depositNumLast + 1) | |
366 | 422 | if (!(contains(supportedAssetsStr, pmtAssetIdStr))) | |
367 | 423 | then throw(((supportedAssetsStr + " doesn't contain ") + pmtAssetIdStr)) | |
368 | 424 | else { | |
369 | 425 | func refreshRewardPerNsbtSUM (accum,nextAsset) = { | |
370 | 426 | let rewardPerNsbtSumNewKEY = keyRewardPerNsbtSumAt(depositNumNew, nextAsset) | |
371 | 427 | let sumLastStr = getStrOrElse(keyRewardPerNsbtSumAt(depositNumLast, nextAsset), "0") | |
372 | 428 | (accum :+ (if ((nextAsset == pmtAssetIdStr)) | |
373 | 429 | then StringEntry(rewardPerNsbtSumNewKEY, toString((parseBigIntValue(sumLastStr) + rewardPerNsbtX18))) | |
374 | 430 | else StringEntry(rewardPerNsbtSumNewKEY, sumLastStr))) | |
375 | 431 | } | |
376 | 432 | ||
377 | 433 | ({ | |
378 | 434 | let $l = supportedAssetsList | |
379 | 435 | let $s = size($l) | |
380 | 436 | let $acc0 = nil | |
381 | 437 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
382 | 438 | then $a | |
383 | 439 | else refreshRewardPerNsbtSUM($a, $l[$i]) | |
384 | 440 | ||
385 | 441 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
386 | 442 | then $a | |
387 | 443 | else throw("List size exceeds 10") | |
388 | 444 | ||
389 | 445 | $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) | |
390 | 446 | } :+ IntegerEntry(depositNumLastKEY, depositNumNew)) | |
391 | 447 | } | |
392 | 448 | } | |
393 | 449 | } | |
394 | 450 | ||
395 | 451 | ||
396 | 452 | ||
397 | 453 | @Callable(i) | |
398 | - | func claimRewards () = { | |
399 | - | let userAddress = i.caller | |
400 | - | let userAddressStr = toString(userAddress) | |
401 | - | if ((size(i.payments) > 0)) | |
402 | - | then throw("payments are not accepted") | |
403 | - | else { | |
404 | - | let $t01617416279 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
405 | - | let isNewUser = $t01617416279._1 | |
406 | - | let stakedAmount = $t01617416279._2 | |
407 | - | let stakingStart = $t01617416279._3 | |
408 | - | let stakedAmountX = toBigInt(stakedAmount) | |
409 | - | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
410 | - | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
411 | - | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
412 | - | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
413 | - | let $t01665016788 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
414 | - | let rewardTotal = $t01665016788._1 | |
415 | - | let cached = $t01665016788._2 | |
416 | - | let dynamic = $t01665016788._3 | |
417 | - | let rewardCachedPartKEY = $t01665016788._4 | |
418 | - | let claimedKEY = keyClaimed(userAddressStr, asset) | |
419 | - | let $t01684816885 = accum | |
420 | - | let data = $t01684816885._1 | |
421 | - | let claimedAmtByAsset = $t01684816885._2 | |
422 | - | let newPart = makeString([asset, toString(rewardTotal)], ":") | |
423 | - | let claimedAmtByAssetNew = makeString([claimedAmtByAsset, newPart], "_") | |
424 | - | if ((0 >= rewardTotal)) | |
425 | - | then $Tuple2(data, claimedAmtByAssetNew) | |
426 | - | else $Tuple2((((data :+ ScriptTransfer(userAddress, rewardTotal, toAssetVect(asset))) :+ IntegerEntry(claimedKEY, (valueOrElse(getInteger(claimedKEY), 0) + rewardTotal))) :+ IntegerEntry(rewardCachedPartKEY, 0)), claimedAmtByAssetNew) | |
427 | - | } | |
454 | + | func claimRewards () = commonClaim(i.caller, i) | |
428 | 455 | ||
429 | - | let $t01734517459 = { | |
430 | - | let $l = supportedAssetsList | |
431 | - | let $s = size($l) | |
432 | - | let $acc0 = $Tuple2(nil, "") | |
433 | - | func $f0_1 ($a,$i) = if (($i >= $s)) | |
434 | - | then $a | |
435 | - | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
436 | 456 | ||
437 | - | func $f0_2 ($a,$i) = if (($i >= $s)) | |
438 | - | then $a | |
439 | - | else throw("List size exceeds 10") | |
440 | 457 | ||
441 | - | $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) | |
442 | - | } | |
443 | - | let transfers = $t01734517459._1 | |
444 | - | let claimedAmtByAssetResult = $t01734517459._2 | |
445 | - | if ((0 >= size(transfers))) | |
446 | - | then throw("nothing to claim") | |
447 | - | else ((transfers :+ IntegerEntry(userRewardFromDepositNumKEY, depositNumLast)) :+ ClaimHistoryEntry(userAddress, i.transactionId, drop(claimedAmtByAssetResult, 1))) | |
448 | - | } | |
449 | - | } | |
458 | + | @Callable(i) | |
459 | + | func claimRewardsByOriginCaller () = commonClaim(i.originCaller, i) | |
450 | 460 | ||
451 | 461 | ||
452 | 462 | ||
453 | 463 | @Callable(i) | |
454 | 464 | func unclaimedRewardsREADONLY (userAddressStr) = { | |
455 | 465 | func forEachAssetZeroReward (accum,asset) = ((accum + makeString([asset, "0", "0"], ":")) + "_") | |
456 | 466 | ||
457 | 467 | let unclaimedRewardStr = if ((userAddressStr == "")) | |
458 | 468 | then { | |
459 | 469 | let $l = supportedAssetsList | |
460 | 470 | let $s = size($l) | |
461 | 471 | let $acc0 = "" | |
462 | 472 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
463 | 473 | then $a | |
464 | 474 | else forEachAssetZeroReward($a, $l[$i]) | |
465 | 475 | ||
466 | 476 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
467 | 477 | then $a | |
468 | 478 | else throw("List size exceeds 10") | |
469 | 479 | ||
470 | 480 | $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) | |
471 | 481 | } | |
472 | 482 | else { | |
473 | 483 | let userAddress = addressFromStringValue(userAddressStr) | |
474 | - | let $ | |
475 | - | let isNewUser = $ | |
476 | - | let stakedAmount = $ | |
477 | - | let stakingStart = $ | |
484 | + | let $t01858118686 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
485 | + | let isNewUser = $t01858118686._1 | |
486 | + | let stakedAmount = $t01858118686._2 | |
487 | + | let stakingStart = $t01858118686._3 | |
478 | 488 | let stakedAmountX = toBigInt(stakedAmount) | |
479 | 489 | let userRewardFromDepositNumKEY = keyUserRewardFromDepositNum(userAddressStr) | |
480 | 490 | let depositNumUser = getIntOrElse(userRewardFromDepositNumKEY, -1) | |
481 | 491 | let depositNumLast = getIntOrElse(keyDepositNumLast(), -1) | |
482 | 492 | func forEachAssetCalcUnclaimedReward (accum,asset) = { | |
483 | - | let $ | |
484 | - | let rewardTotal = $ | |
485 | - | let cached = $ | |
486 | - | let dynamic = $ | |
487 | - | let rewardCachedPartKEY = $ | |
493 | + | let $t01903219170 = calcReward(userAddressStr, asset, stakedAmountX, depositNumUser, depositNumLast) | |
494 | + | let rewardTotal = $t01903219170._1 | |
495 | + | let cached = $t01903219170._2 | |
496 | + | let dynamic = $t01903219170._3 | |
497 | + | let rewardCachedPartKEY = $t01903219170._4 | |
488 | 498 | let claimed = valueOrElse(getInteger(keyClaimed(userAddressStr, asset)), 0) | |
489 | 499 | ((accum + makeString([asset, toString(rewardTotal), toString(claimed)], ":")) + "_") | |
490 | 500 | } | |
491 | 501 | ||
492 | 502 | let $l = supportedAssetsList | |
493 | 503 | let $s = size($l) | |
494 | 504 | let $acc0 = "" | |
495 | 505 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
496 | 506 | then $a | |
497 | 507 | else forEachAssetCalcUnclaimedReward($a, $l[$i]) | |
498 | 508 | ||
499 | 509 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
500 | 510 | then $a | |
501 | 511 | else throw("List size exceeds 10") | |
502 | 512 | ||
503 | 513 | $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) | |
504 | 514 | } | |
505 | 515 | $Tuple2(nil, dropRight(unclaimedRewardStr, 1)) | |
506 | 516 | } | |
507 | 517 | ||
508 | 518 | ||
509 | 519 | ||
510 | 520 | @Callable(i) | |
511 | - | func nsbtStakingSYSREADONLY (userAddressStr) = { | |
521 | + | func nsbtUnstakingSYSREADONLY (userAddressStrOrEmpty,unstakeAmtP) = { | |
522 | + | let resultArray = if ((userAddressStrOrEmpty == "")) | |
523 | + | then [0, 0, 0, 0] | |
524 | + | else { | |
525 | + | let userAddress = addressFromStringValue(userAddressStrOrEmpty) | |
526 | + | let cfgDATA = getParamsOrFail() | |
527 | + | let nsbtAssetId = cfgDATA._1 | |
528 | + | let minLockAmount = cfgDATA._2 | |
529 | + | let halfLife = cfgDATA._3 | |
530 | + | let userDATA = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
531 | + | let isNewUser = userDATA._1 | |
532 | + | let stakedAmount = userDATA._2 | |
533 | + | let lockStart = userDATA._3 | |
534 | + | let unstakeAmt = if ((unstakeAmtP > stakedAmount)) | |
535 | + | then stakedAmount | |
536 | + | else unstakeAmtP | |
537 | + | let stakedAmountNEW = (stakedAmount - unstakeAmt) | |
538 | + | let comissionAmount = if ((unstakeAmt == 0)) | |
539 | + | then 0 | |
540 | + | else asInt(invoke(mathContract, "getUnstakeComissionAmountREADONLY", [unstakeAmt, lockStart, halfLife], nil)) | |
541 | + | let receiveAmount = (unstakeAmt - comissionAmount) | |
542 | + | [stakedAmount, stakedAmountNEW, receiveAmount, comissionAmount] | |
543 | + | } | |
544 | + | $Tuple2(nil, resultArray) | |
545 | + | } | |
546 | + | ||
547 | + | ||
548 | + | ||
549 | + | @Callable(i) | |
550 | + | func nsbtStakingSYSREADONLY (userAddressStr,nsbtDiff) = { | |
512 | 551 | let totalNsbtAmt = getIntOrElse(keyLockParamTotalAmount(), 0) | |
513 | 552 | if ((userAddressStr == "")) | |
514 | 553 | then $Tuple2(nil, [0, totalNsbtAmt, 0]) | |
515 | 554 | else { | |
516 | 555 | let userAddress = toAddressOrFail(userAddressStr) | |
517 | - | let $ | |
518 | - | let isNewUser = $ | |
519 | - | let userNsbtAmt = $ | |
520 | - | let stakingStart = $ | |
556 | + | let $t02084920953 = valueOrElse(getUserParamsOrUnit(userAddress), $Tuple3(true, 0, 0)) | |
557 | + | let isNewUser = $t02084920953._1 | |
558 | + | let userNsbtAmt = $t02084920953._2 | |
559 | + | let stakingStart = $t02084920953._3 | |
521 | 560 | $Tuple2(nil, [userNsbtAmt, totalNsbtAmt, stakingStart]) | |
522 | 561 | } | |
523 | 562 | } | |
524 | 563 | ||
525 | 564 | ||
526 | 565 | @Verifier(tx) | |
527 | 566 | func verify () = { | |
528 | 567 | let pubKeyAdminsListStr = makeString(["GJdLSaLiv5K7xuejac8mcRcHoyo3dPrESrvktG3a6MAR", "EYwZmURd5KKaQRBjsVa6g8DPisFoS6SovRJtFiL5gMHU", "DtmAfuDdCrHK8spdAeAYzq6MsZegeD9gnsrpuTRkCbVA", "5WRXFSjwcTbNfKcJs8ZqXmSSWYsSVJUtMvMqZj5hH4Nc"], SEP) | |
529 | 568 | let pubKeyAdminsList = split(valueOrElse(getString(controlContract, "%s__multisig"), pubKeyAdminsListStr), SEP) | |
530 | 569 | let count = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0]))) | |
531 | 570 | then 1 | |
532 | 571 | else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1]))) | |
533 | 572 | then 1 | |
534 | 573 | else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2]))) | |
535 | 574 | then 1 | |
536 | 575 | else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[3], fromBase58String(pubKeyAdminsList[3]))) | |
537 | 576 | then 2 | |
538 | 577 | else 0)) | |
539 | 578 | (count >= 3) | |
540 | 579 | } | |
541 | 580 |
github/deemru/w8io/786bc32 104.43 ms ◑