tx · AWDnkZCp8uKMFFqTrCi2aaBWcdHFrCrbozUJjkekZen8

3N1Epwa6GQuTQr2K9WzeUcqSFCdERwuvL5T:  -0.02800000 Waves

2022.06.14 18:41 [2096239] smart account 3N1Epwa6GQuTQr2K9WzeUcqSFCdERwuvL5T > SELF 0.00000000 Waves

{ "type": 13, "id": "AWDnkZCp8uKMFFqTrCi2aaBWcdHFrCrbozUJjkekZen8", "fee": 2800000, "feeAssetId": null, "timestamp": 1655221274664, "version": 1, "sender": "3N1Epwa6GQuTQr2K9WzeUcqSFCdERwuvL5T", "senderPublicKey": "7iXEgsFNsnbLZ3ca4tmz8jffnyxMu9keuBV6CuQPJLuA", "proofs": [ "5FLXhN6HJkkWbTjoRtEDi4xcpAYWqxsSK8mHUUBbdRzFPdiYvYXdia6xrYjyNu1bBbtZF5ZawpEZ86Vtn8mE3YnX" ], "script": "base64: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TVVMVDE4AQAAABFrZXlGYWN0b3J5QWRkcmVzcwAAAAACAAAAHCVzJXNfX2NvbmZpZ19fZmFjdG9yeUFkZHJlc3MAAAAAGElkeEZhY3RvcnlDZmdTdGFraW5nRGFwcAAAAAAAAAAAAQAAAAAZSWR4RmFjdG9yeUNmZ0Jvb3N0aW5nRGFwcAAAAAAAAAAAAgAAAAAUSWR4RmFjdG9yeUNmZ0lkb0RhcHAAAAAAAAAAAAMAAAAAFUlkeEZhY3RvcnlDZmdUZWFtRGFwcAAAAAAAAAAABAAAAAAZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAAAAAAAAAAABQAAAAAVSWR4RmFjdG9yeUNmZ1Jlc3REYXBwAAAAAAAAAAAGAAAAABlJZHhGYWN0b3J5Q2ZnU2xpcHBhZ2VEYXBwAAAAAAAAAAAHAQAAAA1rZXlGYWN0b3J5Q2ZnAAAAAAIAAAARJXNfX2ZhY3RvcnlDb25maWcBAAAAE2tleU1hbmFnZXJQdWJsaWNLZXkAAAAAAgAAABQlc19fbWFuYWdlclB1YmxpY0tleQEAAAAaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkAAAAAAgAAABslc19fcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkBAAAAFmtleVN0YWJsZVBvb2xBZGRvbkFkZHIAAAAAAgAAABclc19fc3RhYmxlUG9vbEFkZG9uQWRkcgEAAAAaa2V5RmFjdG9yeUxwMkFzc2V0c01hcHBpbmcAAAABAAAACmxwQXNzZXRTdHIJAAS5AAAAAgkABEwAAAACAgAAAAYlcyVzJXMJAARMAAAAAgUAAAAKbHBBc3NldFN0cgkABEwAAAACAgAAAB5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFAAAAA25pbAUAAAADU0VQAQAAABBrZXlGYWN0b3J5THBMaXN0AAAAAAIAAAAQJXNfX2xwVG9rZW5zTGlzdAEAAAAma2V5RmFjdG9yeUxwQXNzZXRUb1Bvb2xDb250cmFjdEFkZHJlc3MAAAABAAAACmxwQXNzZXRTdHIJAAS5AAAAAgkABEwAAAACAgAAAAYlcyVzJXMJAARMAAAAAgUAAAAKbHBBc3NldFN0cgkABEwAAAACAgAAAB5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFAAAAA25pbAUAAAADU0VQAQAAABRrZXlGYWN0b3J5UG9vbFdlaWdodAAAAAEAAAAPY29udHJhY3RBZGRyZXNzCQAEuQAAAAIJAARMAAAAAgIAAAAEJXMlcwkABEwAAAACAgAAAApwb29sV2VpZ2h0CQAETAAAAAIFAAAAD2NvbnRyYWN0QWRkcmVzcwUAAAADbmlsBQAAAANTRVABAAAACnJlYWRMcExpc3QAAAABAAAAB2ZhY3RvcnkJAAS1AAAAAgkBAAAAC3ZhbHVlT3JFbHNlAAAAAgkABB0AAAACBQAAAAdmYWN0b3J5CQEAAAAQa2V5RmFjdG9yeUxwTGlzdAAAAAACAAAAAAUAAAADU0VQAQAAABRyZWFkRmFjdG9yeUNmZ09yRmFpbAAAAAEAAAAHZmFjdG9yeQkABLUAAAACCQEAAAAYZ2V0U3RyaW5nQnlBZGRyZXNzT3JGYWlsAAAAAgUAAAAHZmFjdG9yeQkBAAAADWtleUZhY3RvcnlDZmcAAAAABQAAAANTRVABAAAAGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAAAAAEAAAAKZmFjdG9yeUNmZwkBAAAAEUBleHRyTmF0aXZlKDEwNjIpAAAAAQkAAZEAAAACBQAAAApmYWN0b3J5Q2ZnBQAAABlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwAQAAABhnZXRFbWlzc2lvbkFkZHJlc3NPckZhaWwAAAABAAAACmZhY3RvcnlDZmcJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEJAAGRAAAAAgUAAAAKZmFjdG9yeUNmZwUAAAAZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAEAAAAXZ2V0U3Rha2luZ0FkZHJlc3NPckZhaWwAAAABAAAACmZhY3RvcnlDZmcJAQAAABFAZXh0ck5hdGl2ZSgxMDYyKQAAAAEJAAGRAAAAAgUAAAAKZmFjdG9yeUNmZwUAAAAYSWR4RmFjdG9yeUNmZ1N0YWtpbmdEYXBwAQAAAB5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQAAAAAAgAAABslcyVzX19yYXRlUGVyQmxvY2tfX2N1cnJlbnQBAAAAIWtleUVtaXNzaW9uUmF0ZVBlckJsb2NrTWF4Q3VycmVudAAAAAACAAAAHiVzJXNfX3JhdGVQZXJCbG9ja01heF9fY3VycmVudAEAAAAVa2V5RW1pc3Npb25TdGFydEJsb2NrAAAAAAIAAAAaJXMlc19fZW1pc3Npb25fX3N0YXJ0QmxvY2sBAAAAG2tleUVtaXNzaW9uRHVyYXRpb25JbkJsb2NrcwAAAAACAAAAGCVzJXNfX2VtaXNzaW9uX19kdXJhdGlvbgEAAAATa2V5RW1pc3Npb25FbmRCbG9jawAAAAACAAAAGCVzJXNfX2VtaXNzaW9uX19lbmRCbG9jawEAAAAPa2V5U3Rha2VkQnlVc2VyAAAAAgAAAA51c2VyQWRkcmVzc1N0cgAAAAxscEFzc2V0SWRTdHIJAAS5AAAAAgkABEwAAAACAgAAAA4lcyVzJXNfX3N0YWtlZAkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgkABEwAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAAA25pbAUAAAADU0VQAQAAAA5rZXlTdGFrZWRUb3RhbAAAAAEAAAAMbHBBc3NldElkU3RyCQABLAAAAAICAAAAFyVzJXMlc19fc3Rha2VkX190b3RhbF9fBQAAAAxscEFzc2V0SWRTdHIBAAAAEGtleUNsYWltZWRCeVVzZXIAAAACAAAADGxwQXNzZXRJZFN0cgAAAA51c2VyQWRkcmVzc1N0cgkABLkAAAACCQAETAAAAAICAAAADyVzJXMlc19fY2xhaW1lZAkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgkABEwAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAAA25pbAUAAAADU0VQAQAAABlrZXlDbGFpbWVkQnlVc2VyTWluUmV3YXJkAAAAAgAAAAxscEFzc2V0SWRTdHIAAAAOdXNlckFkZHJlc3NTdHIJAAS5AAAAAgkABEwAAAACAgAAABglcyVzJXNfX2NsYWltZWRNaW5SZXdhcmQJAARMAAAAAgUAAAAOdXNlckFkZHJlc3NTdHIJAARMAAAAAgUAAAAMbHBBc3NldElkU3RyBQAAAANuaWwFAAAAA1NFUAEAAAAba2V5Q2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkAAAAAgAAAAxscEFzc2V0SWRTdHIAAAAOdXNlckFkZHJlc3NTdHIJAAS5AAAAAgkABEwAAAACAgAAABolcyVzJXNfX2NsYWltZWRCb29zdFJld2FyZAkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgkABEwAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAAA25pbAUAAAADU0VQAQAAAA9rZXlDbGFpbWVkVG90YWwAAAABAAAADGxwQXNzZXRJZFN0cgkABLkAAAACCQAETAAAAAICAAAADyVzJXMlc19fY2xhaW1lZAkABEwAAAACAgAAAAV0b3RhbAkABEwAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAAA25pbAUAAAADU0VQAQAAAApyZWFkU3Rha2VkAAAAAQAAAANrZXkJAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQaAAAAAgUAAAAEdGhpcwUAAAADa2V5AAAAAAAAAAAAAQAAABVrZXlMYXN0VG90YWxMcEJhbGFuY2UAAAABAAAACWxwQXNzZXRJZAkABLkAAAACCQAETAAAAAICAAAABiVzJXMlcwkABEwAAAACBQAAAAlscEFzc2V0SWQJAARMAAAAAgIAAAAFdG90YWwJAARMAAAAAgIAAAADYmFsBQAAAANuaWwFAAAAA1NFUAEAAAAUa2V5TGFzdFVzZXJMcEJhbGFuY2UAAAACAAAACWxwQXNzZXRJZAAAAAt1c2VyQWRkcmVzcwkABLkAAAACCQAETAAAAAICAAAABiVzJXMlcwkABEwAAAACBQAAAAlscEFzc2V0SWQJAARMAAAAAgUAAAALdXNlckFkZHJlc3MJAARMAAAAAgIAAAADYmFsBQAAAANuaWwFAAAAA1NFUAEAAAAZa2V5VG90YWxMcEJhbGFuY2VJbnRlZ3JhbAAAAAEAAAAJbHBBc3NldElkCQAEuQAAAAIJAARMAAAAAgIAAAAGJXMlcyVzCQAETAAAAAIFAAAACWxwQXNzZXRJZAkABEwAAAACAgAAAAV0b3RhbAkABEwAAAACAgAAAAZiYWxJTlQFAAAAA25pbAUAAAADU0VQAQAAABhrZXlVc2VyTHBCYWxhbmNlSW50ZWdyYWwAAAACAAAACWxwQXNzZXRJZAAAAAt1c2VyQWRkcmVzcwkABLkAAAACCQAETAAAAAICAAAABiVzJXMlcwkABEwAAAACBQAAAAlscEFzc2V0SWQJAARMAAAAAgUAAAALdXNlckFkZHJlc3MJAARMAAAAAgIAAAAGYmFsSU5UBQAAAANuaWwFAAAAA1NFUAEAAAAma2V5VG90YWxMcEJhbGFuY2VJbnRlZ3JhbExhc3RVcGRIZWlnaHQAAAABAAAACWxwQXNzZXRJZAkABLkAAAACCQAETAAAAAICAAAABiVzJXMlcwkABEwAAAACBQAAAAlscEFzc2V0SWQJAARMAAAAAgIAAAAFdG90YWwJAARMAAAAAgIAAAAHbGFzdFVwZAUAAAADbmlsBQAAAANTRVABAAAAJWtleVVzZXJMcEJhbGFuY2VJbnRlZ3JhbExhc3RVcGRIZWlnaHQAAAACAAAACWxwQXNzZXRJZAAAAAt1c2VyQWRkcmVzcwkABLkAAAACCQAETAAAAAICAAAABiVzJXMlcwkABEwAAAACBQAAAAlscEFzc2V0SWQJAARMAAAAAgUAAAALdXNlckFkZHJlc3MJAARMAAAAAgIAAAAHbGFzdFVwZAUAAAADbmlsBQAAAANTRVABAAAAEmtleVd4UGVyTHBJbnRlZ3JhbAAAAAEAAAAJbHBBc3NldElkCQAEuQAAAAIJAARMAAAAAgIAAAAIJXMlcyVzJXMJAARMAAAAAgUAAAAJbHBBc3NldElkCQAETAAAAAICAAAABmNvbW1vbgkABEwAAAACAgAAAAVscEludAUAAAADbmlsBQAAAANTRVABAAAAH2tleVd4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHQAAAABAAAACWxwQXNzZXRJZAkABLkAAAACCQAETAAAAAICAAAACCVzJXMlcyVzCQAETAAAAAIFAAAACWxwQXNzZXRJZAkABEwAAAACAgAAAAZjb21tb24JAARMAAAAAgIAAAAGbHBJbnRIBQAAAANuaWwFAAAAA1NFUAEAAAAQa2V5V3hUb0NsYWltVXNlcgAAAAIAAAAJbHBBc3NldElkAAAAC3VzZXJBZGRyZXNzCQAEuQAAAAIJAARMAAAAAgIAAAAIJXMlcyVzJXMJAARMAAAAAgUAAAAJbHBBc3NldElkCQAETAAAAAIFAAAAC3VzZXJBZGRyZXNzCQAETAAAAAICAAAABWxwSW50BQAAAANuaWwFAAAAA1NFUAEAAAAja2V5V3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHQAAAACAAAACWxwQXNzZXRJZAAAAAt1c2VyQWRkcmVzcwkABLkAAAACCQAETAAAAAICAAAACCVzJXMlcyVzCQAETAAAAAIFAAAACWxwQXNzZXRJZAkABEwAAAACBQAAAAt1c2VyQWRkcmVzcwkABEwAAAACAgAAAAZscEludEgFAAAAA25pbAUAAAADU0VQAQAAAAprZXlXeFBlckxwAAAAAQAAAAlscEFzc2V0SWQJAAS5AAAAAgkABEwAAAACAgAAAAIlcwkABEwAAAACBQAAAAlscEFzc2V0SWQJAARMAAAAAgIAAAAHd3hQZXJMcAUAAAADbmlsBQAAAANTRVABAAAADWtleVd4UGVyTHBYMTgAAAABAAAACWxwQXNzZXRJZAkABLkAAAACCQAETAAAAAICAAAAAiVzCQAETAAAAAIFAAAACWxwQXNzZXRJZAkABEwAAAACAgAAAAp3eFBlckxwWDE4BQAAAANuaWwFAAAAA1NFUAEAAAAaa2V5V3hQZXJMcEludGVncmFsVXNlckxhc3QAAAACAAAACWxwQXNzZXRJZAAAAAt1c2VyQWRkcmVzcwkABLkAAAACCQAETAAAAAICAAAACCVzJXMlcyVzCQAETAAAAAIFAAAACWxwQXNzZXRJZAkABEwAAAACBQAAAAt1c2VyQWRkcmVzcwkABEwAAAACAgAAAAV1SW50TAUAAAADbmlsBQAAAANTRVABAAAAGWtleU9wZXJhdGlvbkhpc3RvcnlSZWNvcmQAAAADAAAABHR5cGUAAAALdXNlckFkZHJlc3MAAAAGdHhJZDU4CQAEuQAAAAIJAARMAAAAAgIAAAARJXMlcyVzJXNfX2hpc3RvcnkJAARMAAAAAgUAAAAEdHlwZQkABEwAAAACBQAAAAt1c2VyQWRkcmVzcwkABEwAAAACBQAAAAZ0eElkNTgFAAAAA25pbAUAAAADU0VQAQAAABNmb3JtYXRIaXN0b3J5UmVjb3JkAAAABAAAAAt1c2VyQWRkcmVzcwAAAAlscEFzc2V0SWQAAAAEdHlwZQAAAAZhbW91bnQJAAS5AAAAAgkABEwAAAACAgAAAAwlcyVzJXMlZCVkJWQJAARMAAAAAgUAAAALdXNlckFkZHJlc3MJAARMAAAAAgUAAAAJbHBBc3NldElkCQAETAAAAAIFAAAABHR5cGUJAARMAAAAAgkAAaQAAAABBQAAAAZoZWlnaHQJAARMAAAAAgkAAaQAAAABCAUAAAAJbGFzdEJsb2NrAAAACXRpbWVzdGFtcAkABEwAAAACCQABpAAAAAEFAAAABmFtb3VudAUAAAADbmlsBQAAAANTRVABAAAAFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQAAAAUAAAAEdHlwZQAAAAt1c2VyQWRkcmVzcwAAAAlscEFzc2V0SWQAAAAGYW1vdW50AAAABHR4SWQJAQAAAAtTdHJpbmdFbnRyeQAAAAIJAQAAABlrZXlPcGVyYXRpb25IaXN0b3J5UmVjb3JkAAAAAwUAAAAEdHlwZQUAAAALdXNlckFkZHJlc3MJAAJYAAAAAQUAAAAEdHhJZAkBAAAAE2Zvcm1hdEhpc3RvcnlSZWNvcmQAAAAEBQAAAAt1c2VyQWRkcmVzcwUAAAAJbHBBc3NldElkBQAAAAR0eXBlBQAAAAZhbW91bnQAAAAADmZhY3RvcnlBZGRyZXNzCQEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAgUAAAAEdGhpcwkBAAAAEWtleUZhY3RvcnlBZGRyZXNzAAAAAAAAAAAPZmFjdG9yeUNvbnRyYWN0CQEAAAARQGV4dHJOYXRpdmUoMTA2MikAAAABBQAAAA5mYWN0b3J5QWRkcmVzcwAAAAAKZmFjdG9yeUNmZwkBAAAAFHJlYWRGYWN0b3J5Q2ZnT3JGYWlsAAAAAQUAAAAPZmFjdG9yeUNvbnRyYWN0AAAAABBlbWlzc2lvbkNvbnRyYWN0CQEAAAAYZ2V0RW1pc3Npb25BZGRyZXNzT3JGYWlsAAAAAQUAAAAKZmFjdG9yeUNmZwAAAAAQYm9vc3RpbmdDb250cmFjdAkBAAAAGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAAAAAEFAAAACmZhY3RvcnlDZmcBAAAAG2NhbGNXeFBlckxwSW50ZWdyYWxVc2VyTGFzdAAAAAQAAAAMc3Rha2VkQnlVc2VyAAAAJnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0T3JaZXJvAAAAEnd4UGVyTHBJbnRlZ3JhbE5ldwAAABp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQMDCQAAAAAAAAIFAAAAJnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0T3JaZXJvBQAAAAp6ZXJvQmlnSW50CQABPwAAAAIFAAAADHN0YWtlZEJ5VXNlcgUAAAAKemVyb0JpZ0ludAcFAAAACnplcm9CaWdJbnQDCQAAAAAAAAIFAAAADHN0YWtlZEJ5VXNlcgUAAAAKemVyb0JpZ0ludAUAAAASd3hQZXJMcEludGVncmFsTmV3AwMJAAE/AAAAAgUAAAAmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8FAAAACnplcm9CaWdJbnQJAAE/AAAAAgUAAAAMc3Rha2VkQnlVc2VyBQAAAAp6ZXJvQmlnSW50BwkBAAAABXZhbHVlAAAAAQkAAagAAAABCQEAAAAPZ2V0U3RyaW5nT3JGYWlsAAAAAgUAAAAEdGhpcwUAAAAad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJAAACAAAAAQIAAAAtY2FsY1d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0OiB1bmV4cGVjdGVkIHN0YXRlAQAAABRyZWZyZXNoUG9vbElOVEVHUkFMUwAAAAMAAAAMbHBBc3NldElkU3RyAAAADnBvb2xBZGRyZXNzU3RyAAAADWxwRGVsdGFBbW91bnQEAAAADnN0YWtlZFRvdGFsS0VZCQEAAAAOa2V5U3Rha2VkVG90YWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAAC3N0YWtlZFRvdGFsCQABNgAAAAEJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAOc3Rha2VkVG90YWxLRVkEAAAAEm5vblplcm9TdGFrZWRUb3RhbAMJAAAAAAAAAgUAAAALc3Rha2VkVG90YWwFAAAACnplcm9CaWdJbnQFAAAACW9uZUJpZ0ludAUAAAALc3Rha2VkVG90YWwEAAAACnBvb2xXZWlnaHQJAQAAABFAZXh0ck5hdGl2ZSgxMDUwKQAAAAIFAAAAD2ZhY3RvcnlDb250cmFjdAkBAAAAFGtleUZhY3RvcnlQb29sV2VpZ2h0AAAAAQUAAAAOcG9vbEFkZHJlc3NTdHIEAAAAEmVtaXNzaW9uU3RhcnRCbG9jawkBAAAADGdldEludE9yRmFpbAAAAAIFAAAAEGVtaXNzaW9uQ29udHJhY3QJAQAAABVrZXlFbWlzc2lvblN0YXJ0QmxvY2sAAAAABAAAAAVNVUxUMwAAAAAAAAAD6AQAAAAUd3hFbWlzc2lvblBlckJsb2NrWDMJAABoAAAAAgkBAAAADGdldEludE9yRmFpbAAAAAIFAAAAEGVtaXNzaW9uQ29udHJhY3QJAQAAAB5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQAAAAABQAAAAVNVUxUMwQAAAAYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQAAawAAAAMFAAAAFHd4RW1pc3Npb25QZXJCbG9ja1gzBQAAAApwb29sV2VpZ2h0CQAAaAAAAAIFAAAADlBPT0xXRUlHSFRNVUxUAAAAAAAAAAADBAAAABJ3eFBlckxwSW50ZWdyYWxLRVkJAQAAABJrZXlXeFBlckxwSW50ZWdyYWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAAH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkJAQAAAB9rZXlXeFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0AAAAAQUAAAAMbHBBc3NldElkU3RyBAAAAAp3eFBlckxwS0VZCQEAAAAKa2V5V3hQZXJMcAAAAAEFAAAADGxwQXNzZXRJZFN0cgQAAAAcd3hQZXJMcEludGVncmFsTGFzdFVwZEhlaWdodAkBAAAAD2dldEludE9yRGVmYXVsdAAAAAMFAAAABHRoaXMFAAAAH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkFAAAAEmVtaXNzaW9uU3RhcnRCbG9jawQAAAAPd3hQZXJMcEludGVncmFsCQEAAAAMZ2V0SW50T3JaZXJvAAAAAgUAAAAEdGhpcwUAAAASd3hQZXJMcEludGVncmFsS0VZBAAAAA93eFBlckxwT3JaZXJvWDMAAAAAAAAAAAAEAAAAAmRoCQABlgAAAAEJAARMAAAAAgkAAGUAAAACBQAAAAZoZWlnaHQFAAAAHHd4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHQJAARMAAAAAgAAAAAAAAAAAAUAAAADbmlsBAAAAAl3eFBlckxwWDMDCQEAAAACIT0AAAACBQAAAA93eFBlckxwT3JaZXJvWDMAAAAAAAAAAAAJAAE2AAAAAQUAAAAPd3hQZXJMcE9yWmVyb1gzCQABPAAAAAMJAAE2AAAAAQUAAAAYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQABNgAAAAEFAAAABU1VTFQ4BQAAABJub25aZXJvU3Rha2VkVG90YWwEAAAADnN0YWtlZFRvdGFsTmV3CQABNwAAAAIFAAAAC3N0YWtlZFRvdGFsCQABNgAAAAEFAAAADWxwRGVsdGFBbW91bnQEAAAAFW5vblplcm9TdGFrZWRUb3RhbE5ldwMJAAAAAAAAAgUAAAAOc3Rha2VkVG90YWxOZXcFAAAACnplcm9CaWdJbnQFAAAACW9uZUJpZ0ludAUAAAAOc3Rha2VkVG90YWxOZXcEAAAAEnd4UGVyTHBJbnRlZ3JhbE5ldwkAATcAAAACCQABNgAAAAEFAAAAD3d4UGVyTHBJbnRlZ3JhbAkAATkAAAACBQAAAAl3eFBlckxwWDMJAAE2AAAAAQUAAAACZGgEAAAADHd4UGVyTHBYM05ldwkAAToAAAACCQABNgAAAAEFAAAAGHBvb2xXeEVtaXNzaW9uUGVyQmxvY2tYMwUAAAAVbm9uWmVyb1N0YWtlZFRvdGFsTmV3BAAAAB93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0TmV3BQAAAAZoZWlnaHQEAAAABWRlYnVnCQAEuQAAAAIJAARMAAAAAgIAAAATd3hQZXJMcEludGVncmFsTmV3PQkABEwAAAACCQABpgAAAAEFAAAAEnd4UGVyTHBJbnRlZ3JhbE5ldwkABEwAAAACAgAAAANkaD0JAARMAAAAAgkAAaQAAAABBQAAAAJkaAkABEwAAAACAgAAAAp3eFBlckxwWDM9CQAETAAAAAIJAAGmAAAAAQUAAAAJd3hQZXJMcFgzCQAETAAAAAICAAAADHN0YWtlZFRvdGFsPQkABEwAAAACCQABpgAAAAEFAAAAC3N0YWtlZFRvdGFsCQAETAAAAAICAAAAGXBvb2xXeEVtaXNzaW9uUGVyQmxvY2tYMz0JAARMAAAAAgkAAaQAAAABBQAAABhwb29sV3hFbWlzc2lvblBlckJsb2NrWDMJAARMAAAAAgIAAAAVd3hFbWlzc2lvblBlckJsb2NrWDM9CQAETAAAAAIJAAGkAAAAAQUAAAAUd3hFbWlzc2lvblBlckJsb2NrWDMJAARMAAAAAgIAAAALcG9vbFdlaWdodD0JAARMAAAAAgkAAaQAAAABBQAAAApwb29sV2VpZ2h0BQAAAANuaWwCAAAAAjo6CQAFFQAAAAMFAAAAEnd4UGVyTHBJbnRlZ3JhbE5ldwkABEwAAAACCQEAAAALU3RyaW5nRW50cnkAAAACBQAAABJ3eFBlckxwSW50ZWdyYWxLRVkJAAGmAAAAAQUAAAASd3hQZXJMcEludGVncmFsTmV3CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAB93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0S0VZBQAAAB93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0TmV3CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAACnd4UGVyTHBLRVkJAAGmAAAAAQUAAAAMd3hQZXJMcFgzTmV3BQAAAANuaWwFAAAABWRlYnVnAQAAABByZWZyZXNoSU5URUdSQUxTAAAABAAAAAxscEFzc2V0SWRTdHIAAAAOdXNlckFkZHJlc3NTdHIAAAAOcG9vbEFkZHJlc3NTdHIAAAANbHBEZWx0YUFtb3VudAQAAAANJHQwMTExOTQxMTMxNgkBAAAAFHJlZnJlc2hQb29sSU5URUdSQUxTAAAAAwUAAAAMbHBBc3NldElkU3RyBQAAAA5wb29sQWRkcmVzc1N0cgUAAAANbHBEZWx0YUFtb3VudAQAAAASd3hQZXJMcEludGVncmFsTmV3CAUAAAANJHQwMTExOTQxMTMxNgAAAAJfMQQAAAARcG9vbEludGVncmFsU1RBVEUIBQAAAA0kdDAxMTE5NDExMzE2AAAAAl8yBAAAAAlwb29sREVCVUcIBQAAAA0kdDAxMTE5NDExMzE2AAAAAl8zBAAAAAVNVUxUMwAAAAAAAAAD6AQAAAAPc3Rha2VkQnlVc2VyS0VZCQEAAAAPa2V5U3Rha2VkQnlVc2VyAAAAAgUAAAAOdXNlckFkZHJlc3NTdHIFAAAADGxwQXNzZXRJZFN0cgQAAAAMc3Rha2VkQnlVc2VyCQEAAAAKcmVhZFN0YWtlZAAAAAEFAAAAD3N0YWtlZEJ5VXNlcktFWQQAAAAQd3hUb0NsYWltVXNlcktFWQkBAAAAEGtleVd4VG9DbGFpbVVzZXIAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAADnVzZXJBZGRyZXNzU3RyBAAAACN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodEtFWQkBAAAAI2tleVd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0AAAAAgUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgQAAAAad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJAQAAABprZXlXeFBlckxwSW50ZWdyYWxVc2VyTGFzdAAAAAIFAAAADGxwQXNzZXRJZFN0cgUAAAAOdXNlckFkZHJlc3NTdHIEAAAADXd4VG9DbGFpbVVzZXIJAQAAAAxnZXRJbnRPclplcm8AAAACBQAAAAR0aGlzBQAAABB3eFRvQ2xhaW1Vc2VyS0VZBAAAACZ3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE9yWmVybwkBAAAADGdldEludE9yWmVybwAAAAIFAAAABHRoaXMFAAAAI3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0S0VZBAAAABd3eFBlckxwSW50ZWdyYWxVc2VyTGFzdAkBAAAAG2NhbGNXeFBlckxwSW50ZWdyYWxVc2VyTGFzdAAAAAQJAAE2AAAAAQUAAAAMc3Rha2VkQnlVc2VyCQABNgAAAAEFAAAAJnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0T3JaZXJvBQAAABJ3eFBlckxwSW50ZWdyYWxOZXcFAAAAGnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0S0VZBAAAAAZNVUxUMTEJAABoAAAAAgUAAAAFTVVMVDgFAAAABU1VTFQzBAAAABB3eFRvQ2xhaW1Vc2VyTmV3CQABNwAAAAIJAAE2AAAAAQUAAAANd3hUb0NsYWltVXNlcgkAATwAAAADCQABOAAAAAIFAAAAEnd4UGVyTHBJbnRlZ3JhbE5ldwUAAAAXd3hQZXJMcEludGVncmFsVXNlckxhc3QJAAE2AAAAAQUAAAAMc3Rha2VkQnlVc2VyCQABNgAAAAEFAAAABk1VTFQxMQQAAAAad3hQZXJMcEludGVncmFsVXNlckxhc3ROZXcFAAAAEnd4UGVyTHBJbnRlZ3JhbE5ldwQAAAAjd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHROZXcFAAAABmhlaWdodAQAAAAFZGVidWcJAAS5AAAAAgkABEwAAAACAgAAABF3eFRvQ2xhaW1Vc2VyTmV3PQkABEwAAAACCQABpgAAAAEFAAAAEHd4VG9DbGFpbVVzZXJOZXcJAARMAAAAAgIAAAAYd3hQZXJMcEludGVncmFsVXNlckxhc3Q9CQAETAAAAAIJAAGmAAAAAQUAAAAXd3hQZXJMcEludGVncmFsVXNlckxhc3QJAARMAAAAAgIAAAANc3Rha2VkQnlVc2VyPQkABEwAAAACCQABpAAAAAEFAAAADHN0YWtlZEJ5VXNlcgkABEwAAAACAgAAAApwb29sREVCVUc9CQAETAAAAAIFAAAACXBvb2xERUJVRwkABEwAAAACAgAAAAdoZWlnaHQ9CQAETAAAAAIJAAGkAAAAAQUAAAAGaGVpZ2h0BQAAAANuaWwCAAAAAjo6CQAFFQAAAAMFAAAAEHd4VG9DbGFpbVVzZXJOZXcJAAROAAAAAgUAAAARcG9vbEludGVncmFsU1RBVEUJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAAQd3hUb0NsYWltVXNlcktFWQkAAaYAAAABBQAAABB3eFRvQ2xhaW1Vc2VyTmV3CQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAACN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodEtFWQUAAAAjd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHROZXcJAARMAAAAAgkBAAAAC1N0cmluZ0VudHJ5AAAAAgUAAAAad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJAAGmAAAAAQUAAAAad3hQZXJMcEludGVncmFsVXNlckxhc3ROZXcFAAAAA25pbAUAAAAFZGVidWcBAAAAFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAAAABAAAAAckbWF0Y2gwCQAEIgAAAAEJAQAAABNrZXlNYW5hZ2VyUHVibGljS2V5AAAAAAMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAAGU3RyaW5nBAAAAAFzBQAAAAckbWF0Y2gwCQACWQAAAAEFAAAAAXMDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQFAAAA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byBpdHNlbGYuCQAAAgAAAAECAAAAJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgAAAAFpAQAAAAVzdGFrZQAAAAADCQEAAAACIT0AAAACCQABkAAAAAEIBQAAAAFpAAAACHBheW1lbnRzAAAAAAAAAAABCQAAAgAAAAECAAAANGludmFsaWQgcGF5bWVudCAtIGV4YWN0IG9uZSBwYXltZW50IG11c3QgYmUgYXR0YWNoZWQEAAAAA3BtdAkAAZEAAAACCAUAAAABaQAAAAhwYXltZW50cwAAAAAAAAAAAAQAAAAJbHBBc3NldElkCQEAAAAFdmFsdWUAAAABCAUAAAADcG10AAAAB2Fzc2V0SWQEAAAADGxwQXNzZXRJZFN0cgkAAlgAAAABBQAAAAlscEFzc2V0SWQEAAAABmFtb3VudAgFAAAAA3BtdAAAAAZhbW91bnQEAAAADnBvb2xBZGRyZXNzU3RyCQEAAAATdmFsdWVPckVycm9yTWVzc2FnZQAAAAIJAAQdAAAAAgUAAAAPZmFjdG9yeUNvbnRyYWN0CQEAAAAaa2V5RmFjdG9yeUxwMkFzc2V0c01hcHBpbmcAAAABBQAAAAxscEFzc2V0SWRTdHIJAAEsAAAAAgIAAAAVdW5zdXBwb3J0ZWQgbHAgYXNzZXQgBQAAAAxscEFzc2V0SWRTdHIEAAAACWNhbGxlclN0cgkABCUAAAABCAUAAAABaQAAAAZjYWxsZXIEAAAADnVzZXJBZGRyZXNzU3RyAwkAAAAAAAACBQAAAAljYWxsZXJTdHIFAAAADnBvb2xBZGRyZXNzU3RyCQAEJQAAAAEIBQAAAAFpAAAADG9yaWdpbkNhbGxlcgUAAAAJY2FsbGVyU3RyBAAAAA9zdGFrZWRCeVVzZXJLRVkJAQAAAA9rZXlTdGFrZWRCeVVzZXIAAAACBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAMbHBBc3NldElkU3RyBAAAAA5zdGFrZWRUb3RhbEtFWQkBAAAADmtleVN0YWtlZFRvdGFsAAAAAQUAAAAMbHBBc3NldElkU3RyBAAAAAxzdGFrZWRCeVVzZXIJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAPc3Rha2VkQnlVc2VyS0VZBAAAAAtzdGFrZWRUb3RhbAkBAAAACnJlYWRTdGFrZWQAAAABBQAAAA5zdGFrZWRUb3RhbEtFWQQAAAANJHQwMTU0MTUxNTUzMgkBAAAAEHJlZnJlc2hJTlRFR1JBTFMAAAAEBQAAAAxscEFzc2V0SWRTdHIFAAAADnVzZXJBZGRyZXNzU3RyBQAAAA5wb29sQWRkcmVzc1N0cgUAAAAGYW1vdW50BAAAABB3eFRvQ2xhaW1Vc2VyTmV3CAUAAAANJHQwMTU0MTUxNTUzMgAAAAJfMQQAAAANaW50ZWdyYWxTVEFURQgFAAAADSR0MDE1NDE1MTU1MzIAAAACXzIEAAAABWRlYnVnCAUAAAANJHQwMTU0MTUxNTUzMgAAAAJfMwkABE4AAAACCQAETAAAAAIJAQAAAAxJbnRlZ2VyRW50cnkAAAACBQAAAA9zdGFrZWRCeVVzZXJLRVkJAABkAAAAAgUAAAAMc3Rha2VkQnlVc2VyBQAAAAZhbW91bnQJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAADnN0YWtlZFRvdGFsS0VZCQAAZAAAAAIFAAAAC3N0YWtlZFRvdGFsBQAAAAZhbW91bnQJAARMAAAAAgkBAAAAFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQAAAAUCAAAABXN0YWtlBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAMbHBBc3NldElkU3RyBQAAAAZhbW91bnQIBQAAAAFpAAAADXRyYW5zYWN0aW9uSWQFAAAAA25pbAUAAAANaW50ZWdyYWxTVEFURQAAAAFpAQAAAAd1bnN0YWtlAAAAAgAAAAxscEFzc2V0SWRTdHIAAAAGYW1vdW50BAAAAAlscEFzc2V0SWQJAAJZAAAAAQUAAAAMbHBBc3NldElkU3RyBAAAAA5wb29sQWRkcmVzc1N0cgkBAAAAE3ZhbHVlT3JFcnJvck1lc3NhZ2UAAAACCQAEHQAAAAIFAAAAD2ZhY3RvcnlDb250cmFjdAkBAAAAGmtleUZhY3RvcnlMcDJBc3NldHNNYXBwaW5nAAAAAQUAAAAMbHBBc3NldElkU3RyCQABLAAAAAICAAAAFXVuc3VwcG9ydGVkIGxwIGFzc2V0IAUAAAAMbHBBc3NldElkU3RyBAAAAAlwb29sQWRkb24JAQAAAAt2YWx1ZU9yRWxzZQAAAAIJAAQdAAAAAgUAAAAEdGhpcwkBAAAAFmtleVN0YWJsZVBvb2xBZGRvbkFkZHIAAAAABQAAAA5wb29sQWRkcmVzc1N0cgQAAAAJY2FsbGVyU3RyCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgQAAAAOdXNlckFkZHJlc3NTdHIDAwkAAAAAAAACBQAAAAljYWxsZXJTdHIFAAAADnBvb2xBZGRyZXNzU3RyBgkAAAAAAAACBQAAAAljYWxsZXJTdHIFAAAACXBvb2xBZGRvbgkABCUAAAABCAUAAAABaQAAAAxvcmlnaW5DYWxsZXIFAAAACWNhbGxlclN0cgQAAAAPc3Rha2VkQnlVc2VyS0VZCQEAAAAPa2V5U3Rha2VkQnlVc2VyAAAAAgUAAAAOdXNlckFkZHJlc3NTdHIFAAAADGxwQXNzZXRJZFN0cgQAAAAOc3Rha2VkVG90YWxLRVkJAQAAAA5rZXlTdGFrZWRUb3RhbAAAAAEFAAAADGxwQXNzZXRJZFN0cgQAAAAMc3Rha2VkQnlVc2VyCQEAAAAKcmVhZFN0YWtlZAAAAAEFAAAAD3N0YWtlZEJ5VXNlcktFWQQAAAALc3Rha2VkVG90YWwJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAOc3Rha2VkVG90YWxLRVkEAAAADSR0MDE2NjY5MTY3ODcJAQAAABByZWZyZXNoSU5URUdSQUxTAAAABAUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAOcG9vbEFkZHJlc3NTdHIJAQAAAAEtAAAAAQUAAAAGYW1vdW50BAAAABB3eFRvQ2xhaW1Vc2VyTmV3CAUAAAANJHQwMTY2NjkxNjc4NwAAAAJfMQQAAAANaW50ZWdyYWxTVEFURQgFAAAADSR0MDE2NjY5MTY3ODcAAAACXzIEAAAABWRlYnVnCAUAAAANJHQwMTY2NjkxNjc4NwAAAAJfMwMJAABmAAAAAgUAAAAGYW1vdW50BQAAAAxzdGFrZWRCeVVzZXIJAAACAAAAAQIAAAAkcGFzc2VkIGFtb3VudCBpcyBsZXNzIHRoZW4gYXZhaWxhYmxlCQAETgAAAAIJAARMAAAAAgkBAAAADEludGVnZXJFbnRyeQAAAAIFAAAAD3N0YWtlZEJ5VXNlcktFWQkAAGUAAAACBQAAAAxzdGFrZWRCeVVzZXIFAAAABmFtb3VudAkABEwAAAACCQEAAAAMSW50ZWdlckVudHJ5AAAAAgUAAAAOc3Rha2VkVG90YWxLRVkJAABlAAAAAgUAAAALc3Rha2VkVG90YWwFAAAABmFtb3VudAkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADCAUAAAABaQAAAAZjYWxsZXIFAAAABmFtb3VudAUAAAAJbHBBc3NldElkCQAETAAAAAIJAQAAABVPcGVyYXRpb25IaXN0b3J5RW50cnkAAAAFAgAAAAd1bnN0YWtlBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAMbHBBc3NldElkU3RyBQAAAAZhbW91bnQIBQAAAAFpAAAADXRyYW5zYWN0aW9uSWQFAAAAA25pbAUAAAANaW50ZWdyYWxTVEFURQAAAAFpAQAAAAdjbGFpbVd4AAAAAQAAAAxscEFzc2V0SWRTdHIEAAAAC3VzZXJBZGRyZXNzCAUAAAABaQAAAAZjYWxsZXIEAAAADnVzZXJBZGRyZXNzU3RyCQAEJQAAAAEIBQAAAAFpAAAABmNhbGxlcgQAAAAOcG9vbEFkZHJlc3NTdHIJAQAAABhnZXRTdHJpbmdCeUFkZHJlc3NPckZhaWwAAAACBQAAAA9mYWN0b3J5Q29udHJhY3QJAQAAACZrZXlGYWN0b3J5THBBc3NldFRvUG9vbENvbnRyYWN0QWRkcmVzcwAAAAEFAAAADGxwQXNzZXRJZFN0cgQAAAAQY2xhaW1lZEJ5VXNlcktFWQkBAAAAEGtleUNsYWltZWRCeVVzZXIAAAACBQAAAAxscEFzc2V0SWRTdHIFAAAADnVzZXJBZGRyZXNzU3RyBAAAAA9jbGFpbWVkVG90YWxLRVkJAQAAAA9rZXlDbGFpbWVkVG90YWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAAGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkJAQAAABlrZXlDbGFpbWVkQnlVc2VyTWluUmV3YXJkAAAAAgUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgQAAAAbY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkS0VZCQEAAAAba2V5Q2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkAAAAAgUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgQAAAANY2xhaW1lZEJ5VXNlcgkAATYAAAABCQEAAAAMZ2V0SW50T3JaZXJvAAAAAgUAAAAEdGhpcwUAAAAQY2xhaW1lZEJ5VXNlcktFWQQAAAAWY2xhaW1lZEJ5VXNlck1pblJld2FyZAkAATYAAAABCQEAAAAMZ2V0SW50T3JaZXJvAAAAAgUAAAAEdGhpcwUAAAAZY2xhaW1lZEJ5VXNlck1pblJld2FyZEtFWQQAAAAYY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkCQABNgAAAAEJAQAAAAxnZXRJbnRPclplcm8AAAACBQAAAAR0aGlzBQAAABtjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmRLRVkEAAAADGNsYWltZWRUb3RhbAkAATYAAAABCQEAAAAMZ2V0SW50T3JaZXJvAAAAAgUAAAAEdGhpcwUAAAAPY2xhaW1lZFRvdGFsS0VZBAAAAA0kdDAxODAyMzE4MTM1CQEAAAAQcmVmcmVzaElOVEVHUkFMUwAAAAQFAAAADGxwQXNzZXRJZFN0cgUAAAAOdXNlckFkZHJlc3NTdHIFAAAADnBvb2xBZGRyZXNzU3RyAAAAAAAAAAAABAAAABB3eFRvQ2xhaW1Vc2VyTmV3CAUAAAANJHQwMTgwMjMxODEzNQAAAAJfMQQAAAANaW50ZWdyYWxTVEFURQgFAAAADSR0MDE4MDIzMTgxMzUAAAACXzIEAAAABWRlYnVnCAUAAAANJHQwMTgwMjMxODEzNQAAAAJfMwQAAAAQYXZhaWxhYmxlVG9DbGFpbQkAATgAAAACBQAAABB3eFRvQ2xhaW1Vc2VyTmV3BQAAAA1jbGFpbWVkQnlVc2VyAwkAAUAAAAACBQAAAAp6ZXJvQmlnSW50BQAAABBhdmFpbGFibGVUb0NsYWltCQAAAgAAAAECAAAAEG5vdGhpbmcgdG8gY2xhaW0EAAAAEnd4QW1vdW50Qm9vc3RUb3RhbAkBAAAABWFzSW50AAAAAQkAAZEAAAACCQEAAAAJYXNBbnlMaXN0AAAAAQkAA/wAAAAEBQAAABBib29zdGluZ0NvbnRyYWN0AgAAAAxjbGFpbVd4Qm9vc3QJAARMAAAAAgUAAAAMbHBBc3NldElkU3RyCQAETAAAAAIFAAAADnVzZXJBZGRyZXNzU3RyBQAAAANuaWwFAAAAA25pbAAAAAAAAAAAAAQAAAANbWluUmV3YXJkUGFydAUAAAAQYXZhaWxhYmxlVG9DbGFpbQQAAAAPYm9vc3RSZXdhcmRQYXJ0CQABmQAAAAEJAARMAAAAAgkAATkAAAACBQAAAA1taW5SZXdhcmRQYXJ0CQABNgAAAAEAAAAAAAAAAAIJAARMAAAAAgkAATYAAAABBQAAABJ3eEFtb3VudEJvb3N0VG90YWwFAAAAA25pbAQAAAAJd3hBc3NldElkCQEAAAAMYXNCeXRlVmVjdG9yAAAAAQkAAZEAAAACCQEAAAAJYXNBbnlMaXN0AAAAAQkAA/wAAAAEBQAAABBlbWlzc2lvbkNvbnRyYWN0AgAAAARlbWl0CQAETAAAAAIFAAAADW1pblJld2FyZFBhcnQFAAAAA25pbAUAAAADbmlsAAAAAAAAAAAABAAAAAllbWl0Qm9vc3QJAQAAAAlhc0FueUxpc3QAAAABCQAD/AAAAAQFAAAAEGVtaXNzaW9uQ29udHJhY3QCAAAABGVtaXQJAARMAAAAAgUAAAAPYm9vc3RSZXdhcmRQYXJ0BQAAAANuaWwFAAAAA25pbAMJAAAAAAAAAgUAAAAJZW1pdEJvb3N0BQAAAAllbWl0Qm9vc3QEAAAAEmNsYWltZWRCeVVzZXJWYWx1ZQkAATcAAAACBQAAAA1jbGFpbWVkQnlVc2VyBQAAABBhdmFpbGFibGVUb0NsYWltBAAAAB5jbGFpbWVkQnlVc2VyTWluUmV3YXJkUGx1c1BhcnQJAAE3AAAAAgUAAAAWY2xhaW1lZEJ5VXNlck1pblJld2FyZAUAAAANbWluUmV3YXJkUGFydAQAAAArY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkUGx1c0Jvb3N0UmV3YXJkUGFydAkAATcAAAACBQAAABZjbGFpbWVkQnlVc2VyTWluUmV3YXJkBQAAAA1taW5SZXdhcmRQYXJ0BAAAACBjbGFpbWVkVG90YWxQbHVzQXZhaWxhYmxlVG9DbGFpbQkAATcAAAACBQAAABZjbGFpbWVkQnlVc2VyTWluUmV3YXJkBQAAAA1taW5SZXdhcmRQYXJ0CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAEGNsYWltZWRCeVVzZXJLRVkJAAGmAAAAAQUAAAASY2xhaW1lZEJ5VXNlclZhbHVlCQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkJAAGmAAAAAQUAAAAeY2xhaW1lZEJ5VXNlck1pblJld2FyZFBsdXNQYXJ0CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAG2NsYWltZWRCeVVzZXJCb29zdFJld2FyZEtFWQkAAaYAAAABBQAAACtjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmRQbHVzQm9vc3RSZXdhcmRQYXJ0CQAETAAAAAIJAQAAAAtTdHJpbmdFbnRyeQAAAAIFAAAAD2NsYWltZWRUb3RhbEtFWQkAAaYAAAABBQAAACBjbGFpbWVkVG90YWxQbHVzQXZhaWxhYmxlVG9DbGFpbQkABEwAAAACCQEAAAAOU2NyaXB0VHJhbnNmZXIAAAADBQAAAAt1c2VyQWRkcmVzcwkAAaAAAAABBQAAAA1taW5SZXdhcmRQYXJ0BQAAAAl3eEFzc2V0SWQJAARMAAAAAgkBAAAADlNjcmlwdFRyYW5zZmVyAAAAAwUAAAALdXNlckFkZHJlc3MJAAGgAAAAAQUAAAAPYm9vc3RSZXdhcmRQYXJ0BQAAAAl3eEFzc2V0SWQJAARMAAAAAgkBAAAAFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQAAAAUCAAAABWNsYWltBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAMbHBBc3NldElkU3RyCQABoAAAAAEFAAAAEGF2YWlsYWJsZVRvQ2xhaW0IBQAAAAFpAAAADXRyYW5zYWN0aW9uSWQFAAAAA25pbAkAAAIAAAABAgAAACRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4AAAABaQEAAAAPY2xhaW1XeFJFQURPTkxZAAAAAgAAAAxscEFzc2V0SWRTdHIAAAAOdXNlckFkZHJlc3NTdHIEAAAAD3N0YWtlZEJ5VXNlcktFWQkBAAAAD2tleVN0YWtlZEJ5VXNlcgAAAAIFAAAADnVzZXJBZGRyZXNzU3RyBQAAAAxscEFzc2V0SWRTdHIEAAAADnN0YWtlZFRvdGFsS0VZCQEAAAAOa2V5U3Rha2VkVG90YWwAAAABBQAAAAxscEFzc2V0SWRTdHIEAAAAEGNsYWltZWRCeVVzZXJLRVkJAQAAABBrZXlDbGFpbWVkQnlVc2VyAAAAAgUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgQAAAAMc3Rha2VkQnlVc2VyCQEAAAAKcmVhZFN0YWtlZAAAAAEFAAAAD3N0YWtlZEJ5VXNlcktFWQQAAAALc3Rha2VkVG90YWwJAQAAAApyZWFkU3Rha2VkAAAAAQUAAAAOc3Rha2VkVG90YWxLRVkEAAAADWNsYWltZWRCeVVzZXIJAQAAAAxnZXRJbnRPclplcm8AAAACBQAAAAR0aGlzBQAAABBjbGFpbWVkQnlVc2VyS0VZBAAAAA5wb29sQWRkcmVzc1N0cgkBAAAAGGdldFN0cmluZ0J5QWRkcmVzc09yRmFpbAAAAAIFAAAAD2ZhY3RvcnlDb250cmFjdAkBAAAAJmtleUZhY3RvcnlMcEFzc2V0VG9Qb29sQ29udHJhY3RBZGRyZXNzAAAAAQUAAAAMbHBBc3NldElkU3RyBAAAAApwb29sV2VpZ2h0CQEAAAARQGV4dHJOYXRpdmUoMTA1MCkAAAACBQAAAA9mYWN0b3J5Q29udHJhY3QJAQAAABRrZXlGYWN0b3J5UG9vbFdlaWdodAAAAAEFAAAADnBvb2xBZGRyZXNzU3RyBAAAABJ3eEVtaXNzaW9uUGVyQmxvY2sJAQAAAAxnZXRJbnRPckZhaWwAAAACBQAAABBlbWlzc2lvbkNvbnRyYWN0CQEAAAAea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAAAAAQAAAASZW1pc3Npb25TdGFydEJsb2NrCQEAAAAMZ2V0SW50T3JGYWlsAAAAAgUAAAAQZW1pc3Npb25Db250cmFjdAkBAAAAFWtleUVtaXNzaW9uU3RhcnRCbG9jawAAAAAEAAAADHBhc3NlZEJsb2NrcwMJAABmAAAAAgUAAAASZW1pc3Npb25TdGFydEJsb2NrBQAAAAZoZWlnaHQAAAAAAAAAAAAJAABlAAAAAgUAAAAGaGVpZ2h0BQAAABJlbWlzc2lvblN0YXJ0QmxvY2sEAAAADnBvb2xXeEVtaXNzaW9uCQAAawAAAAMJAABoAAAAAgUAAAASd3hFbWlzc2lvblBlckJsb2NrBQAAAAxwYXNzZWRCbG9ja3MFAAAACnBvb2xXZWlnaHQFAAAADlBPT0xXRUlHSFRNVUxUBAAAAAx1c2VyV3hSZXdhcmQJAABrAAAAAwUAAAAOcG9vbFd4RW1pc3Npb24FAAAADHN0YWtlZEJ5VXNlcgUAAAALc3Rha2VkVG90YWwEAAAADSR0MDIwNzIwMjA4MzIJAQAAABByZWZyZXNoSU5URUdSQUxTAAAABAUAAAAMbHBBc3NldElkU3RyBQAAAA51c2VyQWRkcmVzc1N0cgUAAAAOcG9vbEFkZHJlc3NTdHIAAAAAAAAAAAAEAAAAEHd4VG9DbGFpbVVzZXJOZXcIBQAAAA0kdDAyMDcyMDIwODMyAAAAAl8xBAAAAA1pbnRlZ3JhbFNUQVRFCAUAAAANJHQwMjA3MjAyMDgzMgAAAAJfMgQAAAAFZGVidWcIBQAAAA0kdDAyMDcyMDIwODMyAAAAAl8zBAAAABBhdmFpbGFibGVUb0NsYWltCQABOAAAAAIFAAAAEHd4VG9DbGFpbVVzZXJOZXcJAAE2AAAAAQUAAAANY2xhaW1lZEJ5VXNlcgQAAAAOYm9vc3RJbnZSZXN1bHQJAQAAAAlhc0FueUxpc3QAAAABCQAD/AAAAAQFAAAAEGJvb3N0aW5nQ29udHJhY3QCAAAAFGNsYWltV3hCb29zdFJFQURPTkxZCQAETAAAAAIFAAAADGxwQXNzZXRJZFN0cgkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgUAAAADbmlsBQAAAANuaWwEAAAAEnd4QW1vdW50Qm9vc3RUb3RhbAkBAAAABWFzSW50AAAAAQkAAZEAAAACBQAAAA5ib29zdEludlJlc3VsdAAAAAAAAAAAAAQAAAAKYm9vc3REZWJ1ZwkBAAAACGFzU3RyaW5nAAAAAQkAAZEAAAACBQAAAA5ib29zdEludlJlc3VsdAAAAAAAAAAAAQQAAAANbWluUmV3YXJkUGFydAUAAAAQYXZhaWxhYmxlVG9DbGFpbQQAAAAPYm9vc3RSZXdhcmRQYXJ0CQABmQAAAAEJAARMAAAAAgkAATkAAAACBQAAAA1taW5SZXdhcmRQYXJ0CQABNgAAAAEAAAAAAAAAAAIJAARMAAAAAgkAATYAAAABBQAAABJ3eEFtb3VudEJvb3N0VG90YWwFAAAAA25pbAQAAAALdG90YWxSZXdhcmQJAAE3AAAAAgUAAAANbWluUmV3YXJkUGFydAUAAAAPYm9vc3RSZXdhcmRQYXJ0CQAFFAAAAAIFAAAAA25pbAkABLkAAAACCQAETAAAAAICAAAADiVzJXMlZCVkJWQlZCVzCQAETAAAAAIFAAAADGxwQXNzZXRJZFN0cgkABEwAAAACBQAAAA51c2VyQWRkcmVzc1N0cgkABEwAAAACCQABpgAAAAEFAAAAC3RvdGFsUmV3YXJkCQAETAAAAAIJAAGkAAAAAQUAAAANY2xhaW1lZEJ5VXNlcgkABEwAAAACCQABpgAAAAEFAAAADW1pblJld2FyZFBhcnQJAARMAAAAAgkAAaYAAAABBQAAAA9ib29zdFJld2FyZFBhcnQJAARMAAAAAgkAASwAAAACCQABLAAAAAIJAAEsAAAAAgkAASwAAAACBQAAAAVkZWJ1ZwIAAAACOjoJAAGkAAAAAQUAAAAMdXNlcld4UmV3YXJkAgAAAA46OkJPT1NUREVCVUc6OgUAAAAKYm9vc3REZWJ1ZwUAAAADbmlsBQAAAANTRVAAAAABaQEAAAAOb25Nb2RpZnlXZWlnaHQAAAACAAAADGxwQXNzZXRJZFN0cgAAAA5wb29sQWRkcmVzc1N0cgMJAQAAAAIhPQAAAAIIBQAAAAFpAAAABmNhbGxlcgUAAAAPZmFjdG9yeUNvbnRyYWN0CQAAAgAAAAECAAAAEnBlcm1pc3Npb25zIGRlbmllZAQAAAANJHQwMjE3NDUyMTg1NQkBAAAAFHJlZnJlc2hQb29sSU5URUdSQUxTAAAAAwUAAAAMbHBBc3NldElkU3RyBQAAAA5wb29sQWRkcmVzc1N0cgAAAAAAAAAAAAQAAAASd3hQZXJMcEludGVncmFsTmV3CAUAAAANJHQwMjE3NDUyMTg1NQAAAAJfMQQAAAARcG9vbEludGVncmFsU1RBVEUIBQAAAA0kdDAyMTc0NTIxODU1AAAAAl8yBAAAAAlwb29sREVCVUcIBQAAAA0kdDAyMTc0NTIxODU1AAAAAl8zBQAAABFwb29sSW50ZWdyYWxTVEFURQAAAAEAAAACdHgBAAAABnZlcmlmeQAAAAAEAAAAD3RhcmdldFB1YmxpY0tleQQAAAAHJG1hdGNoMAkBAAAAFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAAAAAwkAAAEAAAACBQAAAAckbWF0Y2gwAgAAAApCeXRlVmVjdG9yBAAAAAJwawUAAAAHJG1hdGNoMAUAAAACcGsDCQAAAQAAAAIFAAAAByRtYXRjaDACAAAABFVuaXQIBQAAAAJ0eAAAAA9zZW5kZXJQdWJsaWNLZXkJAAACAAAAAQIAAAALTWF0Y2ggZXJyb3IJAAH0AAAAAwgFAAAAAnR4AAAACWJvZHlCeXRlcwkAAZEAAAACCAUAAAACdHgAAAAGcHJvb2ZzAAAAAAAAAAAABQAAAA90YXJnZXRQdWJsaWNLZXnKVxVe", "chainId": 84, "height": 2096239, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 3AKn7adiUhyer32L4ETErbBL1nodvwsVk8QGF4sKEg27 Next: HLNGxu9TLaerUEpJcQtmogbk9NNM9ti9MR3q4pH2aa2A 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 toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULT18, toBigInt(origScaleMult))
68+
69+
70+func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULT18))
71+
72+
73+func keyFactoryAddress () = "%s%s__config__factoryAddress"
74+
75+
76+let IdxFactoryCfgStakingDapp = 1
77+
78+let IdxFactoryCfgBoostingDapp = 2
79+
80+let IdxFactoryCfgIdoDapp = 3
81+
82+let IdxFactoryCfgTeamDapp = 4
83+
84+let IdxFactoryCfgEmissionDapp = 5
85+
86+let IdxFactoryCfgRestDapp = 6
87+
88+let IdxFactoryCfgSlippageDapp = 7
89+
90+func keyFactoryCfg () = "%s__factoryConfig"
5591
5692
5793 func keyManagerPublicKey () = "%s__managerPublicKey"
6096 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
6197
6298
63-let assetsStoreContract = addressFromStringValue(getStringOrFail(keyAssetsStoreContract))
99+func keyStablePoolAddonAddr () = "%s__stablePoolAddonAddr"
64100
65-let boostingContract = addressFromStringValue(getStringOrFail(keyBoostingContract))
66101
67-let emissionContract = addressFromStringValue(getStringOrFail(keyEmissionContract))
102+func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
68103
69-let factoryContract = addressFromStringValue(getStringOrFail(keyFactoryContract))
70104
71-let userPoolContract = addressFromStringValue(getStringOrFail(keyUserPoolContract))
105+func keyFactoryLpList () = "%s__lpTokensList"
72106
73-let votingEmissionContract = addressFromStringValue(getStringOrFail(keyVotingEmissionContract))
107+
108+func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
109+
110+
111+func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
112+
113+
114+func readLpList (factory) = split(valueOrElse(getString(factory, keyFactoryLpList()), ""), SEP)
115+
116+
117+func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP)
118+
119+
120+func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
121+
122+
123+func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
124+
125+
126+func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
127+
128+
129+func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
130+
131+
132+func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
133+
134+
135+func keyEmissionStartBlock () = "%s%s__emission__startBlock"
136+
137+
138+func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
139+
140+
141+func keyEmissionEndBlock () = "%s%s__emission__endBlock"
142+
143+
144+func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP)
145+
146+
147+func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr)
148+
149+
150+func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP)
151+
152+
153+func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP)
154+
155+
156+func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP)
157+
158+
159+func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed", "total", lpAssetIdStr], SEP)
160+
161+
162+func readStaked (key) = valueOrElse(getInteger(this, key), 0)
163+
164+
165+func keyLastTotalLpBalance (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "bal"], SEP)
166+
167+
168+func keyLastUserLpBalance (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "bal"], SEP)
169+
170+
171+func keyTotalLpBalanceIntegral (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "balINT"], SEP)
172+
173+
174+func keyUserLpBalanceIntegral (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "balINT"], SEP)
175+
176+
177+func keyTotalLpBalanceIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "lastUpd"], SEP)
178+
179+
180+func keyUserLpBalanceIntegralLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "lastUpd"], SEP)
181+
182+
183+func keyWxPerLpIntegral (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpInt"], SEP)
184+
185+
186+func keyWxPerLpIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpIntH"], SEP)
187+
188+
189+func keyWxToClaimUser (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpInt"], SEP)
190+
191+
192+func keyWxPerLpIntegralUserLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpIntH"], SEP)
193+
194+
195+func keyWxPerLp (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLp"], SEP)
196+
197+
198+func keyWxPerLpX18 (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLpX18"], SEP)
199+
200+
201+func keyWxPerLpIntegralUserLast (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "uIntL"], SEP)
202+
203+
204+func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP)
205+
206+
207+func formatHistoryRecord (userAddress,lpAssetId,type,amount) = makeString(["%s%s%s%d%d%d", userAddress, lpAssetId, type, toString(height), toString(lastBlock.timestamp), toString(amount)], SEP)
208+
209+
210+func OperationHistoryEntry (type,userAddress,lpAssetId,amount,txId) = StringEntry(keyOperationHistoryRecord(type, userAddress, toBase58String(txId)), formatHistoryRecord(userAddress, lpAssetId, type, amount))
211+
212+
213+let factoryAddress = getStringOrFail(this, keyFactoryAddress())
214+
215+let factoryContract = addressFromStringValue(factoryAddress)
216+
217+let factoryCfg = readFactoryCfgOrFail(factoryContract)
218+
219+let emissionContract = getEmissionAddressOrFail(factoryCfg)
220+
221+let boostingContract = getBoostingAddressOrFail(factoryCfg)
222+
223+func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
224+ then (stakedByUser > zeroBigInt)
225+ else false)
226+ then zeroBigInt
227+ else if ((stakedByUser == zeroBigInt))
228+ then wxPerLpIntegralNew
229+ else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > zeroBigInt))
230+ then (stakedByUser > zeroBigInt)
231+ else false)
232+ then value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))
233+ else throw("calcWxPerLpIntegralUserLast: unexpected state")
234+
235+
236+func refreshPoolINTEGRALS (lpAssetIdStr,poolAddressStr,lpDeltaAmount) = {
237+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
238+ let stakedTotal = toBigInt(readStaked(stakedTotalKEY))
239+ let nonZeroStakedTotal = if ((stakedTotal == zeroBigInt))
240+ then oneBigInt
241+ else stakedTotal
242+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
243+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
244+ let MULT3 = 1000
245+ let wxEmissionPerBlockX3 = (getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent()) * MULT3)
246+ let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3))
247+ let wxPerLpIntegralKEY = keyWxPerLpIntegral(lpAssetIdStr)
248+ let wxPerLpIntegralLastUpdHeightKEY = keyWxPerLpIntegralLastUpdHeight(lpAssetIdStr)
249+ let wxPerLpKEY = keyWxPerLp(lpAssetIdStr)
250+ let wxPerLpIntegralLastUpdHeight = getIntOrDefault(this, wxPerLpIntegralLastUpdHeightKEY, emissionStartBlock)
251+ let wxPerLpIntegral = getIntOrZero(this, wxPerLpIntegralKEY)
252+ let wxPerLpOrZeroX3 = 0
253+ let dh = max([(height - wxPerLpIntegralLastUpdHeight), 0])
254+ let wxPerLpX3 = if ((wxPerLpOrZeroX3 != 0))
255+ then toBigInt(wxPerLpOrZeroX3)
256+ else fraction(toBigInt(poolWxEmissionPerBlockX3), toBigInt(MULT8), nonZeroStakedTotal)
257+ let stakedTotalNew = (stakedTotal + toBigInt(lpDeltaAmount))
258+ let nonZeroStakedTotalNew = if ((stakedTotalNew == zeroBigInt))
259+ then oneBigInt
260+ else stakedTotalNew
261+ let wxPerLpIntegralNew = (toBigInt(wxPerLpIntegral) + (wxPerLpX3 * toBigInt(dh)))
262+ let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
263+ let wxPerLpIntegralLastUpdHeightNew = height
264+ let debug = makeString(["wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), "poolWxEmissionPerBlockX3=", toString(poolWxEmissionPerBlockX3), "wxEmissionPerBlockX3=", toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
265+ $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
266+ }
267+
268+
269+func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
270+ let $t01119411316 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
271+ let wxPerLpIntegralNew = $t01119411316._1
272+ let poolIntegralSTATE = $t01119411316._2
273+ let poolDEBUG = $t01119411316._3
274+ let MULT3 = 1000
275+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
276+ let stakedByUser = readStaked(stakedByUserKEY)
277+ let wxToClaimUserKEY = keyWxToClaimUser(lpAssetIdStr, userAddressStr)
278+ let wxPerLpIntegralUserLastUpdHeightKEY = keyWxPerLpIntegralUserLastUpdHeight(lpAssetIdStr, userAddressStr)
279+ let wxPerLpIntegralUserLastKEY = keyWxPerLpIntegralUserLast(lpAssetIdStr, userAddressStr)
280+ let wxToClaimUser = getIntOrZero(this, wxToClaimUserKEY)
281+ let wxPerLpIntegralUserLastUpdHeightOrZero = getIntOrZero(this, wxPerLpIntegralUserLastUpdHeightKEY)
282+ let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(toBigInt(stakedByUser), toBigInt(wxPerLpIntegralUserLastUpdHeightOrZero), wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
283+ let MULT11 = (MULT8 * MULT3)
284+ let wxToClaimUserNew = (toBigInt(wxToClaimUser) + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11)))
285+ let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
286+ let wxPerLpIntegralUserLastUpdHeightNew = height
287+ let debug = makeString(["wxToClaimUserNew=", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast=", toString(wxPerLpIntegralUserLast), "stakedByUser=", toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
288+ $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
289+ }
290+
74291
75292 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
76293 case s: String =>
93310
94311
95312 func mustManager (i) = {
96- let pd = throw("permission denied")
313+ let pd = throw("Permission denied")
97314 match managerPublicKeyOrUnit() {
98315 case pk: ByteVector =>
99316 if ((i.callerPublicKey == pk))
109326 }
110327
111328
112-func asInt (val) = match val {
113- case valInt: Int =>
114- valInt
115- case _ =>
116- throw("failed to cast into Integer")
117-}
118-
119-
120329 @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 {
343- let votingEmissionInv = invoke(votingEmissionContract, "create", [amountAssetId, priceAssetId], nil)
344- if ((votingEmissionInv == votingEmissionInv))
345- then $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
346- else throw("Strict value is not equal to itself.")
347- }
348- else throw("Strict value is not equal to itself.")
349- }
350- else $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
351- actions
352- }
330+func constructor (factoryAddressStr) = {
331+ let checkCaller = mustManager(i)
332+ if ((checkCaller == checkCaller))
333+ then [StringEntry(keyFactoryAddress(), factoryAddressStr)]
353334 else throw("Strict value is not equal to itself.")
354335 }
355336
375356 let pm = pendingManagerPublicKeyOrUnit()
376357 let hasPM = if (isDefined(pm))
377358 then true
378- else throw("no pending manager")
359+ else throw("No pending manager")
379360 if ((hasPM == hasPM))
380361 then {
381362 let checkPM = if ((i.callerPublicKey == value(pm)))
382363 then true
383- else throw("you are not pending manager")
364+ else throw("You are not pending manager")
384365 if ((checkPM == checkPM))
385366 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
386367 else throw("Strict value is not equal to itself.")
387368 }
388369 else throw("Strict value is not equal to itself.")
389370 }
371+
372+
373+
374+@Callable(i)
375+func stake () = if ((size(i.payments) != 1))
376+ then throw("invalid payment - exact one payment must be attached")
377+ else {
378+ let pmt = i.payments[0]
379+ let lpAssetId = value(pmt.assetId)
380+ let lpAssetIdStr = toBase58String(lpAssetId)
381+ let amount = pmt.amount
382+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
383+ let callerStr = toString(i.caller)
384+ let userAddressStr = if ((callerStr == poolAddressStr))
385+ then toString(i.originCaller)
386+ else callerStr
387+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
388+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
389+ let stakedByUser = readStaked(stakedByUserKEY)
390+ let stakedTotal = readStaked(stakedTotalKEY)
391+ let $t01541515532 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
392+ let wxToClaimUserNew = $t01541515532._1
393+ let integralSTATE = $t01541515532._2
394+ let debug = $t01541515532._3
395+ ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
396+ }
397+
398+
399+
400+@Callable(i)
401+func unstake (lpAssetIdStr,amount) = {
402+ let lpAssetId = fromBase58String(lpAssetIdStr)
403+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
404+ let poolAddon = valueOrElse(getString(this, keyStablePoolAddonAddr()), poolAddressStr)
405+ let callerStr = toString(i.caller)
406+ let userAddressStr = if (if ((callerStr == poolAddressStr))
407+ then true
408+ else (callerStr == poolAddon))
409+ then toString(i.originCaller)
410+ else callerStr
411+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
412+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
413+ let stakedByUser = readStaked(stakedByUserKEY)
414+ let stakedTotal = readStaked(stakedTotalKEY)
415+ let $t01666916787 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
416+ let wxToClaimUserNew = $t01666916787._1
417+ let integralSTATE = $t01666916787._2
418+ let debug = $t01666916787._3
419+ if ((amount > stakedByUser))
420+ then throw("passed amount is less then available")
421+ else ([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
422+ }
423+
424+
425+
426+@Callable(i)
427+func claimWx (lpAssetIdStr) = {
428+ let userAddress = i.caller
429+ let userAddressStr = toString(i.caller)
430+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
431+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
432+ let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
433+ let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
434+ let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
435+ let claimedByUser = toBigInt(getIntOrZero(this, claimedByUserKEY))
436+ let claimedByUserMinReward = toBigInt(getIntOrZero(this, claimedByUserMinRewardKEY))
437+ let claimedByUserBoostReward = toBigInt(getIntOrZero(this, claimedByUserBoostRewardKEY))
438+ let claimedTotal = toBigInt(getIntOrZero(this, claimedTotalKEY))
439+ let $t01802318135 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
440+ let wxToClaimUserNew = $t01802318135._1
441+ let integralSTATE = $t01802318135._2
442+ let debug = $t01802318135._3
443+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
444+ if ((zeroBigInt >= availableToClaim))
445+ then throw("nothing to claim")
446+ else {
447+ let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0])
448+ let minRewardPart = availableToClaim
449+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
450+ let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [minRewardPart], nil))[0])
451+ let emitBoost = asAnyList(invoke(emissionContract, "emit", [boostRewardPart], nil))
452+ if ((emitBoost == emitBoost))
453+ then {
454+ let claimedByUserValue = (claimedByUser + availableToClaim)
455+ let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
456+ let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
457+ let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
458+[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)]
459+ }
460+ else throw("Strict value is not equal to itself.")
461+ }
462+ }
463+
464+
465+
466+@Callable(i)
467+func claimWxREADONLY (lpAssetIdStr,userAddressStr) = {
468+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
469+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
470+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
471+ let stakedByUser = readStaked(stakedByUserKEY)
472+ let stakedTotal = readStaked(stakedTotalKEY)
473+ let claimedByUser = getIntOrZero(this, claimedByUserKEY)
474+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
475+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
476+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
477+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
478+ let passedBlocks = if ((emissionStartBlock > height))
479+ then 0
480+ else (height - emissionStartBlock)
481+ let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
482+ let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
483+ let $t02072020832 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
484+ let wxToClaimUserNew = $t02072020832._1
485+ let integralSTATE = $t02072020832._2
486+ let debug = $t02072020832._3
487+ let availableToClaim = (wxToClaimUserNew - toBigInt(claimedByUser))
488+ let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
489+ let wxAmountBoostTotal = asInt(boostInvResult[0])
490+ let boostDebug = asString(boostInvResult[1])
491+ let minRewardPart = availableToClaim
492+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
493+ let totalReward = (minRewardPart + boostRewardPart)
494+ $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))
495+ }
496+
497+
498+
499+@Callable(i)
500+func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
501+ then throw("permissions denied")
502+ else {
503+ let $t02174521855 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
504+ let wxPerLpIntegralNew = $t02174521855._1
505+ let poolIntegralSTATE = $t02174521855._2
506+ let poolDEBUG = $t02174521855._3
507+ poolIntegralSTATE
508+ }
390509
391510
392511 @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 toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULT18, toBigInt(origScaleMult))
68+
69+
70+func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULT18))
71+
72+
73+func keyFactoryAddress () = "%s%s__config__factoryAddress"
74+
75+
76+let IdxFactoryCfgStakingDapp = 1
77+
78+let IdxFactoryCfgBoostingDapp = 2
79+
80+let IdxFactoryCfgIdoDapp = 3
81+
82+let IdxFactoryCfgTeamDapp = 4
83+
84+let IdxFactoryCfgEmissionDapp = 5
85+
86+let IdxFactoryCfgRestDapp = 6
87+
88+let IdxFactoryCfgSlippageDapp = 7
89+
90+func keyFactoryCfg () = "%s__factoryConfig"
5591
5692
5793 func keyManagerPublicKey () = "%s__managerPublicKey"
5894
5995
6096 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
6197
6298
63-let assetsStoreContract = addressFromStringValue(getStringOrFail(keyAssetsStoreContract))
99+func keyStablePoolAddonAddr () = "%s__stablePoolAddonAddr"
64100
65-let boostingContract = addressFromStringValue(getStringOrFail(keyBoostingContract))
66101
67-let emissionContract = addressFromStringValue(getStringOrFail(keyEmissionContract))
102+func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
68103
69-let factoryContract = addressFromStringValue(getStringOrFail(keyFactoryContract))
70104
71-let userPoolContract = addressFromStringValue(getStringOrFail(keyUserPoolContract))
105+func keyFactoryLpList () = "%s__lpTokensList"
72106
73-let votingEmissionContract = addressFromStringValue(getStringOrFail(keyVotingEmissionContract))
107+
108+func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
109+
110+
111+func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
112+
113+
114+func readLpList (factory) = split(valueOrElse(getString(factory, keyFactoryLpList()), ""), SEP)
115+
116+
117+func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP)
118+
119+
120+func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
121+
122+
123+func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
124+
125+
126+func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
127+
128+
129+func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
130+
131+
132+func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
133+
134+
135+func keyEmissionStartBlock () = "%s%s__emission__startBlock"
136+
137+
138+func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
139+
140+
141+func keyEmissionEndBlock () = "%s%s__emission__endBlock"
142+
143+
144+func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP)
145+
146+
147+func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr)
148+
149+
150+func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP)
151+
152+
153+func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP)
154+
155+
156+func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP)
157+
158+
159+func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed", "total", lpAssetIdStr], SEP)
160+
161+
162+func readStaked (key) = valueOrElse(getInteger(this, key), 0)
163+
164+
165+func keyLastTotalLpBalance (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "bal"], SEP)
166+
167+
168+func keyLastUserLpBalance (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "bal"], SEP)
169+
170+
171+func keyTotalLpBalanceIntegral (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "balINT"], SEP)
172+
173+
174+func keyUserLpBalanceIntegral (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "balINT"], SEP)
175+
176+
177+func keyTotalLpBalanceIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "lastUpd"], SEP)
178+
179+
180+func keyUserLpBalanceIntegralLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "lastUpd"], SEP)
181+
182+
183+func keyWxPerLpIntegral (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpInt"], SEP)
184+
185+
186+func keyWxPerLpIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpIntH"], SEP)
187+
188+
189+func keyWxToClaimUser (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpInt"], SEP)
190+
191+
192+func keyWxPerLpIntegralUserLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpIntH"], SEP)
193+
194+
195+func keyWxPerLp (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLp"], SEP)
196+
197+
198+func keyWxPerLpX18 (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLpX18"], SEP)
199+
200+
201+func keyWxPerLpIntegralUserLast (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "uIntL"], SEP)
202+
203+
204+func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP)
205+
206+
207+func formatHistoryRecord (userAddress,lpAssetId,type,amount) = makeString(["%s%s%s%d%d%d", userAddress, lpAssetId, type, toString(height), toString(lastBlock.timestamp), toString(amount)], SEP)
208+
209+
210+func OperationHistoryEntry (type,userAddress,lpAssetId,amount,txId) = StringEntry(keyOperationHistoryRecord(type, userAddress, toBase58String(txId)), formatHistoryRecord(userAddress, lpAssetId, type, amount))
211+
212+
213+let factoryAddress = getStringOrFail(this, keyFactoryAddress())
214+
215+let factoryContract = addressFromStringValue(factoryAddress)
216+
217+let factoryCfg = readFactoryCfgOrFail(factoryContract)
218+
219+let emissionContract = getEmissionAddressOrFail(factoryCfg)
220+
221+let boostingContract = getBoostingAddressOrFail(factoryCfg)
222+
223+func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
224+ then (stakedByUser > zeroBigInt)
225+ else false)
226+ then zeroBigInt
227+ else if ((stakedByUser == zeroBigInt))
228+ then wxPerLpIntegralNew
229+ else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > zeroBigInt))
230+ then (stakedByUser > zeroBigInt)
231+ else false)
232+ then value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))
233+ else throw("calcWxPerLpIntegralUserLast: unexpected state")
234+
235+
236+func refreshPoolINTEGRALS (lpAssetIdStr,poolAddressStr,lpDeltaAmount) = {
237+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
238+ let stakedTotal = toBigInt(readStaked(stakedTotalKEY))
239+ let nonZeroStakedTotal = if ((stakedTotal == zeroBigInt))
240+ then oneBigInt
241+ else stakedTotal
242+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
243+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
244+ let MULT3 = 1000
245+ let wxEmissionPerBlockX3 = (getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent()) * MULT3)
246+ let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3))
247+ let wxPerLpIntegralKEY = keyWxPerLpIntegral(lpAssetIdStr)
248+ let wxPerLpIntegralLastUpdHeightKEY = keyWxPerLpIntegralLastUpdHeight(lpAssetIdStr)
249+ let wxPerLpKEY = keyWxPerLp(lpAssetIdStr)
250+ let wxPerLpIntegralLastUpdHeight = getIntOrDefault(this, wxPerLpIntegralLastUpdHeightKEY, emissionStartBlock)
251+ let wxPerLpIntegral = getIntOrZero(this, wxPerLpIntegralKEY)
252+ let wxPerLpOrZeroX3 = 0
253+ let dh = max([(height - wxPerLpIntegralLastUpdHeight), 0])
254+ let wxPerLpX3 = if ((wxPerLpOrZeroX3 != 0))
255+ then toBigInt(wxPerLpOrZeroX3)
256+ else fraction(toBigInt(poolWxEmissionPerBlockX3), toBigInt(MULT8), nonZeroStakedTotal)
257+ let stakedTotalNew = (stakedTotal + toBigInt(lpDeltaAmount))
258+ let nonZeroStakedTotalNew = if ((stakedTotalNew == zeroBigInt))
259+ then oneBigInt
260+ else stakedTotalNew
261+ let wxPerLpIntegralNew = (toBigInt(wxPerLpIntegral) + (wxPerLpX3 * toBigInt(dh)))
262+ let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
263+ let wxPerLpIntegralLastUpdHeightNew = height
264+ let debug = makeString(["wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), "poolWxEmissionPerBlockX3=", toString(poolWxEmissionPerBlockX3), "wxEmissionPerBlockX3=", toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
265+ $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
266+ }
267+
268+
269+func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
270+ let $t01119411316 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
271+ let wxPerLpIntegralNew = $t01119411316._1
272+ let poolIntegralSTATE = $t01119411316._2
273+ let poolDEBUG = $t01119411316._3
274+ let MULT3 = 1000
275+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
276+ let stakedByUser = readStaked(stakedByUserKEY)
277+ let wxToClaimUserKEY = keyWxToClaimUser(lpAssetIdStr, userAddressStr)
278+ let wxPerLpIntegralUserLastUpdHeightKEY = keyWxPerLpIntegralUserLastUpdHeight(lpAssetIdStr, userAddressStr)
279+ let wxPerLpIntegralUserLastKEY = keyWxPerLpIntegralUserLast(lpAssetIdStr, userAddressStr)
280+ let wxToClaimUser = getIntOrZero(this, wxToClaimUserKEY)
281+ let wxPerLpIntegralUserLastUpdHeightOrZero = getIntOrZero(this, wxPerLpIntegralUserLastUpdHeightKEY)
282+ let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(toBigInt(stakedByUser), toBigInt(wxPerLpIntegralUserLastUpdHeightOrZero), wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
283+ let MULT11 = (MULT8 * MULT3)
284+ let wxToClaimUserNew = (toBigInt(wxToClaimUser) + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11)))
285+ let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
286+ let wxPerLpIntegralUserLastUpdHeightNew = height
287+ let debug = makeString(["wxToClaimUserNew=", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast=", toString(wxPerLpIntegralUserLast), "stakedByUser=", toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
288+ $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
289+ }
290+
74291
75292 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
76293 case s: String =>
77294 fromBase58String(s)
78295 case _: Unit =>
79296 unit
80297 case _ =>
81298 throw("Match error")
82299 }
83300
84301
85302 func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) {
86303 case s: String =>
87304 fromBase58String(s)
88305 case _: Unit =>
89306 unit
90307 case _ =>
91308 throw("Match error")
92309 }
93310
94311
95312 func mustManager (i) = {
96- let pd = throw("permission denied")
313+ let pd = throw("Permission denied")
97314 match managerPublicKeyOrUnit() {
98315 case pk: ByteVector =>
99316 if ((i.callerPublicKey == pk))
100317 then true
101318 else pd
102319 case _: Unit =>
103320 if ((i.caller == this))
104321 then true
105322 else pd
106323 case _ =>
107324 throw("Match error")
108325 }
109326 }
110327
111328
112-func asInt (val) = match val {
113- case valInt: Int =>
114- valInt
115- case _ =>
116- throw("failed to cast into Integer")
117-}
118-
119-
120329 @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 {
343- let votingEmissionInv = invoke(votingEmissionContract, "create", [amountAssetId, priceAssetId], nil)
344- if ((votingEmissionInv == votingEmissionInv))
345- then $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
346- else throw("Strict value is not equal to itself.")
347- }
348- else throw("Strict value is not equal to itself.")
349- }
350- else $Tuple2([DeleteEntry(keyInListAssetId(amountAssetId, priceAssetId))], unit)
351- actions
352- }
330+func constructor (factoryAddressStr) = {
331+ let checkCaller = mustManager(i)
332+ if ((checkCaller == checkCaller))
333+ then [StringEntry(keyFactoryAddress(), factoryAddressStr)]
353334 else throw("Strict value is not equal to itself.")
354335 }
355336
356337
357338
358339 @Callable(i)
359340 func setManager (pendingManagerPublicKey) = {
360341 let checkCaller = mustManager(i)
361342 if ((checkCaller == checkCaller))
362343 then {
363344 let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey)
364345 if ((checkManagerPublicKey == checkManagerPublicKey))
365346 then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)]
366347 else throw("Strict value is not equal to itself.")
367348 }
368349 else throw("Strict value is not equal to itself.")
369350 }
370351
371352
372353
373354 @Callable(i)
374355 func confirmManager () = {
375356 let pm = pendingManagerPublicKeyOrUnit()
376357 let hasPM = if (isDefined(pm))
377358 then true
378- else throw("no pending manager")
359+ else throw("No pending manager")
379360 if ((hasPM == hasPM))
380361 then {
381362 let checkPM = if ((i.callerPublicKey == value(pm)))
382363 then true
383- else throw("you are not pending manager")
364+ else throw("You are not pending manager")
384365 if ((checkPM == checkPM))
385366 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
386367 else throw("Strict value is not equal to itself.")
387368 }
388369 else throw("Strict value is not equal to itself.")
389370 }
371+
372+
373+
374+@Callable(i)
375+func stake () = if ((size(i.payments) != 1))
376+ then throw("invalid payment - exact one payment must be attached")
377+ else {
378+ let pmt = i.payments[0]
379+ let lpAssetId = value(pmt.assetId)
380+ let lpAssetIdStr = toBase58String(lpAssetId)
381+ let amount = pmt.amount
382+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
383+ let callerStr = toString(i.caller)
384+ let userAddressStr = if ((callerStr == poolAddressStr))
385+ then toString(i.originCaller)
386+ else callerStr
387+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
388+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
389+ let stakedByUser = readStaked(stakedByUserKEY)
390+ let stakedTotal = readStaked(stakedTotalKEY)
391+ let $t01541515532 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
392+ let wxToClaimUserNew = $t01541515532._1
393+ let integralSTATE = $t01541515532._2
394+ let debug = $t01541515532._3
395+ ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
396+ }
397+
398+
399+
400+@Callable(i)
401+func unstake (lpAssetIdStr,amount) = {
402+ let lpAssetId = fromBase58String(lpAssetIdStr)
403+ let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
404+ let poolAddon = valueOrElse(getString(this, keyStablePoolAddonAddr()), poolAddressStr)
405+ let callerStr = toString(i.caller)
406+ let userAddressStr = if (if ((callerStr == poolAddressStr))
407+ then true
408+ else (callerStr == poolAddon))
409+ then toString(i.originCaller)
410+ else callerStr
411+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
412+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
413+ let stakedByUser = readStaked(stakedByUserKEY)
414+ let stakedTotal = readStaked(stakedTotalKEY)
415+ let $t01666916787 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
416+ let wxToClaimUserNew = $t01666916787._1
417+ let integralSTATE = $t01666916787._2
418+ let debug = $t01666916787._3
419+ if ((amount > stakedByUser))
420+ then throw("passed amount is less then available")
421+ else ([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
422+ }
423+
424+
425+
426+@Callable(i)
427+func claimWx (lpAssetIdStr) = {
428+ let userAddress = i.caller
429+ let userAddressStr = toString(i.caller)
430+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
431+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
432+ let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
433+ let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
434+ let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
435+ let claimedByUser = toBigInt(getIntOrZero(this, claimedByUserKEY))
436+ let claimedByUserMinReward = toBigInt(getIntOrZero(this, claimedByUserMinRewardKEY))
437+ let claimedByUserBoostReward = toBigInt(getIntOrZero(this, claimedByUserBoostRewardKEY))
438+ let claimedTotal = toBigInt(getIntOrZero(this, claimedTotalKEY))
439+ let $t01802318135 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
440+ let wxToClaimUserNew = $t01802318135._1
441+ let integralSTATE = $t01802318135._2
442+ let debug = $t01802318135._3
443+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
444+ if ((zeroBigInt >= availableToClaim))
445+ then throw("nothing to claim")
446+ else {
447+ let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0])
448+ let minRewardPart = availableToClaim
449+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
450+ let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [minRewardPart], nil))[0])
451+ let emitBoost = asAnyList(invoke(emissionContract, "emit", [boostRewardPart], nil))
452+ if ((emitBoost == emitBoost))
453+ then {
454+ let claimedByUserValue = (claimedByUser + availableToClaim)
455+ let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
456+ let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
457+ let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
458+[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)]
459+ }
460+ else throw("Strict value is not equal to itself.")
461+ }
462+ }
463+
464+
465+
466+@Callable(i)
467+func claimWxREADONLY (lpAssetIdStr,userAddressStr) = {
468+ let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
469+ let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
470+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
471+ let stakedByUser = readStaked(stakedByUserKEY)
472+ let stakedTotal = readStaked(stakedTotalKEY)
473+ let claimedByUser = getIntOrZero(this, claimedByUserKEY)
474+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
475+ let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
476+ let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
477+ let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
478+ let passedBlocks = if ((emissionStartBlock > height))
479+ then 0
480+ else (height - emissionStartBlock)
481+ let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
482+ let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
483+ let $t02072020832 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
484+ let wxToClaimUserNew = $t02072020832._1
485+ let integralSTATE = $t02072020832._2
486+ let debug = $t02072020832._3
487+ let availableToClaim = (wxToClaimUserNew - toBigInt(claimedByUser))
488+ let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
489+ let wxAmountBoostTotal = asInt(boostInvResult[0])
490+ let boostDebug = asString(boostInvResult[1])
491+ let minRewardPart = availableToClaim
492+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
493+ let totalReward = (minRewardPart + boostRewardPart)
494+ $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))
495+ }
496+
497+
498+
499+@Callable(i)
500+func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
501+ then throw("permissions denied")
502+ else {
503+ let $t02174521855 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
504+ let wxPerLpIntegralNew = $t02174521855._1
505+ let poolIntegralSTATE = $t02174521855._2
506+ let poolDEBUG = $t02174521855._3
507+ poolIntegralSTATE
508+ }
390509
391510
392511 @Verifier(tx)
393512 func verify () = {
394513 let targetPublicKey = match managerPublicKeyOrUnit() {
395514 case pk: ByteVector =>
396515 pk
397516 case _: Unit =>
398517 tx.senderPublicKey
399518 case _ =>
400519 throw("Match error")
401520 }
402521 sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
403522 }
404523

github/deemru/w8io/873ac7e 
86.33 ms