tx · 2W6GEYb1Qp7G2TLnpexs7Vtif7LGDSDtNLn2bZSnFGyz

3Myn55vLkduxbX3ZXfiDCZhaQsLxYp1kmCy:  -0.02600000 Waves

2023.09.07 12:02 [2744756] smart account 3Myn55vLkduxbX3ZXfiDCZhaQsLxYp1kmCy > SELF 0.00000000 Waves

{ "type": 13, "id": "2W6GEYb1Qp7G2TLnpexs7Vtif7LGDSDtNLn2bZSnFGyz", "fee": 2600000, "feeAssetId": null, "timestamp": 1694077420688, "version": 2, "chainId": 84, "sender": "3Myn55vLkduxbX3ZXfiDCZhaQsLxYp1kmCy", "senderPublicKey": "9W33iCCNfmFxUbiC6XZcH5x7f6xfwC7Jb3BoExT5q2PV", "proofs": [ "2AuutS5yMh6gQ1EudDQTVDUzcVeqGKLNj7obxxzpWnRmLHfGzCueez6NRMW2JVWsUEfFwbbqBydah96YTrGiRXyu" ], "script": "base64:BgK2LQgCEgUKAwEIAhIDCgEBEgQKAggIEgQKAggIEgMKAQgSAwoBCBIDCgEIEgQKAggBEgMKAQgSABIAEgUKAwgIBBIDCgEIEgMKAQgSBAoCCAgSBAoCCAgSAwoBBCIDU0VQIgZTQ0FMRTgiBU1VTFQ4Ig5QT09MV0VJR0hUTVVMVCIQY29udHJhY3RGaWxlbmFtZSIHU0NBTEUxOCIGTVVMVDE4IghNVUxUMThCSSIOREVDQVlfQ09OU1RBTlQiB3dyYXBFcnIiA21zZyIIdGhyb3dFcnIiD2dldFN0cmluZ09yRmFpbCIHYWRkcmVzcyIDa2V5IgxnZXRJbnRPclplcm8iD2dldEludE9yRGVmYXVsdCIKZGVmYXVsdFZhbCIMZ2V0SW50T3JGYWlsIgNhYnMiA3ZhbCIOZW5zdXJlUG9zaXRpdmUiAXYiAW0iG2tleVJlZmVycmFsc0NvbnRyYWN0QWRkcmVzcyIecmVmZXJyYWxzQ29udHJhY3RBZGRyZXNzT3JGYWlsIhZrZXlSZWZlcnJhbFByb2dyYW1OYW1lIhpyZWZlcnJhbFByb2dyYW1OYW1lRGVmYXVsdCITcmVmZXJyYWxQcm9ncmFtTmFtZSIRa2V5RmFjdG9yeUFkZHJlc3MiGElkeEZhY3RvcnlDZmdTdGFraW5nRGFwcCIZSWR4RmFjdG9yeUNmZ0Jvb3N0aW5nRGFwcCIUSWR4RmFjdG9yeUNmZ0lkb0RhcHAiFUlkeEZhY3RvcnlDZmdUZWFtRGFwcCIZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcCIVSWR4RmFjdG9yeUNmZ1Jlc3REYXBwIhlJZHhGYWN0b3J5Q2ZnU2xpcHBhZ2VEYXBwIhRJZHhGYWN0b3J5Q2ZnRGFvRGFwcCIaSWR4RmFjdG9yeUNmZ01hcmtldGluZ0RhcHAiGklkeEZhY3RvcnlDZmdHd3hSZXdhcmREYXBwIhZJZHhGYWN0b3J5Q2ZnQmlyZHNEYXBwIg1rZXlGYWN0b3J5Q2ZnIiZrZXlGYWN0b3J5THBBc3NldFRvUG9vbENvbnRyYWN0QWRkcmVzcyIKbHBBc3NldFN0ciIUa2V5RmFjdG9yeVBvb2xXZWlnaHQiD2NvbnRyYWN0QWRkcmVzcyIba2V5RmFjdG9yeVBvb2xXZWlnaHRIaXN0b3J5Igtwb29sQWRkcmVzcyIDbnVtIhhyZWFkRmFjdG9yeUFkZHJlc3NPckZhaWwiFHJlYWRGYWN0b3J5Q2ZnT3JGYWlsIgdmYWN0b3J5IhhnZXRCb29zdGluZ0FkZHJlc3NPckZhaWwiCmZhY3RvcnlDZmciGGdldEVtaXNzaW9uQWRkcmVzc09yRmFpbCIXZ2V0U3Rha2luZ0FkZHJlc3NPckZhaWwiGWdldEd3eFJld2FyZEFkZHJlc3NPckZhaWwiE2tleU1hbmFnZXJQdWJsaWNLZXkiFmtleU1hbmFnZXJWYXVsdEFkZHJlc3MiHmtleUVtaXNzaW9uUmF0ZVBlckJsb2NrQ3VycmVudCIha2V5RW1pc3Npb25SYXRlUGVyQmxvY2tNYXhDdXJyZW50IhVrZXlFbWlzc2lvblN0YXJ0QmxvY2siHWtleUJvb3N0aW5nVjJMYXN0VXBkYXRlSGVpZ2h0IhVrZXlCb29zdGluZ1YySW50ZWdyYWwiG2tleUVtaXNzaW9uRHVyYXRpb25JbkJsb2NrcyITa2V5RW1pc3Npb25FbmRCbG9jayINSWR4Q2ZnQXNzZXRJZCITSWR4Q2ZnTWluTG9ja0Ftb3VudCIVSWR4Q2ZnTWluTG9ja0R1cmF0aW9uIhVJZHhDZmdNYXhMb2NrRHVyYXRpb24iEklkeENmZ01hdGhDb250cmFjdCIUSWR4Q2ZnQmxvY2tzSW5QZXJpb2QiFElkeENmZ0xvY2tTdGVwQmxvY2tzIglrZXlDb25maWciFXJlYWRDb25maWdBcnJheU9yRmFpbCIIY2ZnQXJyYXkiB2Fzc2V0SWQiDW1pbkxvY2tBbW91bnQiD21pbkxvY2tEdXJhdGlvbiIPbWF4TG9ja0R1cmF0aW9uIgxtYXRoQ29udHJhY3QiDmJsb2Nrc0luUGVyaW9kIg5sb2NrU3RlcEJsb2NrcyINa2V5U3VzcGVuc2lvbiILaXNTdXNwZW5kZWQiEHRocm93SWZTdXNwZW5kZWQiHGdldE1hbmFnZXJWYXVsdEFkZHJlc3NPclRoaXMiByRtYXRjaDAiAXMiFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQiE21hbmFnZXJWYXVsdEFkZHJlc3MiC211c3RNYW5hZ2VyIgFpIgJwZCICcGsiDUlkeExvY2tBbW91bnQiDElkeExvY2tTdGFydCIPSWR4TG9ja0R1cmF0aW9uIhpJZHhMb2NrTGFzdFVwZGF0ZVRpbWVzdGFtcCIQSWR4TG9ja0d3eEFtb3VudCIQSWR4TG9ja1d4Q2xhaW1lZCITa2V5TG9ja1BhcmFtc1JlY29yZCILdXNlckFkZHJlc3MiBHR4SWQiAWIiGnJlYWRMb2NrUGFyYW1zUmVjb3JkT3JGYWlsIhVrZXlVc2VyR3d4QW1vdW50VG90YWwiFmZvcm1hdExvY2tQYXJhbXNSZWNvcmQiBmFtb3VudCIFc3RhcnQiCGR1cmF0aW9uIglnd3hBbW91bnQiCXd4Q2xhaW1lZCIOa2V5TmV4dFVzZXJOdW0iEmtleVVzZXIyTnVtTWFwcGluZyISa2V5TnVtMlVzZXJNYXBwaW5nIhdrZXlMb2NrUGFyYW1Ub3RhbEFtb3VudCIga2V5U3RhdHNMb2Nrc0R1cmF0aW9uU3VtSW5CbG9ja3MiEmtleVN0YXRzTG9ja3NDb3VudCISa2V5U3RhdHNVc2Vyc0NvdW50IiBrZXlVc2VyQm9vc3RFbWlzc2lvbkxhc3RJTlRFR1JBTCIHdXNlck51bSIia2V5VXNlckxwQm9vc3RFbWlzc2lvbkxhc3RJTlRFR1JBTCIJbHBBc3NldElkIhdrZXlVc2VyTWF4Qm9vc3RJTlRFR1JBTCIYa2V5VG90YWxNYXhCb29zdElOVEVHUkFMIiFrZXlVc2VyQm9vc3RBdmFsYWlibGVUb0NsYWltVG90YWwiE2tleVVzZXJCb29zdENsYWltZWQiC2tleUd3eFRvdGFsIgdrZXlWb3RlIg1hbW91bnRBc3NldElkIgxwcmljZUFzc2V0SWQiBWVwb2NoIhVrZXlTdGFydEhlaWdodEJ5RXBvY2giEWtleUN1cnJlbnRFcG9jaFVpIhVrZXlWb3RpbmdSZXN1bHRTdGFrZWQiDGxwQXNzZXRJZFN0ciIda2V5Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwiJWtleVZvdGluZ1Jlc3VsdFN0YWtlZExhc3RVcGRhdGVIZWlnaHQiIWtleVZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsTGFzdCIVa2V5Vm90ZVN0YWtlZEludGVncmFsIh1rZXlWb3RlU3Rha2VkTGFzdFVwZGF0ZUhlaWdodCIZa2V5Vm90ZVN0YWtlZEludGVncmFsTGFzdCIPa2V5U3Rha2VkQnlVc2VyIg51c2VyQWRkcmVzc1N0ciIPZmFjdG9yeUNvbnRyYWN0IhBlbWlzc2lvbkNvbnRyYWN0Ig9zdGFraW5nQ29udHJhY3QiEWd3eFJld2FyZENvbnRyYWN0IhZscFN0YWtpbmdQb29sc0NvbnRyYWN0IhlrZXlWb3RpbmdFbWlzc2lvbkNvbnRyYWN0IhZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0Ih1rZXlWb3RpbmdFbWlzc2lvblJhdGVDb250cmFjdCIKYm9vc3RDb2VmZiIBQCIZdXNlck51bWJlckJ5QWRkcmVzc09yRmFpbCIRZ2V0R3d4QW1vdW50VG90YWwiEmdldExvY2tlZEd3eEFtb3VudCIMZnVuY3Rpb25OYW1lIhp2b3RpbmdFbWlzc2lvblJhdGVDb250cmFjdCIYbG9ja2VkVm90aW5nRW1pc3Npb25SYXRlIhRsb2NrZWRWb3RpbmdFbWlzc2lvbiIGbG9ja2VkIgxIaXN0b3J5RW50cnkiBHR5cGUiBHVzZXIiCWxvY2tTdGFydCIKaGlzdG9yeUtFWSILaGlzdG9yeURBVEEiClN0YXRzRW50cnkiDnRvdGFsTG9ja2VkSW5jIgtkdXJhdGlvbkluYyIMbG9ja0NvdW50SW5jIg11c2Vyc0NvdW50SW5jIhtsb2Nrc0R1cmF0aW9uU3VtSW5CbG9ja3NLRVkiDWxvY2tzQ291bnRLRVkiDXVzZXJzQ291bnRLRVkiDnRvdGFsQW1vdW50S0VZIhhsb2Nrc0R1cmF0aW9uU3VtSW5CbG9ja3MiCmxvY2tzQ291bnQiCnVzZXJzQ291bnQiC3RvdGFsQW1vdW50Ig9Mb2NrUGFyYW1zRW50cnkiImV4dHJhY3RPcHRpb25hbFBheW1lbnRBbW91bnRPckZhaWwiD2V4cGVjdGVkQXNzZXRJZCIDcG10IhVnZXRVc2VyR3d4QW1vdW50VG90YWwiGmdldFZvdGluZ0VtaXNzaW9uRXBvY2hJbmZvIg0kdDAxNDY4NjE0OTc2Ig5jdXJyZW50RXBvY2hVaSISbGFzdEZpbmFsaXplZEVwb2NoIhdjdXJyZW50RXBvY2hTdGFydEhlaWdodCIYZ2V0UG9vbEFzc2V0c0J5THBBc3NldElkIhBpZHhBbW91bnRBc3NldElkIg9pZHhQcmljZUFzc2V0SWQiB3Bvb2xDZmciFGdldFVzZXJWb3RlRmluYWxpemVkIg0kdDAxNTY2NzE1NzQ3Ig0kdDAxNTc1MDE1ODI1Igt1c2VyVm90ZUtleSIIdXNlclZvdGUiEWdldFVzZXJWb3RlU3Rha2VkIgxzdGFrZWRCeVVzZXIiFWdldFZvdGluZ1Jlc3VsdFN0YWtlZCINJHQwMTYzNjkxNjQ0OSIXdm90aW5nUmVzdWx0U3Rha2VkU3RhcnQiEnZvdGluZ1Jlc3VsdFN0YWtlZCIdZ2V0Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwiDSR0MDE2ODExMTY4OTEiHnZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsUHJldiIidm90aW5nUmVzdWx0U3Rha2VkTGFzdFVwZGF0ZUhlaWdodCIcdm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWxEaCIadm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwiIXJlZnJlc2hWb3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbCIPc3Rha2VkVm90ZURlbHRhIg0kdDAxNzcyODE3ODA4IhV2b3RpbmdSZXN1bHRTdGFrZWROZXciGWdldFVzZXJWb3RlU3Rha2VkSW50ZWdyYWwiDSR0MDE4NDE5MTg0OTkiDnVzZXJWb3RlU3Rha2VkIhp1c2VyVm90ZVN0YWtlZEludGVncmFsUHJldiIedXNlclZvdGVTdGFrZWRMYXN0VXBkYXRlSGVpZ2h0Ihh1c2VyVm90ZVN0YWtlZEludGVncmFsRGgiFnVzZXJWb3RlU3Rha2VkSW50ZWdyYWwiGXJlZnJlc2hWb3RlU3Rha2VkSW50ZWdyYWwiBGVkZ2UiDSR0MDE5Mjg3MTkzNjciEXVzZXJWb3RlRmluYWxpemVkIgdhY3Rpb25zIhN2b3RpbmdSZXN1bHRBY3Rpb25zIgt2b3RlQWN0aW9ucyIbZ2V0U3Rha2VkVm90ZXNJbnRlZ3JhbHNEaWZmIg0kdDAyMDIyMTIwMzAxIh11c2VyVm90ZVN0YWtlZEludGVncmFsTGFzdEtleSIadXNlclZvdGVTdGFrZWRJbnRlZ3JhbExhc3QiIXZvdGluZ1Jlc3VsdFN0YWtlZEludGVncmFsTGFzdEtleSIedm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWxMYXN0Ihp1c2VyVm90ZVN0YWtlZEludGVncmFsRGlmZiIedm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWxEaWZmIhxyZWZyZXNoQm9vc3RFbWlzc2lvbkludGVncmFsIhJ3eEVtaXNzaW9uUGVyQmxvY2siIGJvb3N0aW5nVjJMYXN0VXBkYXRlSGVpZ2h0T3B0aW9uIhhib29zdGluZ1YySW5nZXJnYWxPcHRpb24iC2VtaXNzaW9uRW5kIgFoIgJkaCIQbGFzdFVwZGF0ZUhlaWdodCIVYm9vc3RFbWlzc2lvblBlckJsb2NrIhlib29zdEVtaXNzaW9uSW50ZWdyYWxQcmV2IhVib29zdEVtaXNzaW9uSW50ZWdyYWwiFGludGVybmFsQ2xhaW1XeEJvb3N0IghyZWFkT25seSIIRU1QVFlTVFIiCnBvb2xXZWlnaHQiDnBvb2xBZGRyZXNzU3RyIiJ1c2VyTHBCb29zdEVtaXNzaW9uTGFzdEludGVncmFsS0VZIiB1c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRlZ3JhbEtFWSIddXNlckJvb3N0RW1pc3Npb25MYXN0SW50ZWdyYWwiGXVzZXJCb29zdEVtaXNzaW9uSW50ZWdyYWwiDSR0MDIzODQzMjM5ODIiG3N0YWtlZFZvdGVzSW50ZWdyYWxzQWN0aW9ucyIUdXNlclZvdGVJbnRlZ3JhbERpZmYiFnRvdGFsVm90ZXNJbnRlZ3JhbERpZmYiHXBvb2xVc2VyQm9vc3RFbWlzc2lvbkludGVncmFsIiF1c2VyQm9vc3RBdmFsaWFibGVUb0NsYWltVG90YWxOZXciCWRhdGFTdGF0ZSIFZGVidWciC2xvY2tBY3Rpb25zIgphc3NldElkU3RyIglwbXRBbW91bnQiDm5leHRVc2VyTnVtS0VZIg51c2VySXNFeGlzdGluZyIKdXNlck51bVN0ciIOZ1d4QW1vdW50U3RhcnQiDmd3eEFtb3VudFRvdGFsIhJ1c2VyR3d4QW1vdW50VG90YWwiDGd3eFJld2FyZEludiIDYXJyIhFnZXRXeFdpdGhkcmF3YWJsZSIKdHhJZE9wdGlvbiIPdXNlclJlY29yZEFycmF5Igp1c2VyQW1vdW50Igxsb2NrRHVyYXRpb24iB2xvY2tFbmQiAXQiCGV4cG9uZW50IhN3eFdpdGhkcmF3YWJsZVRvdGFsIg53eFdpdGhkcmF3YWJsZSIPcmVmZXJyZXJBZGRyZXNzIglzaWduYXR1cmUiD3N1c3BlbnNpb25DaGVjayINJHQwMjg0MDAyODQ2NSIRbG9ja0FjdGlvbnNSZXN1bHQiD3JlZmVycmFsQWRkcmVzcyIGcmVmSW52IhF1cGRhdGVSZWZBY3Rpdml0eSINJHQwMjg5NjkyOTAzNCINJHQwMjkzOTAyOTQ5MiISdXNlckJvb3N0QXZhaWxhYmxlIg0kdDAyOTYyNDI5NzI1Igd0eElkU3RyIglnd3hCdXJuZWQiDGd3eFJlbWFpbmluZyIPbG9ja2VkR3d4QW1vdW50IhV1c2VyR3d4QW1vdW50VG90YWxOZXciDHRhcmdldEhlaWdodCILY2hlY2tDYWxsZXIiAnR4IgZ2ZXJpZnkiD3RhcmdldFB1YmxpY0tleY8BAAFhAgJfXwABYgAIAAFjAIDC1y8AAWQFAWMAAWUCDWJvb3N0aW5nLnJpZGUAAWYAEgABZwCAgJC7utat8A0AAWgJALYCAQUBZwABaQAIAQFqAQFrCQC5CQIJAMwIAgUBZQkAzAgCAgI6IAkAzAgCBQFrBQNuaWwCAAEBbAEBawkAAgEJAQFqAQUBawEBbQIBbgFvCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUBbgUBbwkBAWoBCQCsAgIJAKwCAgIPbWFuZGF0b3J5IHRoaXMuBQFvAg8gaXMgbm90IGRlZmluZWQBAXACAW4BbwkBC3ZhbHVlT3JFbHNlAgkAmggCBQFuBQFvAAABAXEDAW4BbwFyCQELdmFsdWVPckVsc2UCCQCaCAIFAW4FAW8FAXIBAXMCAW4BbwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFAW4FAW8JAQFqAQkArAICCQCsAgICD21hbmRhdG9yeSB0aGlzLgUBbwIPIGlzIG5vdCBkZWZpbmVkAQF0AQF1AwkAZgIAAAUBdQkBAS0BBQF1BQF1AQF2AgF3AXgDCQBnAgUBdwAABQF3CQEBbAEJAKwCAgkBC3ZhbHVlT3JFbHNlAgUBeAIFdmFsdWUCEyBzaG91bGQgYmUgcG9zaXRpdmUBAXkACQC5CQIJAMwIAgIEJXMlcwkAzAgCAgZjb25maWcJAMwIAgIYcmVmZXJyYWxzQ29udHJhY3RBZGRyZXNzBQNuaWwFAWEAAXoJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQFtAgUEdGhpcwkBAXkAAAFBCQC5CQIJAMwIAgIEJXMlcwkAzAgCAghyZWZlcnJhbAkAzAgCAgtwcm9ncmFtTmFtZQUDbmlsBQFhAAFCAgZ3eGxvY2sAAUMJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUBQQUBQgEBRAACHCVzJXNfX2NvbmZpZ19fZmFjdG9yeUFkZHJlc3MAAUUAAQABRgACAAFHAAMAAUgABAABSQAFAAFKAAYAAUsABwABTAAIAAFNAAkAAU4ACgABTwALAQFQAAIRJXNfX2ZhY3RvcnlDb25maWcBAVEBAVIJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgUBUgkAzAgCAh5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFA25pbAUBYQEBUwEBVAkAuQkCCQDMCAICBCVzJXMJAMwIAgIKcG9vbFdlaWdodAkAzAgCBQFUBQNuaWwFAWEBAVUCAVYBVwkArAICCQCsAgIJAKwCAgISJXMlc19fcG9vbFdlaWdodF9fBQFWAgJfXwkApAMBBQFXAQFYAAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBAW0CBQR0aGlzCQEBRAABAVkBAVoJALUJAgkBAW0CBQFaCQEBUAAFAWEBAmFhAQJhYgkBEUBleHRyTmF0aXZlKDEwNjIpAQkAkQMCBQJhYgUBRgECYWMBAmFiCQERQGV4dHJOYXRpdmUoMTA2MikBCQCRAwIFAmFiBQFJAQJhZAECYWIJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUCYWIFAUUBAmFlAQJhYgkBEUBleHRyTmF0aXZlKDEwNjIpAQkAkQMCBQJhYgUBTgECYWYAAhQlc19fbWFuYWdlclB1YmxpY0tleQECYWcAAhclc19fbWFuYWdlclZhdWx0QWRkcmVzcwECYWgAAhslcyVzX19yYXRlUGVyQmxvY2tfX2N1cnJlbnQBAmFpAAIeJXMlc19fcmF0ZVBlckJsb2NrTWF4X19jdXJyZW50AQJhagACGiVzJXNfX2VtaXNzaW9uX19zdGFydEJsb2NrAQJhawACHCVzJXNfX2Jvb3N0aW5nVjJfX3N0YXJ0QmxvY2sBAmFsAAIaJXMlc19fYm9vc3RpbmdWMl9faW50ZWdyYWwBAmFtAAIYJXMlc19fZW1pc3Npb25fX2R1cmF0aW9uAQJhbgACGCVzJXNfX2VtaXNzaW9uX19lbmRCbG9jawACYW8AAQACYXAAAgACYXEAAwACYXIABAACYXMABQACYXQABgACYXUABwECYXYAAgolc19fY29uZmlnAQJhdwAJALUJAgkBAW0CBQR0aGlzCQECYXYABQFhAAJheAkBAmF3AAACYXkJANkEAQkAkQMCBQJheAUCYW8AAmF6CQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQJheAUCYXAJAQFqAQIXaW52YWxpZCBtaW4gbG9jayBhbW91bnQAAmFBCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQJheAUCYXEJAQFqAQIZaW52YWxpZCBtaW4gbG9jayBkdXJhdGlvbgACYUIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFAmF4BQJhcgkBAWoBAhlpbnZhbGlkIG1heCBsb2NrIGR1cmF0aW9uAAJhQwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUCYXgFAmFzCQEBagECHWludmFsaWQgbWF0aCBjb250cmFjdCBhZGRyZXNzAAJhRAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUCYXgFAmF0CQEBagECGGludmFsaWQgYmxvY2tzIGluIHBlcmlvZAACYUUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBCQCRAwIFAmF4BQJhdQkBAWoBAhhpbnZhbGlkIGxvY2sgc3RlcCBibG9ja3MAAmFGAg4lc19fc3VzcGVuc2lvbgACYUcJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwUCYUYHAQJhSAADCQEBIQEFAmFHBgkBAWwBAglzdXNwZW5kZWQBAmFJAAQCYUoJAKIIAQkBAmFnAAMJAAECBQJhSgIGU3RyaW5nBAJhSwUCYUoJARFAZXh0ck5hdGl2ZSgxMDYyKQEFAmFLBQR0aGlzAQJhTAAEAmFNCQECYUkABAJhSgkAnQgCBQJhTQkBAmFmAAMJAAECBQJhSgIGU3RyaW5nBAJhSwUCYUoJANkEAQUCYUsDCQABAgUCYUoCBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgECYU4BAmFPBAJhUAkBAWwBAhFQZXJtaXNzaW9uIGRlbmllZAQCYUoJAQJhTAADCQABAgUCYUoCCkJ5dGVWZWN0b3IEAmFRBQJhSgMJAAACCAUCYU8PY2FsbGVyUHVibGljS2V5BQJhUQYFAmFQAwkAAQIFAmFKAgRVbml0AwkAAAIIBQJhTwZjYWxsZXIFBHRoaXMGBQJhUAkAAgECC01hdGNoIGVycm9yAAJhUgABAAJhUwACAAJhVAADAAJhVQAEAAJhVgAFAAJhVwAGAQJhWAICYVkCYVoJALkJAgkAzAgCAgwlcyVzJXNfX2xvY2sJAMwIAgkApQgBBQJhWQkAzAgCBAJhSgUCYVoDCQABAgUCYUoCCkJ5dGVWZWN0b3IEAmJhBQJhSgkA2AQBBQJiYQMJAAECBQJhSgIEVW5pdAIGbGVnYWN5CQACAQILTWF0Y2ggZXJyb3IFA25pbAUBYQECYmICAmFZAmFaCQC1CQIJAQFtAgUEdGhpcwkBAmFYAgUCYVkFAmFaBQFhAQJiYwECYVkJALkJAgkAzAgCAhQlcyVzX19nd3hBbW91bnRUb3RhbAkAzAgCCQClCAEFAmFZBQNuaWwFAWEBAmJkBQJiZQJiZgJiZwJiaAJiaQkAuQkCCQDMCAICDCVkJWQlZCVkJWQlZAkAzAgCCQCkAwEFAmJlCQDMCAIJAKQDAQUCYmYJAMwIAgkApAMBBQJiZwkAzAgCCQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wCQDMCAIJAKQDAQUCYmgJAMwIAgkApAMBBQJiaQUDbmlsBQFhAQJiagACDyVzX19uZXh0VXNlck51bQECYmsBAmFZCQC5CQIJAMwIAgIZJXMlcyVzX19tYXBwaW5nX191c2VyMm51bQkAzAgCBQJhWQUDbmlsBQFhAQJibAEBVwkAuQkCCQDMCAICGSVzJXMlc19fbWFwcGluZ19fbnVtMnVzZXIJAMwIAgUBVwUDbmlsBQFhAQJibQACHiVzJXNfX3N0YXRzX19hY3RpdmVUb3RhbExvY2tlZAECYm4AAiUlcyVzX19zdGF0c19fbG9ja3NEdXJhdGlvblN1bUluQmxvY2tzAQJibwACFyVzJXNfX3N0YXRzX19sb2Nrc0NvdW50AQJicAACHSVzJXNfX3N0YXRzX19hY3RpdmVVc2Vyc0NvdW50AQJicQECYnIJALkJAgkAzAgCAiAlcyVkX191c2VyQm9vc3RFbWlzc2lvbkxhc3RJbnRWMgkAzAgCCQCkAwEFAmJyBQNuaWwFAWEBAmJzAgJicgJidAkAuQkCCQDMCAICICVzJWRfX3VzZXJCb29zdEVtaXNzaW9uTGFzdEludFYyCQDMCAIJAKQDAQUCYnIJAMwIAgUCYnQFA25pbAUBYQECYnUBAmJyCQC5CQIJAMwIAgIRJXMlZF9fbWF4Qm9vc3RJbnQJAMwIAgkApAMBBQJicgUDbmlsBQFhAQJidgACGCVzJXNfX21heEJvb3N0SW50X190b3RhbAECYncBAmJyCQC5CQIJAMwIAgIkJXMlZF9fdXNlckJvb3N0QXZhbGlhYmxlVG9DbGFpbVRvdGFsCQDMCAIJAKQDAQUCYnIFA25pbAUBYQECYngBAmJyCQC5CQIJAMwIAgIWJXMlZF9fdXNlckJvb3N0Q2xhaW1lZAkAzAgCCQCkAwEFAmJyBQNuaWwFAWEBAmJ5AAIQJXMlc19fZ3d4X190b3RhbAECYnoEAmJBAmJCAW4CYkMJALkJAgkAzAgCAgolcyVzJXMlcyVkCQDMCAICBHZvdGUJAMwIAgUCYkEJAMwIAgUCYkIJAMwIAgkApQgBBQFuCQDMCAIJAKQDAQUCYkMFA25pbAUBYQECYkQBAmJDCQC5CQIJAMwIAgIEJXMlZAkAzAgCAgtzdGFydEhlaWdodAkAzAgCCQCkAwEFAmJDBQNuaWwFAWEBAmJFAAkAuQkCCQDMCAICAiVzCQDMCAICDmN1cnJlbnRFcG9jaFVpBQNuaWwFAWEBAmJGAgJiRwJiQwkAuQkCCQDMCAICBiVzJXMlZAkAzAgCAhJ2b3RpbmdSZXN1bHRTdGFrZWQJAMwIAgUCYkcJAMwIAgkApAMBBQJiQwUDbmlsBQFhAQJiSAICYkcCYkMJALkJAgkAzAgCAgYlcyVzJWQJAMwIAgIadm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWwJAMwIAgUCYkcJAMwIAgkApAMBBQJiQwUDbmlsBQFhAQJiSQICYkcCYkMJALkJAgkAzAgCAgYlcyVzJWQJAMwIAgIqdm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWxMYXN0VXBkYXRlSGVpZ2h0CQDMCAIFAmJHCQDMCAIJAKQDAQUCYkMFA25pbAUBYQECYkoDAmJHAW4CYkMJALkJAgkAzAgCAgglcyVzJXMlZAkAzAgCAh52b3RpbmdSZXN1bHRTdGFrZWRJbnRlZ3JhbExhc3QJAMwIAgUCYkcJAMwIAgkApQgBBQFuCQDMCAIJAKQDAQUCYkMFA25pbAUBYQECYksDAmJHAW4CYkMJALkJAgkAzAgCAgglcyVzJXMlZAkAzAgCAhJ2b3RlU3Rha2VkSW50ZWdyYWwJAMwIAgUCYkcJAMwIAgkApQgBBQFuCQDMCAIJAKQDAQUCYkMFA25pbAUBYQECYkwDAmJHAW4CYkMJALkJAgkAzAgCAgglcyVzJXMlZAkAzAgCAiJ2b3RlU3Rha2VkSW50ZWdyYWxMYXN0VXBkYXRlSGVpZ2h0CQDMCAIFAmJHCQDMCAIJAKUIAQUBbgkAzAgCCQCkAwEFAmJDBQNuaWwFAWEBAmJNAwJiRwFuAmJDCQC5CQIJAMwIAgIIJXMlcyVzJWQJAMwIAgIWdm90ZVN0YWtlZEludGVncmFsTGFzdAkAzAgCBQJiRwkAzAgCCQClCAEFAW4JAMwIAgkApAMBBQJiQwUDbmlsBQFhAQJiTgICYk8CYkcJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgIGc3Rha2VkCQDMCAIFAmJPCQDMCAIFAmJHBQNuaWwFAWEAAmJQCQEBWAAAAmFiCQEBWQEFAmJQAAJiUQkBAmFjAQUCYWIAAmJSCQECYWQBBQJhYgACYlMJAQJhZQEFAmFiAAJiVAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQC5CQIJAMwIAgICJXMJAMwIAgIWbHBTdGFraW5nUG9vbHNDb250cmFjdAUDbmlsBQFhCQEBagECLmxwX3N0YWtpbmdfcG9vbHMgY29udHJhY3QgYWRkcmVzcyBpcyB1bmRlZmluZWQJAQFqAQIpaW52YWxpZCBscF9zdGFraW5nX3Bvb2xzIGNvbnRyYWN0IGFkZHJlc3MAAmJVCQC5CQIJAMwIAgICJXMJAMwIAgIWdm90aW5nRW1pc3Npb25Db250cmFjdAUDbmlsBQFhAAJiVgkBEUBleHRyTmF0aXZlKDEwNjIpAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUCYlAFAmJVAAJiVwkAuQkCCQDMCAICAiVzCQDMCAICGnZvdGluZ0VtaXNzaW9uUmF0ZUNvbnRyYWN0BQNuaWwFAWEAAmJYCgACYlkJAPwHBAUCYlECFWdldEJvb3N0Q29lZmZSRUFET05MWQUDbmlsBQNuaWwDCQABAgUCYlkCA0ludAUCYlkJAAIBCQCsAgIJAAMBBQJiWQIYIGNvdWxkbid0IGJlIGNhc3QgdG8gSW50AQJiWgECYVkEAmFKCQCdCAIFBHRoaXMJAQJiawEJAKUIAQUCYVkDCQABAgUCYUoCBlN0cmluZwQCYUsFAmFKCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQUCYUsJAQFqAQITaW52YWxpZCB1c2VyIG51bWJlcgMJAAECBQJhSgIEVW5pdAkBAWwBAgxpbnZhbGlkIHVzZXIJAAIBAgtNYXRjaCBlcnJvcgECY2EACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQJieQAAAAECY2IBAmFZBAJjYwISZ2V0TG9ja2VkR3d4QW1vdW50BAJjZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCBAJhSgkAnQgCBQJiVgUCYlcDCQABAgUCYUoCBFVuaXQFBHVuaXQDCQABAgUCYUoCBlN0cmluZwQCYUsFAmFKCQCmCAEFAmFLCQACAQILTWF0Y2ggZXJyb3IJAQFqAQIkaW52YWxpZCB2b3RpbmcgZW1pc3Npb24gcmF0ZSBhZGRyZXNzBAJjZQoAAmJZCQD8BwQFAmJWBQJjYwkAzAgCCQClCAEFAmFZBQNuaWwFA25pbAMJAAECBQJiWQIDSW50BQJiWQkAAgEJAKwCAgkAAwEFAmJZAhggY291bGRuJ3QgYmUgY2FzdCB0byBJbnQEAmNmCgACYlkJAPwHBAUCY2QFAmNjCQDMCAIJAKUIAQUCYVkFA25pbAUDbmlsAwkAAQIFAmJZAgNJbnQFAmJZCQACAQkArAICCQADAQUCYlkCGCBjb3VsZG4ndCBiZSBjYXN0IHRvIEludAQCY2cJAJYDAQkAzAgCBQJjZQkAzAgCBQJjZgUDbmlsBQJjZwECY2gHAmNpAmNqAmJlAmNrAmJnAmJoAmFPBAJjbAkAuQkCCQDMCAICESVzJXMlcyVzX19oaXN0b3J5CQDMCAIFAmNpCQDMCAIFAmNqCQDMCAIJANgEAQgFAmFPDXRyYW5zYWN0aW9uSWQFA25pbAUBYQQCY20JALkJAgkAzAgCAg4lZCVkJWQlZCVkJWQlZAkAzAgCCQCkAwEIBQlsYXN0QmxvY2sGaGVpZ2h0CQDMCAIJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAMwIAgkApAMBBQJiZQkAzAgCCQCkAwEFAmNrCQDMCAIJAKQDAQUCYmcJAMwIAgkApAMBBQJiaAUDbmlsBQFhCQELU3RyaW5nRW50cnkCBQJjbAUCY20BAmNuBAJjbwJjcAJjcQJjcgQCY3MJAQJibgAEAmN0CQECYm8ABAJjdQkBAmJwAAQCY3YJAQJibQAEAmN3CQEBcAIFBHRoaXMFAmNzBAJjeAkBAXACBQR0aGlzBQJjdAQCY3kJAQFwAgUEdGhpcwUCY3UEAmN6CQEBcAIFBHRoaXMFAmN2CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQJjcwkAZAIFAmN3BQJjcAkAzAgCCQEMSW50ZWdlckVudHJ5AgUCY3QJAGQCBQJjeAUCY3EJAMwIAgkBDEludGVnZXJFbnRyeQIFAmN1CQBkAgUCY3kFAmNyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQJjdgkAZAIFAmN6BQJjbwUDbmlsAQJjQQcCYVkCYVoCYmUCYmYCYmcCYmgCYmkJAMwIAgkBC1N0cmluZ0VudHJ5AgkBAmFYAgUCYVkFAmFaCQECYmQFBQJiZQUCYmYFAmJnBQJiaAUCYmkFA25pbAECY0ICAmFPAmNDAwkAZgIJAJADAQgFAmFPCHBheW1lbnRzAAEJAQFsAQIbb25seSBvbmUgcGF5bWVudCBpcyBhbGxvd2VkAwkAAAIJAJADAQgFAmFPCHBheW1lbnRzAAAAAAQCY0QJAJEDAggFAmFPCHBheW1lbnRzAAADCQECIT0CCQEFdmFsdWUBCAUCY0QHYXNzZXRJZAUCY0MJAQFsAQIbaW52YWxpZCBhc3NldCBpZCBpbiBwYXltZW50CAUCY0QGYW1vdW50AQJjRQECYVkJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBAmJjAQUCYVkAAAECY0YABAJjRwQCY0gJAQV2YWx1ZQEJAJoIAgUCYlYJAQJiRQAEAmNJCQBlAgUCY0gAAQMJAGYCAAAFAmNJCQEBbAECDWludmFsaWQgZXBvY2gJAJQKAgUCY0gFAmNJBAJjSAgFAmNHAl8xBAJjSQgFAmNHAl8yBAJjSgkBBXZhbHVlAQkAmggCBQJiVgkBAmJEAQUCY0gJAJQKAgUCY0kFAmNKAQJjSwECYkcEAmNMAAQEAmNNAAUEAmNOCgACYlkJAPwHBAUCYlACIGdldFBvb2xDb25maWdCeUxwQXNzZXRJZFJFQURPTkxZCQDMCAIFAmJHBQNuaWwFA25pbAMJAAECBQJiWQIJTGlzdFtBbnldBQJiWQkAAgEJAKwCAgkAAwEFAmJZAh4gY291bGRuJ3QgYmUgY2FzdCB0byBMaXN0W0FueV0EAmJBCgACYlkJAJEDAgUCY04FAmNMAwkAAQIFAmJZAgZTdHJpbmcFAmJZCQACAQkArAICCQADAQUCYlkCGyBjb3VsZG4ndCBiZSBjYXN0IHRvIFN0cmluZwQCYkIKAAJiWQkAkQMCBQJjTgUCY00DCQABAgUCYlkCBlN0cmluZwUCYlkJAAIBCQCsAgIJAAMBBQJiWQIbIGNvdWxkbid0IGJlIGNhc3QgdG8gU3RyaW5nCQCUCgIFAmJBBQJiQgECY08CAmJHAmJPBAJhWQkBEUBleHRyTmF0aXZlKDEwNjIpAQUCYk8EAmNQCQECY0YABAJjSQgFAmNQAl8xBAJjSggFAmNQAl8yBAJjUQkBAmNLAQUCYkcEAmJBCAUCY1ECXzEEAmJCCAUCY1ECXzIEAmNSCQECYnoEBQJiQQUCYkIFAmFZBQJjSQQCY1MJAQt2YWx1ZU9yRWxzZQIJAJoIAgUCYlYFAmNSAAAFAmNTAQJjVAICYkcCYk8EAmNVCQELdmFsdWVPckVsc2UCCQCaCAIFAmJSCQECYk4CBQJiTwUCYkcAAAQCY1MJAQJjTwIFAmJHBQJiTwMJAAACBQJjVQAAAAAFAmNTAQJjVgECYkcEAmNXCQECY0YABAJjSQgFAmNXAl8xBAJjSggFAmNXAl8yBAJjWAkBC3ZhbHVlT3JFbHNlAgkAmggCBQJiVgkBAmJGAgUCYkcFAmNJAAAEAmNZCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQJiRgIFAmJHBQJjSQUCY1gFAmNZAQJjWgECYkcEAmRhCQECY0YABAJjSQgFAmRhAl8xBAJjSggFAmRhAl8yBAJjWQkBAmNWAQUCYkcEAmRiCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQJiSAIFAmJHBQJjSQAABAJkYwkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQECYkkCBQJiRwUCY0kFAmNKBAJkZAkAZQIFBmhlaWdodAUCZGMEAmRlCQBkAgkAaAIFAmRkBQJjWQUCZGIFAmRlAQJkZgICYkcCZGcEAmRoCQECY0YABAJjSQgFAmRoAl8xBAJjSggFAmRoAl8yBAJjWQkBAmNWAQUCYkcEAmRpCQBkAgUCY1kFAmRnBAJkZQkBAmNaAQUCYkcJAMwIAgkBDEludGVnZXJFbnRyeQIJAQJiRgIFAmJHBQJjSQUCZGkJAMwIAgkBDEludGVnZXJFbnRyeQIJAQJiSQIFAmJHBQJjSQUGaGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQECYkgCBQJiRwUCY0kFAmRlBQNuaWwBAmRqAgJiRwJiTwQCZGsJAQJjRgAEAmNJCAUCZGsCXzEEAmNKCAUCZGsCXzIEAmFZCQERQGV4dHJOYXRpdmUoMTA2MikBBQJiTwQCZGwJAQJjVAIFAmJHBQJiTwQCZG0JAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBAmJLAwUCYkcFAmFZBQJjSQAABAJkbgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQECYkwDBQJiRwUCYVkFAmNJBQJjSgQCZG8JAGUCBQZoZWlnaHQFAmRuBAJkcAkAZAIJAGgCBQJkbwUCZGwFAmRtBQJkcAECZHEDAmJHAmJPAmRyBAJkcwkBAmNGAAQCY0kIBQJkcwJfMQQCY0oIBQJkcwJfMgQCYVkJARFAZXh0ck5hdGl2ZSgxMDYyKQEFAmJPBAJkdAkBAmNPAgUCYkcFAmJPBAJkdQMJAAACBQJkdAAABQNuaWwEAmRnAwUCZHIFAmR0CQEBLQEFAmR0BAJkdgkBAmRmAgUCYkcFAmRnBAJkcAkBAmRqAgUCYkcFAmJPBAJkdwkAzAgCCQEMSW50ZWdlckVudHJ5AgkBAmJMAwUCYkcFAmFZBQJjSQUGaGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQECYksDBQJiRwUCYVkFAmNJBQJkcAUDbmlsCQDOCAIFAmR2BQJkdwUCZHUBAmR4AgJiRwJiTwQCZHkJAQJjRgAEAmNJCAUCZHkCXzEEAmNKCAUCZHkCXzIEAmFZCQERQGV4dHJOYXRpdmUoMTA2MikBBQJiTwQCZHoJAQJiTQMFAmJHBQJhWQUCY0kEAmRBCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFAmR6AAAEAmRCCQECYkoDBQJiRwUCYVkFAmNJBAJkQwkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQJkQgAABAJkcAkBAmRqAgUCYkcFAmJPBAJkZQkBAmNaAQUCYkcEAmRECQBlAgUCZHAFAmRBBAJkRQkAZQIFAmRlBQJkQwkAlQoDCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQJkegUCZHAJAMwIAgkBDEludGVnZXJFbnRyeQIFAmRCBQJkZQUDbmlsBQJkRAUCZEUBAmRGAAQCZEcJAQFzAgUCYlEJAQJhaAAEAmRICQCaCAIFBHRoaXMJAQJhawAEAmRJCQCaCAIFBHRoaXMJAQJhbAAEAmRKCQEBcwIFAmJRCQECYW4ABAJkSwMJAGYCBQZoZWlnaHQFAmRKBQJkSgUGaGVpZ2h0BAJkTAQCYUoFAmRIAwkAAQIFAmFKAgNJbnQEAmRNBQJhSgkAlgMBCQDMCAIJAGUCBQJkSwUCZE0JAMwIAgAABQNuaWwDCQABAgUCYUoCBFVuaXQAAAkAAgECC01hdGNoIGVycm9yBAJkTgkAaQIJAGgCBQJkRwkAZQIFAmJYAAEFAmJYBAJkTwkBC3ZhbHVlT3JFbHNlAgUCZEkAAAQCZFAJAGQCCQBoAgUCZE4FAmRMBQJkTwkAlAoCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQECYWwABQJkUAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBAmFrAAUGaGVpZ2h0BQNuaWwFAmRQAQJkUQMCYkcCYk8CZFIEAmFZCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUCYk8JAQFqAQIUaW52YWxpZCB1c2VyIGFkZHJlc3MEAmJyCQECYloBBQJhWQMJAAACBQJicgUCYnIEAmRTAgVlbXB0eQQCZFQDCQECIT0CBQJiRwUCZFMEAmRVCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUCYlAJAQFRAQUCYkcJAQFqAQkArAICAhV1bnN1cHBvcnRlZCBscCBhc3NldCAFAmJHCQERQGV4dHJOYXRpdmUoMTA1MCkCBQJiUAkBAVMBBQJkVQMFAmRSAAAJAQFsAQkArAICAihub3QgcmVhZG9ubHkgbW9kZTogdW5zdXBwb3J0ZWQgbHAgYXNzZXQgBQJiRwQCZFYJAQJicwIFAmJyBQJiRwQCZFcJAQJicQEFAmJyBAJkWAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQJkVgkBAXACBQR0aGlzBQJkVwQCZFAICQECZEYAAl8yBAJkWQkAZQIFAmRQBQJkWAMJAGYCAAAFAmRZCQEBbAECEndyb25nIGNhbGN1bGF0aW9ucwQCZFoJAQJkeAIFAmJHBQJiTwQCZWEIBQJkWgJfMQQCZWIIBQJkWgJfMgQCZWMIBQJkWgJfMwQCZWQJAGsDBQJkWQUCZFQFAWQEAmVlAwkAAAIFAmVjAAAAAAkAawMFAmVkBQJlYgUCZWMEAmVmCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIFAmRWBQJkUAUDbmlsBQJlYQQCZWcJALkJAgkAzAgCCQCkAwEFAmRYCQDMCAIJAKQDAQUCZFkJAMwIAgkApAMBBQJkVAkAzAgCCQCkAwEFAmViCQDMCAIJAKQDAQUCZWMFA25pbAIBOgkAlQoDBQJlZQUCZWYFAmVnCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQJlaAICYU8CYmcEAmVpCQDYBAEFAmF5AwkBAiE9AgkAkAMBCAUCYU8IcGF5bWVudHMAAQkBAWwBAjRpbnZhbGlkIHBheW1lbnQgLSBleGFjdCBvbmUgcGF5bWVudCBtdXN0IGJlIGF0dGFjaGVkBAJjRAkAkQMCCAUCYU8IcGF5bWVudHMAAAQCZWoIBQJjRAZhbW91bnQDCQECIT0CBQJheQkBBXZhbHVlAQgFAmNEB2Fzc2V0SWQJAQFsAQkArAICCQCsAgICHmludmFsaWQgYXNzZXQgaXMgaW4gcGF5bWVudCAtIAUCZWkCDCBpcyBleHBlY3RlZAQCZWsJAQJiagAEAmFZCAUCYU8GY2FsbGVyBAJiTwkApQgBBQJhWQQCZWwJAQlpc0RlZmluZWQBCQCiCAEJAQJiawEFAmJPBAJlbQMFAmVsCQEFdmFsdWUBCQCiCAEJAQJiawEFAmJPCQCkAwEJAQFzAgUEdGhpcwUCZWsEAmJyCQENcGFyc2VJbnRWYWx1ZQEFAmVtBAJjawUGaGVpZ2h0AwMJAGYCBQJhegUCZWoJAQIhPQIFAmFZBQJiVAcJAQFsAQkArAICAiJhbW91bnQgaXMgbGVzcyB0aGVuIG1pbkxvY2tBbW91bnQ9CQCkAwEFAmF6AwkAZgIFAmFBBQJiZwkBAWwBCQCsAgICLXBhc3NlZCBkdXJhdGlvbiBpcyBsZXNzIHRoYW4gbWluTG9ja0R1cmF0aW9uPQkApAMBBQJhQQMJAGYCBQJiZwUCYUIJAQFsAQkArAICAjBwYXNzZWQgZHVyYXRpb24gaXMgZ3JlYXRlciB0aGFuIG1heExvY2tEdXJhdGlvbj0JAKQDAQUCYUIDCQECIT0CCQBqAgUCYmcFAmFFAAAJAQFsAQkArAICAixkdXJhdGlvbiBtdXN0IGJlIG11bHRpcGxlIG9mIGxvY2tTdGVwQmxvY2tzPQkApAMBBQJhRQQCZW4JAGsDBQJlagUCYmcFAmFCBAJlbwkBAmNhAAQCZFcJAQJicQEFAmJyBAJkUAgJAQJkRgACXzIEAmVwCQECY0UBBQJhWQQCZXEJAPwHBAUCYlMCEXJlZnJlc2hVc2VyUmV3YXJkCQDMCAIIBQJhWQVieXRlcwkAzAgCBQJicgUDbmlsBQNuaWwDCQAAAgUCZXEFAmVxBAJlcgMFAmVsBQNuaWwJAMwIAgkBDEludGVnZXJFbnRyeQIFAmVrCQBkAgUCYnIAAQkAzAgCCQELU3RyaW5nRW50cnkCCQECYmsBBQJiTwUCZW0JAMwIAgkBC1N0cmluZ0VudHJ5AgkBAmJsAQUCZW0FAmJPBQNuaWwJAJQKAgkAzggCCQDNCAIJAM4IAgkAzggCBQJlcgkBAmNBBwUCYVkIBQJhTw10cmFuc2FjdGlvbklkBQJlagUCY2sFAmJnBQJlbgAACQECY24EBQJlagUCYmcAAQMFAmVsAAAAAQkBAmNoBwIEbG9jawUCYk8FAmVqBQJjawUCYmcFAmVuBQJhTwkAzAgCCQEMSW50ZWdlckVudHJ5AgUCZFcFAmRQCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQECYnkACQBkAgUCZW8FAmVuCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQECYmMBBQJhWQkAZAIFAmVwBQJlbgUDbmlsBQJlbgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECZXMCAmFZAmV0BAJldQkBAmJiAgUCYVkFAmV0BAJldgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFAmV1BQJhUgQCY2sJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJldQUCYVMEAmV3CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUCZXUFAmFUBAJleAkAZAIFAmNrBQJldwQCYmkJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJldQUCYVcEAmV5CQBpAgkAZQIFBmhlaWdodAUCY2sFAmFEBAJlegkAvAIDCQC2AgEFAmV5CQC5AgIJALYCAQkAaAIFAWkFAmFEBQFoCQC2AgEFAmV3BAJlQQMJAGYCBQZoZWlnaHQFAmV4BQJldgkAoAMBCQC8AgMJALYCAQUCZXYJALgCAgUBaAkAdgYJALYCAQAFAAEFAmV6BQFmBQFmBQRET1dOBQFoBAJlQgkAZQIFAmVBBQJiaQUCZUIRAmFPAQdsb2NrUmVmAwJiZwJlQwJlRAQCZUUJAQJhSAADCQAAAgUCZUUFAmVFBAJlRgkBAmVoAgUCYU8FAmJnBAJlRwgFAmVGAl8xBAJlbggFAmVGAl8yBAJlSAkApQgBCAUCYU8GY2FsbGVyBAJlSQMDCQAAAgUCZUMCAAYJAAACBQJlRAEABQR1bml0CQD8BwQFAXoCCmNyZWF0ZVBhaXIJAMwIAgUBQwkAzAgCBQJlQwkAzAgCBQJlSAkAzAgCBQJlRAUDbmlsBQNuaWwDCQAAAgUCZUkFAmVJBAJlSgkA/AcEBQJhQwIWdXBkYXRlUmVmZXJyYWxBY3Rpdml0eQkAzAgCCQClCAEIBQJhTwZjYWxsZXIJAMwIAgUCZW4FA25pbAUDbmlsAwkAAAIFAmVKBQJlSgkAlAoCBQJlRwUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgJhTwEEbG9jawECYmcEAmVFCQECYUgAAwkAAAIFAmVFBQJlRQQCZUsJAQJlaAIFAmFPBQJiZwQCZUcIBQJlSwJfMQQCZW4IBQJlSwJfMgQCZUoJAPwHBAUCYUMCFnVwZGF0ZVJlZmVycmFsQWN0aXZpdHkJAMwIAgkApQgBCAUCYU8GY2FsbGVyCQDMCAIFAmVuBQNuaWwFA25pbAMJAAACBQJlSgUCZUoJAJQKAgUCZUcFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4CYU8BDGNsYWltV3hCb29zdAICYkcCYk8EAmVFCQECYUgAAwkAAAIFAmVFBQJlRQMJAQIhPQIFAmJSCAUCYU8GY2FsbGVyCQEBbAECEnBlcm1pc3Npb25zIGRlbmllZAQCZUwJAQJkUQMFAmJHBQJiTwcEAmVNCAUCZUwCXzEEAmVmCAUCZUwCXzIEAmVnCAUCZUwCXzMJAJQKAgUCZWYJAMwIAgUCZU0FA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgJhTwEUY2xhaW1XeEJvb3N0UkVBRE9OTFkCAmJHAmJPBAJlTgkBAmRRAwUCYkcFAmJPBgQCZU0IBQJlTgJfMQQCZWYIBQJlTgJfMgQCZWcIBQJlTgJfMwkAlAoCBQNuaWwJAMwIAgUCZU0JAMwIAgUCZWcFA25pbAJhTwEGdW5sb2NrAQJlTwQCZUUJAQJhSAADCQAAAgUCZUUFAmVFBAJhWQgFAmFPBmNhbGxlcgQCYk8JAKUIAQUCYVkEAmV0AwkAAAIFAmVPAgAFBHVuaXQJANkEAQUCZU8EAmV1CQECYmICBQJhWQUCZXQEAmV2CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUCZXUFAmFSBAJjawkBDXBhcnNlSW50VmFsdWUBCQCRAwIFAmV1BQJhUwQCZXcJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJldQUCYVQEAmJpCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUCZXUFAmFXBAJiaAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFAmV1BQJhVgQCZXkJAGkCCQBlAgUGaGVpZ2h0BQJjawUCYUQEAmVCCQECZXMCBQJhWQUCZXQEAmVQCQCXAwEJAMwIAgkAawMFAmVCBQJldwUCYUIJAMwIAgUCYmgFA25pbAQCZVEJAQF2AgkAZQIFAmJoBQJlUAIMZ3d4UmVtYWluaW5nBAJlUgkBAmNiAQUCYVkDCQBnAgAABQJlQgkBAWwBAhFub3RoaW5nIHRvIHVubG9jawQCZW8JAQJjYQAEAmVwCQECY0UBBQJhWQQCZVMJAQF2AgkAZQIFAmVwBQJlUAIVdXNlckd3eEFtb3VudFRvdGFsTmV3AwkAZgIFAmVSBQJlUwkBAWwBCQCsAgICE2xvY2tlZCBnd3ggYW1vdW50OiAJAKQDAQUCZVIEAmJyCQENcGFyc2VJbnRWYWx1ZQEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQECYmsBBQJiTwkBAWoBAhNpbnZhbGlkIHVzZXIgbnVtYmVyBAJlcQkA/AcEBQJiUwIRcmVmcmVzaFVzZXJSZXdhcmQJAMwIAggFAmFZBWJ5dGVzCQDMCAIFAmJyBQNuaWwFA25pbAMJAAACBQJlcQUCZXEJAM4IAgkAzQgCCQDNCAIJAM4IAgkBAmNBBwUCYVkFAmV0BQJldgUCY2sFAmV3BQJlUQkAZAIFAmJpBQJlQgkBAmNuBAkBAS0BBQJlQgAAAAAAAAkBAmNoBwIGdW5sb2NrBQJiTwUCZUIFAmNrBQJldwUCZVAFAmFPCQEOU2NyaXB0VHJhbnNmZXIDBQJhWQUCZUIFAmF5CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQECYnkACQEBdgIJAGUCBQJlbwUCZVACCGd3eFRvdGFsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQECYmMBBQJhWQUCZVMFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgJhTwETZ3d4VXNlckluZm9SRUFET05MWQECYk8EAmFZCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUCYk8JAQFqAQIUaW52YWxpZCB1c2VyIGFkZHJlc3MEAmJoCQECY0UBBQJhWQkAlAoCBQNuaWwJAMwIAgUCYmgFA25pbAJhTwEXdXNlck1heER1cmF0aW9uUkVBRE9OTFkBAmJPCQCUCgIFA25pbAkAlAoCAgRsb2NrBQJhQgJhTwEgZ2V0VXNlckd3eEFtb3VudEF0SGVpZ2h0UkVBRE9OTFkCAmJPAmVUBAJhWQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFAmJPCQEBagECFGludmFsaWQgdXNlciBhZGRyZXNzBAJiaAkBAmNFAQUCYVkJAJQKAgUDbmlsBQJiaAJhTwEQZ2V0VXNlckd3eEFtb3VudAECYk8EAmFZCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUCYk8JAQFqAQIUaW52YWxpZCB1c2VyIGFkZHJlc3MEAmJoCQECY0UBBQJhWQkAlAoCBQNuaWwFAmJoAmFPARNnZXRHd3hUb3RhbFJFQURPTkxZAAkAlAoCBQNuaWwJAQJjYQACYU8BFW9uQm9vc3RFbWlzc2lvblVwZGF0ZQAEAmVFCQECYUgAAwkAAAIFAmVFBQJlRQQCZVUDCQAAAggFAmFPBmNhbGxlcgUCYlEGCQECYU4BBQJhTwMJAAACBQJlVQUCZVUJAQJkRgAJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4CYU8BEm9uU3Rha2VkVm90ZVVwZGF0ZQMCYkcCYk8CZHIEAmVFCQECYUgAAwkAAAIFAmVFBQJlRQQCZVUDCQAAAggFAmFPBmNhbGxlcgUCYlIGCQECYU4BBQJhTwMJAAACBQJlVQUCZVUEAmR1CQECZHEDBQJiRwUCYk8FAmRyCQCUCgIFAmR1BQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAmFPAR1nZXRWb3RpbmdSZXN1bHRTdGFrZWRSRUFET05MWQECYkcJAJQKAgUDbmlsCQECY1YBBQJiRwJhTwElZ2V0Vm90aW5nUmVzdWx0U3Rha2VkSW50ZWdyYWxSRUFET05MWQECYkcJAJQKAgUDbmlsCQECY1oBBQJiRwJhTwEcZ2V0VXNlclZvdGVGaW5hbGl6ZWRSRUFET05MWQICYkcCYk8JAJQKAgUDbmlsCQECY08CBQJiRwUCYk8CYU8BIWdldFVzZXJWb3RlU3Rha2VkSW50ZWdyYWxSRUFET05MWQICYkcCYk8JAJQKAgUDbmlsCQECZGoCBQJiRwUCYk8CYU8BB3N1c3BlbmQBAXcEAmVVCQECYU4BBQJhTwMJAAACBQJlVQUCZVUJAJQKAgkAzAgCCQEMQm9vbGVhbkVudHJ5AgUCYUYFAXcFA25pbAUBdwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgECZVYBAmVXAAQCZVgEAmFKCQECYUwAAwkAAQIFAmFKAgpCeXRlVmVjdG9yBAJhUQUCYUoFAmFRAwkAAQIFAmFKAgRVbml0CAUCZVYPc2VuZGVyUHVibGljS2V5CQACAQILTWF0Y2ggZXJyb3IJAPQDAwgFAmVWCWJvZHlCeXRlcwkAkQMCCAUCZVYGcHJvb2ZzAAAFAmVYVftOcw==", "height": 2744756, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: BE7P4d1VrWjaXjVwVjZhZvHBSuLE16cAiF9H8fsC8HEq Next: ALkviD9fwAUxiJqz1Ny53Dun1JkugHS5rUb4nCH6Cttv Diff:
OldNewDifferences
99
1010 let POOLWEIGHTMULT = MULT8
1111
12-func wrapErr (msg) = makeString(["boosting.ride:", msg], " ")
12+let contractFilename = "boosting.ride"
13+
14+let SCALE18 = 18
15+
16+let MULT18 = 1000000000000000000
17+
18+let MULT18BI = toBigInt(MULT18)
19+
20+let DECAY_CONSTANT = 8
21+
22+func wrapErr (msg) = makeString([contractFilename, ": ", msg], "")
1323
1424
1525 func throwErr (msg) = throw(wrapErr(msg))
1626
1727
18-func strf (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
28+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
1929
2030
21-func ioz (address,key) = valueOrElse(getInteger(address, key), 0)
31+func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
2232
2333
24-func iod (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
34+func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
2535
2636
27-func iof (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
37+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
2838
2939
3040 func abs (val) = if ((0 > val))
3242 else val
3343
3444
35-func aal (val) = match val {
36- case valAnyLyst: List[Any] =>
37- valAnyLyst
38- case _ =>
39- throwErr("fail to cast into List[Any]")
40-}
41-
42-
43-func ai (val) = match val {
44- case valInt: Int =>
45- valInt
46- case _ =>
47- throwErr("fail to cast into Int")
48-}
45+func ensurePositive (v,m) = if ((v >= 0))
46+ then v
47+ else throwErr((valueOrElse(m, "value") + " should be positive"))
4948
5049
5150 func keyReferralsContractAddress () = makeString(["%s%s", "config", "referralsContractAddress"], SEP)
5251
5352
54-let referralsContractAddressOrFail = addressFromStringValue(strf(this, keyReferralsContractAddress()))
53+let referralsContractAddressOrFail = addressFromStringValue(getStringOrFail(this, keyReferralsContractAddress()))
5554
5655 let keyReferralProgramName = makeString(["%s%s", "referral", "programName"], SEP)
5756
8786 func keyFactoryCfg () = "%s__factoryConfig"
8887
8988
90-func keyFactoryLpList () = "%s__lpTokensList"
91-
92-
9389 func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
9490
9591
9995 func keyFactoryPoolWeightHistory (poolAddress,num) = ((("%s%s__poolWeight__" + poolAddress) + "__") + toString(num))
10096
10197
102-func readFactoryAddressOrFail () = addressFromStringValue(strf(this, keyFactoryAddress()))
98+func readFactoryAddressOrFail () = addressFromStringValue(getStringOrFail(this, keyFactoryAddress()))
10399
104100
105-func readLpList () = split(valueOrElse(getString(readFactoryAddressOrFail(), keyFactoryLpList()), ""), SEP)
106-
107-
108-func readFactoryCfgOrFail (factory) = split(strf(factory, keyFactoryCfg()), SEP)
101+func readFactoryCfgOrFail (factory) = split(getStringOrFail(factory, keyFactoryCfg()), SEP)
109102
110103
111104 func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
147140 func keyEmissionEndBlock () = "%s%s__emission__endBlock"
148141
149142
150-func keyNextPeriod () = "%s__nextPeriod"
151-
152-
153-func keyGwxRewardEmissionStartHeight () = "%s%s__gwxRewardEmissionPart__startHeight"
154-
155-
156143 let IdxCfgAssetId = 1
157144
158145 let IdxCfgMinLockAmount = 2
163150
164151 let IdxCfgMathContract = 5
165152
153+let IdxCfgBlocksInPeriod = 6
154+
155+let IdxCfgLockStepBlocks = 7
156+
166157 func keyConfig () = "%s__config"
167158
168159
169-func readConfigArrayOrFail () = split(strf(this, keyConfig()), SEP)
160+func readConfigArrayOrFail () = split(getStringOrFail(this, keyConfig()), SEP)
170161
171162
172-let mathContract = addressFromStringValue(readConfigArrayOrFail()[IdxCfgMathContract])
163+let cfgArray = readConfigArrayOrFail()
173164
174-func formatConfigS (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = makeString(["%s%d%d%d", assetId, minLockAmount, minLockDuration, maxLockDuration, mathContract], SEP)
165+let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
175166
167+let minLockAmount = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockAmount]), wrapErr("invalid min lock amount"))
176168
177-func formatConfig (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = formatConfigS(assetId, toString(minLockAmount), toString(minLockDuration), toString(maxLockDuration), mathContract)
169+let minLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockDuration]), wrapErr("invalid min lock duration"))
170+
171+let maxLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMaxLockDuration]), wrapErr("invalid max lock duration"))
172+
173+let mathContract = valueOrErrorMessage(addressFromString(cfgArray[IdxCfgMathContract]), wrapErr("invalid math contract address"))
174+
175+let blocksInPeriod = valueOrErrorMessage(parseInt(cfgArray[IdxCfgBlocksInPeriod]), wrapErr("invalid blocks in period"))
176+
177+let lockStepBlocks = valueOrErrorMessage(parseInt(cfgArray[IdxCfgLockStepBlocks]), wrapErr("invalid lock step blocks"))
178+
179+let keySuspension = "%s__suspension"
180+
181+let isSuspended = valueOrElse(getBoolean(this, keySuspension), false)
182+
183+func throwIfSuspended () = if (!(isSuspended))
184+ then true
185+ else throwErr("suspended")
178186
179187
180188 func getManagerVaultAddressOrThis () = match getString(keyManagerVaultAddress()) {
215223 }
216224
217225
218-let IdxLockUserNum = 1
226+let IdxLockAmount = 1
219227
220-let IdxLockAmount = 2
228+let IdxLockStart = 2
221229
222-let IdxLockStart = 3
230+let IdxLockDuration = 3
223231
224-let IdxLockDuration = 4
232+let IdxLockLastUpdateTimestamp = 4
225233
226-let IdxLockParamK = 5
234+let IdxLockGwxAmount = 5
227235
228-let IdxLockParamB = 6
236+let IdxLockWxClaimed = 6
229237
230-func keyLockParamsRecord (userAddress) = makeString(["%s%s__lock", userAddress], SEP)
238+func keyLockParamsRecord (userAddress,txId) = makeString(["%s%s%s__lock", toString(userAddress), match txId {
239+ case b: ByteVector =>
240+ toBase58String(b)
241+ case _: Unit =>
242+ "legacy"
243+ case _ =>
244+ throw("Match error")
245+}], SEP)
231246
232247
233-func readLockParamsRecordOrFail (userAddress) = split(strf(this, keyLockParamsRecord(userAddress)), SEP)
248+func readLockParamsRecordOrFail (userAddress,txId) = split(getStringOrFail(this, keyLockParamsRecord(userAddress, txId)), SEP)
234249
235250
236-func formatLockParamsRecordS (userNum,amount,start,duration,paramK,paramB,lastUpdTimestamp,gwxAmount) = makeString(["%d%d%d%d%d%d%d%d", userNum, amount, start, duration, paramK, paramB, lastUpdTimestamp, gwxAmount], SEP)
251+func keyUserGwxAmountTotal (userAddress) = makeString(["%s%s__gwxAmountTotal", toString(userAddress)], SEP)
237252
238253
239-func formatLockParamsRecord (userNum,amount,start,duration,paramK,paramB,gwxAmount) = formatLockParamsRecordS(userNum, toString(amount), toString(start), toString(duration), toString(paramK), toString(paramB), toString(lastBlock.timestamp), toString(gwxAmount))
254+func formatLockParamsRecord (amount,start,duration,gwxAmount,wxClaimed) = makeString(["%d%d%d%d%d%d", toString(amount), toString(start), toString(duration), toString(lastBlock.timestamp), toString(gwxAmount), toString(wxClaimed)], SEP)
240255
241256
242257 func keyNextUserNum () = "%s__nextUserNum"
246261
247262
248263 func keyNum2UserMapping (num) = makeString(["%s%s%s__mapping__num2user", num], SEP)
249-
250-
251-func keyLockParamUserAmount (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "amount"], SEP)
252-
253-
254-func keyLockParamStartBlock (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "start"], SEP)
255-
256-
257-func keyLockParamDuration (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "duration"], SEP)
258-
259-
260-func keyLockParamK (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "k"], SEP)
261-
262-
263-func keyLockParamB (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "b"], SEP)
264-
265-
266-func keyLockParamByPeriodK (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "k", period], SEP)
267-
268-
269-func keyLockParamByPeriodB (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "b", period], SEP)
270264
271265
272266 func keyLockParamTotalAmount () = "%s%s__stats__activeTotalLocked"
281275 func keyStatsUsersCount () = "%s%s__stats__activeUsersCount"
282276
283277
284-func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum], SEP)
278+func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum)], SEP)
285279
286280
287-func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum, lpAssetId], SEP)
281+func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum), lpAssetId], SEP)
288282
289283
290-func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", userNum], SEP)
284+func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", toString(userNum)], SEP)
291285
292286
293287 func keyTotalMaxBoostINTEGRAL () = "%s%s__maxBoostInt__total"
294288
295289
296-func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", userNum], SEP)
290+func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", toString(userNum)], SEP)
297291
298292
299-func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", userNum], SEP)
293+func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", toString(userNum)], SEP)
300294
301295
302-func keyTotalCachedGwx () = "%s%s__gwxCached__total"
303-
304-
305-func keyTotalCachedGwxCorrective () = "%s__gwxCachedTotalCorrective"
296+func keyGwxTotal () = "%s%s__gwx__total"
306297
307298
308299 func keyVote (amountAssetId,priceAssetId,address,epoch) = makeString(["%s%s%s%s%d", "vote", amountAssetId, priceAssetId, toString(address), toString(epoch)], SEP)
354345
355346 let votingEmissionContract = addressFromStringValue(getStringValue(factoryContract, keyVotingEmissionContract))
356347
348+let keyVotingEmissionRateContract = makeString(["%s", "votingEmissionRateContract"], SEP)
349+
357350 let boostCoeff = {
358351 let @ = invoke(emissionContract, "getBoostCoeffREADONLY", nil, nil)
359352 if ($isInstanceOf(@, "Int"))
361354 else throw(($getType(@) + " couldn't be cast to Int"))
362355 }
363356
364-func getTotalCachedGwx (correct) = {
365- let currentEpochUi = getIntegerValue(votingEmissionContract, keyCurrentEpochUi())
366- let keyTargetEpoch = makeString(["%s%s", "totalCachedGwxCorrection__activationEpoch"], SEP)
367- let targetEpochOption = getInteger(this, keyTargetEpoch)
368- let totalCachedGwxRaw = valueOrElse(getInteger(this, keyTotalCachedGwx()), 0)
369- let isCorrectionActivated = if (isDefined(targetEpochOption))
370- then (currentEpochUi >= value(targetEpochOption))
371- else false
372- let corrective = if (if (isCorrectionActivated)
373- then correct
374- else false)
375- then valueOrElse(getInteger(this, keyTotalCachedGwxCorrective()), 0)
376- else 0
377- max([0, (totalCachedGwxRaw + corrective)])
357+func userNumberByAddressOrFail (userAddress) = match getString(this, keyUser2NumMapping(toString(userAddress))) {
358+ case s: String =>
359+ valueOrErrorMessage(parseInt(s), wrapErr("invalid user number"))
360+ case _: Unit =>
361+ throwErr("invalid user")
362+ case _ =>
363+ throw("Match error")
364+}
365+
366+
367+func getGwxAmountTotal () = valueOrElse(getInteger(this, keyGwxTotal()), 0)
368+
369+
370+func getLockedGwxAmount (userAddress) = {
371+ let functionName = "getLockedGwxAmount"
372+ let votingEmissionRateContract = valueOrErrorMessage( match getString(votingEmissionContract, keyVotingEmissionRateContract) {
373+ case _: Unit =>
374+ unit
375+ case s: String =>
376+ addressFromString(s)
377+ case _ =>
378+ throw("Match error")
379+ }, wrapErr("invalid voting emission rate address"))
380+ let lockedVotingEmissionRate = {
381+ let @ = invoke(votingEmissionContract, functionName, [toString(userAddress)], nil)
382+ if ($isInstanceOf(@, "Int"))
383+ then @
384+ else throw(($getType(@) + " couldn't be cast to Int"))
385+ }
386+ let lockedVotingEmission = {
387+ let @ = invoke(votingEmissionRateContract, functionName, [toString(userAddress)], nil)
388+ if ($isInstanceOf(@, "Int"))
389+ then @
390+ else throw(($getType(@) + " couldn't be cast to Int"))
391+ }
392+ let locked = max([lockedVotingEmissionRate, lockedVotingEmission])
393+ locked
378394 }
379395
380396
381-func HistoryEntry (type,user,amount,lockStart,duration,k,b,i) = {
397+func HistoryEntry (type,user,amount,lockStart,duration,gwxAmount,i) = {
382398 let historyKEY = makeString(["%s%s%s%s__history", type, user, toBase58String(i.transactionId)], SEP)
383- let historyDATA = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(amount), toString(lockStart), toString(duration), toString(k), toString(b)], SEP)
399+ let historyDATA = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(amount), toString(lockStart), toString(duration), toString(gwxAmount)], SEP)
384400 StringEntry(historyKEY, historyDATA)
385401 }
386402
390406 let locksCountKEY = keyStatsLocksCount()
391407 let usersCountKEY = keyStatsUsersCount()
392408 let totalAmountKEY = keyLockParamTotalAmount()
393- let locksDurationSumInBlocks = ioz(this, locksDurationSumInBlocksKEY)
394- let locksCount = ioz(this, locksCountKEY)
395- let usersCount = ioz(this, usersCountKEY)
396- let totalAmount = ioz(this, totalAmountKEY)
409+ let locksDurationSumInBlocks = getIntOrZero(this, locksDurationSumInBlocksKEY)
410+ let locksCount = getIntOrZero(this, locksCountKEY)
411+ let usersCount = getIntOrZero(this, usersCountKEY)
412+ let totalAmount = getIntOrZero(this, totalAmountKEY)
397413 [IntegerEntry(locksDurationSumInBlocksKEY, (locksDurationSumInBlocks + durationInc)), IntegerEntry(locksCountKEY, (locksCount + lockCountInc)), IntegerEntry(usersCountKEY, (usersCount + usersCountInc)), IntegerEntry(totalAmountKEY, (totalAmount + totalLockedInc))]
398414 }
399415
400416
401-func calcGwxAmount (kRaw,bRaw,h) = {
402- let SCALE = 1000
403- (((kRaw * h) + bRaw) / SCALE)
404- }
405-
406-
407-func LockParamsEntry (userAddress,userNum,amount,start,duration,k,b,period) = {
408- let userAmountKEY = keyLockParamUserAmount(userNum)
409- let startBlockKEY = keyLockParamStartBlock(userNum)
410- let durationKEY = keyLockParamDuration(userNum)
411- let kKEY = keyLockParamK(userNum)
412- let bKEY = keyLockParamB(userNum)
413- let kByPeriodKEY = keyLockParamByPeriodK(userNum, period)
414- let bByPeriodKEY = keyLockParamByPeriodB(userNum, period)
415- let gwxAmount = calcGwxAmount(k, b, height)
416-[IntegerEntry(userAmountKEY, amount), IntegerEntry(startBlockKEY, start), IntegerEntry(durationKEY, duration), IntegerEntry(kKEY, k), IntegerEntry(bKEY, b), IntegerEntry(kByPeriodKEY, k), IntegerEntry(bByPeriodKEY, b), StringEntry(keyLockParamsRecord(userAddress), formatLockParamsRecord(userNum, amount, start, duration, k, b, gwxAmount))]
417- }
417+func LockParamsEntry (userAddress,txId,amount,start,duration,gwxAmount,wxClaimed) = [StringEntry(keyLockParamsRecord(userAddress, txId), formatLockParamsRecord(amount, start, duration, gwxAmount, wxClaimed))]
418418
419419
420420 func extractOptionalPaymentAmountOrFail (i,expectedAssetId) = if ((size(i.payments) > 1))
429429 }
430430
431431
432-func calcUserGwxAmountAtHeight (userAddress,targetHeight) = {
433- let EMPTY = "empty"
434- let user2NumMappingKEY = keyUser2NumMapping(userAddress)
435- let userNum = valueOrElse(getString(user2NumMappingKEY), EMPTY)
436- let k = valueOrElse(getInteger(keyLockParamK(userNum)), 0)
437- let b = valueOrElse(getInteger(keyLockParamB(userNum)), 0)
438- let gwxAmountCalc = calcGwxAmount(k, b, targetHeight)
439- let gwxAmount = if ((0 > gwxAmountCalc))
440- then 0
441- else gwxAmountCalc
442- gwxAmount
443- }
444-
445-
446-func calcCurrentGwxAmount (userAddress) = calcUserGwxAmountAtHeight(userAddress, height)
432+func getUserGwxAmountTotal (userAddress) = valueOrElse(getInteger(this, keyUserGwxAmountTotal(userAddress)), 0)
447433
448434
449435 func getVotingEmissionEpochInfo () = {
450- let $t01718617476 = {
436+ let $t01468614976 = {
451437 let currentEpochUi = value(getInteger(votingEmissionContract, keyCurrentEpochUi()))
452438 let lastFinalizedEpoch = (currentEpochUi - 1)
453439 if ((0 > lastFinalizedEpoch))
454440 then throwErr("invalid epoch")
455441 else $Tuple2(currentEpochUi, lastFinalizedEpoch)
456442 }
457- let currentEpochUi = $t01718617476._1
458- let lastFinalizedEpoch = $t01718617476._2
443+ let currentEpochUi = $t01468614976._1
444+ let lastFinalizedEpoch = $t01468614976._2
459445 let currentEpochStartHeight = value(getInteger(votingEmissionContract, keyStartHeightByEpoch(currentEpochUi)))
460446 $Tuple2(lastFinalizedEpoch, currentEpochStartHeight)
461447 }
488474
489475 func getUserVoteFinalized (lpAssetIdStr,userAddressStr) = {
490476 let userAddress = addressFromStringValue(userAddressStr)
491- let $t01816718247 = getVotingEmissionEpochInfo()
492- let lastFinalizedEpoch = $t01816718247._1
493- let currentEpochStartHeight = $t01816718247._2
494- let $t01825018325 = getPoolAssetsByLpAssetId(lpAssetIdStr)
495- let amountAssetId = $t01825018325._1
496- let priceAssetId = $t01825018325._2
477+ let $t01566715747 = getVotingEmissionEpochInfo()
478+ let lastFinalizedEpoch = $t01566715747._1
479+ let currentEpochStartHeight = $t01566715747._2
480+ let $t01575015825 = getPoolAssetsByLpAssetId(lpAssetIdStr)
481+ let amountAssetId = $t01575015825._1
482+ let priceAssetId = $t01575015825._2
497483 let userVoteKey = keyVote(amountAssetId, priceAssetId, userAddress, lastFinalizedEpoch)
498484 let userVote = valueOrElse(getInteger(votingEmissionContract, userVoteKey), 0)
499485 userVote
510496
511497
512498 func getVotingResultStaked (lpAssetIdStr) = {
513- let $t01886918949 = getVotingEmissionEpochInfo()
514- let lastFinalizedEpoch = $t01886918949._1
515- let currentEpochStartHeight = $t01886918949._2
499+ let $t01636916449 = getVotingEmissionEpochInfo()
500+ let lastFinalizedEpoch = $t01636916449._1
501+ let currentEpochStartHeight = $t01636916449._2
516502 let votingResultStakedStart = valueOrElse(getInteger(votingEmissionContract, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), 0)
517503 let votingResultStaked = valueOrElse(getInteger(this, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), votingResultStakedStart)
518504 votingResultStaked
520506
521507
522508 func getVotingResultStakedIntegral (lpAssetIdStr) = {
523- let $t01931119391 = getVotingEmissionEpochInfo()
524- let lastFinalizedEpoch = $t01931119391._1
525- let currentEpochStartHeight = $t01931119391._2
509+ let $t01681116891 = getVotingEmissionEpochInfo()
510+ let lastFinalizedEpoch = $t01681116891._1
511+ let currentEpochStartHeight = $t01681116891._2
526512 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
527513 let votingResultStakedIntegralPrev = valueOrElse(getInteger(this, keyVotingResultStakedIntegral(lpAssetIdStr, lastFinalizedEpoch)), 0)
528514 let votingResultStakedLastUpdateHeight = valueOrElse(getInteger(this, keyVotingResultStakedLastUpdateHeight(lpAssetIdStr, lastFinalizedEpoch)), currentEpochStartHeight)
533519
534520
535521 func refreshVotingResultStakedIntegral (lpAssetIdStr,stakedVoteDelta) = {
536- let $t02022820308 = getVotingEmissionEpochInfo()
537- let lastFinalizedEpoch = $t02022820308._1
538- let currentEpochStartHeight = $t02022820308._2
522+ let $t01772817808 = getVotingEmissionEpochInfo()
523+ let lastFinalizedEpoch = $t01772817808._1
524+ let currentEpochStartHeight = $t01772817808._2
539525 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
540526 let votingResultStakedNew = (votingResultStaked + stakedVoteDelta)
541527 let votingResultStakedIntegral = getVotingResultStakedIntegral(lpAssetIdStr)
544530
545531
546532 func getUserVoteStakedIntegral (lpAssetIdStr,userAddressStr) = {
547- let $t02091920999 = getVotingEmissionEpochInfo()
548- let lastFinalizedEpoch = $t02091920999._1
549- let currentEpochStartHeight = $t02091920999._2
533+ let $t01841918499 = getVotingEmissionEpochInfo()
534+ let lastFinalizedEpoch = $t01841918499._1
535+ let currentEpochStartHeight = $t01841918499._2
550536 let userAddress = addressFromStringValue(userAddressStr)
551537 let userVoteStaked = getUserVoteStaked(lpAssetIdStr, userAddressStr)
552538 let userVoteStakedIntegralPrev = valueOrElse(getInteger(this, keyVoteStakedIntegral(lpAssetIdStr, userAddress, lastFinalizedEpoch)), 0)
558544
559545
560546 func refreshVoteStakedIntegral (lpAssetIdStr,userAddressStr,edge) = {
561- let $t02178721867 = getVotingEmissionEpochInfo()
562- let lastFinalizedEpoch = $t02178721867._1
563- let currentEpochStartHeight = $t02178721867._2
547+ let $t01928719367 = getVotingEmissionEpochInfo()
548+ let lastFinalizedEpoch = $t01928719367._1
549+ let currentEpochStartHeight = $t01928719367._2
564550 let userAddress = addressFromStringValue(userAddressStr)
565551 let userVoteFinalized = getUserVoteFinalized(lpAssetIdStr, userAddressStr)
566552 let actions = if ((userVoteFinalized == 0))
579565
580566
581567 func getStakedVotesIntegralsDiff (lpAssetIdStr,userAddressStr) = {
582- let $t02272122801 = getVotingEmissionEpochInfo()
583- let lastFinalizedEpoch = $t02272122801._1
584- let currentEpochStartHeight = $t02272122801._2
568+ let $t02022120301 = getVotingEmissionEpochInfo()
569+ let lastFinalizedEpoch = $t02022120301._1
570+ let currentEpochStartHeight = $t02022120301._2
585571 let userAddress = addressFromStringValue(userAddressStr)
586572 let userVoteStakedIntegralLastKey = keyVoteStakedIntegralLast(lpAssetIdStr, userAddress, lastFinalizedEpoch)
587573 let userVoteStakedIntegralLast = valueOrElse(getInteger(this, userVoteStakedIntegralLastKey), 0)
596582
597583
598584 func refreshBoostEmissionIntegral () = {
599- let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
585+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
600586 let boostingV2LastUpdateHeightOption = getInteger(this, keyBoostingV2LastUpdateHeight())
601587 let boostingV2IngergalOption = getInteger(this, keyBoostingV2Integral())
602- let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
588+ let emissionEnd = getIntOrFail(emissionContract, keyEmissionEndBlock())
603589 let h = if ((height > emissionEnd))
604590 then emissionEnd
605591 else height
619605
620606
621607 func internalClaimWxBoost (lpAssetIdStr,userAddressStr,readOnly) = {
622- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
623- if ((userRecordOption == unit))
624- then $Tuple3(0, nil, "userRecord::is::empty")
625- else {
626- let userRecordArray = split(value(userRecordOption), SEP)
627- let userNumStr = userRecordArray[IdxLockUserNum]
608+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
609+ let userNum = userNumberByAddressOrFail(userAddress)
610+ if ((userNum == userNum))
611+ then {
628612 let EMPTYSTR = "empty"
629613 let poolWeight = if ((lpAssetIdStr != EMPTYSTR))
630614 then {
634618 else if (readOnly)
635619 then 0
636620 else throwErr(("not readonly mode: unsupported lp asset " + lpAssetIdStr))
637- let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNumStr, lpAssetIdStr)
638- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
639- let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), ioz(this, userBoostEmissionLastIntegralKEY))
621+ let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNum, lpAssetIdStr)
622+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
623+ let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), getIntOrZero(this, userBoostEmissionLastIntegralKEY))
640624 let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
641625 let userBoostEmissionIntegral = (boostEmissionIntegral - userBoostEmissionLastIntegral)
642626 if ((0 > userBoostEmissionIntegral))
643627 then throwErr("wrong calculations")
644628 else {
645- let $t02642026559 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
646- let stakedVotesIntegralsActions = $t02642026559._1
647- let userVoteIntegralDiff = $t02642026559._2
648- let totalVotesIntegralDiff = $t02642026559._3
629+ let $t02384323982 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
630+ let stakedVotesIntegralsActions = $t02384323982._1
631+ let userVoteIntegralDiff = $t02384323982._2
632+ let totalVotesIntegralDiff = $t02384323982._3
649633 let poolUserBoostEmissionIntegral = fraction(userBoostEmissionIntegral, poolWeight, POOLWEIGHTMULT)
650634 let userBoostAvaliableToClaimTotalNew = if ((totalVotesIntegralDiff == 0))
651635 then 0
655639 $Tuple3(userBoostAvaliableToClaimTotalNew, dataState, debug)
656640 }
657641 }
642+ else throw("Strict value is not equal to itself.")
658643 }
659644
660645
661646 func lockActions (i,duration) = {
662- let cfgArray = readConfigArrayOrFail()
663- let assetIdStr = cfgArray[IdxCfgAssetId]
664- let assetId = fromBase58String(assetIdStr)
665- let minLockAmount = parseIntValue(cfgArray[IdxCfgMinLockAmount])
666- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
667- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
647+ let assetIdStr = toBase58String(assetId)
668648 if ((size(i.payments) != 1))
669649 then throwErr("invalid payment - exact one payment must be attached")
670650 else {
674654 then throwErr((("invalid asset is in payment - " + assetIdStr) + " is expected"))
675655 else {
676656 let nextUserNumKEY = keyNextUserNum()
677- let userAddressStr = toString(i.caller)
657+ let userAddress = i.caller
658+ let userAddressStr = toString(userAddress)
678659 let userIsExisting = isDefined(getString(keyUser2NumMapping(userAddressStr)))
679660 let userNumStr = if (userIsExisting)
680661 then value(getString(keyUser2NumMapping(userAddressStr)))
681- else toString(iof(this, nextUserNumKEY))
662+ else toString(getIntOrFail(this, nextUserNumKEY))
682663 let userNum = parseIntValue(userNumStr)
683664 let lockStart = height
684- let startBlockKEY = keyLockParamStartBlock(userNumStr)
685- let durationKEY = keyLockParamDuration(userNumStr)
686- let userAmountKEY = keyLockParamUserAmount(userNumStr)
687665 if (if ((minLockAmount > pmtAmount))
688- then (i.caller != lpStakingPoolsContract)
666+ then (userAddress != lpStakingPoolsContract)
689667 else false)
690668 then throwErr(("amount is less then minLockAmount=" + toString(minLockAmount)))
691669 else if ((minLockDuration > duration))
692- then throwErr(("passed duration is less then minLockDuration=" + toString(minLockDuration)))
670+ then throwErr(("passed duration is less than minLockDuration=" + toString(minLockDuration)))
693671 else if ((duration > maxLockDuration))
694- then throwErr(("passed duration is greater then maxLockDuration=" + toString(maxLockDuration)))
695- else if (if (userIsExisting)
696- then ((iof(this, startBlockKEY) + iof(this, durationKEY)) >= lockStart)
697- else false)
698- then throwErr("there is an active lock - consider to use increaseLock")
699- else if ((ioz(this, userAmountKEY) > 0))
700- then throwErr(("there are locked WXs - consider to use increaseLock " + userAmountKEY))
701- else {
702- let coeffX8 = fraction(duration, MULT8, maxLockDuration)
703- let gWxAmountStart = fraction(pmtAmount, coeffX8, MULT8)
704- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStart, duration], nil))
705- let k = ai(gWxParamsResultList[0])
706- let b = ai(gWxParamsResultList[1])
707- let period = toString(ai(gWxParamsResultList[2]))
708- let totalCachedGwxRaw = getTotalCachedGwx(false)
709- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
710- let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
711- let arr = if (userIsExisting)
712- then nil
713- else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
714- $Tuple2(((((arr ++ LockParamsEntry(userAddressStr, userNumStr, pmtAmount, lockStart, duration, k, b, period)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
715- then 0
716- else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gWxAmountStart))]), gWxAmountStart)
717- }
672+ then throwErr(("passed duration is greater than maxLockDuration=" + toString(maxLockDuration)))
673+ else if (((duration % lockStepBlocks) != 0))
674+ then throwErr(("duration must be multiple of lockStepBlocks=" + toString(lockStepBlocks)))
675+ else {
676+ let gWxAmountStart = fraction(pmtAmount, duration, maxLockDuration)
677+ let gwxAmountTotal = getGwxAmountTotal()
678+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
679+ let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
680+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
681+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
682+ if ((gwxRewardInv == gwxRewardInv))
683+ then {
684+ let arr = if (userIsExisting)
685+ then nil
686+ else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
687+ $Tuple2(((((arr ++ LockParamsEntry(userAddress, i.transactionId, pmtAmount, lockStart, duration, gWxAmountStart, 0)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
688+ then 0
689+ else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, gWxAmountStart, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyGwxTotal(), (gwxAmountTotal + gWxAmountStart)), IntegerEntry(keyUserGwxAmountTotal(userAddress), (userGwxAmountTotal + gWxAmountStart))]), gWxAmountStart)
690+ }
691+ else throw("Strict value is not equal to itself.")
692+ }
718693 }
719694 }
720695 }
721696
722697
698+func getWxWithdrawable (userAddress,txIdOption) = {
699+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
700+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
701+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
702+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
703+ let lockEnd = (lockStart + lockDuration)
704+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
705+ let t = ((height - lockStart) / blocksInPeriod)
706+ let exponent = fraction(toBigInt(t), (toBigInt((DECAY_CONSTANT * blocksInPeriod)) * MULT18BI), toBigInt(lockDuration))
707+ let wxWithdrawableTotal = if ((height > lockEnd))
708+ then userAmount
709+ else toInt(fraction(toBigInt(userAmount), (MULT18BI - pow(toBigInt(5), 1, exponent, SCALE18, SCALE18, DOWN)), MULT18BI))
710+ let wxWithdrawable = (wxWithdrawableTotal - wxClaimed)
711+ wxWithdrawable
712+ }
713+
714+
723715 @Callable(i)
724-func constructor (factoryAddressStr,lockAssetIdStr,minLockAmount,minDuration,maxDuration,mathContract) = {
725- let checkCaller = mustManager(i)
726- if ((checkCaller == checkCaller))
727- then ([IntegerEntry(keyNextUserNum(), 0), StringEntry(keyConfig(), formatConfig(lockAssetIdStr, minLockAmount, minDuration, maxDuration, mathContract)), StringEntry(keyFactoryAddress(), factoryAddressStr)] ++ StatsEntry(0, 0, 0, 0))
716+func lockRef (duration,referrerAddress,signature) = {
717+ let suspensionCheck = throwIfSuspended()
718+ if ((suspensionCheck == suspensionCheck))
719+ then {
720+ let $t02840028465 = lockActions(i, duration)
721+ let lockActionsResult = $t02840028465._1
722+ let gWxAmountStart = $t02840028465._2
723+ let referralAddress = toString(i.caller)
724+ let refInv = if (if ((referrerAddress == ""))
725+ then true
726+ else (signature == base58''))
727+ then unit
728+ else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
729+ if ((refInv == refInv))
730+ then {
731+ let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
732+ if ((updateRefActivity == updateRefActivity))
733+ then $Tuple2(lockActionsResult, unit)
734+ else throw("Strict value is not equal to itself.")
735+ }
736+ else throw("Strict value is not equal to itself.")
737+ }
728738 else throw("Strict value is not equal to itself.")
729739 }
730740
731741
732742
733743 @Callable(i)
734-func lockRef (duration,referrerAddress,signature) = {
735- let $t03117031235 = lockActions(i, duration)
736- let lockActionsResult = $t03117031235._1
737- let gWxAmountStart = $t03117031235._2
738- let referralAddress = toString(i.caller)
739- let refInv = if (if ((referrerAddress == ""))
740- then true
741- else (signature == base58''))
742- then unit
743- else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
744- if ((refInv == refInv))
744+func lock (duration) = {
745+ let suspensionCheck = throwIfSuspended()
746+ if ((suspensionCheck == suspensionCheck))
745747 then {
748+ let $t02896929034 = lockActions(i, duration)
749+ let lockActionsResult = $t02896929034._1
750+ let gWxAmountStart = $t02896929034._2
746751 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
747752 if ((updateRefActivity == updateRefActivity))
748753 then $Tuple2(lockActionsResult, unit)
754759
755760
756761 @Callable(i)
757-func lock (duration) = {
758- let $t03169331758 = lockActions(i, duration)
759- let lockActionsResult = $t03169331758._1
760- let gWxAmountStart = $t03169331758._2
761- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
762- if ((updateRefActivity == updateRefActivity))
763- then $Tuple2(lockActionsResult, unit)
762+func claimWxBoost (lpAssetIdStr,userAddressStr) = {
763+ let suspensionCheck = throwIfSuspended()
764+ if ((suspensionCheck == suspensionCheck))
765+ then if ((stakingContract != i.caller))
766+ then throwErr("permissions denied")
767+ else {
768+ let $t02939029492 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
769+ let userBoostAvailable = $t02939029492._1
770+ let dataState = $t02939029492._2
771+ let debug = $t02939029492._3
772+ $Tuple2(dataState, [userBoostAvailable])
773+ }
764774 else throw("Strict value is not equal to itself.")
765775 }
766776
767777
768778
769779 @Callable(i)
770-func increaseLock (deltaDuration) = {
771- let cfgArray = readConfigArrayOrFail()
772- let assetIdStr = cfgArray[IdxCfgAssetId]
773- let assetId = fromBase58String(assetIdStr)
774- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
775- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
776- let pmtAmount = extractOptionalPaymentAmountOrFail(i, assetId)
777- let userAddressStr = toString(i.caller)
778- let userRecordArray = readLockParamsRecordOrFail(userAddressStr)
779- let userNumStr = userRecordArray[IdxLockUserNum]
780- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
781- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
782- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
783- let lockEnd = (lockStart + lockDuration)
784- let remainingDuration = max([(lockEnd - height), 0])
785- let userAmountNew = (userAmount + pmtAmount)
786- let lockDurationNew = (remainingDuration + deltaDuration)
787- if ((0 > deltaDuration))
788- then throwErr("duration is less then zero")
789- else if ((minLockDuration > lockDurationNew))
790- then throwErr(("lockDurationNew is less then minLockDuration=" + toString(minLockDuration)))
791- else if ((lockDurationNew > maxLockDuration))
792- then throwErr(("deltaDuration + existedLockDuration is greater then maxLockDuration=" + toString(maxLockDuration)))
793- else {
794- let coeffX8 = fraction(lockDurationNew, MULT8, maxLockDuration)
795- let gWxAmountStart = fraction(userAmountNew, coeffX8, MULT8)
796- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
797- if ((updateRefActivity == updateRefActivity))
798- then {
799- let lockStartNew = height
800- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStartNew, lockDurationNew], nil))
801- let k = ai(gWxParamsResultList[0])
802- let b = ai(gWxParamsResultList[1])
803- let period = toString(ai(gWxParamsResultList[2]))
804- let currUserGwx = calcCurrentGwxAmount(userAddressStr)
805- let gwxDiff = (gWxAmountStart - currUserGwx)
806- if ((0 > gwxDiff))
807- then throwErr(("gwxDiff is less then 0: " + toString(gwxDiff)))
808- else {
809- let totalCachedGwxRaw = getTotalCachedGwx(false)
810- let totalCachedGwxCorrected = getTotalCachedGwx(true)
811- (((LockParamsEntry(userAddressStr, userNumStr, userAmountNew, lockStartNew, lockDurationNew, k, b, period) ++ StatsEntry(pmtAmount, deltaDuration, 0, 0)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, lockDurationNew, k, b, i)) ++ [IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gwxDiff))])
812- }
813- }
814- else throw("Strict value is not equal to itself.")
815- }
816- }
817-
818-
819-
820-@Callable(i)
821-func claimWxBoost (lpAssetIdStr,userAddressStr) = if ((stakingContract != i.caller))
822- then throwErr("permissions denied")
823- else {
824- let $t03486334965 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
825- let userBoostAvailable = $t03486334965._1
826- let dataState = $t03486334965._2
827- let debug = $t03486334965._3
828- $Tuple2(dataState, [userBoostAvailable])
829- }
830-
831-
832-
833-@Callable(i)
834780 func claimWxBoostREADONLY (lpAssetIdStr,userAddressStr) = {
835- let $t03509735198 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
836- let userBoostAvailable = $t03509735198._1
837- let dataState = $t03509735198._2
838- let debug = $t03509735198._3
781+ let $t02962429725 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
782+ let userBoostAvailable = $t02962429725._1
783+ let dataState = $t02962429725._2
784+ let debug = $t02962429725._3
839785 $Tuple2(nil, [userBoostAvailable, debug])
840786 }
841787
842788
843789
844790 @Callable(i)
845-func unlock (userAddress) = {
846- let userRecordArray = readLockParamsRecordOrFail(userAddress)
847- let userNumStr = userRecordArray[IdxLockUserNum]
848- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
849- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
850- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
851- let lockEnd = (lockStart + lockDuration)
852- let cfgArray = readConfigArrayOrFail()
853- let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
854- if ((lockEnd >= height))
855- then throwErr((("wait " + toString(lockEnd)) + " to unlock"))
856- else if ((0 >= userAmount))
857- then throwErr("nothing to unlock")
858- else {
859- let period = valueOrElse(getInteger(mathContract, keyNextPeriod()), 0)
860- (((LockParamsEntry(userAddress, userNumStr, 0, lockStart, lockDuration, 0, 0, toString(period)) ++ StatsEntry(-(userAmount), 0, 0, -1)) :+ HistoryEntry("unlock", userAddress, userAmount, lockStart, lockDuration, 0, 0, i)) :+ ScriptTransfer(addressFromStringValue(userAddress), userAmount, assetId))
861- }
791+func unlock (txIdStr) = {
792+ let suspensionCheck = throwIfSuspended()
793+ if ((suspensionCheck == suspensionCheck))
794+ then {
795+ let userAddress = i.caller
796+ let userAddressStr = toString(userAddress)
797+ let txIdOption = if ((txIdStr == ""))
798+ then unit
799+ else fromBase58String(txIdStr)
800+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
801+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
802+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
803+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
804+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
805+ let gwxAmount = parseIntValue(userRecordArray[IdxLockGwxAmount])
806+ let t = ((height - lockStart) / blocksInPeriod)
807+ let wxWithdrawable = getWxWithdrawable(userAddress, txIdOption)
808+ let gwxBurned = min([fraction(wxWithdrawable, lockDuration, maxLockDuration), gwxAmount])
809+ let gwxRemaining = ensurePositive((gwxAmount - gwxBurned), "gwxRemaining")
810+ let lockedGwxAmount = getLockedGwxAmount(userAddress)
811+ if ((0 >= wxWithdrawable))
812+ then throwErr("nothing to unlock")
813+ else {
814+ let gwxAmountTotal = getGwxAmountTotal()
815+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
816+ let userGwxAmountTotalNew = ensurePositive((userGwxAmountTotal - gwxBurned), "userGwxAmountTotalNew")
817+ if ((lockedGwxAmount > userGwxAmountTotalNew))
818+ then throwErr(("locked gwx amount: " + toString(lockedGwxAmount)))
819+ else {
820+ let userNum = parseIntValue(valueOrErrorMessage(getString(keyUser2NumMapping(userAddressStr)), wrapErr("invalid user number")))
821+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
822+ if ((gwxRewardInv == gwxRewardInv))
823+ then ((((LockParamsEntry(userAddress, txIdOption, userAmount, lockStart, lockDuration, gwxRemaining, (wxClaimed + wxWithdrawable)) ++ StatsEntry(-(wxWithdrawable), 0, 0, 0)) :+ HistoryEntry("unlock", userAddressStr, wxWithdrawable, lockStart, lockDuration, gwxBurned, i)) :+ ScriptTransfer(userAddress, wxWithdrawable, assetId)) ++ [IntegerEntry(keyGwxTotal(), ensurePositive((gwxAmountTotal - gwxBurned), "gwxTotal")), IntegerEntry(keyUserGwxAmountTotal(userAddress), userGwxAmountTotalNew)])
824+ else throw("Strict value is not equal to itself.")
825+ }
826+ }
827+ }
828+ else throw("Strict value is not equal to itself.")
862829 }
863830
864831
865832
866833 @Callable(i)
867-func gwxUserInfoREADONLY (userAddress) = {
868- let gwxAmount = calcCurrentGwxAmount(userAddress)
834+func gwxUserInfoREADONLY (userAddressStr) = {
835+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
836+ let gwxAmount = getUserGwxAmountTotal(userAddress)
869837 $Tuple2(nil, [gwxAmount])
870838 }
871839
872840
873841
874842 @Callable(i)
875-func userMaxDurationREADONLY (userAddressStr) = {
876- let cfgArray = readConfigArrayOrFail()
877- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
878- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
879- if ((userRecordOption == unit))
880- then $Tuple2(nil, $Tuple2("lock", maxLockDuration))
881- else {
882- let userRecordArray = split(value(userRecordOption), SEP)
883- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
884- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
885- let lockEnd = (lockStart + lockDuration)
886- let remainingDuration = max([(lockEnd - height), 0])
887- let maxDeltaDuration = (maxLockDuration - remainingDuration)
888- $Tuple2(nil, $Tuple2("increaseLock", maxDeltaDuration))
889- }
890- }
843+func userMaxDurationREADONLY (userAddressStr) = $Tuple2(nil, $Tuple2("lock", maxLockDuration))
891844
892845
893846
894847 @Callable(i)
895-func getUserGwxAmountAtHeightREADONLY (userAddress,targetHeight) = {
896- let gwxAmount = calcUserGwxAmountAtHeight(userAddress, targetHeight)
848+func getUserGwxAmountAtHeightREADONLY (userAddressStr,targetHeight) = {
849+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
850+ let gwxAmount = getUserGwxAmountTotal(userAddress)
897851 $Tuple2(nil, gwxAmount)
898852 }
899853
900854
901855
902856 @Callable(i)
903-func getTotalCachedGwxREADONLY () = $Tuple2(nil, getTotalCachedGwx(true))
857+func getUserGwxAmount (userAddressStr) = {
858+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
859+ let gwxAmount = getUserGwxAmountTotal(userAddress)
860+ $Tuple2(nil, gwxAmount)
861+ }
862+
863+
864+
865+@Callable(i)
866+func getGwxTotalREADONLY () = $Tuple2(nil, getGwxAmountTotal())
904867
905868
906869
907870 @Callable(i)
908871 func onBoostEmissionUpdate () = {
909- let checkCaller = if ((i.caller == emissionContract))
910- then true
911- else mustManager(i)
912- if ((checkCaller == checkCaller))
913- then refreshBoostEmissionIntegral()
872+ let suspensionCheck = throwIfSuspended()
873+ if ((suspensionCheck == suspensionCheck))
874+ then {
875+ let checkCaller = if ((i.caller == emissionContract))
876+ then true
877+ else mustManager(i)
878+ if ((checkCaller == checkCaller))
879+ then refreshBoostEmissionIntegral()
880+ else throw("Strict value is not equal to itself.")
881+ }
914882 else throw("Strict value is not equal to itself.")
915883 }
916884
918886
919887 @Callable(i)
920888 func onStakedVoteUpdate (lpAssetIdStr,userAddressStr,edge) = {
921- let checkCaller = if ((i.caller == stakingContract))
922- then true
923- else mustManager(i)
924- if ((checkCaller == checkCaller))
889+ let suspensionCheck = throwIfSuspended()
890+ if ((suspensionCheck == suspensionCheck))
925891 then {
926- let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
927- $Tuple2(actions, unit)
892+ let checkCaller = if ((i.caller == stakingContract))
893+ then true
894+ else mustManager(i)
895+ if ((checkCaller == checkCaller))
896+ then {
897+ let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
898+ $Tuple2(actions, unit)
899+ }
900+ else throw("Strict value is not equal to itself.")
928901 }
929902 else throw("Strict value is not equal to itself.")
930903 }
950923 func getUserVoteStakedIntegralREADONLY (lpAssetIdStr,userAddressStr) = $Tuple2(nil, getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr))
951924
952925
926+
927+@Callable(i)
928+func suspend (v) = {
929+ let checkCaller = mustManager(i)
930+ if ((checkCaller == checkCaller))
931+ then $Tuple2([BooleanEntry(keySuspension, v)], v)
932+ else throw("Strict value is not equal to itself.")
933+ }
934+
935+
953936 @Verifier(tx)
954937 func verify () = {
955938 let targetPublicKey = match managerPublicKeyOrUnit() {
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let SEP = "__"
55
66 let SCALE8 = 8
77
88 let MULT8 = 100000000
99
1010 let POOLWEIGHTMULT = MULT8
1111
12-func wrapErr (msg) = makeString(["boosting.ride:", msg], " ")
12+let contractFilename = "boosting.ride"
13+
14+let SCALE18 = 18
15+
16+let MULT18 = 1000000000000000000
17+
18+let MULT18BI = toBigInt(MULT18)
19+
20+let DECAY_CONSTANT = 8
21+
22+func wrapErr (msg) = makeString([contractFilename, ": ", msg], "")
1323
1424
1525 func throwErr (msg) = throw(wrapErr(msg))
1626
1727
18-func strf (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
28+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
1929
2030
21-func ioz (address,key) = valueOrElse(getInteger(address, key), 0)
31+func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
2232
2333
24-func iod (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
34+func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
2535
2636
27-func iof (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
37+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), wrapErr((("mandatory this." + key) + " is not defined")))
2838
2939
3040 func abs (val) = if ((0 > val))
3141 then -(val)
3242 else val
3343
3444
35-func aal (val) = match val {
36- case valAnyLyst: List[Any] =>
37- valAnyLyst
38- case _ =>
39- throwErr("fail to cast into List[Any]")
40-}
41-
42-
43-func ai (val) = match val {
44- case valInt: Int =>
45- valInt
46- case _ =>
47- throwErr("fail to cast into Int")
48-}
45+func ensurePositive (v,m) = if ((v >= 0))
46+ then v
47+ else throwErr((valueOrElse(m, "value") + " should be positive"))
4948
5049
5150 func keyReferralsContractAddress () = makeString(["%s%s", "config", "referralsContractAddress"], SEP)
5251
5352
54-let referralsContractAddressOrFail = addressFromStringValue(strf(this, keyReferralsContractAddress()))
53+let referralsContractAddressOrFail = addressFromStringValue(getStringOrFail(this, keyReferralsContractAddress()))
5554
5655 let keyReferralProgramName = makeString(["%s%s", "referral", "programName"], SEP)
5756
5857 let referralProgramNameDefault = "wxlock"
5958
6059 let referralProgramName = valueOrElse(getString(this, keyReferralProgramName), referralProgramNameDefault)
6160
6261 func keyFactoryAddress () = "%s%s__config__factoryAddress"
6362
6463
6564 let IdxFactoryCfgStakingDapp = 1
6665
6766 let IdxFactoryCfgBoostingDapp = 2
6867
6968 let IdxFactoryCfgIdoDapp = 3
7069
7170 let IdxFactoryCfgTeamDapp = 4
7271
7372 let IdxFactoryCfgEmissionDapp = 5
7473
7574 let IdxFactoryCfgRestDapp = 6
7675
7776 let IdxFactoryCfgSlippageDapp = 7
7877
7978 let IdxFactoryCfgDaoDapp = 8
8079
8180 let IdxFactoryCfgMarketingDapp = 9
8281
8382 let IdxFactoryCfgGwxRewardDapp = 10
8483
8584 let IdxFactoryCfgBirdsDapp = 11
8685
8786 func keyFactoryCfg () = "%s__factoryConfig"
8887
8988
90-func keyFactoryLpList () = "%s__lpTokensList"
91-
92-
9389 func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
9490
9591
9692 func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
9793
9894
9995 func keyFactoryPoolWeightHistory (poolAddress,num) = ((("%s%s__poolWeight__" + poolAddress) + "__") + toString(num))
10096
10197
102-func readFactoryAddressOrFail () = addressFromStringValue(strf(this, keyFactoryAddress()))
98+func readFactoryAddressOrFail () = addressFromStringValue(getStringOrFail(this, keyFactoryAddress()))
10399
104100
105-func readLpList () = split(valueOrElse(getString(readFactoryAddressOrFail(), keyFactoryLpList()), ""), SEP)
106-
107-
108-func readFactoryCfgOrFail (factory) = split(strf(factory, keyFactoryCfg()), SEP)
101+func readFactoryCfgOrFail (factory) = split(getStringOrFail(factory, keyFactoryCfg()), SEP)
109102
110103
111104 func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
112105
113106
114107 func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
115108
116109
117110 func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
118111
119112
120113 func getGwxRewardAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgGwxRewardDapp])
121114
122115
123116 func keyManagerPublicKey () = "%s__managerPublicKey"
124117
125118
126119 func keyManagerVaultAddress () = "%s__managerVaultAddress"
127120
128121
129122 func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
130123
131124
132125 func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
133126
134127
135128 func keyEmissionStartBlock () = "%s%s__emission__startBlock"
136129
137130
138131 func keyBoostingV2LastUpdateHeight () = "%s%s__boostingV2__startBlock"
139132
140133
141134 func keyBoostingV2Integral () = "%s%s__boostingV2__integral"
142135
143136
144137 func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
145138
146139
147140 func keyEmissionEndBlock () = "%s%s__emission__endBlock"
148141
149142
150-func keyNextPeriod () = "%s__nextPeriod"
151-
152-
153-func keyGwxRewardEmissionStartHeight () = "%s%s__gwxRewardEmissionPart__startHeight"
154-
155-
156143 let IdxCfgAssetId = 1
157144
158145 let IdxCfgMinLockAmount = 2
159146
160147 let IdxCfgMinLockDuration = 3
161148
162149 let IdxCfgMaxLockDuration = 4
163150
164151 let IdxCfgMathContract = 5
165152
153+let IdxCfgBlocksInPeriod = 6
154+
155+let IdxCfgLockStepBlocks = 7
156+
166157 func keyConfig () = "%s__config"
167158
168159
169-func readConfigArrayOrFail () = split(strf(this, keyConfig()), SEP)
160+func readConfigArrayOrFail () = split(getStringOrFail(this, keyConfig()), SEP)
170161
171162
172-let mathContract = addressFromStringValue(readConfigArrayOrFail()[IdxCfgMathContract])
163+let cfgArray = readConfigArrayOrFail()
173164
174-func formatConfigS (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = makeString(["%s%d%d%d", assetId, minLockAmount, minLockDuration, maxLockDuration, mathContract], SEP)
165+let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
175166
167+let minLockAmount = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockAmount]), wrapErr("invalid min lock amount"))
176168
177-func formatConfig (assetId,minLockAmount,minLockDuration,maxLockDuration,mathContract) = formatConfigS(assetId, toString(minLockAmount), toString(minLockDuration), toString(maxLockDuration), mathContract)
169+let minLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMinLockDuration]), wrapErr("invalid min lock duration"))
170+
171+let maxLockDuration = valueOrErrorMessage(parseInt(cfgArray[IdxCfgMaxLockDuration]), wrapErr("invalid max lock duration"))
172+
173+let mathContract = valueOrErrorMessage(addressFromString(cfgArray[IdxCfgMathContract]), wrapErr("invalid math contract address"))
174+
175+let blocksInPeriod = valueOrErrorMessage(parseInt(cfgArray[IdxCfgBlocksInPeriod]), wrapErr("invalid blocks in period"))
176+
177+let lockStepBlocks = valueOrErrorMessage(parseInt(cfgArray[IdxCfgLockStepBlocks]), wrapErr("invalid lock step blocks"))
178+
179+let keySuspension = "%s__suspension"
180+
181+let isSuspended = valueOrElse(getBoolean(this, keySuspension), false)
182+
183+func throwIfSuspended () = if (!(isSuspended))
184+ then true
185+ else throwErr("suspended")
178186
179187
180188 func getManagerVaultAddressOrThis () = match getString(keyManagerVaultAddress()) {
181189 case s: String =>
182190 addressFromStringValue(s)
183191 case _ =>
184192 this
185193 }
186194
187195
188196 func managerPublicKeyOrUnit () = {
189197 let managerVaultAddress = getManagerVaultAddressOrThis()
190198 match getString(managerVaultAddress, keyManagerPublicKey()) {
191199 case s: String =>
192200 fromBase58String(s)
193201 case _: Unit =>
194202 unit
195203 case _ =>
196204 throw("Match error")
197205 }
198206 }
199207
200208
201209 func mustManager (i) = {
202210 let pd = throwErr("Permission denied")
203211 match managerPublicKeyOrUnit() {
204212 case pk: ByteVector =>
205213 if ((i.callerPublicKey == pk))
206214 then true
207215 else pd
208216 case _: Unit =>
209217 if ((i.caller == this))
210218 then true
211219 else pd
212220 case _ =>
213221 throw("Match error")
214222 }
215223 }
216224
217225
218-let IdxLockUserNum = 1
226+let IdxLockAmount = 1
219227
220-let IdxLockAmount = 2
228+let IdxLockStart = 2
221229
222-let IdxLockStart = 3
230+let IdxLockDuration = 3
223231
224-let IdxLockDuration = 4
232+let IdxLockLastUpdateTimestamp = 4
225233
226-let IdxLockParamK = 5
234+let IdxLockGwxAmount = 5
227235
228-let IdxLockParamB = 6
236+let IdxLockWxClaimed = 6
229237
230-func keyLockParamsRecord (userAddress) = makeString(["%s%s__lock", userAddress], SEP)
238+func keyLockParamsRecord (userAddress,txId) = makeString(["%s%s%s__lock", toString(userAddress), match txId {
239+ case b: ByteVector =>
240+ toBase58String(b)
241+ case _: Unit =>
242+ "legacy"
243+ case _ =>
244+ throw("Match error")
245+}], SEP)
231246
232247
233-func readLockParamsRecordOrFail (userAddress) = split(strf(this, keyLockParamsRecord(userAddress)), SEP)
248+func readLockParamsRecordOrFail (userAddress,txId) = split(getStringOrFail(this, keyLockParamsRecord(userAddress, txId)), SEP)
234249
235250
236-func formatLockParamsRecordS (userNum,amount,start,duration,paramK,paramB,lastUpdTimestamp,gwxAmount) = makeString(["%d%d%d%d%d%d%d%d", userNum, amount, start, duration, paramK, paramB, lastUpdTimestamp, gwxAmount], SEP)
251+func keyUserGwxAmountTotal (userAddress) = makeString(["%s%s__gwxAmountTotal", toString(userAddress)], SEP)
237252
238253
239-func formatLockParamsRecord (userNum,amount,start,duration,paramK,paramB,gwxAmount) = formatLockParamsRecordS(userNum, toString(amount), toString(start), toString(duration), toString(paramK), toString(paramB), toString(lastBlock.timestamp), toString(gwxAmount))
254+func formatLockParamsRecord (amount,start,duration,gwxAmount,wxClaimed) = makeString(["%d%d%d%d%d%d", toString(amount), toString(start), toString(duration), toString(lastBlock.timestamp), toString(gwxAmount), toString(wxClaimed)], SEP)
240255
241256
242257 func keyNextUserNum () = "%s__nextUserNum"
243258
244259
245260 func keyUser2NumMapping (userAddress) = makeString(["%s%s%s__mapping__user2num", userAddress], SEP)
246261
247262
248263 func keyNum2UserMapping (num) = makeString(["%s%s%s__mapping__num2user", num], SEP)
249-
250-
251-func keyLockParamUserAmount (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "amount"], SEP)
252-
253-
254-func keyLockParamStartBlock (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "start"], SEP)
255-
256-
257-func keyLockParamDuration (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "duration"], SEP)
258-
259-
260-func keyLockParamK (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "k"], SEP)
261-
262-
263-func keyLockParamB (userNum) = makeString(["%s%d%s__paramByUserNum", userNum, "b"], SEP)
264-
265-
266-func keyLockParamByPeriodK (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "k", period], SEP)
267-
268-
269-func keyLockParamByPeriodB (userNum,period) = makeString(["%s%d%s%d__paramByPeriod", userNum, "b", period], SEP)
270264
271265
272266 func keyLockParamTotalAmount () = "%s%s__stats__activeTotalLocked"
273267
274268
275269 func keyStatsLocksDurationSumInBlocks () = "%s%s__stats__locksDurationSumInBlocks"
276270
277271
278272 func keyStatsLocksCount () = "%s%s__stats__locksCount"
279273
280274
281275 func keyStatsUsersCount () = "%s%s__stats__activeUsersCount"
282276
283277
284-func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum], SEP)
278+func keyUserBoostEmissionLastINTEGRAL (userNum) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum)], SEP)
285279
286280
287-func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", userNum, lpAssetId], SEP)
281+func keyUserLpBoostEmissionLastINTEGRAL (userNum,lpAssetId) = makeString(["%s%d__userBoostEmissionLastIntV2", toString(userNum), lpAssetId], SEP)
288282
289283
290-func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", userNum], SEP)
284+func keyUserMaxBoostINTEGRAL (userNum) = makeString(["%s%d__maxBoostInt", toString(userNum)], SEP)
291285
292286
293287 func keyTotalMaxBoostINTEGRAL () = "%s%s__maxBoostInt__total"
294288
295289
296-func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", userNum], SEP)
290+func keyUserBoostAvalaibleToClaimTotal (userNum) = makeString(["%s%d__userBoostAvaliableToClaimTotal", toString(userNum)], SEP)
297291
298292
299-func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", userNum], SEP)
293+func keyUserBoostClaimed (userNum) = makeString(["%s%d__userBoostClaimed", toString(userNum)], SEP)
300294
301295
302-func keyTotalCachedGwx () = "%s%s__gwxCached__total"
303-
304-
305-func keyTotalCachedGwxCorrective () = "%s__gwxCachedTotalCorrective"
296+func keyGwxTotal () = "%s%s__gwx__total"
306297
307298
308299 func keyVote (amountAssetId,priceAssetId,address,epoch) = makeString(["%s%s%s%s%d", "vote", amountAssetId, priceAssetId, toString(address), toString(epoch)], SEP)
309300
310301
311302 func keyStartHeightByEpoch (epoch) = makeString(["%s%d", "startHeight", toString(epoch)], SEP)
312303
313304
314305 func keyCurrentEpochUi () = makeString(["%s", "currentEpochUi"], SEP)
315306
316307
317308 func keyVotingResultStaked (lpAssetIdStr,epoch) = makeString(["%s%s%d", "votingResultStaked", lpAssetIdStr, toString(epoch)], SEP)
318309
319310
320311 func keyVotingResultStakedIntegral (lpAssetIdStr,epoch) = makeString(["%s%s%d", "votingResultStakedIntegral", lpAssetIdStr, toString(epoch)], SEP)
321312
322313
323314 func keyVotingResultStakedLastUpdateHeight (lpAssetIdStr,epoch) = makeString(["%s%s%d", "votingResultStakedIntegralLastUpdateHeight", lpAssetIdStr, toString(epoch)], SEP)
324315
325316
326317 func keyVotingResultStakedIntegralLast (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "votingResultStakedIntegralLast", lpAssetIdStr, toString(address), toString(epoch)], SEP)
327318
328319
329320 func keyVoteStakedIntegral (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "voteStakedIntegral", lpAssetIdStr, toString(address), toString(epoch)], SEP)
330321
331322
332323 func keyVoteStakedLastUpdateHeight (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "voteStakedIntegralLastUpdateHeight", lpAssetIdStr, toString(address), toString(epoch)], SEP)
333324
334325
335326 func keyVoteStakedIntegralLast (lpAssetIdStr,address,epoch) = makeString(["%s%s%s%d", "voteStakedIntegralLast", lpAssetIdStr, toString(address), toString(epoch)], SEP)
336327
337328
338329 func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s", "staked", userAddressStr, lpAssetIdStr], SEP)
339330
340331
341332 let factoryContract = readFactoryAddressOrFail()
342333
343334 let factoryCfg = readFactoryCfgOrFail(factoryContract)
344335
345336 let emissionContract = getEmissionAddressOrFail(factoryCfg)
346337
347338 let stakingContract = getStakingAddressOrFail(factoryCfg)
348339
349340 let gwxRewardContract = getGwxRewardAddressOrFail(factoryCfg)
350341
351342 let lpStakingPoolsContract = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(makeString(["%s", "lpStakingPoolsContract"], SEP)), wrapErr("lp_staking_pools contract address is undefined"))), wrapErr("invalid lp_staking_pools contract address"))
352343
353344 let keyVotingEmissionContract = makeString(["%s", "votingEmissionContract"], SEP)
354345
355346 let votingEmissionContract = addressFromStringValue(getStringValue(factoryContract, keyVotingEmissionContract))
356347
348+let keyVotingEmissionRateContract = makeString(["%s", "votingEmissionRateContract"], SEP)
349+
357350 let boostCoeff = {
358351 let @ = invoke(emissionContract, "getBoostCoeffREADONLY", nil, nil)
359352 if ($isInstanceOf(@, "Int"))
360353 then @
361354 else throw(($getType(@) + " couldn't be cast to Int"))
362355 }
363356
364-func getTotalCachedGwx (correct) = {
365- let currentEpochUi = getIntegerValue(votingEmissionContract, keyCurrentEpochUi())
366- let keyTargetEpoch = makeString(["%s%s", "totalCachedGwxCorrection__activationEpoch"], SEP)
367- let targetEpochOption = getInteger(this, keyTargetEpoch)
368- let totalCachedGwxRaw = valueOrElse(getInteger(this, keyTotalCachedGwx()), 0)
369- let isCorrectionActivated = if (isDefined(targetEpochOption))
370- then (currentEpochUi >= value(targetEpochOption))
371- else false
372- let corrective = if (if (isCorrectionActivated)
373- then correct
374- else false)
375- then valueOrElse(getInteger(this, keyTotalCachedGwxCorrective()), 0)
376- else 0
377- max([0, (totalCachedGwxRaw + corrective)])
357+func userNumberByAddressOrFail (userAddress) = match getString(this, keyUser2NumMapping(toString(userAddress))) {
358+ case s: String =>
359+ valueOrErrorMessage(parseInt(s), wrapErr("invalid user number"))
360+ case _: Unit =>
361+ throwErr("invalid user")
362+ case _ =>
363+ throw("Match error")
364+}
365+
366+
367+func getGwxAmountTotal () = valueOrElse(getInteger(this, keyGwxTotal()), 0)
368+
369+
370+func getLockedGwxAmount (userAddress) = {
371+ let functionName = "getLockedGwxAmount"
372+ let votingEmissionRateContract = valueOrErrorMessage( match getString(votingEmissionContract, keyVotingEmissionRateContract) {
373+ case _: Unit =>
374+ unit
375+ case s: String =>
376+ addressFromString(s)
377+ case _ =>
378+ throw("Match error")
379+ }, wrapErr("invalid voting emission rate address"))
380+ let lockedVotingEmissionRate = {
381+ let @ = invoke(votingEmissionContract, functionName, [toString(userAddress)], nil)
382+ if ($isInstanceOf(@, "Int"))
383+ then @
384+ else throw(($getType(@) + " couldn't be cast to Int"))
385+ }
386+ let lockedVotingEmission = {
387+ let @ = invoke(votingEmissionRateContract, functionName, [toString(userAddress)], nil)
388+ if ($isInstanceOf(@, "Int"))
389+ then @
390+ else throw(($getType(@) + " couldn't be cast to Int"))
391+ }
392+ let locked = max([lockedVotingEmissionRate, lockedVotingEmission])
393+ locked
378394 }
379395
380396
381-func HistoryEntry (type,user,amount,lockStart,duration,k,b,i) = {
397+func HistoryEntry (type,user,amount,lockStart,duration,gwxAmount,i) = {
382398 let historyKEY = makeString(["%s%s%s%s__history", type, user, toBase58String(i.transactionId)], SEP)
383- let historyDATA = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(amount), toString(lockStart), toString(duration), toString(k), toString(b)], SEP)
399+ let historyDATA = makeString(["%d%d%d%d%d%d%d", toString(lastBlock.height), toString(lastBlock.timestamp), toString(amount), toString(lockStart), toString(duration), toString(gwxAmount)], SEP)
384400 StringEntry(historyKEY, historyDATA)
385401 }
386402
387403
388404 func StatsEntry (totalLockedInc,durationInc,lockCountInc,usersCountInc) = {
389405 let locksDurationSumInBlocksKEY = keyStatsLocksDurationSumInBlocks()
390406 let locksCountKEY = keyStatsLocksCount()
391407 let usersCountKEY = keyStatsUsersCount()
392408 let totalAmountKEY = keyLockParamTotalAmount()
393- let locksDurationSumInBlocks = ioz(this, locksDurationSumInBlocksKEY)
394- let locksCount = ioz(this, locksCountKEY)
395- let usersCount = ioz(this, usersCountKEY)
396- let totalAmount = ioz(this, totalAmountKEY)
409+ let locksDurationSumInBlocks = getIntOrZero(this, locksDurationSumInBlocksKEY)
410+ let locksCount = getIntOrZero(this, locksCountKEY)
411+ let usersCount = getIntOrZero(this, usersCountKEY)
412+ let totalAmount = getIntOrZero(this, totalAmountKEY)
397413 [IntegerEntry(locksDurationSumInBlocksKEY, (locksDurationSumInBlocks + durationInc)), IntegerEntry(locksCountKEY, (locksCount + lockCountInc)), IntegerEntry(usersCountKEY, (usersCount + usersCountInc)), IntegerEntry(totalAmountKEY, (totalAmount + totalLockedInc))]
398414 }
399415
400416
401-func calcGwxAmount (kRaw,bRaw,h) = {
402- let SCALE = 1000
403- (((kRaw * h) + bRaw) / SCALE)
404- }
405-
406-
407-func LockParamsEntry (userAddress,userNum,amount,start,duration,k,b,period) = {
408- let userAmountKEY = keyLockParamUserAmount(userNum)
409- let startBlockKEY = keyLockParamStartBlock(userNum)
410- let durationKEY = keyLockParamDuration(userNum)
411- let kKEY = keyLockParamK(userNum)
412- let bKEY = keyLockParamB(userNum)
413- let kByPeriodKEY = keyLockParamByPeriodK(userNum, period)
414- let bByPeriodKEY = keyLockParamByPeriodB(userNum, period)
415- let gwxAmount = calcGwxAmount(k, b, height)
416-[IntegerEntry(userAmountKEY, amount), IntegerEntry(startBlockKEY, start), IntegerEntry(durationKEY, duration), IntegerEntry(kKEY, k), IntegerEntry(bKEY, b), IntegerEntry(kByPeriodKEY, k), IntegerEntry(bByPeriodKEY, b), StringEntry(keyLockParamsRecord(userAddress), formatLockParamsRecord(userNum, amount, start, duration, k, b, gwxAmount))]
417- }
417+func LockParamsEntry (userAddress,txId,amount,start,duration,gwxAmount,wxClaimed) = [StringEntry(keyLockParamsRecord(userAddress, txId), formatLockParamsRecord(amount, start, duration, gwxAmount, wxClaimed))]
418418
419419
420420 func extractOptionalPaymentAmountOrFail (i,expectedAssetId) = if ((size(i.payments) > 1))
421421 then throwErr("only one payment is allowed")
422422 else if ((size(i.payments) == 0))
423423 then 0
424424 else {
425425 let pmt = i.payments[0]
426426 if ((value(pmt.assetId) != expectedAssetId))
427427 then throwErr("invalid asset id in payment")
428428 else pmt.amount
429429 }
430430
431431
432-func calcUserGwxAmountAtHeight (userAddress,targetHeight) = {
433- let EMPTY = "empty"
434- let user2NumMappingKEY = keyUser2NumMapping(userAddress)
435- let userNum = valueOrElse(getString(user2NumMappingKEY), EMPTY)
436- let k = valueOrElse(getInteger(keyLockParamK(userNum)), 0)
437- let b = valueOrElse(getInteger(keyLockParamB(userNum)), 0)
438- let gwxAmountCalc = calcGwxAmount(k, b, targetHeight)
439- let gwxAmount = if ((0 > gwxAmountCalc))
440- then 0
441- else gwxAmountCalc
442- gwxAmount
443- }
444-
445-
446-func calcCurrentGwxAmount (userAddress) = calcUserGwxAmountAtHeight(userAddress, height)
432+func getUserGwxAmountTotal (userAddress) = valueOrElse(getInteger(this, keyUserGwxAmountTotal(userAddress)), 0)
447433
448434
449435 func getVotingEmissionEpochInfo () = {
450- let $t01718617476 = {
436+ let $t01468614976 = {
451437 let currentEpochUi = value(getInteger(votingEmissionContract, keyCurrentEpochUi()))
452438 let lastFinalizedEpoch = (currentEpochUi - 1)
453439 if ((0 > lastFinalizedEpoch))
454440 then throwErr("invalid epoch")
455441 else $Tuple2(currentEpochUi, lastFinalizedEpoch)
456442 }
457- let currentEpochUi = $t01718617476._1
458- let lastFinalizedEpoch = $t01718617476._2
443+ let currentEpochUi = $t01468614976._1
444+ let lastFinalizedEpoch = $t01468614976._2
459445 let currentEpochStartHeight = value(getInteger(votingEmissionContract, keyStartHeightByEpoch(currentEpochUi)))
460446 $Tuple2(lastFinalizedEpoch, currentEpochStartHeight)
461447 }
462448
463449
464450 func getPoolAssetsByLpAssetId (lpAssetIdStr) = {
465451 let idxAmountAssetId = 4
466452 let idxPriceAssetId = 5
467453 let poolCfg = {
468454 let @ = invoke(factoryContract, "getPoolConfigByLpAssetIdREADONLY", [lpAssetIdStr], nil)
469455 if ($isInstanceOf(@, "List[Any]"))
470456 then @
471457 else throw(($getType(@) + " couldn't be cast to List[Any]"))
472458 }
473459 let amountAssetId = {
474460 let @ = poolCfg[idxAmountAssetId]
475461 if ($isInstanceOf(@, "String"))
476462 then @
477463 else throw(($getType(@) + " couldn't be cast to String"))
478464 }
479465 let priceAssetId = {
480466 let @ = poolCfg[idxPriceAssetId]
481467 if ($isInstanceOf(@, "String"))
482468 then @
483469 else throw(($getType(@) + " couldn't be cast to String"))
484470 }
485471 $Tuple2(amountAssetId, priceAssetId)
486472 }
487473
488474
489475 func getUserVoteFinalized (lpAssetIdStr,userAddressStr) = {
490476 let userAddress = addressFromStringValue(userAddressStr)
491- let $t01816718247 = getVotingEmissionEpochInfo()
492- let lastFinalizedEpoch = $t01816718247._1
493- let currentEpochStartHeight = $t01816718247._2
494- let $t01825018325 = getPoolAssetsByLpAssetId(lpAssetIdStr)
495- let amountAssetId = $t01825018325._1
496- let priceAssetId = $t01825018325._2
477+ let $t01566715747 = getVotingEmissionEpochInfo()
478+ let lastFinalizedEpoch = $t01566715747._1
479+ let currentEpochStartHeight = $t01566715747._2
480+ let $t01575015825 = getPoolAssetsByLpAssetId(lpAssetIdStr)
481+ let amountAssetId = $t01575015825._1
482+ let priceAssetId = $t01575015825._2
497483 let userVoteKey = keyVote(amountAssetId, priceAssetId, userAddress, lastFinalizedEpoch)
498484 let userVote = valueOrElse(getInteger(votingEmissionContract, userVoteKey), 0)
499485 userVote
500486 }
501487
502488
503489 func getUserVoteStaked (lpAssetIdStr,userAddressStr) = {
504490 let stakedByUser = valueOrElse(getInteger(stakingContract, keyStakedByUser(userAddressStr, lpAssetIdStr)), 0)
505491 let userVote = getUserVoteFinalized(lpAssetIdStr, userAddressStr)
506492 if ((stakedByUser == 0))
507493 then 0
508494 else userVote
509495 }
510496
511497
512498 func getVotingResultStaked (lpAssetIdStr) = {
513- let $t01886918949 = getVotingEmissionEpochInfo()
514- let lastFinalizedEpoch = $t01886918949._1
515- let currentEpochStartHeight = $t01886918949._2
499+ let $t01636916449 = getVotingEmissionEpochInfo()
500+ let lastFinalizedEpoch = $t01636916449._1
501+ let currentEpochStartHeight = $t01636916449._2
516502 let votingResultStakedStart = valueOrElse(getInteger(votingEmissionContract, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), 0)
517503 let votingResultStaked = valueOrElse(getInteger(this, keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch)), votingResultStakedStart)
518504 votingResultStaked
519505 }
520506
521507
522508 func getVotingResultStakedIntegral (lpAssetIdStr) = {
523- let $t01931119391 = getVotingEmissionEpochInfo()
524- let lastFinalizedEpoch = $t01931119391._1
525- let currentEpochStartHeight = $t01931119391._2
509+ let $t01681116891 = getVotingEmissionEpochInfo()
510+ let lastFinalizedEpoch = $t01681116891._1
511+ let currentEpochStartHeight = $t01681116891._2
526512 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
527513 let votingResultStakedIntegralPrev = valueOrElse(getInteger(this, keyVotingResultStakedIntegral(lpAssetIdStr, lastFinalizedEpoch)), 0)
528514 let votingResultStakedLastUpdateHeight = valueOrElse(getInteger(this, keyVotingResultStakedLastUpdateHeight(lpAssetIdStr, lastFinalizedEpoch)), currentEpochStartHeight)
529515 let votingResultStakedIntegralDh = (height - votingResultStakedLastUpdateHeight)
530516 let votingResultStakedIntegral = ((votingResultStakedIntegralDh * votingResultStaked) + votingResultStakedIntegralPrev)
531517 votingResultStakedIntegral
532518 }
533519
534520
535521 func refreshVotingResultStakedIntegral (lpAssetIdStr,stakedVoteDelta) = {
536- let $t02022820308 = getVotingEmissionEpochInfo()
537- let lastFinalizedEpoch = $t02022820308._1
538- let currentEpochStartHeight = $t02022820308._2
522+ let $t01772817808 = getVotingEmissionEpochInfo()
523+ let lastFinalizedEpoch = $t01772817808._1
524+ let currentEpochStartHeight = $t01772817808._2
539525 let votingResultStaked = getVotingResultStaked(lpAssetIdStr)
540526 let votingResultStakedNew = (votingResultStaked + stakedVoteDelta)
541527 let votingResultStakedIntegral = getVotingResultStakedIntegral(lpAssetIdStr)
542528 [IntegerEntry(keyVotingResultStaked(lpAssetIdStr, lastFinalizedEpoch), votingResultStakedNew), IntegerEntry(keyVotingResultStakedLastUpdateHeight(lpAssetIdStr, lastFinalizedEpoch), height), IntegerEntry(keyVotingResultStakedIntegral(lpAssetIdStr, lastFinalizedEpoch), votingResultStakedIntegral)]
543529 }
544530
545531
546532 func getUserVoteStakedIntegral (lpAssetIdStr,userAddressStr) = {
547- let $t02091920999 = getVotingEmissionEpochInfo()
548- let lastFinalizedEpoch = $t02091920999._1
549- let currentEpochStartHeight = $t02091920999._2
533+ let $t01841918499 = getVotingEmissionEpochInfo()
534+ let lastFinalizedEpoch = $t01841918499._1
535+ let currentEpochStartHeight = $t01841918499._2
550536 let userAddress = addressFromStringValue(userAddressStr)
551537 let userVoteStaked = getUserVoteStaked(lpAssetIdStr, userAddressStr)
552538 let userVoteStakedIntegralPrev = valueOrElse(getInteger(this, keyVoteStakedIntegral(lpAssetIdStr, userAddress, lastFinalizedEpoch)), 0)
553539 let userVoteStakedLastUpdateHeight = valueOrElse(getInteger(this, keyVoteStakedLastUpdateHeight(lpAssetIdStr, userAddress, lastFinalizedEpoch)), currentEpochStartHeight)
554540 let userVoteStakedIntegralDh = (height - userVoteStakedLastUpdateHeight)
555541 let userVoteStakedIntegral = ((userVoteStakedIntegralDh * userVoteStaked) + userVoteStakedIntegralPrev)
556542 userVoteStakedIntegral
557543 }
558544
559545
560546 func refreshVoteStakedIntegral (lpAssetIdStr,userAddressStr,edge) = {
561- let $t02178721867 = getVotingEmissionEpochInfo()
562- let lastFinalizedEpoch = $t02178721867._1
563- let currentEpochStartHeight = $t02178721867._2
547+ let $t01928719367 = getVotingEmissionEpochInfo()
548+ let lastFinalizedEpoch = $t01928719367._1
549+ let currentEpochStartHeight = $t01928719367._2
564550 let userAddress = addressFromStringValue(userAddressStr)
565551 let userVoteFinalized = getUserVoteFinalized(lpAssetIdStr, userAddressStr)
566552 let actions = if ((userVoteFinalized == 0))
567553 then nil
568554 else {
569555 let stakedVoteDelta = if (edge)
570556 then userVoteFinalized
571557 else -(userVoteFinalized)
572558 let votingResultActions = refreshVotingResultStakedIntegral(lpAssetIdStr, stakedVoteDelta)
573559 let userVoteStakedIntegral = getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr)
574560 let voteActions = [IntegerEntry(keyVoteStakedLastUpdateHeight(lpAssetIdStr, userAddress, lastFinalizedEpoch), height), IntegerEntry(keyVoteStakedIntegral(lpAssetIdStr, userAddress, lastFinalizedEpoch), userVoteStakedIntegral)]
575561 (votingResultActions ++ voteActions)
576562 }
577563 actions
578564 }
579565
580566
581567 func getStakedVotesIntegralsDiff (lpAssetIdStr,userAddressStr) = {
582- let $t02272122801 = getVotingEmissionEpochInfo()
583- let lastFinalizedEpoch = $t02272122801._1
584- let currentEpochStartHeight = $t02272122801._2
568+ let $t02022120301 = getVotingEmissionEpochInfo()
569+ let lastFinalizedEpoch = $t02022120301._1
570+ let currentEpochStartHeight = $t02022120301._2
585571 let userAddress = addressFromStringValue(userAddressStr)
586572 let userVoteStakedIntegralLastKey = keyVoteStakedIntegralLast(lpAssetIdStr, userAddress, lastFinalizedEpoch)
587573 let userVoteStakedIntegralLast = valueOrElse(getInteger(this, userVoteStakedIntegralLastKey), 0)
588574 let votingResultStakedIntegralLastKey = keyVotingResultStakedIntegralLast(lpAssetIdStr, userAddress, lastFinalizedEpoch)
589575 let votingResultStakedIntegralLast = valueOrElse(getInteger(this, votingResultStakedIntegralLastKey), 0)
590576 let userVoteStakedIntegral = getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr)
591577 let votingResultStakedIntegral = getVotingResultStakedIntegral(lpAssetIdStr)
592578 let userVoteStakedIntegralDiff = (userVoteStakedIntegral - userVoteStakedIntegralLast)
593579 let votingResultStakedIntegralDiff = (votingResultStakedIntegral - votingResultStakedIntegralLast)
594580 $Tuple3([IntegerEntry(userVoteStakedIntegralLastKey, userVoteStakedIntegral), IntegerEntry(votingResultStakedIntegralLastKey, votingResultStakedIntegral)], userVoteStakedIntegralDiff, votingResultStakedIntegralDiff)
595581 }
596582
597583
598584 func refreshBoostEmissionIntegral () = {
599- let wxEmissionPerBlock = iof(emissionContract, keyEmissionRatePerBlockCurrent())
585+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
600586 let boostingV2LastUpdateHeightOption = getInteger(this, keyBoostingV2LastUpdateHeight())
601587 let boostingV2IngergalOption = getInteger(this, keyBoostingV2Integral())
602- let emissionEnd = iof(emissionContract, keyEmissionEndBlock())
588+ let emissionEnd = getIntOrFail(emissionContract, keyEmissionEndBlock())
603589 let h = if ((height > emissionEnd))
604590 then emissionEnd
605591 else height
606592 let dh = match boostingV2LastUpdateHeightOption {
607593 case lastUpdateHeight: Int =>
608594 max([(h - lastUpdateHeight), 0])
609595 case _: Unit =>
610596 0
611597 case _ =>
612598 throw("Match error")
613599 }
614600 let boostEmissionPerBlock = ((wxEmissionPerBlock * (boostCoeff - 1)) / boostCoeff)
615601 let boostEmissionIntegralPrev = valueOrElse(boostingV2IngergalOption, 0)
616602 let boostEmissionIntegral = ((boostEmissionPerBlock * dh) + boostEmissionIntegralPrev)
617603 $Tuple2([IntegerEntry(keyBoostingV2Integral(), boostEmissionIntegral), IntegerEntry(keyBoostingV2LastUpdateHeight(), height)], boostEmissionIntegral)
618604 }
619605
620606
621607 func internalClaimWxBoost (lpAssetIdStr,userAddressStr,readOnly) = {
622- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
623- if ((userRecordOption == unit))
624- then $Tuple3(0, nil, "userRecord::is::empty")
625- else {
626- let userRecordArray = split(value(userRecordOption), SEP)
627- let userNumStr = userRecordArray[IdxLockUserNum]
608+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
609+ let userNum = userNumberByAddressOrFail(userAddress)
610+ if ((userNum == userNum))
611+ then {
628612 let EMPTYSTR = "empty"
629613 let poolWeight = if ((lpAssetIdStr != EMPTYSTR))
630614 then {
631615 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr)), wrapErr(("unsupported lp asset " + lpAssetIdStr)))
632616 getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
633617 }
634618 else if (readOnly)
635619 then 0
636620 else throwErr(("not readonly mode: unsupported lp asset " + lpAssetIdStr))
637- let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNumStr, lpAssetIdStr)
638- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
639- let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), ioz(this, userBoostEmissionLastIntegralKEY))
621+ let userLpBoostEmissionLastIntegralKEY = keyUserLpBoostEmissionLastINTEGRAL(userNum, lpAssetIdStr)
622+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
623+ let userBoostEmissionLastIntegral = valueOrElse(getInteger(this, userLpBoostEmissionLastIntegralKEY), getIntOrZero(this, userBoostEmissionLastIntegralKEY))
640624 let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
641625 let userBoostEmissionIntegral = (boostEmissionIntegral - userBoostEmissionLastIntegral)
642626 if ((0 > userBoostEmissionIntegral))
643627 then throwErr("wrong calculations")
644628 else {
645- let $t02642026559 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
646- let stakedVotesIntegralsActions = $t02642026559._1
647- let userVoteIntegralDiff = $t02642026559._2
648- let totalVotesIntegralDiff = $t02642026559._3
629+ let $t02384323982 = getStakedVotesIntegralsDiff(lpAssetIdStr, userAddressStr)
630+ let stakedVotesIntegralsActions = $t02384323982._1
631+ let userVoteIntegralDiff = $t02384323982._2
632+ let totalVotesIntegralDiff = $t02384323982._3
649633 let poolUserBoostEmissionIntegral = fraction(userBoostEmissionIntegral, poolWeight, POOLWEIGHTMULT)
650634 let userBoostAvaliableToClaimTotalNew = if ((totalVotesIntegralDiff == 0))
651635 then 0
652636 else fraction(poolUserBoostEmissionIntegral, userVoteIntegralDiff, totalVotesIntegralDiff)
653637 let dataState = ([IntegerEntry(userLpBoostEmissionLastIntegralKEY, boostEmissionIntegral)] ++ stakedVotesIntegralsActions)
654638 let debug = makeString([toString(userBoostEmissionLastIntegral), toString(userBoostEmissionIntegral), toString(poolWeight), toString(userVoteIntegralDiff), toString(totalVotesIntegralDiff)], ":")
655639 $Tuple3(userBoostAvaliableToClaimTotalNew, dataState, debug)
656640 }
657641 }
642+ else throw("Strict value is not equal to itself.")
658643 }
659644
660645
661646 func lockActions (i,duration) = {
662- let cfgArray = readConfigArrayOrFail()
663- let assetIdStr = cfgArray[IdxCfgAssetId]
664- let assetId = fromBase58String(assetIdStr)
665- let minLockAmount = parseIntValue(cfgArray[IdxCfgMinLockAmount])
666- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
667- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
647+ let assetIdStr = toBase58String(assetId)
668648 if ((size(i.payments) != 1))
669649 then throwErr("invalid payment - exact one payment must be attached")
670650 else {
671651 let pmt = i.payments[0]
672652 let pmtAmount = pmt.amount
673653 if ((assetId != value(pmt.assetId)))
674654 then throwErr((("invalid asset is in payment - " + assetIdStr) + " is expected"))
675655 else {
676656 let nextUserNumKEY = keyNextUserNum()
677- let userAddressStr = toString(i.caller)
657+ let userAddress = i.caller
658+ let userAddressStr = toString(userAddress)
678659 let userIsExisting = isDefined(getString(keyUser2NumMapping(userAddressStr)))
679660 let userNumStr = if (userIsExisting)
680661 then value(getString(keyUser2NumMapping(userAddressStr)))
681- else toString(iof(this, nextUserNumKEY))
662+ else toString(getIntOrFail(this, nextUserNumKEY))
682663 let userNum = parseIntValue(userNumStr)
683664 let lockStart = height
684- let startBlockKEY = keyLockParamStartBlock(userNumStr)
685- let durationKEY = keyLockParamDuration(userNumStr)
686- let userAmountKEY = keyLockParamUserAmount(userNumStr)
687665 if (if ((minLockAmount > pmtAmount))
688- then (i.caller != lpStakingPoolsContract)
666+ then (userAddress != lpStakingPoolsContract)
689667 else false)
690668 then throwErr(("amount is less then minLockAmount=" + toString(minLockAmount)))
691669 else if ((minLockDuration > duration))
692- then throwErr(("passed duration is less then minLockDuration=" + toString(minLockDuration)))
670+ then throwErr(("passed duration is less than minLockDuration=" + toString(minLockDuration)))
693671 else if ((duration > maxLockDuration))
694- then throwErr(("passed duration is greater then maxLockDuration=" + toString(maxLockDuration)))
695- else if (if (userIsExisting)
696- then ((iof(this, startBlockKEY) + iof(this, durationKEY)) >= lockStart)
697- else false)
698- then throwErr("there is an active lock - consider to use increaseLock")
699- else if ((ioz(this, userAmountKEY) > 0))
700- then throwErr(("there are locked WXs - consider to use increaseLock " + userAmountKEY))
701- else {
702- let coeffX8 = fraction(duration, MULT8, maxLockDuration)
703- let gWxAmountStart = fraction(pmtAmount, coeffX8, MULT8)
704- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStart, duration], nil))
705- let k = ai(gWxParamsResultList[0])
706- let b = ai(gWxParamsResultList[1])
707- let period = toString(ai(gWxParamsResultList[2]))
708- let totalCachedGwxRaw = getTotalCachedGwx(false)
709- let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNumStr)
710- let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
711- let arr = if (userIsExisting)
712- then nil
713- else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
714- $Tuple2(((((arr ++ LockParamsEntry(userAddressStr, userNumStr, pmtAmount, lockStart, duration, k, b, period)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
715- then 0
716- else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, k, b, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gWxAmountStart))]), gWxAmountStart)
717- }
672+ then throwErr(("passed duration is greater than maxLockDuration=" + toString(maxLockDuration)))
673+ else if (((duration % lockStepBlocks) != 0))
674+ then throwErr(("duration must be multiple of lockStepBlocks=" + toString(lockStepBlocks)))
675+ else {
676+ let gWxAmountStart = fraction(pmtAmount, duration, maxLockDuration)
677+ let gwxAmountTotal = getGwxAmountTotal()
678+ let userBoostEmissionLastIntegralKEY = keyUserBoostEmissionLastINTEGRAL(userNum)
679+ let boostEmissionIntegral = refreshBoostEmissionIntegral()._2
680+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
681+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
682+ if ((gwxRewardInv == gwxRewardInv))
683+ then {
684+ let arr = if (userIsExisting)
685+ then nil
686+ else [IntegerEntry(nextUserNumKEY, (userNum + 1)), StringEntry(keyUser2NumMapping(userAddressStr), userNumStr), StringEntry(keyNum2UserMapping(userNumStr), userAddressStr)]
687+ $Tuple2(((((arr ++ LockParamsEntry(userAddress, i.transactionId, pmtAmount, lockStart, duration, gWxAmountStart, 0)) ++ StatsEntry(pmtAmount, duration, 1, if (userIsExisting)
688+ then 0
689+ else 1)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, duration, gWxAmountStart, i)) ++ [IntegerEntry(userBoostEmissionLastIntegralKEY, boostEmissionIntegral), IntegerEntry(keyGwxTotal(), (gwxAmountTotal + gWxAmountStart)), IntegerEntry(keyUserGwxAmountTotal(userAddress), (userGwxAmountTotal + gWxAmountStart))]), gWxAmountStart)
690+ }
691+ else throw("Strict value is not equal to itself.")
692+ }
718693 }
719694 }
720695 }
721696
722697
698+func getWxWithdrawable (userAddress,txIdOption) = {
699+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
700+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
701+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
702+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
703+ let lockEnd = (lockStart + lockDuration)
704+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
705+ let t = ((height - lockStart) / blocksInPeriod)
706+ let exponent = fraction(toBigInt(t), (toBigInt((DECAY_CONSTANT * blocksInPeriod)) * MULT18BI), toBigInt(lockDuration))
707+ let wxWithdrawableTotal = if ((height > lockEnd))
708+ then userAmount
709+ else toInt(fraction(toBigInt(userAmount), (MULT18BI - pow(toBigInt(5), 1, exponent, SCALE18, SCALE18, DOWN)), MULT18BI))
710+ let wxWithdrawable = (wxWithdrawableTotal - wxClaimed)
711+ wxWithdrawable
712+ }
713+
714+
723715 @Callable(i)
724-func constructor (factoryAddressStr,lockAssetIdStr,minLockAmount,minDuration,maxDuration,mathContract) = {
725- let checkCaller = mustManager(i)
726- if ((checkCaller == checkCaller))
727- then ([IntegerEntry(keyNextUserNum(), 0), StringEntry(keyConfig(), formatConfig(lockAssetIdStr, minLockAmount, minDuration, maxDuration, mathContract)), StringEntry(keyFactoryAddress(), factoryAddressStr)] ++ StatsEntry(0, 0, 0, 0))
716+func lockRef (duration,referrerAddress,signature) = {
717+ let suspensionCheck = throwIfSuspended()
718+ if ((suspensionCheck == suspensionCheck))
719+ then {
720+ let $t02840028465 = lockActions(i, duration)
721+ let lockActionsResult = $t02840028465._1
722+ let gWxAmountStart = $t02840028465._2
723+ let referralAddress = toString(i.caller)
724+ let refInv = if (if ((referrerAddress == ""))
725+ then true
726+ else (signature == base58''))
727+ then unit
728+ else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
729+ if ((refInv == refInv))
730+ then {
731+ let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
732+ if ((updateRefActivity == updateRefActivity))
733+ then $Tuple2(lockActionsResult, unit)
734+ else throw("Strict value is not equal to itself.")
735+ }
736+ else throw("Strict value is not equal to itself.")
737+ }
728738 else throw("Strict value is not equal to itself.")
729739 }
730740
731741
732742
733743 @Callable(i)
734-func lockRef (duration,referrerAddress,signature) = {
735- let $t03117031235 = lockActions(i, duration)
736- let lockActionsResult = $t03117031235._1
737- let gWxAmountStart = $t03117031235._2
738- let referralAddress = toString(i.caller)
739- let refInv = if (if ((referrerAddress == ""))
740- then true
741- else (signature == base58''))
742- then unit
743- else invoke(referralsContractAddressOrFail, "createPair", [referralProgramName, referrerAddress, referralAddress, signature], nil)
744- if ((refInv == refInv))
744+func lock (duration) = {
745+ let suspensionCheck = throwIfSuspended()
746+ if ((suspensionCheck == suspensionCheck))
745747 then {
748+ let $t02896929034 = lockActions(i, duration)
749+ let lockActionsResult = $t02896929034._1
750+ let gWxAmountStart = $t02896929034._2
746751 let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
747752 if ((updateRefActivity == updateRefActivity))
748753 then $Tuple2(lockActionsResult, unit)
749754 else throw("Strict value is not equal to itself.")
750755 }
751756 else throw("Strict value is not equal to itself.")
752757 }
753758
754759
755760
756761 @Callable(i)
757-func lock (duration) = {
758- let $t03169331758 = lockActions(i, duration)
759- let lockActionsResult = $t03169331758._1
760- let gWxAmountStart = $t03169331758._2
761- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
762- if ((updateRefActivity == updateRefActivity))
763- then $Tuple2(lockActionsResult, unit)
762+func claimWxBoost (lpAssetIdStr,userAddressStr) = {
763+ let suspensionCheck = throwIfSuspended()
764+ if ((suspensionCheck == suspensionCheck))
765+ then if ((stakingContract != i.caller))
766+ then throwErr("permissions denied")
767+ else {
768+ let $t02939029492 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
769+ let userBoostAvailable = $t02939029492._1
770+ let dataState = $t02939029492._2
771+ let debug = $t02939029492._3
772+ $Tuple2(dataState, [userBoostAvailable])
773+ }
764774 else throw("Strict value is not equal to itself.")
765775 }
766776
767777
768778
769779 @Callable(i)
770-func increaseLock (deltaDuration) = {
771- let cfgArray = readConfigArrayOrFail()
772- let assetIdStr = cfgArray[IdxCfgAssetId]
773- let assetId = fromBase58String(assetIdStr)
774- let minLockDuration = parseIntValue(cfgArray[IdxCfgMinLockDuration])
775- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
776- let pmtAmount = extractOptionalPaymentAmountOrFail(i, assetId)
777- let userAddressStr = toString(i.caller)
778- let userRecordArray = readLockParamsRecordOrFail(userAddressStr)
779- let userNumStr = userRecordArray[IdxLockUserNum]
780- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
781- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
782- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
783- let lockEnd = (lockStart + lockDuration)
784- let remainingDuration = max([(lockEnd - height), 0])
785- let userAmountNew = (userAmount + pmtAmount)
786- let lockDurationNew = (remainingDuration + deltaDuration)
787- if ((0 > deltaDuration))
788- then throwErr("duration is less then zero")
789- else if ((minLockDuration > lockDurationNew))
790- then throwErr(("lockDurationNew is less then minLockDuration=" + toString(minLockDuration)))
791- else if ((lockDurationNew > maxLockDuration))
792- then throwErr(("deltaDuration + existedLockDuration is greater then maxLockDuration=" + toString(maxLockDuration)))
793- else {
794- let coeffX8 = fraction(lockDurationNew, MULT8, maxLockDuration)
795- let gWxAmountStart = fraction(userAmountNew, coeffX8, MULT8)
796- let updateRefActivity = invoke(mathContract, "updateReferralActivity", [toString(i.caller), gWxAmountStart], nil)
797- if ((updateRefActivity == updateRefActivity))
798- then {
799- let lockStartNew = height
800- let gWxParamsResultList = aal(invoke(mathContract, "calcGwxParamsREADONLY", [gWxAmountStart, lockStartNew, lockDurationNew], nil))
801- let k = ai(gWxParamsResultList[0])
802- let b = ai(gWxParamsResultList[1])
803- let period = toString(ai(gWxParamsResultList[2]))
804- let currUserGwx = calcCurrentGwxAmount(userAddressStr)
805- let gwxDiff = (gWxAmountStart - currUserGwx)
806- if ((0 > gwxDiff))
807- then throwErr(("gwxDiff is less then 0: " + toString(gwxDiff)))
808- else {
809- let totalCachedGwxRaw = getTotalCachedGwx(false)
810- let totalCachedGwxCorrected = getTotalCachedGwx(true)
811- (((LockParamsEntry(userAddressStr, userNumStr, userAmountNew, lockStartNew, lockDurationNew, k, b, period) ++ StatsEntry(pmtAmount, deltaDuration, 0, 0)) :+ HistoryEntry("lock", userAddressStr, pmtAmount, lockStart, lockDurationNew, k, b, i)) ++ [IntegerEntry(keyTotalCachedGwx(), (totalCachedGwxRaw + gwxDiff))])
812- }
813- }
814- else throw("Strict value is not equal to itself.")
815- }
816- }
817-
818-
819-
820-@Callable(i)
821-func claimWxBoost (lpAssetIdStr,userAddressStr) = if ((stakingContract != i.caller))
822- then throwErr("permissions denied")
823- else {
824- let $t03486334965 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, false)
825- let userBoostAvailable = $t03486334965._1
826- let dataState = $t03486334965._2
827- let debug = $t03486334965._3
828- $Tuple2(dataState, [userBoostAvailable])
829- }
830-
831-
832-
833-@Callable(i)
834780 func claimWxBoostREADONLY (lpAssetIdStr,userAddressStr) = {
835- let $t03509735198 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
836- let userBoostAvailable = $t03509735198._1
837- let dataState = $t03509735198._2
838- let debug = $t03509735198._3
781+ let $t02962429725 = internalClaimWxBoost(lpAssetIdStr, userAddressStr, true)
782+ let userBoostAvailable = $t02962429725._1
783+ let dataState = $t02962429725._2
784+ let debug = $t02962429725._3
839785 $Tuple2(nil, [userBoostAvailable, debug])
840786 }
841787
842788
843789
844790 @Callable(i)
845-func unlock (userAddress) = {
846- let userRecordArray = readLockParamsRecordOrFail(userAddress)
847- let userNumStr = userRecordArray[IdxLockUserNum]
848- let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
849- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
850- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
851- let lockEnd = (lockStart + lockDuration)
852- let cfgArray = readConfigArrayOrFail()
853- let assetId = fromBase58String(cfgArray[IdxCfgAssetId])
854- if ((lockEnd >= height))
855- then throwErr((("wait " + toString(lockEnd)) + " to unlock"))
856- else if ((0 >= userAmount))
857- then throwErr("nothing to unlock")
858- else {
859- let period = valueOrElse(getInteger(mathContract, keyNextPeriod()), 0)
860- (((LockParamsEntry(userAddress, userNumStr, 0, lockStart, lockDuration, 0, 0, toString(period)) ++ StatsEntry(-(userAmount), 0, 0, -1)) :+ HistoryEntry("unlock", userAddress, userAmount, lockStart, lockDuration, 0, 0, i)) :+ ScriptTransfer(addressFromStringValue(userAddress), userAmount, assetId))
861- }
791+func unlock (txIdStr) = {
792+ let suspensionCheck = throwIfSuspended()
793+ if ((suspensionCheck == suspensionCheck))
794+ then {
795+ let userAddress = i.caller
796+ let userAddressStr = toString(userAddress)
797+ let txIdOption = if ((txIdStr == ""))
798+ then unit
799+ else fromBase58String(txIdStr)
800+ let userRecordArray = readLockParamsRecordOrFail(userAddress, txIdOption)
801+ let userAmount = parseIntValue(userRecordArray[IdxLockAmount])
802+ let lockStart = parseIntValue(userRecordArray[IdxLockStart])
803+ let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
804+ let wxClaimed = parseIntValue(userRecordArray[IdxLockWxClaimed])
805+ let gwxAmount = parseIntValue(userRecordArray[IdxLockGwxAmount])
806+ let t = ((height - lockStart) / blocksInPeriod)
807+ let wxWithdrawable = getWxWithdrawable(userAddress, txIdOption)
808+ let gwxBurned = min([fraction(wxWithdrawable, lockDuration, maxLockDuration), gwxAmount])
809+ let gwxRemaining = ensurePositive((gwxAmount - gwxBurned), "gwxRemaining")
810+ let lockedGwxAmount = getLockedGwxAmount(userAddress)
811+ if ((0 >= wxWithdrawable))
812+ then throwErr("nothing to unlock")
813+ else {
814+ let gwxAmountTotal = getGwxAmountTotal()
815+ let userGwxAmountTotal = getUserGwxAmountTotal(userAddress)
816+ let userGwxAmountTotalNew = ensurePositive((userGwxAmountTotal - gwxBurned), "userGwxAmountTotalNew")
817+ if ((lockedGwxAmount > userGwxAmountTotalNew))
818+ then throwErr(("locked gwx amount: " + toString(lockedGwxAmount)))
819+ else {
820+ let userNum = parseIntValue(valueOrErrorMessage(getString(keyUser2NumMapping(userAddressStr)), wrapErr("invalid user number")))
821+ let gwxRewardInv = invoke(gwxRewardContract, "refreshUserReward", [userAddress.bytes, userNum], nil)
822+ if ((gwxRewardInv == gwxRewardInv))
823+ then ((((LockParamsEntry(userAddress, txIdOption, userAmount, lockStart, lockDuration, gwxRemaining, (wxClaimed + wxWithdrawable)) ++ StatsEntry(-(wxWithdrawable), 0, 0, 0)) :+ HistoryEntry("unlock", userAddressStr, wxWithdrawable, lockStart, lockDuration, gwxBurned, i)) :+ ScriptTransfer(userAddress, wxWithdrawable, assetId)) ++ [IntegerEntry(keyGwxTotal(), ensurePositive((gwxAmountTotal - gwxBurned), "gwxTotal")), IntegerEntry(keyUserGwxAmountTotal(userAddress), userGwxAmountTotalNew)])
824+ else throw("Strict value is not equal to itself.")
825+ }
826+ }
827+ }
828+ else throw("Strict value is not equal to itself.")
862829 }
863830
864831
865832
866833 @Callable(i)
867-func gwxUserInfoREADONLY (userAddress) = {
868- let gwxAmount = calcCurrentGwxAmount(userAddress)
834+func gwxUserInfoREADONLY (userAddressStr) = {
835+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
836+ let gwxAmount = getUserGwxAmountTotal(userAddress)
869837 $Tuple2(nil, [gwxAmount])
870838 }
871839
872840
873841
874842 @Callable(i)
875-func userMaxDurationREADONLY (userAddressStr) = {
876- let cfgArray = readConfigArrayOrFail()
877- let maxLockDuration = parseIntValue(cfgArray[IdxCfgMaxLockDuration])
878- let userRecordOption = getString(this, keyLockParamsRecord(userAddressStr))
879- if ((userRecordOption == unit))
880- then $Tuple2(nil, $Tuple2("lock", maxLockDuration))
881- else {
882- let userRecordArray = split(value(userRecordOption), SEP)
883- let lockStart = parseIntValue(userRecordArray[IdxLockStart])
884- let lockDuration = parseIntValue(userRecordArray[IdxLockDuration])
885- let lockEnd = (lockStart + lockDuration)
886- let remainingDuration = max([(lockEnd - height), 0])
887- let maxDeltaDuration = (maxLockDuration - remainingDuration)
888- $Tuple2(nil, $Tuple2("increaseLock", maxDeltaDuration))
889- }
890- }
843+func userMaxDurationREADONLY (userAddressStr) = $Tuple2(nil, $Tuple2("lock", maxLockDuration))
891844
892845
893846
894847 @Callable(i)
895-func getUserGwxAmountAtHeightREADONLY (userAddress,targetHeight) = {
896- let gwxAmount = calcUserGwxAmountAtHeight(userAddress, targetHeight)
848+func getUserGwxAmountAtHeightREADONLY (userAddressStr,targetHeight) = {
849+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
850+ let gwxAmount = getUserGwxAmountTotal(userAddress)
897851 $Tuple2(nil, gwxAmount)
898852 }
899853
900854
901855
902856 @Callable(i)
903-func getTotalCachedGwxREADONLY () = $Tuple2(nil, getTotalCachedGwx(true))
857+func getUserGwxAmount (userAddressStr) = {
858+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
859+ let gwxAmount = getUserGwxAmountTotal(userAddress)
860+ $Tuple2(nil, gwxAmount)
861+ }
862+
863+
864+
865+@Callable(i)
866+func getGwxTotalREADONLY () = $Tuple2(nil, getGwxAmountTotal())
904867
905868
906869
907870 @Callable(i)
908871 func onBoostEmissionUpdate () = {
909- let checkCaller = if ((i.caller == emissionContract))
910- then true
911- else mustManager(i)
912- if ((checkCaller == checkCaller))
913- then refreshBoostEmissionIntegral()
872+ let suspensionCheck = throwIfSuspended()
873+ if ((suspensionCheck == suspensionCheck))
874+ then {
875+ let checkCaller = if ((i.caller == emissionContract))
876+ then true
877+ else mustManager(i)
878+ if ((checkCaller == checkCaller))
879+ then refreshBoostEmissionIntegral()
880+ else throw("Strict value is not equal to itself.")
881+ }
914882 else throw("Strict value is not equal to itself.")
915883 }
916884
917885
918886
919887 @Callable(i)
920888 func onStakedVoteUpdate (lpAssetIdStr,userAddressStr,edge) = {
921- let checkCaller = if ((i.caller == stakingContract))
922- then true
923- else mustManager(i)
924- if ((checkCaller == checkCaller))
889+ let suspensionCheck = throwIfSuspended()
890+ if ((suspensionCheck == suspensionCheck))
925891 then {
926- let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
927- $Tuple2(actions, unit)
892+ let checkCaller = if ((i.caller == stakingContract))
893+ then true
894+ else mustManager(i)
895+ if ((checkCaller == checkCaller))
896+ then {
897+ let actions = refreshVoteStakedIntegral(lpAssetIdStr, userAddressStr, edge)
898+ $Tuple2(actions, unit)
899+ }
900+ else throw("Strict value is not equal to itself.")
928901 }
929902 else throw("Strict value is not equal to itself.")
930903 }
931904
932905
933906
934907 @Callable(i)
935908 func getVotingResultStakedREADONLY (lpAssetIdStr) = $Tuple2(nil, getVotingResultStaked(lpAssetIdStr))
936909
937910
938911
939912 @Callable(i)
940913 func getVotingResultStakedIntegralREADONLY (lpAssetIdStr) = $Tuple2(nil, getVotingResultStakedIntegral(lpAssetIdStr))
941914
942915
943916
944917 @Callable(i)
945918 func getUserVoteFinalizedREADONLY (lpAssetIdStr,userAddressStr) = $Tuple2(nil, getUserVoteFinalized(lpAssetIdStr, userAddressStr))
946919
947920
948921
949922 @Callable(i)
950923 func getUserVoteStakedIntegralREADONLY (lpAssetIdStr,userAddressStr) = $Tuple2(nil, getUserVoteStakedIntegral(lpAssetIdStr, userAddressStr))
951924
952925
926+
927+@Callable(i)
928+func suspend (v) = {
929+ let checkCaller = mustManager(i)
930+ if ((checkCaller == checkCaller))
931+ then $Tuple2([BooleanEntry(keySuspension, v)], v)
932+ else throw("Strict value is not equal to itself.")
933+ }
934+
935+
953936 @Verifier(tx)
954937 func verify () = {
955938 let targetPublicKey = match managerPublicKeyOrUnit() {
956939 case pk: ByteVector =>
957940 pk
958941 case _: Unit =>
959942 tx.senderPublicKey
960943 case _ =>
961944 throw("Match error")
962945 }
963946 sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
964947 }
965948

github/deemru/w8io/3ef1775 
195.28 ms