tx · 8nqr4Zs3FDv3Zeahgkz6kwPNowYm7AjX658eYbjCHNy6

3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz:  -0.03500000 Waves

2022.06.14 19:33 [2096297] smart account 3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz > SELF 0.00000000 Waves

{ "type": 13, "id": "8nqr4Zs3FDv3Zeahgkz6kwPNowYm7AjX658eYbjCHNy6", "fee": 3500000, "feeAssetId": null, "timestamp": 1655224454999, "version": 1, "sender": "3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz", "senderPublicKey": "D28XoueZWsMfm8Y5pa6C5ZFuYoWgre2Wm8tzJANJgMnq", "proofs": [ "ozV44z1ZKeTatozBPFzKeYd1sumjrbSZxzCVbf2ikHBF2v7RCLtiMt9gGxmcgTM9of2LePttW2QcMjyMJ5VgyaV" ], "script": "base64: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YXRjaDAJAAQdAAAAAgUAAAAHYWRkcmVzcwUAAAADa2V5AwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAAZTdHJpbmcEAAAAAXMFAAAAByRtYXRjaDAJAQAAAAV2YWx1ZQAAAAEJAAGoAAAAAQUAAAABcwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAEVW5pdAUAAAAKZGVmYXVsdFZhbAkAAAIAAAABAgAAAAtNYXRjaCBlcnJvcgEAAAAFdG9YMTgAAAACAAAAB29yaWdWYWwAAAANb3JpZ1NjYWxlTXVsdAkAATwAAAADCQABNgAAAAEFAAAAB29yaWdWYWwFAAAABk1VTFQxOAkAATYAAAABBQAAAA1vcmlnU2NhbGVNdWx0AQAAAAdmcm9tWDE4AAAAAgAAAAN2YWwAAAAPcmVzdWx0U2NhbGVNdWx0CQABoAAAAAEJAAE8AAAAAwUAAAADdmFsCQABNgAAAAEFAAAAD3Jlc3VsdFNjYWxlTXVsdAUAAAAGTVVMVDE4AQAAABFrZXlGYWN0b3J5QWRkcmVzcwAAAAACAAAAHCVzJXNfX2NvbmZpZ19fZmFjdG9yeUFkZHJlc3MAAAAAGElkeEZhY3RvcnlDZmdTdGFraW5nRGFwcAAAAAAAAAAAAQAAAAAZSWR4RmFjdG9yeUNmZ0Jvb3N0aW5nRGFwcAAAAAAAAAAAAgAAAAAUSWR4RmFjdG9yeUNmZ0lkb0RhcHAAAAAAAAAAAAMAAAAAFUlkeEZhY3RvcnlDZmdUZWFtRGFwcAAAAAAAAAAABAAAAAAZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAAAAAAAAAAABQAAAAAVSWR4RmFjdG9yeUNmZ1Jlc3REYXBwAAAAAAAAAAAGAAAAABlJZHhGYWN0b3J5Q2ZnU2xpcHBhZ2VEYXBwAAAAAAAAAAAHAQAAAA1rZXlGYWN0b3J5Q2ZnAAAAAAIAAAARJXNfX2ZhY3RvcnlDb25maWcBAAAAE2tleU1hbmFnZXJQdWJsaWNLZXkAAAAAAgAAABQlc19fbWFuYWdlclB1YmxpY0tleQEAAAAaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkAAAAAAgAAABslc19fcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkBAAAAFmtleVN0YWJsZVBvb2xBZGRvbkFkZHIAAAAAAgAAABclc19fc3RhYmxlUG9vbEFkZG9uQWRkcgEAAAAaa2V5RmFjdG9yeUxwMkFzc2V0c01hcHBpbmcAAAABAAAACmxwQXNzZXRTdHIJAAS5AAAAAgkABEwAAAACAgAAAAYlcyVzJXMJAARMAAAAAgUAAAAKbHBBc3NldFN0cgkABEwAAAACAgAAAB5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFAAAAA25pbAUAAAADU0VQAQAAABBrZXlGYWN0b3J5THBMaXN0AAAAAAIAAAAQJXNfX2xwVG9rZW5zTGlzdAEAAAAma2V5RmFjdG9yeUxwQXNzZXRUb1Bvb2xDb250cmFjdEFkZHJlc3MAAAABAAAACmxwQXNzZXRTdHIJAAS5AAAAAgkABEwAAAACAgAAAAYlcyVzJXMJAARMAAAAAgUAAAAKbHBBc3NldFN0cgkABEwAAAACAgAAAB5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFAAAAA25pbAUAAAADU0VQAQAAABRrZXlGYWN0b3J5UG9vbFdlaWdodAAAAAEAAAAPY29udHJhY3RBZGRyZXNzCQAEuQAAAAIJAARMAAAAAgIAAAAEJXMlcwkABEwAAAACAgAAAApwb29sV2VpZ2h0CQAETAAAAAIFAAAAD2NvbnRyYWN0QWRkcmVzcwUAAAADbmlsBQAAAANTRVABAAAACnJlYWRMcExpc3QAAAABAAAAB2ZhY3RvcnkJAAS1AAAAAgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABB0AAAACBQAAAAdmYWN0b3J5CQEAAAAQa2V5RmFjdG9yeUxwTGlzdAAAAAACAAAAAAUAAAADU0VQAQAAABRyZWFkRmFjdG9yeUNmZ09yRmFpbAAAAAEAAAAHZmFjdG9yeQkABLUAAAACCQEAAAAYZ2V0U3RyaW5nQnlBZGRyZXNzT3JGYWlsAAAAAgUAAAAHZmFjdG9yeQkBAAAADWtleUZhY3RvcnlDZmcAAAAABQAAAANTRVABAAAAGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAAAAAEAAAAKZmFjdG9yeUNmZwkBAAAAEUBleHRyTmF0aXZlKDEwNjIpAAAAAQkAAZEAAAACBQAAAApmYWN0b3J5Q2ZnBQAAABlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwAQAAABhnZXRFbWlzc2lvbkFkZHJlc3NPckZhaWwAAAABAAAACmZhY3RvcnlDZmcJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEJAAGRAAAAAgUAAAAKZmFjdG9yeUNmZwUAAAAZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAEAAAAXZ2V0U3Rha2luZ0FkZHJlc3NPckZhaWwAAAABAAAACmZhY3RvcnlDZmcJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEJAAGRAAAAAgUAAAAKZmFjdG9yeUNmZwUAAAAYSWR4RmFjdG9yeUNmZ1N0YWtpbmdEYXBwAQAAAB5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQAAAAAAgAAABslcyVzX19yYXRlUGVyQmxvY2tfX2N1cnJlbnQBAAAAIWtleUVtaXNzaW9uUmF0ZVBlckJsb2NrTWF4Q3VycmVudAAAAAACAAAAHiVzJXNfX3JhdGVQZXJCbG9ja01heF9fY3VycmVudAEAAAAVa2V5RW1pc3Npb25TdGFydEJsb2NrAAAAAAIAAAAaJXMlc19fZW1pc3Npb25fX3N0YXJ0QmxvY2sBAAAAG2tleUVtaXNzaW9uRHVyYXRpb25JbkJsb2NrcwAAAAACAAAAGCVzJXNfX2VtaXNzaW9uX19kdXJhdGlvbgEAAAATa2V5RW1pc3Npb25FbmRCbG9jawAAAAACAAAAGCVzJXNfX2VtaXNzaW9uX19lbmRCbG9jawEAAAAPa2V5U3Rha2VkQnlVc2VyAAAAAgAAAA51c2VyQWRkcmVzc1N0cgAAAAxscEFzc2V0SWRTdHIJAAS5AAAAAgkABEwAAAACAgAAAA4lcyVzJXNfX3N0YWtlZAkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgkABEwAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAAA25pbAUAAAADU0VQAQAAAA5rZXlTdGFrZWRUb3RhbAAAAAEAAAAMbHBBc3NldElkU3RyCQABLAAAAAICAAAAFyVzJXMlc19fc3Rha2VkX190b3RhbF9fBQAAAAxscEFzc2V0SWRTdHIBAAAAEGtleUNsYWltZWRCeVVzZXIAAAACAAAADGxwQXNzZXRJZFN0cgAAAA51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eUNmZwkBAAAAFHJlYWRGYWN0b3J5Q2ZnT3JGYWlsAAAAAQUAAAAPZmFjdG9yeUNvbnRyYWN0AAAAABBlbWlzc2lvbkNvbnRyYWN0CQEAAAAYZ2V0RW1pc3Npb25BZGRyZXNzT3JGYWlsAAAAAQUAAAAKZmFjdG9yeUNmZwAAAAAQYm9vc3RpbmdDb250cmFjdAkBAAAAGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAAAAAEFAAAACmZhY3RvcnlDZmcBAAAAG2NhbGNXeFBlckxwSW50ZWdyYWxVc2VyTGFzdAAAAAQAAAAMc3Rha2VkQnlVc2VyAAAAJnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0T3JaZXJvAAAAEnd4UGVyTHBJbnRlZ3JhbE5ldwAAABp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQMDCQAAAAAAAAIFAAAAJnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0T3JaZXJvBQAAAAp6ZXJvQmlnSW50CQABPwAAAAIFAAAADHN0YWtlZEJ5VXNlcgUAAAAKemVyb0JpZ0ludAcFAAAACnplcm9CaWdJbnQDCQAAAAAAAAIFAAAADHN0YWtlZEJ5VXNlcgUAAAAKemVyb0JpZ0ludAUAAAASd3hQZXJMcEludGVncmFsTmV3AwMJAAE/AAAAAgUAAAAmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8FAAAACnplcm9CaWdJbnQJAAE/AAAAAgUAAAAMc3Rha2VkQnlVc2VyBQAAAAp6ZXJvQmlnSW50BwkBAAAABXZhbHVlAAAAAQkAAagAAAABCQEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAgUAAAAEdGhpcwUAAAAad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJAAACAAAAAQIAAAAtY2FsY1d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0OiB1bmV4cGVjdGVkIHN0YXRlAQAAABRyZWZyZXNoUG9vbElOVEVHUkFMUwAAAAMAAAAMbHBBc3NldElkU3RyAAAADnBvb2xBZGRyZXNzU3RyAAAADWxwRGVsdGFBbW91bnQEAAAADnN0YWtlZFRvdGFsS0VZCQEAAAAOa2V5U3Rha2VkVG90YWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAAC3N0YWtlZFRvdGFsCQABNgAAAAEJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAOc3Rha2VkVG90YWxLRVkEAAAAEm5vblplcm9TdGFrZWRUb3RhbAMJAAAAAAAAAgUAAAALc3Rha2VkVG90YWwFAAAACnplcm9CaWdJbnQFAAAACW9uZUJpZ0ludAUAAAALc3Rha2VkVG90YWwEAAAACnBvb2xXZWlnaHQJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAAD2ZhY3RvcnlDb250cmFjdAkBAAAAFGtleUZhY3RvcnlQb29sV2VpZ2h0AAAAAQUAAAAOcG9vbEFkZHJlc3NTdHIEAAAAEmVtaXNzaW9uU3RhcnRCbG9jawkBAAAADGdldEludE9yRmFpbAAAAAIFAAAAEGVtaXNzaW9uQ29udHJhY3QJAQAAABVrZXlFbWlzc2lvblN0YXJ0QmxvY2sAAAAABAAAAAVNVUxUMwAAAAAAAAAD6AQAAAAUd3hFbWlzc2lvblBlckJsb2NrWDMJAABoAAAAAgkBAAAADGdldEludE9yRmFpbAAAAAIFAAAAEGVtaXNzaW9uQ29udHJhY3QJAQAAAB5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQAAAAABQAAAAVNVUxUMwQAAAAYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQAAawAAAAMFAAAAFHd4RW1pc3Npb25QZXJCbG9ja1gzBQAAAApwb29sV2VpZ2h0CQAAaAAAAAIFAAAADlBPT0xXRUlHSFRNVUxUAAAAAAAAAAADBAAAABJ3eFBlckxwSW50ZWdyYWxLRVkJAQAAABJrZXlXeFBlckxwSW50ZWdyYWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAAH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkJAQAAAB9rZXlXeFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0AAAAAQUAAAAMbHBBc3NldElkU3RyBAAAAAp3eFBlckxwS0VZCQEAAAAKa2V5V3hQZXJMcAAAAAEFAAAADGxwQXNzZXRJZFN0cgQAAAAcd3hQZXJMcEludGVncmFsTGFzdFVwZEhlaWdodAkBAAAAD2dldEludE9yRGVmYXVsdAAAAAMFAAAABHRoaXMFAAAAH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkFAAAAEmVtaXNzaW9uU3RhcnRCbG9jawQAAAAPd3hQZXJMcEludGVncmFsCQEAAAAZZ2V0QmlnSW50RnJvbVN0cmluZ09yWmVybwAAAAIFAAAABHRoaXMFAAAAEnd4UGVyTHBJbnRlZ3JhbEtFWQQAAAAPd3hQZXJMcE9yWmVyb1gzAAAAAAAAAAAABAAAAAJkaAkAAZYAAAABCQAETAAAAAIJAABlAAAAAgUAAAAGaGVpZ2h0BQAAABx3eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0CQAETAAAAAIAAAAAAAAAAAAFAAAAA25pbAQAAAAJd3hQZXJMcFgzAwkBAAAAAiE9AAAAAgUAAAAPd3hQZXJMcE9yWmVyb1gzAAAAAAAAAAAACQABNgAAAAEFAAAAD3d4UGVyTHBPclplcm9YMwkAATwAAAADCQABNgAAAAEFAAAAGHBvb2xXeEVtaXNzaW9uUGVyQmxvY2tYMwkAATYAAAABBQAAAAVNVUxUOAUAAAASbm9uWmVyb1N0YWtlZFRvdGFsBAAAAA5zdGFrZWRUb3RhbE5ldwkAATcAAAACBQAAAAtzdGFrZWRUb3RhbAkAATYAAAABBQAAAA1scERlbHRhQW1vdW50BAAAABVub25aZXJvU3Rha2VkVG90YWxOZXcDCQAAAAAAAAIFAAAADnN0YWtlZFRvdGFsTmV3BQAAAAp6ZXJvQmlnSW50BQAAAAlvbmVCaWdJbnQFAAAADnN0YWtlZFRvdGFsTmV3BAAAABJ3eFBlckxwSW50ZWdyYWxOZXcJAAE3AAAAAgUAAAAPd3hQZXJMcEludGVncmFsCQABOQAAAAIFAAAACXd4UGVyTHBYMwkAATYAAAABBQAAAAJkaAQAAAAMd3hQZXJMcFgzTmV3CQABOgAAAAIJAAE2AAAAAQUAAAAYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzBQAAABVub25aZXJvU3Rha2VkVG90YWxOZXcEAAAAH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHROZXcFAAAABmhlaWdodAQAAAAFZGVidWcJAAS5AAAAAgkABEwAAAACAgAAABN3eFBlckxwSW50ZWdyYWxOZXc9CQAETAAAAAIJAAGmAAAAAQUAAAASd3hQZXJMcEludGVncmFsTmV3CQAETAAAAAICAAAAA2RoPQkABEwAAAACCQABpAAAAAEFAAAAAmRoCQAETAAAAAICAAAACnd4UGVyTHBYMz0JAARMAAAAAgkAAaYAAAABBQAAAAl3eFBlckxwWDMJAARMAAAAAgIAAAAMc3Rha2VkVG90YWw9CQAETAAAAAIJAAGmAAAAAQUAAAALc3Rha2VkVG90YWwJAARMAAAAAgIAAAAZcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzPQkABEwAAAACCQABpAAAAAEFAAAAGHBvb2xXeEVtaXNzaW9uUGVyQmxvY2tYMwkABEwAAAACAgAAABV3eEVtaXNzaW9uUGVyQmxvY2tYMz0JAARMAAAAAgkAAaQAAAABBQAAABR3eEVtaXNzaW9uUGVyQmxvY2tYMwkABEwAAAACAgAAAAtwb29sV2VpZ2h0PQkABEwAAAACCQABpAAAAAEFAAAACnBvb2xXZWlnaHQFAAAAA25pbAIAAAACOjoJAAUVAAAAAwUAAAASd3hQZXJMcEludGVncmFsTmV3CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEnd4UGVyTHBJbnRlZ3JhbEtFWQkAAaYAAAABBQAAABJ3eFBlckxwSW50ZWdyYWxOZXcJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkFAAAAH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHROZXcJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAAKd3hQZXJMcEtFWQkAAaYAAAABBQAAAAx3eFBlckxwWDNOZXcFAAAAA25pbAUAAAAFZGVidWcBAAAAEHJlZnJlc2hJTlRFR1JBTFMAAAAEAAAADGxwQXNzZXRJZFN0cgAAAA51c2VyQWRkcmVzc1N0cgAAAA5wb29sQWRkcmVzc1N0cgAAAA1scERlbHRhQW1vdW50BAAAAA0kdDAxMTUxODExNjQwCQEAAAAUcmVmcmVzaFBvb2xJTlRFR1JBTFMAAAADBQAAAAxscEFzc2V0SWRTdHIFAAAADnBvb2xBZGRyZXNzU3RyBQAAAA1scERlbHRhQW1vdW50BAAAABJ3eFBlckxwSW50ZWdyYWxOZXcIBQAAAA0kdDAxMTUxODExNjQwAAAAAl8xBAAAABFwb29sSW50ZWdyYWxTVEFURQgFAAAADSR0MDExNTE4MTE2NDAAAAACXzIEAAAACXBvb2xERUJVRwgFAAAADSR0MDExNTE4MTE2NDAAAAACXzMEAAAABU1VTFQzAAAAAAAAAAPoBAAAAA9zdGFrZWRCeVVzZXJLRVkJAQAAAA9rZXlTdGFrZWRCeVVzZXIAAAACBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAMbHBBc3NldElkU3RyBAAAAAxzdGFrZWRCeVVzZXIJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAPc3Rha2VkQnlVc2VyS0VZBAAAABB3eFRvQ2xhaW1Vc2VyS0VZCQEAAAAQa2V5V3hUb0NsYWltVXNlcgAAAAIFAAAADGxwQXNzZXRJZFN0cgUAAAAOdXNlckFkZHJlc3NTdHIEAAAAI3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0S0VZCQEAAAAja2V5V3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHQAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAADnVzZXJBZGRyZXNzU3RyBAAAABp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQkBAAAAGmtleVd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0AAAAAgUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgQAAAANd3hUb0NsYWltVXNlcgkBAAAAGWdldEJpZ0ludEZyb21TdHJpbmdPclplcm8AAAACBQAAAAR0aGlzBQAAABB3eFRvQ2xhaW1Vc2VyS0VZBAAAACZ3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE9yWmVybwkBAAAADGdldEludE9yWmVybwAAAAIFAAAABHRoaXMFAAAAI3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0S0VZBAAAABd3eFBlckxwSW50ZWdyYWxVc2VyTGFzdAkBAAAAG2NhbGNXeFBlckxwSW50ZWdyYWxVc2VyTGFzdAAAAAQJAAE2AAAAAQUAAAAMc3Rha2VkQnlVc2VyCQABNgAAAAEFAAAAJnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0T3JaZXJvBQAAABJ3eFBlckxwSW50ZWdyYWxOZXcFAAAAGnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0S0VZBAAAAAZNVUxUMTEJAABoAAAAAgUAAAAFTVVMVDgFAAAABU1VTFQzBAAAABB3eFRvQ2xhaW1Vc2VyTmV3CQABNwAAAAIFAAAADXd4VG9DbGFpbVVzZXIJAAE8AAAAAwkAATgAAAACBQAAABJ3eFBlckxwSW50ZWdyYWxOZXcFAAAAF3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0CQABNgAAAAEFAAAADHN0YWtlZEJ5VXNlcgkAATYAAAABBQAAAAZNVUxUMTEEAAAAGnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0TmV3BQAAABJ3eFBlckxwSW50ZWdyYWxOZXcEAAAAI3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0TmV3BQAAAAZoZWlnaHQEAAAABWRlYnVnCQAEuQAAAAIJAARMAAAAAgIAAAAnd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm89CQAETAAAAAIJAAGkAAAAAQUAAAAmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8JAARMAAAAAgIAAABHdGhpcy5nZXRTdHJpbmdPckZhaWwod3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkpLnBhcnNlQmlnSW50KCkudmFsdWUoKT0JAARMAAAAAgkAAaYAAAABCQEAAAAFdmFsdWUAAAABCQABqAAAAAEJAQAAAA9nZXRTdHJpbmdPckZhaWwAAAACBQAAAAR0aGlzBQAAABp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQkABEwAAAACAgAAABN3eFBlckxwSW50ZWdyYWxOZXc9CQAETAAAAAIJAAGmAAAAAQUAAAASd3hQZXJMcEludGVncmFsTmV3CQAETAAAAAICAAAAEXd4VG9DbGFpbVVzZXJOZXc9CQAETAAAAAIJAAGmAAAAAQUAAAAQd3hUb0NsYWltVXNlck5ldwkABEwAAAACAgAAABh3eFBlckxwSW50ZWdyYWxVc2VyTGFzdD0JAARMAAAAAgkAAaYAAAABBQAAABd3eFBlckxwSW50ZWdyYWxVc2VyTGFzdAkABEwAAAACAgAAAA1zdGFrZWRCeVVzZXI9CQAETAAAAAIJAAGkAAAAAQUAAAAMc3Rha2VkQnlVc2VyCQAETAAAAAICAAAACnBvb2xERUJVRz0JAARMAAAAAgUAAAAJcG9vbERFQlVHCQAETAAAAAICAAAAB2hlaWdodD0JAARMAAAAAgkAAaQAAAABBQAAAAZoZWlnaHQFAAAAA25pbAIAAAACOjoJAAUVAAAAAwUAAAAQd3hUb0NsYWltVXNlck5ldwkABE4AAAACBQAAABFwb29sSW50ZWdyYWxTVEFURQkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAABB3eFRvQ2xhaW1Vc2VyS0VZCQABpgAAAAEFAAAAEHd4VG9DbGFpbVVzZXJOZXcJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAI3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0S0VZBQAAACN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE5ldwkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAABp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQkAAaYAAAABBQAAABp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdE5ldwUAAAADbmlsBQAAAAVkZWJ1ZwEAAAAWbWFuYWdlclB1YmxpY0tleU9yVW5pdAAAAAAEAAAAByRtYXRjaDAJAAQiAAAAAQkBAAAAE2tleU1hbmFnZXJQdWJsaWNLZXkAAAAAAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAAZTdHJpbmcEAAAAAXMFAAAAByRtYXRjaDAJAAJZAAAAAQUAAAABcwMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAEVW5pdAUAAAAEdW5pdAkAAAIAAAABAgAAAAtNYXRjaCBlcnJvcgEAAAAdcGVuZGluZ01hbmFnZXJQdWJsaWNLZXlPclVuaXQAAAAABAAAAAckbWF0Y2gwCQAEIgAAAAEJAQAAABprZXlQZW5kaW5nTWFuYWdlclB1YmxpY0tleQAAAAADCQAAAQAAAAIF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AQIAAAA0aW52YWxpZCBwYXltZW50IC0gZXhhY3Qgb25lIHBheW1lbnQgbXVzdCBiZSBhdHRhY2hlZAQAAAADcG10CQABkQAAAAIIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAAABAAAAAlscEFzc2V0SWQJAQAAAAV2YWx1ZQAAAAEIBQAAAANwbXQAAAAHYXNzZXRJZAQAAAAMbHBBc3NldElkU3RyCQACWAAAAAEFAAAACWxwQXNzZXRJZAQAAAAGYW1vdW50CAUAAAADcG10AAAABmFtb3VudAQAAAAOcG9vbEFkZHJlc3NTdHIJAQAAABN2YWx1ZU9yRXJyb3JNZXNzYWdlAAAAAgkABB0AAAACBQAAAA9mYWN0b3J5Q29udHJhY3QJAQAAABprZXlGYWN0b3J5THAyQXNzZXRzTWFwcGluZwAAAAEFAAAADGxwQXNzZXRJZFN0cgkAASwAAAACAgAAABV1bnN1cHBvcnRlZCBscCBhc3NldCAFAAAADGxwQXNzZXRJZFN0cgQAAAAJY2FsbGVyU3RyCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgQAAAAOdXNlckFkZHJlc3NTdHIDCQAAAAAAAAIFAAAACWNhbGxlclN0cgUAAAAOcG9vbEFkZHJlc3NTdHIJAAQlAAAAAQgFAAAAAWkAAAAMb3JpZ2luQ2FsbGVyBQAAAAljYWxsZXJTdHIEAAAAD3N0YWtlZEJ5VXNlcktFWQkBAAAAD2tleVN0YWtlZEJ5VXNlcgAAAAIFAAAADnVzZXJBZGRyZXNzU3RyBQAAAAxscEFzc2V0SWRTdHIEAAAADnN0YWtlZFRvdGFsS0VZCQEAAAAOa2V5U3Rha2VkVG90YWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAADHN0YWtlZEJ5VXNlcgkBAAAACnJlYWRTdGFrZWQAAAABBQAAAA9zdGFrZWRCeVVzZXJLRVkEAAAAC3N0YWtlZFRvdGFsCQEAAAAKcmVhZFN0YWtlZAAAAAEFAAAADnN0YWtlZFRvdGFsS0VZBAAAAA0kdDAxNjA3MTE2MTg4CQEAAAAQcmVmcmVzaElOVEVHUkFMUwAAAAQFAAAADGxwQXNzZXRJZFN0cgUAAAAOdXNlckFkZHJlc3NTdHIFAAAADnBvb2xBZGRyZXNzU3RyBQAAAAZhbW91bnQEAAAAEHd4VG9DbGFpbVVzZXJOZXcIBQAAAA0kdDAxNjA3MTE2MTg4AAAAAl8xBAAAAA1pbnRlZ3JhbFNUQVRFCAUAAAANJHQwMTYwNzExNjE4OAAAAAJfMgQAAAAFZGVidWcIBQAAAA0kdDAxNjA3MTE2MTg4AAAAAl8zCQAETgAAAAIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAD3N0YWtlZEJ5VXNlcktFWQkAAGQAAAACBQAAAAxzdGFrZWRCeVVzZXIFAAAABmFtb3VudAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAOc3Rha2VkVG90YWxLRVkJAABkAAAAAgUAAAALc3Rha2VkVG90YWwFAAAABmFtb3VudAkABEwAAAACCQEAAAAVT3BlcmF0aW9uSGlzdG9yeUVudHJ5AAAABQIAAAAFc3Rha2UFAAAADnVzZXJBZGRyZXNzU3RyBQAAAAxscEFzc2V0SWRTdHIFAAAABmFtb3VudAgFAAAAAWkAAAANdHJhbnNhY3Rpb25JZAUAAAADbmlsBQAAAA1pbnRlZ3JhbFNUQVRFAAAAAWkBAAAAB3Vuc3Rha2UAAAACAAAADGxwQXNzZXRJZFN0cgAAAAZhbW91bnQEAAAACWxwQXNzZXRJZAkAAlkAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAADnBvb2xBZGRyZXNzU3RyCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQdAAAAAgUAAAAPZmFjdG9yeUNvbnRyYWN0CQEAAAAaa2V5RmFjdG9yeUxwMkFzc2V0c01hcHBpbmcAAAABBQAAAAxscEFzc2V0SWRTdHIJAAEsAAAAAgIAAAAVdW5zdXBwb3J0ZWQgbHAgYXNzZXQgBQAAAAxscEFzc2V0SWRTdHIEAAAACXBvb2xBZGRvbgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABB0AAAACBQAAAAR0aGlzCQEAAAAWa2V5U3RhYmxlUG9vbEFkZG9uQWRkcgAAAAAFAAAADnBvb2xBZGRyZXNzU3RyBAAAAAljYWxsZXJTdHIJAAQlAAAAAQgFAAAAAWkAAAAGY2FsbGVyBAAAAA51c2VyQWRkcmVzc1N0cgMDCQAAAAAAAAIFAAAACWNhbGxlclN0cgUAAAAOcG9vbEFkZHJlc3NTdHIGCQAAAAAAAAIFAAAACWNhbGxlclN0cgUAAAAJcG9vbEFkZG9uCQAEJQAAAAEIBQAAAAFpAAAADG9yaWdpbkNhbGxlcgUAAAAJY2FsbGVyU3RyBAAAAA9zdGFrZWRCeVVzZXJLRVkJAQAAAA9rZXlTdGFrZWRCeVVzZXIAAAACBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAMbHBBc3NldElkU3RyBAAAAA5zdGFrZWRUb3RhbEtFWQkBAAAADmtleVN0YWtlZFRvdGFsAAAAAQUAAAAMbHBBc3NldElkU3RyBAAAAAxzdGFrZWRCeVVzZXIJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAPc3Rha2VkQnlVc2VyS0VZBAAAAAtzdGFrZWRUb3RhbAkBAAAACnJlYWRTdGFrZWQAAAABBQAAAA5zdGFrZWRUb3RhbEtFWQQAAAANJHQwMTczMjUxNzQ0MwkBAAAAEHJlZnJlc2hJTlRFR1JBTFMAAAAEBQAAAAxscEFzc2V0SWRTdHIFAAAADnVzZXJBZGRyZXNzU3RyBQAAAA5wb29sQWRkcmVzc1N0cgkBAAAAAS0AAAABBQAAAAZhbW91bnQEAAAAEHd4VG9DbGFpbVVzZXJOZXcIBQAAAA0kdDAxNzMyNTE3NDQzAAAAAl8xBAAAAA1pbnRlZ3JhbFNUQVRFCAUAAAANJHQwMTczMjUxNzQ0MwAAAAJfMgQAAAAFZGVidWcIBQAAAA0kdDAxNzMyNTE3NDQzAAAAAl8zAwkAAGYAAAACBQAAAAZhbW91bnQFAAAADHN0YWtlZEJ5VXNlcgkAAAIAAAABAgAAACRwYXNzZWQgYW1vdW50IGlzIGxlc3MgdGhlbiBhdmFpbGFibGUJAAROAAAAAgkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAPc3Rha2VkQnlVc2VyS0VZCQAAZQAAAAIFAAAADHN0YWtlZEJ5VXNlcgUAAAAGYW1vdW50CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAA5zdGFrZWRUb3RhbEtFWQkAAGUAAAACBQAAAAtzdGFrZWRUb3RhbAUAAAAGYW1vdW50CQAETAAAAAIJAQAAAA5TY3JpcHRUcmFuc2ZlcgAAAAMIBQAAAAFpAAAABmNhbGxlcgUAAAAGYW1vdW50BQAAAAlscEFzc2V0SWQJAARMAAAAAgkBAAAAFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQAAAAUCAAAAB3Vuc3Rha2UFAAAADnVzZXJBZGRyZXNzU3RyBQAAAAxscEFzc2V0SWRTdHIFAAAABmFtb3VudAgFAAAAAWkAAAANdHJhbnNhY3Rpb25JZAUAAAADbmlsBQAAAA1pbnRlZ3JhbFNUQVRFAAAAAWkBAAAAB2NsYWltV3gAAAABAAAADGxwQXNzZXRJZFN0cgQAAAALdXNlckFkZHJlc3MIBQAAAAFpAAAABmNhbGxlcgQAAAAOdXNlckFkZHJlc3NTdHIJAAQlAAAAAQgFAAAAAWkAAAAGY2FsbGVyBAAAAA5wb29sQWRkcmVzc1N0cgkBAAAAGGdldFN0cmluZ0J5QWRkcmVzc09yRmFpbAAAAAIFAAAAD2ZhY3RvcnlDb250cmFjdAkBAAAAJmtleUZhY3RvcnlMcEFzc2V0VG9Qb29sQ29udHJhY3RBZGRyZXNzAAAAAQUAAAAMbHBBc3NldElkU3RyBAAAABBjbGFpbWVkQnlVc2VyS0VZCQEAAAAQa2V5Q2xhaW1lZEJ5VXNlcgAAAAIFAAAADGxwQXNzZXRJZFN0cgUAAAAOdXNlckFkZHJlc3NTdHIEAAAAD2NsYWltZWRUb3RhbEtFWQkBAAAAD2tleUNsYWltZWRUb3RhbAAAAAEFAAAADGxwQXNzZXRJZFN0cgQAAAAZY2xhaW1lZEJ5VXNlck1pblJld2FyZEtFWQkBAAAAGWtleUNsYWltZWRCeVVzZXJNaW5SZXdhcmQAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAADnVzZXJBZGRyZXNzU3RyBAAAABtjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmRLRVkJAQAAABtrZXlDbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmQAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAADnVzZXJBZGRyZXNzU3RyBAAAAA1jbGFpbWVkQnlVc2VyCQABNgAAAAEJAQAAAAxnZXRJbnRPclplcm8AAAACBQAAAAR0aGlzBQAAABBjbGFpbWVkQnlVc2VyS0VZBAAAABZjbGFpbWVkQnlVc2VyTWluUmV3YXJkCQABNgAAAAEJAQAAAAxnZXRJbnRPclplcm8AAAACBQAAAAR0aGlzBQAAABljbGFpbWVkQnlVc2VyTWluUmV3YXJkS0VZBAAAABhjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmQJAAE2AAAAAQkBAAAADGdldEludE9yWmVybwAAAAIFAAAABHRoaXMFAAAAG2NsYWltZWRCeVVzZXJCb29zdFJld2FyZEtFWQQAAAAMY2xhaW1lZFRvdGFsCQABNgAAAAEJAQAAAAxnZXRJbnRPclplcm8AAAACBQAAAAR0aGlzBQAAAA9jbGFpbWVkVG90YWxLRVkEAAAADSR0MDE4Njc5MTg3OTEJAQAAABByZWZyZXNoSU5URUdSQUxTAAAABAUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAOcG9vbEFkZHJlc3NTdHIAAAAAAAAAAAAEAAAAEHd4VG9DbGFpbVVzZXJOZXcIBQAAAA0kdDAxODY3OTE4NzkxAAAAAl8xBAAAAA1pbnRlZ3JhbFNUQVRFCAUAAAANJHQwMTg2NzkxODc5MQAAAAJfMgQAAAAFZGVidWcIBQAAAA0kdDAxODY3OTE4NzkxAAAAAl8zBAAAABBhdmFpbGFibGVUb0NsYWltCQABOAAAAAIFAAAAEHd4VG9DbGFpbVVzZXJOZXcFAAAADWNsYWltZWRCeVVzZXIDCQABQAAAAAIFAAAACnplcm9CaWdJbnQFAAAAEGF2YWlsYWJsZVRvQ2xhaW0JAAACAAAAAQIAAAAQbm90aGluZyB0byBjbGFpbQQAAAASd3hBbW91bnRCb29zdFRvdGFsCQEAAAAFYXNJbnQAAAABCQABkQAAAAIJAQAAAAlhc0FueUxpc3QAAAABCQAD/AAAAAQFAAAAEGJvb3N0aW5nQ29udHJhY3QCAAAADGNsYWltV3hCb29zdAkABEwAAAACBQAAAAxscEFzc2V0SWRTdHIJAARMAAAAAgUAAAAOdXNlckFkZHJlc3NTdHIFAAAAA25pbAUAAAADbmlsAAAAAAAAAAAABAAAAA1taW5SZXdhcmRQYXJ0BQAAABBhdmFpbGFibGVUb0NsYWltBAAAAA9ib29zdFJld2FyZFBhcnQJAAGZAAAAAQkABEwAAAACCQABOQAAAAIFAAAADW1pblJld2FyZFBhcnQJAAE2AAAAAQAAAAAAAAAAAgkABEwAAAACCQABNgAAAAEFAAAAEnd4QW1vdW50Qm9vc3RUb3RhbAUAAAADbmlsBAAAAAl3eEFzc2V0SWQJAQAAAAxhc0J5dGVWZWN0b3IAAAABCQABkQAAAAIJAQAAAAlhc0FueUxpc3QAAAABCQAD/AAAAAQFAAAAEGVtaXNzaW9uQ29udHJhY3QCAAAABGVtaXQJAARMAAAAAgkAAaAAAAABBQAAAA1taW5SZXdhcmRQYXJ0BQAAAANuaWwFAAAAA25pbAAAAAAAAAAAAAQAAAAJZW1pdEJvb3N0CQEAAAAJYXNBbnlMaXN0AAAAAQkAA/wAAAAEBQAAABBlbWlzc2lvbkNvbnRyYWN0AgAAAARlbWl0CQAETAAAAAIJAAGgAAAAAQUAAAAPYm9vc3RSZXdhcmRQYXJ0BQAAAANuaWwFAAAAA25pbAMJAAAAAAAAAgUAAAAJZW1pdEJvb3N0BQAAAAllbWl0Qm9vc3QEAAAAEmNsYWltZWRCeVVzZXJWYWx1ZQkAATcAAAACBQAAAA1jbGFpbWVkQnlVc2VyBQAAABBhdmFpbGFibGVUb0NsYWltBAAAAB5jbGFpbWVkQnlVc2VyTWluUmV3YXJkUGx1c1BhcnQJAAE3AAAAAgUAAAAWY2xhaW1lZEJ5VXNlck1pblJld2FyZAUAAAANbWluUmV3YXJkUGFydAQAAAArY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkUGx1c0Jvb3N0UmV3YXJkUGFydAkAATcAAAACBQAAABZjbGFpbWVkQnlVc2VyTWluUmV3YXJkBQAAAA1taW5SZXdhcmRQYXJ0BAAAACBjbGFpbWVkVG90YWxQbHVzQXZhaWxhYmxlVG9DbGFpbQkAATcAAAACBQAAABZjbGFpbWVkQnlVc2VyTWluUmV3YXJkBQAAAA1taW5SZXdhcmRQYXJ0CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEGNsYWltZWRCeVVzZXJLRVkJAAGmAAAAAQUAAAASY2xhaW1lZEJ5VXNlclZhbHVlCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkJAAGmAAAAAQUAAAAeY2xhaW1lZEJ5VXNlck1pblJld2FyZFBsdXNQYXJ0CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAG2NsYWltZWRCeVVzZXJCb29zdFJld2FyZEtFWQkAAaYAAAABBQAAACtjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmRQbHVzQm9vc3RSZXdhcmRQYXJ0CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAD2NsYWltZWRUb3RhbEtFWQkAAaYAAAABBQAAACBjbGFpbWVkVG90YWxQbHVzQXZhaWxhYmxlVG9DbGFpbQkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAAAt1c2VyQWRkcmVzcwkAAaAAAAABBQAAAA1taW5SZXdhcmRQYXJ0BQAAAAl3eEFzc2V0SWQJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAALdXNlckFkZHJlc3MJAAGgAAAAAQUAAAAPYm9vc3RSZXdhcmRQYXJ0BQAAAAl3eEFzc2V0SWQJAARMAAAAAgkBAAAAFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQAAAAUCAAAABWNsYWltBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAMbHBBc3NldElkU3RyCQABoAAAAAEFAAAAEGF2YWlsYWJsZVRvQ2xhaW0IBQAAAAFpAAAADXRyYW5zYWN0aW9uSWQFAAAAA25pbAkAAAIAAAABAgAAACRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4AAAABaQEAAAAPY2xhaW1XeFJFQURPTkxZAAAAAgAAAAxscEFzc2V0SWRTdHIAAAAOdXNlckFkZHJlc3NTdHIEAAAAD3N0YWtlZEJ5VXNlcktFWQkBAAAAD2tleVN0YWtlZEJ5VXNlcgAAAAIFAAAADnVzZXJBZGRyZXNzU3RyBQAAAAxscEFzc2V0SWRTdHIEAAAADnN0YWtlZFRvdGFsS0VZCQEAAAAOa2V5U3Rha2VkVG90YWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAAEGNsYWltZWRCeVVzZXJLRVkJAQAAABBrZXlDbGFpbWVkQnlVc2VyAAAAAgUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgQAAAAMc3Rha2VkQnlVc2VyCQEAAAAKcmVhZFN0YWtlZAAAAAEFAAAAD3N0YWtlZEJ5VXNlcktFWQQAAAALc3Rha2VkVG90YWwJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAOc3Rha2VkVG90YWxLRVkEAAAADWNsYWltZWRCeVVzZXIJAQAAAAxnZXRJbnRPclplcm8AAAACBQAAAAR0aGlzBQAAABBjbGFpbWVkQnlVc2VyS0VZBAAAAA5wb29sQWRkcmVzc1N0cgkBAAAAGGdldFN0cmluZ0J5QWRkcmVzc09yRmFpbAAAAAIFAAAAD2ZhY3RvcnlDb250cmFjdAkBAAAAJmtleUZhY3RvcnlMcEFzc2V0VG9Qb29sQ29udHJhY3RBZGRyZXNzAAAAAQUAAAAMbHBBc3NldElkU3RyBAAAAApwb29sV2VpZ2h0CQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAA9mYWN0b3J5Q29udHJhY3QJAQAAABRrZXlGYWN0b3J5UG9vbFdlaWdodAAAAAEFAAAADnBvb2xBZGRyZXNzU3RyBAAAABJ3eEVtaXNzaW9uUGVyQmxvY2sJAQAAAAxnZXRJbnRPckZhaWwAAAACBQAAABBlbWlzc2lvbkNvbnRyYWN0CQEAAAAea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAAAAAQAAAASZW1pc3Npb25TdGFydEJsb2NrCQEAAAAMZ2V0SW50T3JGYWlsAAAAAgUAAAAQZW1pc3Npb25Db250cmFjdAkBAAAAFWtleUVtaXNzaW9uU3RhcnRCbG9jawAAAAAEAAAADHBhc3NlZEJsb2NrcwMJAABmAAAAAgUAAAASZW1pc3Npb25TdGFydEJsb2NrBQAAAAZoZWlnaHQAAAAAAAAAAAAJAABlAAAAAgUAAAAGaGVpZ2h0BQAAABJlbWlzc2lvblN0YXJ0QmxvY2sEAAAADnBvb2xXeEVtaXNzaW9uCQAAawAAAAMJAABoAAAAAgUAAAASd3hFbWlzc2lvblBlckJsb2NrBQAAAAxwYXNzZWRCbG9ja3MFAAAACnBvb2xXZWlnaHQFAAAADlBPT0xXRUlHSFRNVUxUBAAAAAx1c2VyV3hSZXdhcmQJAABrAAAAAwUAAAAOcG9vbFd4RW1pc3Npb24FAAAADHN0YWtlZEJ5VXNlcgUAAAALc3Rha2VkVG90YWwEAAAADSR0MDIxNDU0MjE1NjYJAQAAABByZWZyZXNoSU5URUdSQUxTAAAABAUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAOcG9vbEFkZHJlc3NTdHIAAAAAAAAAAAAEAAAAEHd4VG9DbGFpbVVzZXJOZXcIBQAAAA0kdDAyMTQ1NDIxNTY2AAAAAl8xBAAAAA1pbnRlZ3JhbFNUQVRFCAUAAAANJHQwMjE0NTQyMTU2NgAAAAJfMgQAAAAFZGVidWcIBQAAAA0kdDAyMTQ1NDIxNTY2AAAAAl8zBAAAABBhdmFpbGFibGVUb0NsYWltCQABOAAAAAIFAAAAEHd4VG9DbGFpbVVzZXJOZXcJAAE2AAAAAQUAAAANY2xhaW1lZEJ5VXNlcgQAAAAOYm9vc3RJbnZSZXN1bHQJAQAAAAlhc0FueUxpc3QAAAABCQAD/AAAAAQFAAAAEGJvb3N0aW5nQ29udHJhY3QCAAAAFGNsYWltV3hCb29zdFJFQURPTkxZCQAETAAAAAIFAAAADGxwQXNzZXRJZFN0cgkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgUAAAADbmlsBQAAAANuaWwEAAAAEnd4QW1vdW50Qm9vc3RUb3RhbAkBAAAABWFzSW50AAAAAQkAAZEAAAACBQAAAA5ib29zdEludlJlc3VsdAAAAAAAAAAAAAQAAAAKYm9vc3REZWJ1ZwkBAAAACGFzU3RyaW5nAAAAAQkAAZEAAAACBQAAAA5ib29zdEludlJlc3VsdAAAAAAAAAAAAQQAAAANbWluUmV3YXJkUGFydAUAAAAQYXZhaWxhYmxlVG9DbGFpbQQAAAAPYm9vc3RSZXdhcmRQYXJ0CQABmQAAAAEJAARMAAAAAgkAATkAAAACBQAAAA1taW5SZXdhcmRQYXJ0CQABNgAAAAEAAAAAAAAAAAIJAARMAAAAAgkAATYAAAABBQAAABJ3eEFtb3VudEJvb3N0VG90YWwFAAAAA25pbAQAAAALdG90YWxSZXdhcmQJAAE3AAAAAgUAAAANbWluUmV3YXJkUGFydAUAAAAPYm9vc3RSZXdhcmRQYXJ0CQAFFAAAAAIFAAAAA25pbAkABLkAAAACCQAETAAAAAICAAAADiVzJXMlZCVkJWQlZCVzCQAETAAAAAIFAAAADGxwQXNzZXRJZFN0cgkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgkABEwAAAACCQABpgAAAAEFAAAAC3RvdGFsUmV3YXJkCQAETAAAAAIJAAGkAAAAAQUAAAANY2xhaW1lZEJ5VXNlcgkABEwAAAACCQABpgAAAAEFAAAADW1pblJld2FyZFBhcnQJAARMAAAAAgkAAaYAAAABBQAAAA9ib29zdFJld2FyZFBhcnQJAARMAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACBQAAAAVkZWJ1ZwIAAAACOjoJAAGkAAAAAQUAAAAMdXNlcld4UmV3YXJkAgAAAA46OkJPT1NUREVCVUc6OgUAAAAKYm9vc3REZWJ1ZwUAAAADbmlsBQAAAANTRVAAAAABaQEAAAAOb25Nb2RpZnlXZWlnaHQAAAACAAAADGxwQXNzZXRJZFN0cgAAAA5wb29sQWRkcmVzc1N0cgMJAQAAAAIhPQAAAAIIBQAAAAFpAAAABmNhbGxlcgUAAAAPZmFjdG9yeUNvbnRyYWN0CQAAAgAAAAECAAAAEnBlcm1pc3Npb25zIGRlbmllZAQAAAANJHQwMjI0NzkyMjU4OQkBAAAAFHJlZnJlc2hQb29sSU5URUdSQUxTAAAAAwUAAAAMbHBBc3NldElkU3RyBQAAAA5wb29sQWRkcmVzc1N0cgAAAAAAAAAAAAQAAAASd3hQZXJMcEludGVncmFsTmV3CAUAAAANJHQwMjI0NzkyMjU4OQAAAAJfMQQAAAARcG9vbEludGVncmFsU1RBVEUIBQAAAA0kdDAyMjQ3OTIyNTg5AAAAAl8yBAAAAAlwb29sREVCVUcIBQAAAA0kdDAyMjQ3OTIyNTg5AAAAAl8zBQAAABFwb29sSW50ZWdyYWxTVEFURQAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAEAAAAD3RhcmdldFB1YmxpY0tleQQAAAAHJG1hdGNoMAkBAAAAFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAAAAAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAApCeXRlVmVjdG9yBAAAAAJwawUAAAAHJG1hdGNoMAUAAAACcGsDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQIBQAAAAJ0eAAAAA9zZW5kZXJQdWJsaWNLZXkJAAACAAAAAQIAAAALTWF0Y2ggZXJyb3IJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAABQAAAA90YXJnZXRQdWJsaWNLZXniaHzP", "chainId": 84, "height": 2096297, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: FBDbamP4ZyrJRxzxEfCFhTeqBpPrkHkHD317bw7y6WD8 Next: 3qQcMWveB9cmsmqzWrAA7vGu5ctM4R6W73RtAhzdZJBg Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 5 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let separator = "__"
4+let SCALE8 = 8
55
6-let keyFeeAmount = makeString(["%s", "fee"], separator)
6+let MULT8 = 100000000
77
8-let keyUsdnAssetId = makeString(["%s", "usdnAssetId"], separator)
8+let SCALE18 = 18
99
10-let keyEpochLength = makeString(["%s", "epochLength"], separator)
10+let MULT18 = toBigInt(1000000000000000000)
1111
12-let keyFinalizeReward = makeString(["%s", "finalizeReward"], separator)
12+let SEP = "__"
1313
14-let keyWxAssetId = makeString(["%s", "wxAssetId"], separator)
14+let POOLWEIGHTMULT = MULT8
1515
16-let keyAssetsStoreContract = makeString(["%s", "assetsStoreContract"], separator)
16+let zeroBigInt = toBigInt(0)
1717
18-let keyUserPoolContract = makeString(["%s", "userPoolContract"], separator)
18+let oneBigInt = toBigInt(1)
1919
20-let keyEmissionContract = makeString(["%s", "emissionContract"], separator)
21-
22-let keyBoostingContract = makeString(["%s", "boostingContract"], separator)
23-
24-let keyFactoryContract = makeString(["%s", "factoryContract"], separator)
25-
26-let keyVotingEmissionContract = makeString(["%s", "votingEmissionContract"], separator)
27-
28-func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), (key + " is not defined"))
20+func asAnyList (val) = match val {
21+ case valAnyLyst: List[Any] =>
22+ valAnyLyst
23+ case _ =>
24+ throw("fail to cast into List[Any]")
25+}
2926
3027
31-func keyInListAssetId (amountAssetId,priceAssetId) = makeString(["%s%s%s", "inList", amountAssetId, priceAssetId], separator)
28+func asInt (val) = match val {
29+ case valInt: Int =>
30+ valInt
31+ case _ =>
32+ throw("fail to cast into Int")
33+}
3234
3335
34-func keySuggestIndex (amountAssetId,priceAssetId) = makeString(["%s%s%s", "suggestIndex", amountAssetId, priceAssetId], separator)
36+func asString (val) = match val {
37+ case valStr: String =>
38+ valStr
39+ case _ =>
40+ throw("fail to cast into Int")
41+}
3542
3643
37-func keyStartHeight (amountAssetId,priceAssetId,suggestIndex) = makeString(["%s%s%s%d", "startHeight", amountAssetId, priceAssetId, toString(suggestIndex)], separator)
44+func asByteVector (val) = match val {
45+ case valBin: ByteVector =>
46+ valBin
47+ case _ =>
48+ throw("fail to cast into Int")
49+}
3850
3951
40-func keyVotingResult (amountAssetId,priceAssetId,suggestIndex) = makeString(["%s%s%s%d", "votingResult", amountAssetId, priceAssetId, toString(suggestIndex)], separator)
52+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (("mandatory this." + key) + " is not defined"))
4153
4254
43-func totalVotes (totalYes,totalNo) = makeString(["%d%d", totalYes, totalNo], separator)
55+func getStringByAddressOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined"))
4456
4557
46-func keyVote (amountAssetId,priceAssetId,suggestIndex,voterAddress) = makeString(["%s%s%s%d%s", "vote", amountAssetId, priceAssetId, toString(suggestIndex), voterAddress], separator)
58+func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
4759
4860
49-func keyVoteValue (gwxAmount,vote) = {
50- let key = if (vote)
51- then makeString(["%d%s", gwxAmount, "yes"], separator)
52- else makeString(["%d%s", gwxAmount, "no"], separator)
53- key
54- }
61+func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
62+
63+
64+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined"))
65+
66+
67+func getBigIntFromStringOrZero (address,key) = value(parseBigInt(valueOrElse(getString(address, key), "0")))
68+
69+
70+func getBigIntFromStringOrDefault (address,key,defaultVal) = match getString(address, key) {
71+ case s: String =>
72+ value(parseBigInt(s))
73+ case _: Unit =>
74+ defaultVal
75+ case _ =>
76+ throw("Match error")
77+}
78+
79+
80+func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULT18, toBigInt(origScaleMult))
81+
82+
83+func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULT18))
84+
85+
86+func keyFactoryAddress () = "%s%s__config__factoryAddress"
87+
88+
89+let IdxFactoryCfgStakingDapp = 1
90+
91+let IdxFactoryCfgBoostingDapp = 2
92+
93+let IdxFactoryCfgIdoDapp = 3
94+
95+let IdxFactoryCfgTeamDapp = 4
96+
97+let IdxFactoryCfgEmissionDapp = 5
98+
99+let IdxFactoryCfgRestDapp = 6
100+
101+let IdxFactoryCfgSlippageDapp = 7
102+
103+func keyFactoryCfg () = "%s__factoryConfig"
55104
56105
57106 func keyManagerPublicKey () = "%s__managerPublicKey"
60109 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
61110
62111
63-let assetsStoreContract = addressFromStringValue(getStringOrFail(keyAssetsStoreContract))
112+func keyStablePoolAddonAddr () = "%s__stablePoolAddonAddr"
64113
65-let boostingContract = addressFromStringValue(getStringOrFail(keyBoostingContract))
66114
67-let emissionContract = addressFromStringValue(getStringOrFail(keyEmissionContract))
115+func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
68116
69-let factoryContract = addressFromStringValue(getStringOrFail(keyFactoryContract))
70117
71-let userPoolContract = addressFromStringValue(getStringOrFail(keyUserPoolContract))
118+func keyFactoryLpList () = "%s__lpTokensList"
72119
73-let votingEmissionContract = addressFromStringValue(getStringOrFail(keyVotingEmissionContract))
120+
121+func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
122+
123+
124+func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
125+
126+
127+func readLpList (factory) = split(valueOrElse(getString(factory, keyFactoryLpList()), ""), SEP)
128+
129+
130+func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP)
131+
132+
133+func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
134+
135+
136+func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
137+
138+
139+func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
140+
141+
142+func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
143+
144+
145+func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
146+
147+
148+func keyEmissionStartBlock () = "%s%s__emission__startBlock"
149+
150+
151+func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
152+
153+
154+func keyEmissionEndBlock () = "%s%s__emission__endBlock"
155+
156+
157+func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP)
158+
159+
160+func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr)
161+
162+
163+func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP)
164+
165+
166+func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP)
167+
168+
169+func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP)
170+
171+
172+func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed", "total", lpAssetIdStr], SEP)
173+
174+
175+func readStaked (key) = valueOrElse(getInteger(this, key), 0)
176+
177+
178+func keyLastTotalLpBalance (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "bal"], SEP)
179+
180+
181+func keyLastUserLpBalance (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "bal"], SEP)
182+
183+
184+func keyTotalLpBalanceIntegral (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "balINT"], SEP)
185+
186+
187+func keyUserLpBalanceIntegral (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "balINT"], SEP)
188+
189+
190+func keyTotalLpBalanceIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "lastUpd"], SEP)
191+
192+
193+func keyUserLpBalanceIntegralLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "lastUpd"], SEP)
194+
195+
196+func keyWxPerLpIntegral (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpInt"], SEP)
197+
198+
199+func keyWxPerLpIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpIntH"], SEP)
200+
201+
202+func keyWxToClaimUser (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpInt"], SEP)
203+
204+
205+func keyWxPerLpIntegralUserLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpIntH"], SEP)
206+
207+
208+func keyWxPerLp (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLp"], SEP)
209+
210+
211+func keyWxPerLpX18 (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLpX18"], SEP)
212+
213+
214+func keyWxPerLpIntegralUserLast (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "uIntL"], SEP)
215+
216+
217+func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP)
218+
219+
220+func formatHistoryRecord (userAddress,lpAssetId,type,amount) = makeString(["%s%s%s%d%d%d", userAddress, lpAssetId, type, toString(height), toString(lastBlock.timestamp), toString(amount)], SEP)
221+
222+
223+func OperationHistoryEntry (type,userAddress,lpAssetId,amount,txId) = StringEntry(keyOperationHistoryRecord(type, userAddress, toBase58String(txId)), formatHistoryRecord(userAddress, lpAssetId, type, amount))
224+
225+
226+let factoryAddress = getStringOrFail(this, keyFactoryAddress())
227+
228+let factoryContract = addressFromStringValue(factoryAddress)
229+
230+let factoryCfg = readFactoryCfgOrFail(factoryContract)
231+
232+let emissionContract = getEmissionAddressOrFail(factoryCfg)
233+
234+let boostingContract = getBoostingAddressOrFail(factoryCfg)
235+
236+func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
237+ then (stakedByUser > zeroBigInt)
238+ else false)
239+ then zeroBigInt
240+ else if ((stakedByUser == zeroBigInt))
241+ then wxPerLpIntegralNew
242+ else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > zeroBigInt))
243+ then (stakedByUser > zeroBigInt)
244+ else false)
245+ then value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))
246+ else throw("calcWxPerLpIntegralUserLast: unexpected state")
247+
248+
249+func refreshPoolINTEGRALS (lpAssetIdStr,poolAddressStr,lpDeltaAmount) = {
250+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
251+ let stakedTotal = toBigInt(readStaked(stakedTotalKEY))
252+ let nonZeroStakedTotal = if ((stakedTotal == zeroBigInt))
253+ then oneBigInt
254+ else stakedTotal
255+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
256+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
257+ let MULT3 = 1000
258+ let wxEmissionPerBlockX3 = (getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent()) * MULT3)
259+ let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3))
260+ let wxPerLpIntegralKEY = keyWxPerLpIntegral(lpAssetIdStr)
261+ let wxPerLpIntegralLastUpdHeightKEY = keyWxPerLpIntegralLastUpdHeight(lpAssetIdStr)
262+ let wxPerLpKEY = keyWxPerLp(lpAssetIdStr)
263+ let wxPerLpIntegralLastUpdHeight = getIntOrDefault(this, wxPerLpIntegralLastUpdHeightKEY, emissionStartBlock)
264+ let wxPerLpIntegral = getBigIntFromStringOrZero(this, wxPerLpIntegralKEY)
265+ let wxPerLpOrZeroX3 = 0
266+ let dh = max([(height - wxPerLpIntegralLastUpdHeight), 0])
267+ let wxPerLpX3 = if ((wxPerLpOrZeroX3 != 0))
268+ then toBigInt(wxPerLpOrZeroX3)
269+ else fraction(toBigInt(poolWxEmissionPerBlockX3), toBigInt(MULT8), nonZeroStakedTotal)
270+ let stakedTotalNew = (stakedTotal + toBigInt(lpDeltaAmount))
271+ let nonZeroStakedTotalNew = if ((stakedTotalNew == zeroBigInt))
272+ then oneBigInt
273+ else stakedTotalNew
274+ let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * toBigInt(dh)))
275+ let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
276+ let wxPerLpIntegralLastUpdHeightNew = height
277+ let debug = makeString(["wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), "poolWxEmissionPerBlockX3=", toString(poolWxEmissionPerBlockX3), "wxEmissionPerBlockX3=", toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
278+ $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
279+ }
280+
281+
282+func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
283+ let $t01151811640 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
284+ let wxPerLpIntegralNew = $t01151811640._1
285+ let poolIntegralSTATE = $t01151811640._2
286+ let poolDEBUG = $t01151811640._3
287+ let MULT3 = 1000
288+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
289+ let stakedByUser = readStaked(stakedByUserKEY)
290+ let wxToClaimUserKEY = keyWxToClaimUser(lpAssetIdStr, userAddressStr)
291+ let wxPerLpIntegralUserLastUpdHeightKEY = keyWxPerLpIntegralUserLastUpdHeight(lpAssetIdStr, userAddressStr)
292+ let wxPerLpIntegralUserLastKEY = keyWxPerLpIntegralUserLast(lpAssetIdStr, userAddressStr)
293+ let wxToClaimUser = getBigIntFromStringOrZero(this, wxToClaimUserKEY)
294+ let wxPerLpIntegralUserLastUpdHeightOrZero = getIntOrZero(this, wxPerLpIntegralUserLastUpdHeightKEY)
295+ let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(toBigInt(stakedByUser), toBigInt(wxPerLpIntegralUserLastUpdHeightOrZero), wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
296+ let MULT11 = (MULT8 * MULT3)
297+ let wxToClaimUserNew = (wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11)))
298+ let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
299+ let wxPerLpIntegralUserLastUpdHeightNew = height
300+ let debug = makeString(["wxPerLpIntegralUserLastUpdHeightOrZero=", toString(wxPerLpIntegralUserLastUpdHeightOrZero), "this.getStringOrFail(wxPerLpIntegralUserLastKEY).parseBigInt().value()=", toString(value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))), "wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "wxToClaimUserNew=", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast=", toString(wxPerLpIntegralUserLast), "stakedByUser=", toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
301+ $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
302+ }
303+
74304
75305 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
76306 case s: String =>
93323
94324
95325 func mustManager (i) = {
96- let pd = throw("permission denied")
326+ let pd = throw("Permission denied")
97327 match managerPublicKeyOrUnit() {
98328 case pk: ByteVector =>
99329 if ((i.callerPublicKey == pk))
109339 }
110340
111341
112-func asInt (val) = match val {
113- case valInt: Int =>
114- valInt
115- case _ =>
116- throw("failed to cast into Integer")
117-}
118-
119-
120342 @Callable(i)
121-func constructor (assetsStoreContractPrm,boostingContractPrm,emissionContractPrm,factoryContractPrm,userPoolContractPrm,votingEmissionContractPrm,feeAmountPrm,wxAssetIdPrm,votingDurationPrm,usdnAssetIdPrm,finalizeRewardPrm) = {
122- let checks = [mustManager(i), if (isDefined(addressFromString(assetsStoreContractPrm)))
123- then true
124- else throw("Invalid asset_store contract address"), if (isDefined(addressFromString(boostingContractPrm)))
125- then true
126- else throw("Invalid boosting contract address"), if (isDefined(addressFromString(userPoolContractPrm)))
127- then true
128- else throw("Invalid user_pools contract address"), if (isDefined(addressFromString(emissionContractPrm)))
129- then true
130- else throw("Invalid emission contract address"), if (isDefined(addressFromString(factoryContractPrm)))
131- then true
132- else throw("Invalid factory contract address"), if ((feeAmountPrm >= 0))
133- then true
134- else throw("Invalid fee amount"), if ((votingDurationPrm > 0))
135- then true
136- else throw("Invalid voting duration"), if ((finalizeRewardPrm > 0))
137- then true
138- else throw("Invalid finalize reward"), if (isDefined(assetInfo(fromBase58String(wxAssetIdPrm))))
139- then true
140- else throw("Invalid WX asset ID"), if (isDefined(assetInfo(fromBase58String(usdnAssetIdPrm))))
141- then true
142- else throw("Invalid USDN asset ID")]
143- if ((checks == checks))
144- then $Tuple2([StringEntry(keyAssetsStoreContract, assetsStoreContractPrm), StringEntry(keyBoostingContract, boostingContractPrm), StringEntry(keyEmissionContract, emissionContractPrm), StringEntry(keyFactoryContract, factoryContractPrm), StringEntry(keyUserPoolContract, userPoolContractPrm), StringEntry(keyVotingEmissionContract, votingEmissionContractPrm), IntegerEntry(keyFeeAmount, feeAmountPrm), IntegerEntry(keyEpochLength, votingDurationPrm), IntegerEntry(keyFinalizeReward, finalizeRewardPrm), StringEntry(keyWxAssetId, wxAssetIdPrm), StringEntry(keyUsdnAssetId, usdnAssetIdPrm)], unit)
145- else throw("Strict value is not equal to itself.")
146- }
147-
148-
149-
150-@Callable(i)
151-func suggest (amountAssetId,priceAssetId) = {
152- let payment = value(i.payments[0])
153- let info = valueOrErrorMessage(assetInfo(fromBase58String(amountAssetId)), "invalid amountAssetId ID")
154- let checks = [if ((info.issuer == i.caller))
155- then true
156- else throw("asset can only be suggested by its issuer"), if ((info.scripted == false))
157- then true
158- else throw("asset is smart"), if ((toBase58String(value(payment.assetId)) == value(getString(keyWxAssetId))))
159- then true
160- else throw("invalid fee asset"), if ((payment.amount == value(getInteger(keyFeeAmount))))
161- then true
162- else throw("invalid fee amount"), if ((priceAssetId == value(getString(keyUsdnAssetId))))
163- then true
164- else throw("priceAssetId is not USDN"), if ((getInteger(keyInListAssetId(amountAssetId, priceAssetId)) == unit))
165- then true
166- else throw("already in voting list")]
167- if ((checks == checks))
168- then {
169- let ensureActive = match invoke(userPoolContract, "statusREADONLY", [amountAssetId, priceAssetId], nil) {
170- case s: String =>
171- if ((s == "active"))
172- then true
173- else throw("user pool is not active")
174- case _ =>
175- throw("user pool is not active")
176- }
177- if ((ensureActive == ensureActive))
178- then {
179- let ensureAmountAssetVerified = match invoke(assetsStoreContract, "isVerifiedREADONLY", [amountAssetId], nil) {
180- case b: Boolean =>
181- if (b)
182- then true
183- else throw("asset is not verified")
184- case _ =>
185- throw("asset is not verified")
186- }
187- if ((ensureAmountAssetVerified == ensureAmountAssetVerified))
188- then {
189- let burnFeeInv = invoke(emissionContract, "burn", nil, [AttachedPayment(payment.assetId, payment.amount)])
190- if ((burnFeeInv == burnFeeInv))
191- then {
192- let newSuggestIndex = match getInteger(keySuggestIndex(amountAssetId, priceAssetId)) {
193- case int: Int =>
194- (int + 1)
195- case _ =>
196- 0
197- }
198- $Tuple2([IntegerEntry(keyInListAssetId(amountAssetId, priceAssetId), newSuggestIndex), IntegerEntry(keyStartHeight(amountAssetId, priceAssetId, newSuggestIndex), height), StringEntry(keyVotingResult(amountAssetId, priceAssetId, newSuggestIndex), totalVotes("0", "0")), IntegerEntry(keySuggestIndex(amountAssetId, priceAssetId), newSuggestIndex)], unit)
199- }
200- else throw("Strict value is not equal to itself.")
201- }
202- else throw("Strict value is not equal to itself.")
203- }
204- else throw("Strict value is not equal to itself.")
205- }
206- else throw("Strict value is not equal to itself.")
207- }
208-
209-
210-
211-@Callable(i)
212-func vote (amountAssetId,priceAssetId,inFavor) = {
213- let suggestIndex = value(getInteger(keyInListAssetId(amountAssetId, priceAssetId)))
214- let votingFinishHeight = (value(getInteger(keyStartHeight(amountAssetId, priceAssetId, suggestIndex))) + value(getInteger(keyEpochLength)))
215- let checks = [if (isDefined(getInteger(keyInListAssetId(amountAssetId, priceAssetId))))
216- then true
217- else throw("the token isn't on the voting list"), if ((votingFinishHeight > height))
218- then true
219- else throw("too late to vote")]
220- if ((checks == checks))
221- then {
222- let gwxAmount = invoke(boostingContract, "getUserGwxAmountAtHeightREADONLY", [toString(i.caller), votingFinishHeight], nil)
223- let notZero = if ((asInt(gwxAmount) > 0))
224- then true
225- else throw("you don't have gwx")
226- if ((notZero == notZero))
227- then {
228- let vote = match getString(keyVote(amountAssetId, priceAssetId, suggestIndex, toString(i.caller))) {
229- case s: String =>
230- let vote = split(s, separator)
231- let voteValue = vote[1]
232- let voteType = vote[2]
233- let isVoteTypeSimilar = if (if ((voteType == "yes"))
234- then (inFavor == true)
235- else false)
236- then true
237- else if ((voteType == "no"))
238- then (inFavor == false)
239- else false
240- let isVoteValueSimilar = if (isVoteTypeSimilar)
241- then (asInt(gwxAmount) == parseIntValue(voteValue))
242- else false
243- let isNewVoteSimilar = if (if (isVoteTypeSimilar)
244- then isVoteValueSimilar
245- else false)
246- then throw("you already voted")
247- else invoke(this, "cancelVote", [amountAssetId, priceAssetId], nil)
248- isNewVoteSimilar
249- case u: Unit =>
250- u
251- case _ =>
252- throw("Match error")
253- }
254- if ((vote == vote))
255- then {
256- let votingResult = split(value(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))), separator)
257- let positiveVotes = votingResult[1]
258- let negativeVotes = votingResult[2]
259- let newPositiveAndNegativeVotes = if (inFavor)
260- then {
261- let newPositiveVotes = (parseIntValue(positiveVotes) + asInt(gwxAmount))
262-[toString(newPositiveVotes), negativeVotes]
263- }
264- else {
265- let newNegativeVotes = (parseIntValue(negativeVotes) + asInt(gwxAmount))
266-[positiveVotes, toString(newNegativeVotes)]
267- }
268- let voteKey = keyVote(amountAssetId, priceAssetId, suggestIndex, toString(i.caller))
269- let voteValue = keyVoteValue(toString(asInt(gwxAmount)), inFavor)
270- $Tuple2([StringEntry(keyVotingResult(amountAssetId, priceAssetId, suggestIndex), totalVotes(newPositiveAndNegativeVotes[0], newPositiveAndNegativeVotes[1])), StringEntry(voteKey, voteValue)], unit)
271- }
272- else throw("Strict value is not equal to itself.")
273- }
274- else throw("Strict value is not equal to itself.")
275- }
276- else throw("Strict value is not equal to itself.")
277- }
278-
279-
280-
281-@Callable(i)
282-func cancelVote (amountAssetId,priceAssetId) = {
283- let userAddress = if ((i.caller == this))
284- then toString(i.originCaller)
285- else toString(i.caller)
286- let suggestIndex = value(getInteger(keyInListAssetId(amountAssetId, priceAssetId)))
287- let checks = [if (isDefined(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))))
288- then true
289- else throw("no vote for assets pair")]
290- if ((checks == checks))
291- then {
292- let vote = split(value(getString(keyVote(amountAssetId, priceAssetId, suggestIndex, userAddress))), separator)
293- let voteValue = vote[1]
294- let voteType = vote[2]
295- let votingResult = split(value(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))), separator)
296- let positiveVotes = votingResult[1]
297- let negativeVotes = votingResult[2]
298- let actions = if ((voteType == "yes"))
299- then {
300- let newPositiveVotes = (parseIntValue(positiveVotes) - parseIntValue(voteValue))
301- $Tuple2([StringEntry(keyVotingResult(amountAssetId, priceAssetId, suggestIndex), totalVotes(toString(newPositiveVotes), negativeVotes)), DeleteEntry(keyVote(amountAssetId, priceAssetId, suggestIndex, userAddress))], unit)
302- }
303- else {
304- let newNegativeVotes = (parseIntValue(negativeVotes) - parseIntValue(voteValue))
305- $Tuple2([StringEntry(keyVotingResult(amountAssetId, priceAssetId, suggestIndex), totalVotes(positiveVotes, toString(newNegativeVotes))), DeleteEntry(keyVote(amountAssetId, priceAssetId, suggestIndex, userAddress))], unit)
306- }
307- actions
308- }
309- else throw("Strict value is not equal to itself.")
310- }
311-
312-
313-
314-@Callable(i)
315-func setFee (newFee) = {
316- let checks = [mustManager(i)]
317- if ((checks == checks))
318- then [IntegerEntry(keyFeeAmount, newFee)]
319- else throw("Strict value is not equal to itself.")
320- }
321-
322-
323-
324-@Callable(i)
325-func finalize (amountAssetId,priceAssetId) = {
326- let suggestIndex = value(getInteger(keyInListAssetId(amountAssetId, priceAssetId)))
327- let votingFinishHeight = (value(getInteger(keyStartHeight(amountAssetId, priceAssetId, suggestIndex))) + value(getInteger(keyEpochLength)))
328- let checks = [if (isDefined(getInteger(keyInListAssetId(amountAssetId, priceAssetId))))
329- then true
330- else throw("no assets pair"), if ((height >= votingFinishHeight))
331- then true
332- else throw("insufficient height for completion")]
333- if ((checks == checks))
334- then {
335- let votingResult = split(value(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))), separator)
336- let positiveVotes = parseIntValue(votingResult[1])
337- let negativeVotes = parseIntValue(votingResult[2])
338- let actions = if ((positiveVotes > negativeVotes))
339- then {
340- let res = invoke(factoryContract, "setWxEmissionPoolLabel", [amountAssetId, priceAssetId], nil)
341- if ((res == res))
342- then $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
343- else throw("Strict value is not equal to itself.")
344- }
345- else $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
346- actions
347- }
343+func constructor (factoryAddressStr) = {
344+ let checkCaller = mustManager(i)
345+ if ((checkCaller == checkCaller))
346+ then [StringEntry(keyFactoryAddress(), factoryAddressStr)]
348347 else throw("Strict value is not equal to itself.")
349348 }
350349
370369 let pm = pendingManagerPublicKeyOrUnit()
371370 let hasPM = if (isDefined(pm))
372371 then true
373- else throw("no pending manager")
372+ else throw("No pending manager")
374373 if ((hasPM == hasPM))
375374 then {
376375 let checkPM = if ((i.callerPublicKey == value(pm)))
377376 then true
378- else throw("you are not pending manager")
377+ else throw("You are not pending manager")
379378 if ((checkPM == checkPM))
380379 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
381380 else throw("Strict value is not equal to itself.")
382381 }
383382 else throw("Strict value is not equal to itself.")
384383 }
384+
385+
386+
387+@Callable(i)
388+func stake () = if ((size(i.payments) != 1))
389+ then throw("invalid payment - exact one payment must be attached")
390+ else {
391+ let pmt = i.payments[0]
392+ let lpAssetId = value(pmt.assetId)
393+ let lpAssetIdStr = toBase58String(lpAssetId)
394+ let amount = pmt.amount
395+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
396+ let callerStr = toString(i.caller)
397+ let userAddressStr = if ((callerStr == poolAddressStr))
398+ then toString(i.originCaller)
399+ else callerStr
400+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
401+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
402+ let stakedByUser = readStaked(stakedByUserKEY)
403+ let stakedTotal = readStaked(stakedTotalKEY)
404+ let $t01607116188 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
405+ let wxToClaimUserNew = $t01607116188._1
406+ let integralSTATE = $t01607116188._2
407+ let debug = $t01607116188._3
408+ ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
409+ }
410+
411+
412+
413+@Callable(i)
414+func unstake (lpAssetIdStr,amount) = {
415+ let lpAssetId = fromBase58String(lpAssetIdStr)
416+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
417+ let poolAddon = valueOrElse(getString(this, keyStablePoolAddonAddr()), poolAddressStr)
418+ let callerStr = toString(i.caller)
419+ let userAddressStr = if (if ((callerStr == poolAddressStr))
420+ then true
421+ else (callerStr == poolAddon))
422+ then toString(i.originCaller)
423+ else callerStr
424+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
425+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
426+ let stakedByUser = readStaked(stakedByUserKEY)
427+ let stakedTotal = readStaked(stakedTotalKEY)
428+ let $t01732517443 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
429+ let wxToClaimUserNew = $t01732517443._1
430+ let integralSTATE = $t01732517443._2
431+ let debug = $t01732517443._3
432+ if ((amount > stakedByUser))
433+ then throw("passed amount is less then available")
434+ else ([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
435+ }
436+
437+
438+
439+@Callable(i)
440+func claimWx (lpAssetIdStr) = {
441+ let userAddress = i.caller
442+ let userAddressStr = toString(i.caller)
443+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
444+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
445+ let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
446+ let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
447+ let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
448+ let claimedByUser = toBigInt(getIntOrZero(this, claimedByUserKEY))
449+ let claimedByUserMinReward = toBigInt(getIntOrZero(this, claimedByUserMinRewardKEY))
450+ let claimedByUserBoostReward = toBigInt(getIntOrZero(this, claimedByUserBoostRewardKEY))
451+ let claimedTotal = toBigInt(getIntOrZero(this, claimedTotalKEY))
452+ let $t01867918791 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
453+ let wxToClaimUserNew = $t01867918791._1
454+ let integralSTATE = $t01867918791._2
455+ let debug = $t01867918791._3
456+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
457+ if ((zeroBigInt >= availableToClaim))
458+ then throw("nothing to claim")
459+ else {
460+ let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0])
461+ let minRewardPart = availableToClaim
462+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
463+ let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [toInt(minRewardPart)], nil))[0])
464+ let emitBoost = asAnyList(invoke(emissionContract, "emit", [toInt(boostRewardPart)], nil))
465+ if ((emitBoost == emitBoost))
466+ then {
467+ let claimedByUserValue = (claimedByUser + availableToClaim)
468+ let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
469+ let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
470+ let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
471+[StringEntry(claimedByUserKEY, toString(claimedByUserValue)), StringEntry(claimedByUserMinRewardKEY, toString(claimedByUserMinRewardPlusPart)), StringEntry(claimedByUserBoostRewardKEY, toString(claimedByUserBoostRewardPlusBoostRewardPart)), StringEntry(claimedTotalKEY, toString(claimedTotalPlusAvailableToClaim)), ScriptTransfer(userAddress, toInt(minRewardPart), wxAssetId), ScriptTransfer(userAddress, toInt(boostRewardPart), wxAssetId), OperationHistoryEntry("claim", userAddressStr, lpAssetIdStr, toInt(availableToClaim), i.transactionId)]
472+ }
473+ else throw("Strict value is not equal to itself.")
474+ }
475+ }
476+
477+
478+
479+@Callable(i)
480+func claimWxREADONLY (lpAssetIdStr,userAddressStr) = {
481+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
482+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
483+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
484+ let stakedByUser = readStaked(stakedByUserKEY)
485+ let stakedTotal = readStaked(stakedTotalKEY)
486+ let claimedByUser = getIntOrZero(this, claimedByUserKEY)
487+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
488+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
489+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
490+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
491+ let passedBlocks = if ((emissionStartBlock > height))
492+ then 0
493+ else (height - emissionStartBlock)
494+ let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
495+ let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
496+ let $t02145421566 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
497+ let wxToClaimUserNew = $t02145421566._1
498+ let integralSTATE = $t02145421566._2
499+ let debug = $t02145421566._3
500+ let availableToClaim = (wxToClaimUserNew - toBigInt(claimedByUser))
501+ let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
502+ let wxAmountBoostTotal = asInt(boostInvResult[0])
503+ let boostDebug = asString(boostInvResult[1])
504+ let minRewardPart = availableToClaim
505+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
506+ let totalReward = (minRewardPart + boostRewardPart)
507+ $Tuple2(nil, makeString(["%s%s%d%d%d%d%s", lpAssetIdStr, userAddressStr, toString(totalReward), toString(claimedByUser), toString(minRewardPart), toString(boostRewardPart), ((((debug + "::") + toString(userWxReward)) + "::BOOSTDEBUG::") + boostDebug)], SEP))
508+ }
509+
510+
511+
512+@Callable(i)
513+func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
514+ then throw("permissions denied")
515+ else {
516+ let $t02247922589 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
517+ let wxPerLpIntegralNew = $t02247922589._1
518+ let poolIntegralSTATE = $t02247922589._2
519+ let poolDEBUG = $t02247922589._3
520+ poolIntegralSTATE
521+ }
385522
386523
387524 @Verifier(tx)
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 5 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let separator = "__"
4+let SCALE8 = 8
55
6-let keyFeeAmount = makeString(["%s", "fee"], separator)
6+let MULT8 = 100000000
77
8-let keyUsdnAssetId = makeString(["%s", "usdnAssetId"], separator)
8+let SCALE18 = 18
99
10-let keyEpochLength = makeString(["%s", "epochLength"], separator)
10+let MULT18 = toBigInt(1000000000000000000)
1111
12-let keyFinalizeReward = makeString(["%s", "finalizeReward"], separator)
12+let SEP = "__"
1313
14-let keyWxAssetId = makeString(["%s", "wxAssetId"], separator)
14+let POOLWEIGHTMULT = MULT8
1515
16-let keyAssetsStoreContract = makeString(["%s", "assetsStoreContract"], separator)
16+let zeroBigInt = toBigInt(0)
1717
18-let keyUserPoolContract = makeString(["%s", "userPoolContract"], separator)
18+let oneBigInt = toBigInt(1)
1919
20-let keyEmissionContract = makeString(["%s", "emissionContract"], separator)
21-
22-let keyBoostingContract = makeString(["%s", "boostingContract"], separator)
23-
24-let keyFactoryContract = makeString(["%s", "factoryContract"], separator)
25-
26-let keyVotingEmissionContract = makeString(["%s", "votingEmissionContract"], separator)
27-
28-func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), (key + " is not defined"))
20+func asAnyList (val) = match val {
21+ case valAnyLyst: List[Any] =>
22+ valAnyLyst
23+ case _ =>
24+ throw("fail to cast into List[Any]")
25+}
2926
3027
31-func keyInListAssetId (amountAssetId,priceAssetId) = makeString(["%s%s%s", "inList", amountAssetId, priceAssetId], separator)
28+func asInt (val) = match val {
29+ case valInt: Int =>
30+ valInt
31+ case _ =>
32+ throw("fail to cast into Int")
33+}
3234
3335
34-func keySuggestIndex (amountAssetId,priceAssetId) = makeString(["%s%s%s", "suggestIndex", amountAssetId, priceAssetId], separator)
36+func asString (val) = match val {
37+ case valStr: String =>
38+ valStr
39+ case _ =>
40+ throw("fail to cast into Int")
41+}
3542
3643
37-func keyStartHeight (amountAssetId,priceAssetId,suggestIndex) = makeString(["%s%s%s%d", "startHeight", amountAssetId, priceAssetId, toString(suggestIndex)], separator)
44+func asByteVector (val) = match val {
45+ case valBin: ByteVector =>
46+ valBin
47+ case _ =>
48+ throw("fail to cast into Int")
49+}
3850
3951
40-func keyVotingResult (amountAssetId,priceAssetId,suggestIndex) = makeString(["%s%s%s%d", "votingResult", amountAssetId, priceAssetId, toString(suggestIndex)], separator)
52+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (("mandatory this." + key) + " is not defined"))
4153
4254
43-func totalVotes (totalYes,totalNo) = makeString(["%d%d", totalYes, totalNo], separator)
55+func getStringByAddressOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined"))
4456
4557
46-func keyVote (amountAssetId,priceAssetId,suggestIndex,voterAddress) = makeString(["%s%s%s%d%s", "vote", amountAssetId, priceAssetId, toString(suggestIndex), voterAddress], separator)
58+func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
4759
4860
49-func keyVoteValue (gwxAmount,vote) = {
50- let key = if (vote)
51- then makeString(["%d%s", gwxAmount, "yes"], separator)
52- else makeString(["%d%s", gwxAmount, "no"], separator)
53- key
54- }
61+func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
62+
63+
64+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined"))
65+
66+
67+func getBigIntFromStringOrZero (address,key) = value(parseBigInt(valueOrElse(getString(address, key), "0")))
68+
69+
70+func getBigIntFromStringOrDefault (address,key,defaultVal) = match getString(address, key) {
71+ case s: String =>
72+ value(parseBigInt(s))
73+ case _: Unit =>
74+ defaultVal
75+ case _ =>
76+ throw("Match error")
77+}
78+
79+
80+func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULT18, toBigInt(origScaleMult))
81+
82+
83+func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULT18))
84+
85+
86+func keyFactoryAddress () = "%s%s__config__factoryAddress"
87+
88+
89+let IdxFactoryCfgStakingDapp = 1
90+
91+let IdxFactoryCfgBoostingDapp = 2
92+
93+let IdxFactoryCfgIdoDapp = 3
94+
95+let IdxFactoryCfgTeamDapp = 4
96+
97+let IdxFactoryCfgEmissionDapp = 5
98+
99+let IdxFactoryCfgRestDapp = 6
100+
101+let IdxFactoryCfgSlippageDapp = 7
102+
103+func keyFactoryCfg () = "%s__factoryConfig"
55104
56105
57106 func keyManagerPublicKey () = "%s__managerPublicKey"
58107
59108
60109 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
61110
62111
63-let assetsStoreContract = addressFromStringValue(getStringOrFail(keyAssetsStoreContract))
112+func keyStablePoolAddonAddr () = "%s__stablePoolAddonAddr"
64113
65-let boostingContract = addressFromStringValue(getStringOrFail(keyBoostingContract))
66114
67-let emissionContract = addressFromStringValue(getStringOrFail(keyEmissionContract))
115+func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
68116
69-let factoryContract = addressFromStringValue(getStringOrFail(keyFactoryContract))
70117
71-let userPoolContract = addressFromStringValue(getStringOrFail(keyUserPoolContract))
118+func keyFactoryLpList () = "%s__lpTokensList"
72119
73-let votingEmissionContract = addressFromStringValue(getStringOrFail(keyVotingEmissionContract))
120+
121+func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
122+
123+
124+func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
125+
126+
127+func readLpList (factory) = split(valueOrElse(getString(factory, keyFactoryLpList()), ""), SEP)
128+
129+
130+func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP)
131+
132+
133+func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
134+
135+
136+func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
137+
138+
139+func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
140+
141+
142+func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
143+
144+
145+func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
146+
147+
148+func keyEmissionStartBlock () = "%s%s__emission__startBlock"
149+
150+
151+func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
152+
153+
154+func keyEmissionEndBlock () = "%s%s__emission__endBlock"
155+
156+
157+func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP)
158+
159+
160+func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr)
161+
162+
163+func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP)
164+
165+
166+func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP)
167+
168+
169+func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP)
170+
171+
172+func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed", "total", lpAssetIdStr], SEP)
173+
174+
175+func readStaked (key) = valueOrElse(getInteger(this, key), 0)
176+
177+
178+func keyLastTotalLpBalance (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "bal"], SEP)
179+
180+
181+func keyLastUserLpBalance (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "bal"], SEP)
182+
183+
184+func keyTotalLpBalanceIntegral (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "balINT"], SEP)
185+
186+
187+func keyUserLpBalanceIntegral (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "balINT"], SEP)
188+
189+
190+func keyTotalLpBalanceIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "lastUpd"], SEP)
191+
192+
193+func keyUserLpBalanceIntegralLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "lastUpd"], SEP)
194+
195+
196+func keyWxPerLpIntegral (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpInt"], SEP)
197+
198+
199+func keyWxPerLpIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpIntH"], SEP)
200+
201+
202+func keyWxToClaimUser (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpInt"], SEP)
203+
204+
205+func keyWxPerLpIntegralUserLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpIntH"], SEP)
206+
207+
208+func keyWxPerLp (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLp"], SEP)
209+
210+
211+func keyWxPerLpX18 (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLpX18"], SEP)
212+
213+
214+func keyWxPerLpIntegralUserLast (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "uIntL"], SEP)
215+
216+
217+func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP)
218+
219+
220+func formatHistoryRecord (userAddress,lpAssetId,type,amount) = makeString(["%s%s%s%d%d%d", userAddress, lpAssetId, type, toString(height), toString(lastBlock.timestamp), toString(amount)], SEP)
221+
222+
223+func OperationHistoryEntry (type,userAddress,lpAssetId,amount,txId) = StringEntry(keyOperationHistoryRecord(type, userAddress, toBase58String(txId)), formatHistoryRecord(userAddress, lpAssetId, type, amount))
224+
225+
226+let factoryAddress = getStringOrFail(this, keyFactoryAddress())
227+
228+let factoryContract = addressFromStringValue(factoryAddress)
229+
230+let factoryCfg = readFactoryCfgOrFail(factoryContract)
231+
232+let emissionContract = getEmissionAddressOrFail(factoryCfg)
233+
234+let boostingContract = getBoostingAddressOrFail(factoryCfg)
235+
236+func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
237+ then (stakedByUser > zeroBigInt)
238+ else false)
239+ then zeroBigInt
240+ else if ((stakedByUser == zeroBigInt))
241+ then wxPerLpIntegralNew
242+ else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > zeroBigInt))
243+ then (stakedByUser > zeroBigInt)
244+ else false)
245+ then value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))
246+ else throw("calcWxPerLpIntegralUserLast: unexpected state")
247+
248+
249+func refreshPoolINTEGRALS (lpAssetIdStr,poolAddressStr,lpDeltaAmount) = {
250+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
251+ let stakedTotal = toBigInt(readStaked(stakedTotalKEY))
252+ let nonZeroStakedTotal = if ((stakedTotal == zeroBigInt))
253+ then oneBigInt
254+ else stakedTotal
255+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
256+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
257+ let MULT3 = 1000
258+ let wxEmissionPerBlockX3 = (getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent()) * MULT3)
259+ let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3))
260+ let wxPerLpIntegralKEY = keyWxPerLpIntegral(lpAssetIdStr)
261+ let wxPerLpIntegralLastUpdHeightKEY = keyWxPerLpIntegralLastUpdHeight(lpAssetIdStr)
262+ let wxPerLpKEY = keyWxPerLp(lpAssetIdStr)
263+ let wxPerLpIntegralLastUpdHeight = getIntOrDefault(this, wxPerLpIntegralLastUpdHeightKEY, emissionStartBlock)
264+ let wxPerLpIntegral = getBigIntFromStringOrZero(this, wxPerLpIntegralKEY)
265+ let wxPerLpOrZeroX3 = 0
266+ let dh = max([(height - wxPerLpIntegralLastUpdHeight), 0])
267+ let wxPerLpX3 = if ((wxPerLpOrZeroX3 != 0))
268+ then toBigInt(wxPerLpOrZeroX3)
269+ else fraction(toBigInt(poolWxEmissionPerBlockX3), toBigInt(MULT8), nonZeroStakedTotal)
270+ let stakedTotalNew = (stakedTotal + toBigInt(lpDeltaAmount))
271+ let nonZeroStakedTotalNew = if ((stakedTotalNew == zeroBigInt))
272+ then oneBigInt
273+ else stakedTotalNew
274+ let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * toBigInt(dh)))
275+ let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
276+ let wxPerLpIntegralLastUpdHeightNew = height
277+ let debug = makeString(["wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), "poolWxEmissionPerBlockX3=", toString(poolWxEmissionPerBlockX3), "wxEmissionPerBlockX3=", toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
278+ $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
279+ }
280+
281+
282+func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
283+ let $t01151811640 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
284+ let wxPerLpIntegralNew = $t01151811640._1
285+ let poolIntegralSTATE = $t01151811640._2
286+ let poolDEBUG = $t01151811640._3
287+ let MULT3 = 1000
288+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
289+ let stakedByUser = readStaked(stakedByUserKEY)
290+ let wxToClaimUserKEY = keyWxToClaimUser(lpAssetIdStr, userAddressStr)
291+ let wxPerLpIntegralUserLastUpdHeightKEY = keyWxPerLpIntegralUserLastUpdHeight(lpAssetIdStr, userAddressStr)
292+ let wxPerLpIntegralUserLastKEY = keyWxPerLpIntegralUserLast(lpAssetIdStr, userAddressStr)
293+ let wxToClaimUser = getBigIntFromStringOrZero(this, wxToClaimUserKEY)
294+ let wxPerLpIntegralUserLastUpdHeightOrZero = getIntOrZero(this, wxPerLpIntegralUserLastUpdHeightKEY)
295+ let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(toBigInt(stakedByUser), toBigInt(wxPerLpIntegralUserLastUpdHeightOrZero), wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
296+ let MULT11 = (MULT8 * MULT3)
297+ let wxToClaimUserNew = (wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11)))
298+ let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
299+ let wxPerLpIntegralUserLastUpdHeightNew = height
300+ let debug = makeString(["wxPerLpIntegralUserLastUpdHeightOrZero=", toString(wxPerLpIntegralUserLastUpdHeightOrZero), "this.getStringOrFail(wxPerLpIntegralUserLastKEY).parseBigInt().value()=", toString(value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))), "wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "wxToClaimUserNew=", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast=", toString(wxPerLpIntegralUserLast), "stakedByUser=", toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
301+ $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
302+ }
303+
74304
75305 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
76306 case s: String =>
77307 fromBase58String(s)
78308 case _: Unit =>
79309 unit
80310 case _ =>
81311 throw("Match error")
82312 }
83313
84314
85315 func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) {
86316 case s: String =>
87317 fromBase58String(s)
88318 case _: Unit =>
89319 unit
90320 case _ =>
91321 throw("Match error")
92322 }
93323
94324
95325 func mustManager (i) = {
96- let pd = throw("permission denied")
326+ let pd = throw("Permission denied")
97327 match managerPublicKeyOrUnit() {
98328 case pk: ByteVector =>
99329 if ((i.callerPublicKey == pk))
100330 then true
101331 else pd
102332 case _: Unit =>
103333 if ((i.caller == this))
104334 then true
105335 else pd
106336 case _ =>
107337 throw("Match error")
108338 }
109339 }
110340
111341
112-func asInt (val) = match val {
113- case valInt: Int =>
114- valInt
115- case _ =>
116- throw("failed to cast into Integer")
117-}
118-
119-
120342 @Callable(i)
121-func constructor (assetsStoreContractPrm,boostingContractPrm,emissionContractPrm,factoryContractPrm,userPoolContractPrm,votingEmissionContractPrm,feeAmountPrm,wxAssetIdPrm,votingDurationPrm,usdnAssetIdPrm,finalizeRewardPrm) = {
122- let checks = [mustManager(i), if (isDefined(addressFromString(assetsStoreContractPrm)))
123- then true
124- else throw("Invalid asset_store contract address"), if (isDefined(addressFromString(boostingContractPrm)))
125- then true
126- else throw("Invalid boosting contract address"), if (isDefined(addressFromString(userPoolContractPrm)))
127- then true
128- else throw("Invalid user_pools contract address"), if (isDefined(addressFromString(emissionContractPrm)))
129- then true
130- else throw("Invalid emission contract address"), if (isDefined(addressFromString(factoryContractPrm)))
131- then true
132- else throw("Invalid factory contract address"), if ((feeAmountPrm >= 0))
133- then true
134- else throw("Invalid fee amount"), if ((votingDurationPrm > 0))
135- then true
136- else throw("Invalid voting duration"), if ((finalizeRewardPrm > 0))
137- then true
138- else throw("Invalid finalize reward"), if (isDefined(assetInfo(fromBase58String(wxAssetIdPrm))))
139- then true
140- else throw("Invalid WX asset ID"), if (isDefined(assetInfo(fromBase58String(usdnAssetIdPrm))))
141- then true
142- else throw("Invalid USDN asset ID")]
143- if ((checks == checks))
144- then $Tuple2([StringEntry(keyAssetsStoreContract, assetsStoreContractPrm), StringEntry(keyBoostingContract, boostingContractPrm), StringEntry(keyEmissionContract, emissionContractPrm), StringEntry(keyFactoryContract, factoryContractPrm), StringEntry(keyUserPoolContract, userPoolContractPrm), StringEntry(keyVotingEmissionContract, votingEmissionContractPrm), IntegerEntry(keyFeeAmount, feeAmountPrm), IntegerEntry(keyEpochLength, votingDurationPrm), IntegerEntry(keyFinalizeReward, finalizeRewardPrm), StringEntry(keyWxAssetId, wxAssetIdPrm), StringEntry(keyUsdnAssetId, usdnAssetIdPrm)], unit)
145- else throw("Strict value is not equal to itself.")
146- }
147-
148-
149-
150-@Callable(i)
151-func suggest (amountAssetId,priceAssetId) = {
152- let payment = value(i.payments[0])
153- let info = valueOrErrorMessage(assetInfo(fromBase58String(amountAssetId)), "invalid amountAssetId ID")
154- let checks = [if ((info.issuer == i.caller))
155- then true
156- else throw("asset can only be suggested by its issuer"), if ((info.scripted == false))
157- then true
158- else throw("asset is smart"), if ((toBase58String(value(payment.assetId)) == value(getString(keyWxAssetId))))
159- then true
160- else throw("invalid fee asset"), if ((payment.amount == value(getInteger(keyFeeAmount))))
161- then true
162- else throw("invalid fee amount"), if ((priceAssetId == value(getString(keyUsdnAssetId))))
163- then true
164- else throw("priceAssetId is not USDN"), if ((getInteger(keyInListAssetId(amountAssetId, priceAssetId)) == unit))
165- then true
166- else throw("already in voting list")]
167- if ((checks == checks))
168- then {
169- let ensureActive = match invoke(userPoolContract, "statusREADONLY", [amountAssetId, priceAssetId], nil) {
170- case s: String =>
171- if ((s == "active"))
172- then true
173- else throw("user pool is not active")
174- case _ =>
175- throw("user pool is not active")
176- }
177- if ((ensureActive == ensureActive))
178- then {
179- let ensureAmountAssetVerified = match invoke(assetsStoreContract, "isVerifiedREADONLY", [amountAssetId], nil) {
180- case b: Boolean =>
181- if (b)
182- then true
183- else throw("asset is not verified")
184- case _ =>
185- throw("asset is not verified")
186- }
187- if ((ensureAmountAssetVerified == ensureAmountAssetVerified))
188- then {
189- let burnFeeInv = invoke(emissionContract, "burn", nil, [AttachedPayment(payment.assetId, payment.amount)])
190- if ((burnFeeInv == burnFeeInv))
191- then {
192- let newSuggestIndex = match getInteger(keySuggestIndex(amountAssetId, priceAssetId)) {
193- case int: Int =>
194- (int + 1)
195- case _ =>
196- 0
197- }
198- $Tuple2([IntegerEntry(keyInListAssetId(amountAssetId, priceAssetId), newSuggestIndex), IntegerEntry(keyStartHeight(amountAssetId, priceAssetId, newSuggestIndex), height), StringEntry(keyVotingResult(amountAssetId, priceAssetId, newSuggestIndex), totalVotes("0", "0")), IntegerEntry(keySuggestIndex(amountAssetId, priceAssetId), newSuggestIndex)], unit)
199- }
200- else throw("Strict value is not equal to itself.")
201- }
202- else throw("Strict value is not equal to itself.")
203- }
204- else throw("Strict value is not equal to itself.")
205- }
206- else throw("Strict value is not equal to itself.")
207- }
208-
209-
210-
211-@Callable(i)
212-func vote (amountAssetId,priceAssetId,inFavor) = {
213- let suggestIndex = value(getInteger(keyInListAssetId(amountAssetId, priceAssetId)))
214- let votingFinishHeight = (value(getInteger(keyStartHeight(amountAssetId, priceAssetId, suggestIndex))) + value(getInteger(keyEpochLength)))
215- let checks = [if (isDefined(getInteger(keyInListAssetId(amountAssetId, priceAssetId))))
216- then true
217- else throw("the token isn't on the voting list"), if ((votingFinishHeight > height))
218- then true
219- else throw("too late to vote")]
220- if ((checks == checks))
221- then {
222- let gwxAmount = invoke(boostingContract, "getUserGwxAmountAtHeightREADONLY", [toString(i.caller), votingFinishHeight], nil)
223- let notZero = if ((asInt(gwxAmount) > 0))
224- then true
225- else throw("you don't have gwx")
226- if ((notZero == notZero))
227- then {
228- let vote = match getString(keyVote(amountAssetId, priceAssetId, suggestIndex, toString(i.caller))) {
229- case s: String =>
230- let vote = split(s, separator)
231- let voteValue = vote[1]
232- let voteType = vote[2]
233- let isVoteTypeSimilar = if (if ((voteType == "yes"))
234- then (inFavor == true)
235- else false)
236- then true
237- else if ((voteType == "no"))
238- then (inFavor == false)
239- else false
240- let isVoteValueSimilar = if (isVoteTypeSimilar)
241- then (asInt(gwxAmount) == parseIntValue(voteValue))
242- else false
243- let isNewVoteSimilar = if (if (isVoteTypeSimilar)
244- then isVoteValueSimilar
245- else false)
246- then throw("you already voted")
247- else invoke(this, "cancelVote", [amountAssetId, priceAssetId], nil)
248- isNewVoteSimilar
249- case u: Unit =>
250- u
251- case _ =>
252- throw("Match error")
253- }
254- if ((vote == vote))
255- then {
256- let votingResult = split(value(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))), separator)
257- let positiveVotes = votingResult[1]
258- let negativeVotes = votingResult[2]
259- let newPositiveAndNegativeVotes = if (inFavor)
260- then {
261- let newPositiveVotes = (parseIntValue(positiveVotes) + asInt(gwxAmount))
262-[toString(newPositiveVotes), negativeVotes]
263- }
264- else {
265- let newNegativeVotes = (parseIntValue(negativeVotes) + asInt(gwxAmount))
266-[positiveVotes, toString(newNegativeVotes)]
267- }
268- let voteKey = keyVote(amountAssetId, priceAssetId, suggestIndex, toString(i.caller))
269- let voteValue = keyVoteValue(toString(asInt(gwxAmount)), inFavor)
270- $Tuple2([StringEntry(keyVotingResult(amountAssetId, priceAssetId, suggestIndex), totalVotes(newPositiveAndNegativeVotes[0], newPositiveAndNegativeVotes[1])), StringEntry(voteKey, voteValue)], unit)
271- }
272- else throw("Strict value is not equal to itself.")
273- }
274- else throw("Strict value is not equal to itself.")
275- }
276- else throw("Strict value is not equal to itself.")
277- }
278-
279-
280-
281-@Callable(i)
282-func cancelVote (amountAssetId,priceAssetId) = {
283- let userAddress = if ((i.caller == this))
284- then toString(i.originCaller)
285- else toString(i.caller)
286- let suggestIndex = value(getInteger(keyInListAssetId(amountAssetId, priceAssetId)))
287- let checks = [if (isDefined(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))))
288- then true
289- else throw("no vote for assets pair")]
290- if ((checks == checks))
291- then {
292- let vote = split(value(getString(keyVote(amountAssetId, priceAssetId, suggestIndex, userAddress))), separator)
293- let voteValue = vote[1]
294- let voteType = vote[2]
295- let votingResult = split(value(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))), separator)
296- let positiveVotes = votingResult[1]
297- let negativeVotes = votingResult[2]
298- let actions = if ((voteType == "yes"))
299- then {
300- let newPositiveVotes = (parseIntValue(positiveVotes) - parseIntValue(voteValue))
301- $Tuple2([StringEntry(keyVotingResult(amountAssetId, priceAssetId, suggestIndex), totalVotes(toString(newPositiveVotes), negativeVotes)), DeleteEntry(keyVote(amountAssetId, priceAssetId, suggestIndex, userAddress))], unit)
302- }
303- else {
304- let newNegativeVotes = (parseIntValue(negativeVotes) - parseIntValue(voteValue))
305- $Tuple2([StringEntry(keyVotingResult(amountAssetId, priceAssetId, suggestIndex), totalVotes(positiveVotes, toString(newNegativeVotes))), DeleteEntry(keyVote(amountAssetId, priceAssetId, suggestIndex, userAddress))], unit)
306- }
307- actions
308- }
309- else throw("Strict value is not equal to itself.")
310- }
311-
312-
313-
314-@Callable(i)
315-func setFee (newFee) = {
316- let checks = [mustManager(i)]
317- if ((checks == checks))
318- then [IntegerEntry(keyFeeAmount, newFee)]
319- else throw("Strict value is not equal to itself.")
320- }
321-
322-
323-
324-@Callable(i)
325-func finalize (amountAssetId,priceAssetId) = {
326- let suggestIndex = value(getInteger(keyInListAssetId(amountAssetId, priceAssetId)))
327- let votingFinishHeight = (value(getInteger(keyStartHeight(amountAssetId, priceAssetId, suggestIndex))) + value(getInteger(keyEpochLength)))
328- let checks = [if (isDefined(getInteger(keyInListAssetId(amountAssetId, priceAssetId))))
329- then true
330- else throw("no assets pair"), if ((height >= votingFinishHeight))
331- then true
332- else throw("insufficient height for completion")]
333- if ((checks == checks))
334- then {
335- let votingResult = split(value(getString(keyVotingResult(amountAssetId, priceAssetId, suggestIndex))), separator)
336- let positiveVotes = parseIntValue(votingResult[1])
337- let negativeVotes = parseIntValue(votingResult[2])
338- let actions = if ((positiveVotes > negativeVotes))
339- then {
340- let res = invoke(factoryContract, "setWxEmissionPoolLabel", [amountAssetId, priceAssetId], nil)
341- if ((res == res))
342- then $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
343- else throw("Strict value is not equal to itself.")
344- }
345- else $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
346- actions
347- }
343+func constructor (factoryAddressStr) = {
344+ let checkCaller = mustManager(i)
345+ if ((checkCaller == checkCaller))
346+ then [StringEntry(keyFactoryAddress(), factoryAddressStr)]
348347 else throw("Strict value is not equal to itself.")
349348 }
350349
351350
352351
353352 @Callable(i)
354353 func setManager (pendingManagerPublicKey) = {
355354 let checkCaller = mustManager(i)
356355 if ((checkCaller == checkCaller))
357356 then {
358357 let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey)
359358 if ((checkManagerPublicKey == checkManagerPublicKey))
360359 then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)]
361360 else throw("Strict value is not equal to itself.")
362361 }
363362 else throw("Strict value is not equal to itself.")
364363 }
365364
366365
367366
368367 @Callable(i)
369368 func confirmManager () = {
370369 let pm = pendingManagerPublicKeyOrUnit()
371370 let hasPM = if (isDefined(pm))
372371 then true
373- else throw("no pending manager")
372+ else throw("No pending manager")
374373 if ((hasPM == hasPM))
375374 then {
376375 let checkPM = if ((i.callerPublicKey == value(pm)))
377376 then true
378- else throw("you are not pending manager")
377+ else throw("You are not pending manager")
379378 if ((checkPM == checkPM))
380379 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
381380 else throw("Strict value is not equal to itself.")
382381 }
383382 else throw("Strict value is not equal to itself.")
384383 }
384+
385+
386+
387+@Callable(i)
388+func stake () = if ((size(i.payments) != 1))
389+ then throw("invalid payment - exact one payment must be attached")
390+ else {
391+ let pmt = i.payments[0]
392+ let lpAssetId = value(pmt.assetId)
393+ let lpAssetIdStr = toBase58String(lpAssetId)
394+ let amount = pmt.amount
395+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
396+ let callerStr = toString(i.caller)
397+ let userAddressStr = if ((callerStr == poolAddressStr))
398+ then toString(i.originCaller)
399+ else callerStr
400+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
401+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
402+ let stakedByUser = readStaked(stakedByUserKEY)
403+ let stakedTotal = readStaked(stakedTotalKEY)
404+ let $t01607116188 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
405+ let wxToClaimUserNew = $t01607116188._1
406+ let integralSTATE = $t01607116188._2
407+ let debug = $t01607116188._3
408+ ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
409+ }
410+
411+
412+
413+@Callable(i)
414+func unstake (lpAssetIdStr,amount) = {
415+ let lpAssetId = fromBase58String(lpAssetIdStr)
416+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
417+ let poolAddon = valueOrElse(getString(this, keyStablePoolAddonAddr()), poolAddressStr)
418+ let callerStr = toString(i.caller)
419+ let userAddressStr = if (if ((callerStr == poolAddressStr))
420+ then true
421+ else (callerStr == poolAddon))
422+ then toString(i.originCaller)
423+ else callerStr
424+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
425+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
426+ let stakedByUser = readStaked(stakedByUserKEY)
427+ let stakedTotal = readStaked(stakedTotalKEY)
428+ let $t01732517443 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
429+ let wxToClaimUserNew = $t01732517443._1
430+ let integralSTATE = $t01732517443._2
431+ let debug = $t01732517443._3
432+ if ((amount > stakedByUser))
433+ then throw("passed amount is less then available")
434+ else ([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
435+ }
436+
437+
438+
439+@Callable(i)
440+func claimWx (lpAssetIdStr) = {
441+ let userAddress = i.caller
442+ let userAddressStr = toString(i.caller)
443+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
444+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
445+ let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
446+ let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
447+ let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
448+ let claimedByUser = toBigInt(getIntOrZero(this, claimedByUserKEY))
449+ let claimedByUserMinReward = toBigInt(getIntOrZero(this, claimedByUserMinRewardKEY))
450+ let claimedByUserBoostReward = toBigInt(getIntOrZero(this, claimedByUserBoostRewardKEY))
451+ let claimedTotal = toBigInt(getIntOrZero(this, claimedTotalKEY))
452+ let $t01867918791 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
453+ let wxToClaimUserNew = $t01867918791._1
454+ let integralSTATE = $t01867918791._2
455+ let debug = $t01867918791._3
456+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
457+ if ((zeroBigInt >= availableToClaim))
458+ then throw("nothing to claim")
459+ else {
460+ let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0])
461+ let minRewardPart = availableToClaim
462+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
463+ let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [toInt(minRewardPart)], nil))[0])
464+ let emitBoost = asAnyList(invoke(emissionContract, "emit", [toInt(boostRewardPart)], nil))
465+ if ((emitBoost == emitBoost))
466+ then {
467+ let claimedByUserValue = (claimedByUser + availableToClaim)
468+ let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
469+ let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
470+ let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
471+[StringEntry(claimedByUserKEY, toString(claimedByUserValue)), StringEntry(claimedByUserMinRewardKEY, toString(claimedByUserMinRewardPlusPart)), StringEntry(claimedByUserBoostRewardKEY, toString(claimedByUserBoostRewardPlusBoostRewardPart)), StringEntry(claimedTotalKEY, toString(claimedTotalPlusAvailableToClaim)), ScriptTransfer(userAddress, toInt(minRewardPart), wxAssetId), ScriptTransfer(userAddress, toInt(boostRewardPart), wxAssetId), OperationHistoryEntry("claim", userAddressStr, lpAssetIdStr, toInt(availableToClaim), i.transactionId)]
472+ }
473+ else throw("Strict value is not equal to itself.")
474+ }
475+ }
476+
477+
478+
479+@Callable(i)
480+func claimWxREADONLY (lpAssetIdStr,userAddressStr) = {
481+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
482+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
483+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
484+ let stakedByUser = readStaked(stakedByUserKEY)
485+ let stakedTotal = readStaked(stakedTotalKEY)
486+ let claimedByUser = getIntOrZero(this, claimedByUserKEY)
487+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
488+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
489+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
490+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
491+ let passedBlocks = if ((emissionStartBlock > height))
492+ then 0
493+ else (height - emissionStartBlock)
494+ let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
495+ let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
496+ let $t02145421566 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
497+ let wxToClaimUserNew = $t02145421566._1
498+ let integralSTATE = $t02145421566._2
499+ let debug = $t02145421566._3
500+ let availableToClaim = (wxToClaimUserNew - toBigInt(claimedByUser))
501+ let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
502+ let wxAmountBoostTotal = asInt(boostInvResult[0])
503+ let boostDebug = asString(boostInvResult[1])
504+ let minRewardPart = availableToClaim
505+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
506+ let totalReward = (minRewardPart + boostRewardPart)
507+ $Tuple2(nil, makeString(["%s%s%d%d%d%d%s", lpAssetIdStr, userAddressStr, toString(totalReward), toString(claimedByUser), toString(minRewardPart), toString(boostRewardPart), ((((debug + "::") + toString(userWxReward)) + "::BOOSTDEBUG::") + boostDebug)], SEP))
508+ }
509+
510+
511+
512+@Callable(i)
513+func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
514+ then throw("permissions denied")
515+ else {
516+ let $t02247922589 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
517+ let wxPerLpIntegralNew = $t02247922589._1
518+ let poolIntegralSTATE = $t02247922589._2
519+ let poolDEBUG = $t02247922589._3
520+ poolIntegralSTATE
521+ }
385522
386523
387524 @Verifier(tx)
388525 func verify () = {
389526 let targetPublicKey = match managerPublicKeyOrUnit() {
390527 case pk: ByteVector =>
391528 pk
392529 case _: Unit =>
393530 tx.senderPublicKey
394531 case _ =>
395532 throw("Match error")
396533 }
397534 sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
398535 }
399536

github/deemru/w8io/c3f4982 
79.35 ms