tx · 4ja9B4yvtWjQSx7fWucT3m5KYMRU4g5Mj9ffigvmEpAc

3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz:  -0.02900000 Waves

2022.06.29 14:50 [2117692] smart account 3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz > SELF 0.00000000 Waves

{ "type": 13, "id": "4ja9B4yvtWjQSx7fWucT3m5KYMRU4g5Mj9ffigvmEpAc", "fee": 2900000, "feeAssetId": null, "timestamp": 1656503532908, "version": 1, "sender": "3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz", "senderPublicKey": "D28XoueZWsMfm8Y5pa6C5ZFuYoWgre2Wm8tzJANJgMnq", "proofs": [ "t46KRagzEZUXFVPKMC71HaL4DB5s9coApZ2ML8qUKsMt6MdCRAXAtUmdSo8iPViQ3vBR1f8UQHG8r97JHwgSTN9" ], "script": "base64:BgI3CAISAwoBCBIDCgEIEgMKAQgSABIAEgQKAggBEgMKAQgSBAoCCAgSBAoCCAgSAwoBCBIECgIICF8ABlNDQUxFOAAIAAVNVUxUOACAwtcvAAdTQ0FMRTE4ABIABk1VTFQxOAkAtgIBAICAkLu61q3wDQADU0VQAgJfXwAOUE9PTFdFSUdIVE1VTFQFBU1VTFQ4AAp6ZXJvQmlnSW50CQC2AgEAAAAJb25lQmlnSW50CQC2AgEAAQEJYXNBbnlMaXN0AQN2YWwEByRtYXRjaDAFA3ZhbAMJAAECBQckbWF0Y2gwAglMaXN0W0FueV0ECnZhbEFueUx5c3QFByRtYXRjaDAFCnZhbEFueUx5c3QJAAIBAhtmYWlsIHRvIGNhc3QgaW50byBMaXN0W0FueV0BBWFzSW50AQN2YWwEByRtYXRjaDAFA3ZhbAMJAAECBQckbWF0Y2gwAgNJbnQEBnZhbEludAUHJG1hdGNoMAUGdmFsSW50CQACAQIVZmFpbCB0byBjYXN0IGludG8gSW50AQhhc1N0cmluZwEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAZ2YWxTdHIFByRtYXRjaDAFBnZhbFN0cgkAAgECFWZhaWwgdG8gY2FzdCBpbnRvIEludAEMYXNCeXRlVmVjdG9yAQN2YWwEByRtYXRjaDAFA3ZhbAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAZ2YWxCaW4FByRtYXRjaDAFBnZhbEJpbgkAAgECFWZhaWwgdG8gY2FzdCBpbnRvIEludAEPZ2V0U3RyaW5nT3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFB2FkZHJlc3MFA2tleQkArAICCQCsAgICD21hbmRhdG9yeSB0aGlzLgUDa2V5Ag8gaXMgbm90IGRlZmluZWQBGGdldFN0cmluZ0J5QWRkcmVzc09yRmFpbAIHYWRkcmVzcwNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQdhZGRyZXNzBQNrZXkJAKwCAgkArAICCQCsAgIJAKwCAgIKbWFuZGF0b3J5IAkApQgBBQdhZGRyZXNzAgEuBQNrZXkCDyBpcyBub3QgZGVmaW5lZAEMZ2V0SW50T3JaZXJvAgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQdhZGRyZXNzBQNrZXkAAAEPZ2V0SW50T3JEZWZhdWx0AwdhZGRyZXNzA2tleQpkZWZhdWx0VmFsCQELdmFsdWVPckVsc2UCCQCaCAIFB2FkZHJlc3MFA2tleQUKZGVmYXVsdFZhbAEMZ2V0SW50T3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFB2FkZHJlc3MFA2tleQkArAICCQCsAgICD21hbmRhdG9yeSB0aGlzLgUDa2V5Ag8gaXMgbm90IGRlZmluZWQBGWdldEJpZ0ludEZyb21TdHJpbmdPclplcm8CB2FkZHJlc3MDa2V5CQEFdmFsdWUBCQCoAwEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUHYWRkcmVzcwUDa2V5AgEwARxnZXRCaWdJbnRGcm9tU3RyaW5nT3JEZWZhdWx0AwdhZGRyZXNzA2tleQpkZWZhdWx0VmFsBAckbWF0Y2gwCQCdCAIFB2FkZHJlc3MFA2tleQMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJAQV2YWx1ZQEJAKgDAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQpkZWZhdWx0VmFsCQACAQILTWF0Y2ggZXJyb3IBBXRvWDE4AgdvcmlnVmFsDW9yaWdTY2FsZU11bHQJALwCAwkAtgIBBQdvcmlnVmFsBQZNVUxUMTgJALYCAQUNb3JpZ1NjYWxlTXVsdAEHZnJvbVgxOAIDdmFsD3Jlc3VsdFNjYWxlTXVsdAkAoAMBCQC8AgMFA3ZhbAkAtgIBBQ9yZXN1bHRTY2FsZU11bHQFBk1VTFQxOAERa2V5RmFjdG9yeUFkZHJlc3MAAhwlcyVzX19jb25maWdfX2ZhY3RvcnlBZGRyZXNzARlrZXlWb3RpbmdFbWlzc2lvbkNvbnRyYWN0AAIaJXNfX3ZvdGluZ0VtaXNzaW9uQ29udHJhY3QAGElkeEZhY3RvcnlDZmdTdGFraW5nRGFwcAABABlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwAAIAFElkeEZhY3RvcnlDZmdJZG9EYXBwAAMAFUlkeEZhY3RvcnlDZmdUZWFtRGFwcAAEABlJZHhGYWN0b3J5Q2ZnRW1pc3Npb25EYXBwAAUAFUlkeEZhY3RvcnlDZmdSZXN0RGFwcAAGABlJZHhGYWN0b3J5Q2ZnU2xpcHBhZ2VEYXBwAAcBDWtleUZhY3RvcnlDZmcAAhElc19fZmFjdG9yeUNvbmZpZwETa2V5TWFuYWdlclB1YmxpY0tleQACFCVzX19tYW5hZ2VyUHVibGljS2V5ARRrZXlNaWdyYXRvclB1YmxpY0tleQACFSVzX19taWdyYXRvclB1YmxpY0tleQEaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkAAhslc19fcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkBFmtleVN0YWJsZVBvb2xBZGRvbkFkZHIAAhclc19fc3RhYmxlUG9vbEFkZG9uQWRkcgEaa2V5RmFjdG9yeUxwMkFzc2V0c01hcHBpbmcBCmxwQXNzZXRTdHIJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgUKbHBBc3NldFN0cgkAzAgCAh5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFA25pbAUDU0VQARBrZXlGYWN0b3J5THBMaXN0AAIQJXNfX2xwVG9rZW5zTGlzdAEma2V5RmFjdG9yeUxwQXNzZXRUb1Bvb2xDb250cmFjdEFkZHJlc3MBCmxwQXNzZXRTdHIJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgUKbHBBc3NldFN0cgkAzAgCAh5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFA25pbAUDU0VQARRrZXlGYWN0b3J5UG9vbFdlaWdodAEPY29udHJhY3RBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgpwb29sV2VpZ2h0CQDMCAIFD2NvbnRyYWN0QWRkcmVzcwUDbmlsBQNTRVABCnJlYWRMcExpc3QBB2ZhY3RvcnkJALUJAgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQdmYWN0b3J5CQEQa2V5RmFjdG9yeUxwTGlzdAACAAUDU0VQARRyZWFkRmFjdG9yeUNmZ09yRmFpbAEHZmFjdG9yeQkAtQkCCQEYZ2V0U3RyaW5nQnlBZGRyZXNzT3JGYWlsAgUHZmFjdG9yeQkBDWtleUZhY3RvcnlDZmcABQNTRVABGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAEKZmFjdG9yeUNmZwkBEUBleHRyTmF0aXZlKDEwNjIpAQkAkQMCBQpmYWN0b3J5Q2ZnBRlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwARhnZXRFbWlzc2lvbkFkZHJlc3NPckZhaWwBCmZhY3RvcnlDZmcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUKZmFjdG9yeUNmZwUZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAEXZ2V0U3Rha2luZ0FkZHJlc3NPckZhaWwBCmZhY3RvcnlDZmcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUKZmFjdG9yeUNmZwUYSWR4RmFjdG9yeUNmZ1N0YWtpbmdEYXBwAR5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQAAhslcyVzX19yYXRlUGVyQmxvY2tfX2N1cnJlbnQBIWtleUVtaXNzaW9uUmF0ZVBlckJsb2NrTWF4Q3VycmVudAACHiVzJXNfX3JhdGVQZXJCbG9ja01heF9fY3VycmVudAEVa2V5RW1pc3Npb25TdGFydEJsb2NrAAIaJXMlc19fZW1pc3Npb25fX3N0YXJ0QmxvY2sBG2tleUVtaXNzaW9uRHVyYXRpb25JbkJsb2NrcwACGCVzJXNfX2VtaXNzaW9uX19kdXJhdGlvbgETa2V5RW1pc3Npb25FbmRCbG9jawACGCVzJXNfX2VtaXNzaW9uX19lbmRCbG9jawEPa2V5U3Rha2VkQnlVc2VyAg51c2VyQWRkcmVzc1N0cgxscEFzc2V0SWRTdHIJALkJAgkAzAgCAg4lcyVzJXNfX3N0YWtlZAkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCBQxscEFzc2V0SWRTdHIFA25pbAUDU0VQAQ5rZXlTdGFrZWRUb3RhbAEMbHBBc3NldElkU3RyCQCsAgICFyVzJXMlc19fc3Rha2VkX190b3RhbF9fBQxscEFzc2V0SWRTdHIBEGtleUNsYWltZWRCeVVzZXICDGxwQXNzZXRJZFN0cg51c2VyQWRkcmVzc1N0cgkAuQkCCQDMCAICDyVzJXMlc19fY2xhaW1lZAkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCBQxscEFzc2V0SWRTdHIFA25pbAUDU0VQARlrZXlDbGFpbWVkQnlVc2VyTWluUmV3YXJkAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIJALkJAgkAzAgCAhglcyVzJXNfX2NsYWltZWRNaW5SZXdhcmQJAMwIAgUOdXNlckFkZHJlc3NTdHIJAMwIAgUMbHBBc3NldElkU3RyBQNuaWwFA1NFUAEba2V5Q2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIJALkJAgkAzAgCAholcyVzJXNfX2NsYWltZWRCb29zdFJld2FyZAkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCBQxscEFzc2V0SWRTdHIFA25pbAUDU0VQAQ9rZXlDbGFpbWVkVG90YWwBDGxwQXNzZXRJZFN0cgkAuQkCCQDMCAICFiVzJXMlc19fY2xhaW1lZF9fdG90YWwJAMwIAgUMbHBBc3NldElkU3RyBQNuaWwFA1NFUAEKcmVhZFN0YWtlZAEDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFA2tleQAAARVrZXlMYXN0VG90YWxMcEJhbGFuY2UBCWxwQXNzZXRJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgIFdG90YWwJAMwIAgIDYmFsBQNuaWwFA1NFUAEUa2V5TGFzdFVzZXJMcEJhbGFuY2UCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIDYmFsBQNuaWwFA1NFUAEZa2V5VG90YWxMcEJhbGFuY2VJbnRlZ3JhbAEJbHBBc3NldElkCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAgV0b3RhbAkAzAgCAgZiYWxJTlQFA25pbAUDU0VQARhrZXlVc2VyTHBCYWxhbmNlSW50ZWdyYWwCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIGYmFsSU5UBQNuaWwFA1NFUAEma2V5VG90YWxMcEJhbGFuY2VJbnRlZ3JhbExhc3RVcGRIZWlnaHQBCWxwQXNzZXRJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgIFdG90YWwJAMwIAgIHbGFzdFVwZAUDbmlsBQNTRVABJWtleVVzZXJMcEJhbGFuY2VJbnRlZ3JhbExhc3RVcGRIZWlnaHQCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIHbGFzdFVwZAUDbmlsBQNTRVABEmtleVd4UGVyTHBJbnRlZ3JhbAEJbHBBc3NldElkCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgUJbHBBc3NldElkCQDMCAICBmNvbW1vbgkAzAgCAgVscEludAUDbmlsBQNTRVABH2tleVd4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHQBCWxwQXNzZXRJZAkAuQkCCQDMCAICCCVzJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAgZjb21tb24JAMwIAgIGbHBJbnRIBQNuaWwFA1NFUAEQa2V5V3hUb0NsYWltVXNlcgIJbHBBc3NldElkC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgUJbHBBc3NldElkCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAICBWxwSW50BQNuaWwFA1NFUAEja2V5V3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHQCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICCCVzJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCAgZscEludEgFA25pbAUDU0VQAQprZXlXeFBlckxwAQlscEFzc2V0SWQJALkJAgkAzAgCAgIlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgIHd3hQZXJMcAUDbmlsBQNTRVABDWtleVd4UGVyTHBYMTgBCWxwQXNzZXRJZAkAuQkCCQDMCAICAiVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAgp3eFBlckxwWDE4BQNuaWwFA1NFUAEaa2V5V3hQZXJMcEludGVncmFsVXNlckxhc3QCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICCCVzJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCAgV1SW50TAUDbmlsBQNTRVABGWtleU9wZXJhdGlvbkhpc3RvcnlSZWNvcmQDBHR5cGULdXNlckFkZHJlc3MGdHhJZDU4CQC5CQIJAMwIAgIRJXMlcyVzJXNfX2hpc3RvcnkJAMwIAgUEdHlwZQkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCBQZ0eElkNTgFA25pbAUDU0VQARNmb3JtYXRIaXN0b3J5UmVjb3JkBAt1c2VyQWRkcmVzcwlscEFzc2V0SWQEdHlwZQZhbW91bnQJALkJAgkAzAgCAgwlcyVzJXMlZCVkJWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgUJbHBBc3NldElkCQDMCAIFBHR5cGUJAMwIAgkApAMBBQZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCkAwEFBmFtb3VudAUDbmlsBQNTRVABFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQUEdHlwZQt1c2VyQWRkcmVzcwlscEFzc2V0SWQGYW1vdW50BHR4SWQJAQtTdHJpbmdFbnRyeQIJARlrZXlPcGVyYXRpb25IaXN0b3J5UmVjb3JkAwUEdHlwZQULdXNlckFkZHJlc3MJANgEAQUEdHhJZAkBE2Zvcm1hdEhpc3RvcnlSZWNvcmQEBQt1c2VyQWRkcmVzcwUJbHBBc3NldElkBQR0eXBlBQZhbW91bnQADmZhY3RvcnlBZGRyZXNzCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBEWtleUZhY3RvcnlBZGRyZXNzAAAPZmFjdG9yeUNvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBBQ5mYWN0b3J5QWRkcmVzcwAKZmFjdG9yeUNmZwkBFHJlYWRGYWN0b3J5Q2ZnT3JGYWlsAQUPZmFjdG9yeUNvbnRyYWN0ABBlbWlzc2lvbkNvbnRyYWN0CQEYZ2V0RW1pc3Npb25BZGRyZXNzT3JGYWlsAQUKZmFjdG9yeUNmZwAQYm9vc3RpbmdDb250cmFjdAkBGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAEFCmZhY3RvcnlDZmcBC2tleU5leHRVc2VyAQlscEFzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAghuZXh0VXNlcgUDbmlsBQNTRVABEGdldFVzZXJzTGlzdE5hbWUBCWxwQXNzZXRJZAkAuQkCCQDMCAICBXVzZXJzCQDMCAIFCWxwQXNzZXRJZAUDbmlsBQNTRVABC2tleUxpc3RIZWFkAQhsaXN0TmFtZQkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQhsaXN0TmFtZQkAzAgCAgRoZWFkBQNuaWwFA1NFUAELa2V5TGlzdFNpemUBCGxpc3ROYW1lCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAIFCGxpc3ROYW1lCQDMCAICBHNpemUFA25pbAUDU0VQAQtrZXlMaXN0UHJldgIIbGlzdE5hbWUCaWQJALkJAgkAzAgCAgglcyVzJXMlcwkAzAgCBQhsaXN0TmFtZQkAzAgCBQJpZAkAzAgCAgRwcmV2BQNuaWwFA1NFUAELa2V5TGlzdE5leHQCCGxpc3ROYW1lAmlkCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgUIbGlzdE5hbWUJAMwIAgUCaWQJAMwIAgIEbmV4dAUDbmlsBQNTRVABDGNvbnRhaW5zTm9kZQIIbGlzdE5hbWUCaWQECmhlYWRPclVuaXQJAJ0IAgUEdGhpcwkBC2tleUxpc3RIZWFkAQUIbGlzdE5hbWUECnByZXZPclVuaXQJAJ0IAgUEdGhpcwkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUFAmlkBApuZXh0T3JVbml0CQCdCAIFBHRoaXMJAQtrZXlMaXN0TmV4dAIFCGxpc3ROYW1lBQJpZAMDCQAAAgUCaWQJAQt2YWx1ZU9yRWxzZQIFCmhlYWRPclVuaXQCAAYJAQIhPQIFCnByZXZPclVuaXQFBHVuaXQGCQECIT0CBQpuZXh0T3JVbml0BQR1bml0ARFpbnNlcnROb2RlQWN0aW9ucwIIbGlzdE5hbWUCaWQECmhlYWRPclVuaXQJAJ0IAgUEdGhpcwkBC2tleUxpc3RIZWFkAQUIbGlzdE5hbWUECGxpc3RTaXplCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQtrZXlMaXN0U2l6ZQEFCGxpc3ROYW1lAAAECWNoZWNrTm9kZQMJAQEhAQkBDGNvbnRhaW5zTm9kZQIFCGxpc3ROYW1lBQJpZAYJAAIBAgtOb2RlIGV4aXN0cwMJAAACBQljaGVja05vZGUFCWNoZWNrTm9kZQkAzggCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJAQtrZXlMaXN0U2l6ZQEFCGxpc3ROYW1lCQBkAgUIbGlzdFNpemUAAQUDbmlsAwkBAiE9AgUKaGVhZE9yVW5pdAUEdW5pdAkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TGlzdE5leHQCBQhsaXN0TmFtZQUCaWQJAQV2YWx1ZQEFCmhlYWRPclVuaXQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCmhlYWRPclVuaXQFAmlkBQNuaWwFA25pbAkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TGlzdEhlYWQBBQhsaXN0TmFtZQUCaWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgERZGVsZXRlTm9kZUFjdGlvbnMCCGxpc3ROYW1lAmlkBApoZWFkT3JVbml0CQCdCAIFBHRoaXMJAQtrZXlMaXN0SGVhZAEFCGxpc3ROYW1lBAhsaXN0U2l6ZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQELa2V5TGlzdFNpemUBBQhsaXN0TmFtZQAABApwcmV2T3JVbml0CQCdCAIFBHRoaXMJAQtrZXlMaXN0UHJldgIFCGxpc3ROYW1lBQJpZAQKbmV4dE9yVW5pdAkAnQgCBQR0aGlzCQELa2V5TGlzdE5leHQCBQhsaXN0TmFtZQUCaWQJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBC2tleUxpc3RTaXplAQUIbGlzdE5hbWUJAGUCBQhsaXN0U2l6ZQABBQNuaWwDAwkBAiE9AgUKcHJldk9yVW5pdAUEdW5pdAkBAiE9AgUKbmV4dE9yVW5pdAUEdW5pdAcJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleUxpc3ROZXh0AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCnByZXZPclVuaXQJAQV2YWx1ZQEFCm5leHRPclVuaXQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCm5leHRPclVuaXQJAQV2YWx1ZQEFCnByZXZPclVuaXQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUFAmlkCQDMCAIJAQtEZWxldGVFbnRyeQEJAQtrZXlMaXN0TmV4dAIFCGxpc3ROYW1lBQJpZAUDbmlsAwkBAiE9AgUKbmV4dE9yVW5pdAUEdW5pdAkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TGlzdEhlYWQBBQhsaXN0TmFtZQkBBXZhbHVlAQUKbmV4dE9yVW5pdAkAzAgCCQELRGVsZXRlRW50cnkBCQELa2V5TGlzdE5leHQCBQhsaXN0TmFtZQUCaWQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCm5leHRPclVuaXQFA25pbAMJAQIhPQIFCnByZXZPclVuaXQFBHVuaXQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUFAmlkCQDMCAIJAQtEZWxldGVFbnRyeQEJAQtrZXlMaXN0TmV4dAIFCGxpc3ROYW1lCQEFdmFsdWUBBQpwcmV2T3JVbml0BQNuaWwDCQAAAgUCaWQJAQt2YWx1ZU9yRWxzZQIFCmhlYWRPclVuaXQCAAkAzAgCCQELRGVsZXRlRW50cnkBCQELa2V5TGlzdEhlYWQBBQhsaXN0TmFtZQUDbmlsCQACAQkArAICCQCsAgIJAKwCAgIOaW52YWxpZCBub2RlOiAFCGxpc3ROYW1lAgEuBQJpZAEbY2FsY1d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0BAxzdGFrZWRCeVVzZXImd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8Sd3hQZXJMcEludGVncmFsTmV3Gnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0S0VZAwMJAAACBSZ3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE9yWmVybwUKemVyb0JpZ0ludAkAvwICBQxzdGFrZWRCeVVzZXIFCnplcm9CaWdJbnQHBQp6ZXJvQmlnSW50AwkAAAIFDHN0YWtlZEJ5VXNlcgUKemVyb0JpZ0ludAUSd3hQZXJMcEludGVncmFsTmV3AwMJAL8CAgUmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8FCnplcm9CaWdJbnQJAL8CAgUMc3Rha2VkQnlVc2VyBQp6ZXJvQmlnSW50BwkBBXZhbHVlAQkAqAMBCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwUad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJAAIBAi1jYWxjV3hQZXJMcEludGVncmFsVXNlckxhc3Q6IHVuZXhwZWN0ZWQgc3RhdGUBFHJlZnJlc2hQb29sSU5URUdSQUxTAwxscEFzc2V0SWRTdHIOcG9vbEFkZHJlc3NTdHINbHBEZWx0YUFtb3VudAQOc3Rha2VkVG90YWxLRVkJAQ5rZXlTdGFrZWRUb3RhbAEFDGxwQXNzZXRJZFN0cgQLc3Rha2VkVG90YWwJALYCAQkBCnJlYWRTdGFrZWQBBQ5zdGFrZWRUb3RhbEtFWQQSbm9uWmVyb1N0YWtlZFRvdGFsAwkAAAIFC3N0YWtlZFRvdGFsBQp6ZXJvQmlnSW50BQlvbmVCaWdJbnQFC3N0YWtlZFRvdGFsBApwb29sV2VpZ2h0CQERQGV4dHJOYXRpdmUoMTA1MCkCBQ9mYWN0b3J5Q29udHJhY3QJARRrZXlGYWN0b3J5UG9vbFdlaWdodAEFDnBvb2xBZGRyZXNzU3RyBBJlbWlzc2lvblN0YXJ0QmxvY2sJAQxnZXRJbnRPckZhaWwCBRBlbWlzc2lvbkNvbnRyYWN0CQEVa2V5RW1pc3Npb25TdGFydEJsb2NrAAQFTVVMVDMA6AcEFHd4RW1pc3Npb25QZXJCbG9ja1gzCQBoAgkBDGdldEludE9yRmFpbAIFEGVtaXNzaW9uQ29udHJhY3QJAR5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQABQVNVUxUMwQYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQBrAwUUd3hFbWlzc2lvblBlckJsb2NrWDMFCnBvb2xXZWlnaHQJAGgCBQ5QT09MV0VJR0hUTVVMVAADBBJ3eFBlckxwSW50ZWdyYWxLRVkJARJrZXlXeFBlckxwSW50ZWdyYWwBBQxscEFzc2V0SWRTdHIEH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkJAR9rZXlXeFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0AQUMbHBBc3NldElkU3RyBAp3eFBlckxwS0VZCQEKa2V5V3hQZXJMcAEFDGxwQXNzZXRJZFN0cgQcd3hQZXJMcEludGVncmFsTGFzdFVwZEhlaWdodAkBD2dldEludE9yRGVmYXVsdAMFBHRoaXMFH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkFEmVtaXNzaW9uU3RhcnRCbG9jawQPd3hQZXJMcEludGVncmFsCQEZZ2V0QmlnSW50RnJvbVN0cmluZ09yWmVybwIFBHRoaXMFEnd4UGVyTHBJbnRlZ3JhbEtFWQQPd3hQZXJMcE9yWmVyb1gzAAAEAmRoCQCWAwEJAMwIAgkAZQIFBmhlaWdodAUcd3hQZXJMcEludGVncmFsTGFzdFVwZEhlaWdodAkAzAgCAAAFA25pbAQJd3hQZXJMcFgzAwkBAiE9AgUPd3hQZXJMcE9yWmVyb1gzAAAJALYCAQUPd3hQZXJMcE9yWmVyb1gzCQC8AgMJALYCAQUYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQC2AgEFBU1VTFQ4BRJub25aZXJvU3Rha2VkVG90YWwEDnN0YWtlZFRvdGFsTmV3CQC3AgIFC3N0YWtlZFRvdGFsCQC2AgEFDWxwRGVsdGFBbW91bnQEFW5vblplcm9TdGFrZWRUb3RhbE5ldwMJAAACBQ5zdGFrZWRUb3RhbE5ldwUKemVyb0JpZ0ludAUJb25lQmlnSW50BQ5zdGFrZWRUb3RhbE5ldwQSd3hQZXJMcEludGVncmFsTmV3CQC3AgIFD3d4UGVyTHBJbnRlZ3JhbAkAuQICBQl3eFBlckxwWDMJALYCAQUCZGgEDHd4UGVyTHBYM05ldwkAugICCQC2AgEFGHBvb2xXeEVtaXNzaW9uUGVyQmxvY2tYMwUVbm9uWmVyb1N0YWtlZFRvdGFsTmV3BB93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0TmV3BQZoZWlnaHQEBWRlYnVnCQC5CQIJAMwIAgkApgMBBRJ3eFBlckxwSW50ZWdyYWxOZXcJAMwIAgkApAMBBQJkaAkAzAgCCQCmAwEFCXd4UGVyTHBYMwkAzAgCCQCmAwEFC3N0YWtlZFRvdGFsCQDMCAIJAKQDAQUYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQDMCAIJAKQDAQUUd3hFbWlzc2lvblBlckJsb2NrWDMJAMwIAgkApAMBBQpwb29sV2VpZ2h0BQNuaWwCAjo6CQCVCgMFEnd4UGVyTHBJbnRlZ3JhbE5ldwkAzAgCCQELU3RyaW5nRW50cnkCBRJ3eFBlckxwSW50ZWdyYWxLRVkJAKYDAQUSd3hQZXJMcEludGVncmFsTmV3CQDMCAIJAQxJbnRlZ2VyRW50cnkCBR93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0S0VZBR93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0TmV3CQDMCAIJAQtTdHJpbmdFbnRyeQIFCnd4UGVyTHBLRVkJAKYDAQUMd3hQZXJMcFgzTmV3BQNuaWwFBWRlYnVnARByZWZyZXNoSU5URUdSQUxTBAxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIOcG9vbEFkZHJlc3NTdHINbHBEZWx0YUFtb3VudAQNJHQwMTQzMDIxNDQyNAkBFHJlZnJlc2hQb29sSU5URUdSQUxTAwUMbHBBc3NldElkU3RyBQ5wb29sQWRkcmVzc1N0cgUNbHBEZWx0YUFtb3VudAQSd3hQZXJMcEludGVncmFsTmV3CAUNJHQwMTQzMDIxNDQyNAJfMQQRcG9vbEludGVncmFsU1RBVEUIBQ0kdDAxNDMwMjE0NDI0Al8yBAlwb29sREVCVUcIBQ0kdDAxNDMwMjE0NDI0Al8zBAVNVUxUMwDoBwQPc3Rha2VkQnlVc2VyS0VZCQEPa2V5U3Rha2VkQnlVc2VyAgUOdXNlckFkZHJlc3NTdHIFDGxwQXNzZXRJZFN0cgQMc3Rha2VkQnlVc2VyCQEKcmVhZFN0YWtlZAEFD3N0YWtlZEJ5VXNlcktFWQQQd3hUb0NsYWltVXNlcktFWQkBEGtleVd4VG9DbGFpbVVzZXICBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBCN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodEtFWQkBI2tleVd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0AgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgQad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJARprZXlXeFBlckxwSW50ZWdyYWxVc2VyTGFzdAIFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIEDXd4VG9DbGFpbVVzZXIJARlnZXRCaWdJbnRGcm9tU3RyaW5nT3JaZXJvAgUEdGhpcwUQd3hUb0NsYWltVXNlcktFWQQmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8JAQxnZXRJbnRPclplcm8CBQR0aGlzBSN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodEtFWQQXd3hQZXJMcEludGVncmFsVXNlckxhc3QJARtjYWxjV3hQZXJMcEludGVncmFsVXNlckxhc3QECQC2AgEFDHN0YWtlZEJ5VXNlcgkAtgIBBSZ3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE9yWmVybwUSd3hQZXJMcEludGVncmFsTmV3BRp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQQGTVVMVDExCQBoAgUFTVVMVDgFBU1VTFQzBBB3eFRvQ2xhaW1Vc2VyTmV3CQCYAwEJAMwIAgkAtwICBQ13eFRvQ2xhaW1Vc2VyCQC8AgMJALgCAgUSd3hQZXJMcEludGVncmFsTmV3BRd3eFBlckxwSW50ZWdyYWxVc2VyTGFzdAkAtgIBBQxzdGFrZWRCeVVzZXIJALYCAQUGTVVMVDExCQDMCAIFCnplcm9CaWdJbnQFA25pbAQad3hQZXJMcEludGVncmFsVXNlckxhc3ROZXcFEnd4UGVyTHBJbnRlZ3JhbE5ldwQjd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHROZXcFBmhlaWdodAQFZGVidWcJALkJAgkAzAgCCQCmAwEFDXd4VG9DbGFpbVVzZXIJAMwIAgkApgMBBRd3eFBlckxwSW50ZWdyYWxVc2VyTGFzdAkAzAgCCQCkAwEFDHN0YWtlZEJ5VXNlcgkAzAgCBQlwb29sREVCVUcJAMwIAgkApAMBBQZoZWlnaHQFA25pbAICOjoJAJUKAwUQd3hUb0NsYWltVXNlck5ldwkAzggCBRFwb29sSW50ZWdyYWxTVEFURQkAzAgCCQELU3RyaW5nRW50cnkCBRB3eFRvQ2xhaW1Vc2VyS0VZCQCmAwEFEHd4VG9DbGFpbVVzZXJOZXcJAMwIAgkBDEludGVnZXJFbnRyeQIFI3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0S0VZBSN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE5ldwkAzAgCCQELU3RyaW5nRW50cnkCBRp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQkApgMBBRp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdE5ldwUDbmlsBQVkZWJ1ZwEWbWFuYWdlclB1YmxpY0tleU9yVW5pdAAEByRtYXRjaDAJAKIIAQkBE2tleU1hbmFnZXJQdWJsaWNLZXkAAwkAAQIFByRtYXRjaDACBlN0cmluZwQBcwUHJG1hdGNoMAkA2QQBBQFzAwkAAQIFByRtYXRjaDACBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgEXbWlncmF0b3JQdWJsaWNLZXlPclVuaXQABAckbWF0Y2gwCQCiCAEJARRrZXlNaWdyYXRvclB1YmxpY0tleQADCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQDZBAEFAXMDCQABAgUHJG1hdGNoMAIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yAR1wZW5kaW5nTWFuYWdlclB1YmxpY0tleU9yVW5pdAAEByRtYXRjaDAJAKIIAQkBGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJANkEAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IAFXBlcm1pc3Npb25EZW5pZWRFcnJvcgkAAgECEVBlcm1pc3Npb24gZGVuaWVkAQhtdXN0VGhpcwEBaQMJAAACCAUBaQZjYWxsZXIFBHRoaXMGBRVwZXJtaXNzaW9uRGVuaWVkRXJyb3IBC211c3RNYW5hZ2VyAQFpBAckbWF0Y2gwCQEWbWFuYWdlclB1YmxpY0tleU9yVW5pdAADCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQCcGsFByRtYXRjaDADCQAAAggFAWkPY2FsbGVyUHVibGljS2V5BQJwawYFFXBlcm1pc3Npb25EZW5pZWRFcnJvcgMJAAECBQckbWF0Y2gwAgRVbml0AwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYFFXBlcm1pc3Npb25EZW5pZWRFcnJvcgkAAgECC01hdGNoIGVycm9yCwFpAQtjb25zdHJ1Y3RvcgERZmFjdG9yeUFkZHJlc3NTdHIEC2NoZWNrQ2FsbGVyCQELbXVzdE1hbmFnZXIBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgkAzAgCCQELU3RyaW5nRW50cnkCCQERa2V5RmFjdG9yeUFkZHJlc3MABRFmYWN0b3J5QWRkcmVzc1N0cgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWNvbnN0cnVjdG9yVjIBFnZvdGluZ0VtaXNzaW9uQ29udHJhY3QEBWNoZWtzCQDMCAIJAQttdXN0TWFuYWdlcgEFAWkJAMwIAgMJAQIhPQIJAKYIAQUWdm90aW5nRW1pc3Npb25Db250cmFjdAUEdW5pdAYCKGludmFsaWQgdm90aW5nIGVtaXNzaW9uIGNvbnRyYWN0IGFkZHJlc3MFA25pbAMJAAACBQVjaGVrcwUFY2hla3MJAMwIAgkBC1N0cmluZ0VudHJ5AgkBGWtleVZvdGluZ0VtaXNzaW9uQ29udHJhY3QABRZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKc2V0TWFuYWdlcgEXcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkEC2NoZWNrQ2FsbGVyCQELbXVzdE1hbmFnZXIBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQVY2hlY2tNYW5hZ2VyUHVibGljS2V5CQDZBAEFF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5AwkAAAIFFWNoZWNrTWFuYWdlclB1YmxpY0tleQUVY2hlY2tNYW5hZ2VyUHVibGljS2V5CQDMCAIJAQtTdHJpbmdFbnRyeQIJARprZXlQZW5kaW5nTWFuYWdlclB1YmxpY0tleQAFF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEOY29uZmlybU1hbmFnZXIABAJwbQkBHXBlbmRpbmdNYW5hZ2VyUHVibGljS2V5T3JVbml0AAQFaGFzUE0DCQEJaXNEZWZpbmVkAQUCcG0GCQACAQISTm8gcGVuZGluZyBtYW5hZ2VyAwkAAAIFBWhhc1BNBQVoYXNQTQQHY2hlY2tQTQMJAAACCAUBaQ9jYWxsZXJQdWJsaWNLZXkJAQV2YWx1ZQEFAnBtBgkAAgECG1lvdSBhcmUgbm90IHBlbmRpbmcgbWFuYWdlcgMJAAACBQdjaGVja1BNBQdjaGVja1BNCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNrZXlNYW5hZ2VyUHVibGljS2V5AAkA2AQBCQEFdmFsdWUBBQJwbQkAzAgCCQELRGVsZXRlRW50cnkBCQEaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkABQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEFc3Rha2UAAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQI0aW52YWxpZCBwYXltZW50IC0gZXhhY3Qgb25lIHBheW1lbnQgbXVzdCBiZSBhdHRhY2hlZAQDcG10CQCRAwIIBQFpCHBheW1lbnRzAAAECWxwQXNzZXRJZAkBBXZhbHVlAQgFA3BtdAdhc3NldElkBAxscEFzc2V0SWRTdHIJANgEAQUJbHBBc3NldElkBAZhbW91bnQIBQNwbXQGYW1vdW50BA5wb29sQWRkcmVzc1N0cgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFD2ZhY3RvcnlDb250cmFjdAkBGmtleUZhY3RvcnlMcDJBc3NldHNNYXBwaW5nAQUMbHBBc3NldElkU3RyCQCsAgICFXVuc3VwcG9ydGVkIGxwIGFzc2V0IAUMbHBBc3NldElkU3RyBAljYWxsZXJTdHIJAKUIAQgFAWkGY2FsbGVyBA51c2VyQWRkcmVzc1N0cgMJAAACBQljYWxsZXJTdHIFDnBvb2xBZGRyZXNzU3RyCQClCAEIBQFpDG9yaWdpbkNhbGxlcgUJY2FsbGVyU3RyBA9zdGFrZWRCeVVzZXJLRVkJAQ9rZXlTdGFrZWRCeVVzZXICBQ51c2VyQWRkcmVzc1N0cgUMbHBBc3NldElkU3RyBA5zdGFrZWRUb3RhbEtFWQkBDmtleVN0YWtlZFRvdGFsAQUMbHBBc3NldElkU3RyBAxzdGFrZWRCeVVzZXIJAQpyZWFkU3Rha2VkAQUPc3Rha2VkQnlVc2VyS0VZBAtzdGFrZWRUb3RhbAkBCnJlYWRTdGFrZWQBBQ5zdGFrZWRUb3RhbEtFWQQNJHQwMTkwMzQxOTE1MQkBEHJlZnJlc2hJTlRFR1JBTFMEBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBQ5wb29sQWRkcmVzc1N0cgUGYW1vdW50BBB3eFRvQ2xhaW1Vc2VyTmV3CAUNJHQwMTkwMzQxOTE1MQJfMQQNaW50ZWdyYWxTVEFURQgFDSR0MDE5MDM0MTkxNTECXzIEBWRlYnVnCAUNJHQwMTkwMzQxOTE1MQJfMwQIbGlzdE5hbWUJARBnZXRVc2Vyc0xpc3ROYW1lAQUMbHBBc3NldElkU3RyBAtsaXN0QWN0aW9ucwMJAQxjb250YWluc05vZGUCBQhsaXN0TmFtZQUOdXNlckFkZHJlc3NTdHIFA25pbAkBEWluc2VydE5vZGVBY3Rpb25zAgUIbGlzdE5hbWUFDnVzZXJBZGRyZXNzU3RyCQDOCAIJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUPc3Rha2VkQnlVc2VyS0VZCQBkAgUMc3Rha2VkQnlVc2VyBQZhbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIFDnN0YWtlZFRvdGFsS0VZCQBkAgULc3Rha2VkVG90YWwFBmFtb3VudAkAzAgCCQEVT3BlcmF0aW9uSGlzdG9yeUVudHJ5BQIFc3Rha2UFDnVzZXJBZGRyZXNzU3RyBQxscEFzc2V0SWRTdHIFBmFtb3VudAgFAWkNdHJhbnNhY3Rpb25JZAUDbmlsBQ1pbnRlZ3JhbFNUQVRFBQtsaXN0QWN0aW9ucwFpAQd1bnN0YWtlAgxscEFzc2V0SWRTdHIGYW1vdW50BAlscEFzc2V0SWQJANkEAQUMbHBBc3NldElkU3RyBA5wb29sQWRkcmVzc1N0cgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFD2ZhY3RvcnlDb250cmFjdAkBGmtleUZhY3RvcnlMcDJBc3NldHNNYXBwaW5nAQUMbHBBc3NldElkU3RyCQCsAgICFXVuc3VwcG9ydGVkIGxwIGFzc2V0IAUMbHBBc3NldElkU3RyBAlwb29sQWRkb24JAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkBFmtleVN0YWJsZVBvb2xBZGRvbkFkZHIABQ5wb29sQWRkcmVzc1N0cgQJY2FsbGVyU3RyCQClCAEIBQFpBmNhbGxlcgQOdXNlckFkZHJlc3NTdHIDAwkAAAIFCWNhbGxlclN0cgUOcG9vbEFkZHJlc3NTdHIGCQAAAgUJY2FsbGVyU3RyBQlwb29sQWRkb24JAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBQljYWxsZXJTdHIED3N0YWtlZEJ5VXNlcktFWQkBD2tleVN0YWtlZEJ5VXNlcgIFDnVzZXJBZGRyZXNzU3RyBQxscEFzc2V0SWRTdHIEDnN0YWtlZFRvdGFsS0VZCQEOa2V5U3Rha2VkVG90YWwBBQxscEFzc2V0SWRTdHIEDHN0YWtlZEJ5VXNlcgkBCnJlYWRTdGFrZWQBBQ9zdGFrZWRCeVVzZXJLRVkEC3N0YWtlZFRvdGFsCQEKcmVhZFN0YWtlZAEFDnN0YWtlZFRvdGFsS0VZBA0kdDAyMDQ4NjIwNjA0CQEQcmVmcmVzaElOVEVHUkFMUwQFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIFDnBvb2xBZGRyZXNzU3RyCQEBLQEFBmFtb3VudAQQd3hUb0NsYWltVXNlck5ldwgFDSR0MDIwNDg2MjA2MDQCXzEEDWludGVncmFsU1RBVEUIBQ0kdDAyMDQ4NjIwNjA0Al8yBAVkZWJ1ZwgFDSR0MDIwNDg2MjA2MDQCXzMECGxpc3ROYW1lCQEQZ2V0VXNlcnNMaXN0TmFtZQEFDGxwQXNzZXRJZFN0cgQLbGlzdEFjdGlvbnMDCQEMY29udGFpbnNOb2RlAgUIbGlzdE5hbWUFDnVzZXJBZGRyZXNzU3RyCQERZGVsZXRlTm9kZUFjdGlvbnMCBQhsaXN0TmFtZQUOdXNlckFkZHJlc3NTdHIFA25pbAMJAGYCBQZhbW91bnQFDHN0YWtlZEJ5VXNlcgkAAgECJHBhc3NlZCBhbW91bnQgaXMgbGVzcyB0aGVuIGF2YWlsYWJsZQkAzggCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIFD3N0YWtlZEJ5VXNlcktFWQkAZQIFDHN0YWtlZEJ5VXNlcgUGYW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5zdGFrZWRUb3RhbEtFWQkAZQIFC3N0YWtlZFRvdGFsBQZhbW91bnQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQZhbW91bnQFCWxwQXNzZXRJZAkAzAgCCQEVT3BlcmF0aW9uSGlzdG9yeUVudHJ5BQIHdW5zdGFrZQUOdXNlckFkZHJlc3NTdHIFDGxwQXNzZXRJZFN0cgUGYW1vdW50CAUBaQ10cmFuc2FjdGlvbklkBQNuaWwFDWludGVncmFsU1RBVEUFC2xpc3RBY3Rpb25zAWkBB2NsYWltV3gBDGxwQXNzZXRJZFN0cgQOdXNlckFkZHJlc3NTdHIJAKUIAQgFAWkGY2FsbGVyBAZyZXN1bHQJAPwHBAUEdGhpcwIPY2xhaW1XeElOVEVSTkFMCQDMCAIFDGxwQXNzZXRJZFN0cgkAzAgCBQ51c2VyQWRkcmVzc1N0cgUDbmlsBQNuaWwJAJQKAgUDbmlsBQZyZXN1bHQBaQEPY2xhaW1XeElOVEVSTkFMAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIEC2NoZWNrQ2FsbGVyCQEIbXVzdFRoaXMBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQLdXNlckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQ51c2VyQWRkcmVzc1N0cgIlY2xhaW1XeElOVEVSTkFMOiBpbnZhbGlkIHVzZXIgYWRkcmVzcwQOcG9vbEFkZHJlc3NTdHIJARhnZXRTdHJpbmdCeUFkZHJlc3NPckZhaWwCBQ9mYWN0b3J5Q29udHJhY3QJASZrZXlGYWN0b3J5THBBc3NldFRvUG9vbENvbnRyYWN0QWRkcmVzcwEFDGxwQXNzZXRJZFN0cgQQY2xhaW1lZEJ5VXNlcktFWQkBEGtleUNsYWltZWRCeVVzZXICBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBA9jbGFpbWVkVG90YWxLRVkJAQ9rZXlDbGFpbWVkVG90YWwBBQxscEFzc2V0SWRTdHIEGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkJARlrZXlDbGFpbWVkQnlVc2VyTWluUmV3YXJkAgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgQbY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkS0VZCQEba2V5Q2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkAgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgQNY2xhaW1lZEJ5VXNlcgkBGWdldEJpZ0ludEZyb21TdHJpbmdPclplcm8CBQR0aGlzBRBjbGFpbWVkQnlVc2VyS0VZBBZjbGFpbWVkQnlVc2VyTWluUmV3YXJkCQEZZ2V0QmlnSW50RnJvbVN0cmluZ09yWmVybwIFBHRoaXMFGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkEGGNsYWltZWRCeVVzZXJCb29zdFJld2FyZAkBGWdldEJpZ0ludEZyb21TdHJpbmdPclplcm8CBQR0aGlzBRtjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmRLRVkEDGNsYWltZWRUb3RhbAkBGWdldEJpZ0ludEZyb21TdHJpbmdPclplcm8CBQR0aGlzBQ9jbGFpbWVkVG90YWxLRVkEDSR0MDIyMzUyMjI0NjQJARByZWZyZXNoSU5URUdSQUxTBAUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgUOcG9vbEFkZHJlc3NTdHIAAAQQd3hUb0NsYWltVXNlck5ldwgFDSR0MDIyMzUyMjI0NjQCXzEEDWludGVncmFsU1RBVEUIBQ0kdDAyMjM1MjIyNDY0Al8yBAVkZWJ1ZwgFDSR0MDIyMzUyMjI0NjQCXzMEEGF2YWlsYWJsZVRvQ2xhaW0JAJgDAQkAzAgCCQC4AgIFEHd4VG9DbGFpbVVzZXJOZXcFDWNsYWltZWRCeVVzZXIJAMwIAgUKemVyb0JpZ0ludAUDbmlsAwkAwAICBQp6ZXJvQmlnSW50BRBhdmFpbGFibGVUb0NsYWltCQACAQIQbm90aGluZyB0byBjbGFpbQQSd3hBbW91bnRCb29zdFRvdGFsCQCWAwEJAMwIAgkBBWFzSW50AQkAkQMCCQEJYXNBbnlMaXN0AQkA/AcEBRBib29zdGluZ0NvbnRyYWN0AgxjbGFpbVd4Qm9vc3QJAMwIAgUMbHBBc3NldElkU3RyCQDMCAIFDnVzZXJBZGRyZXNzU3RyBQNuaWwFA25pbAAACQDMCAIAAAUDbmlsBA1taW5SZXdhcmRQYXJ0BRBhdmFpbGFibGVUb0NsYWltBA9ib29zdFJld2FyZFBhcnQJAJkDAQkAzAgCCQC5AgIFDW1pblJld2FyZFBhcnQJALYCAQACCQDMCAIJALYCAQUSd3hBbW91bnRCb29zdFRvdGFsBQNuaWwECXd4QXNzZXRJZAkBDGFzQnl0ZVZlY3RvcgEJAJEDAgkBCWFzQW55TGlzdAEJAPwHBAUQZW1pc3Npb25Db250cmFjdAIEZW1pdAkAzAgCCQCgAwEFDW1pblJld2FyZFBhcnQFA25pbAUDbmlsAAAECWVtaXRCb29zdAkBCWFzQW55TGlzdAEJAPwHBAUQZW1pc3Npb25Db250cmFjdAIEZW1pdAkAzAgCCQCgAwEFD2Jvb3N0UmV3YXJkUGFydAUDbmlsBQNuaWwDCQAAAgUJZW1pdEJvb3N0BQllbWl0Qm9vc3QEEmNsYWltZWRCeVVzZXJWYWx1ZQkAtwICBQ1jbGFpbWVkQnlVc2VyBRBhdmFpbGFibGVUb0NsYWltBB5jbGFpbWVkQnlVc2VyTWluUmV3YXJkUGx1c1BhcnQJALcCAgUWY2xhaW1lZEJ5VXNlck1pblJld2FyZAUNbWluUmV3YXJkUGFydAQrY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkUGx1c0Jvb3N0UmV3YXJkUGFydAkAtwICBRZjbGFpbWVkQnlVc2VyTWluUmV3YXJkBQ1taW5SZXdhcmRQYXJ0BCBjbGFpbWVkVG90YWxQbHVzQXZhaWxhYmxlVG9DbGFpbQkAtwICBRZjbGFpbWVkQnlVc2VyTWluUmV3YXJkBQ1taW5SZXdhcmRQYXJ0CQDMCAIJAQtTdHJpbmdFbnRyeQIFEGNsYWltZWRCeVVzZXJLRVkJAKYDAQUSY2xhaW1lZEJ5VXNlclZhbHVlCQDMCAIJAQtTdHJpbmdFbnRyeQIFGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkJAKYDAQUeY2xhaW1lZEJ5VXNlck1pblJld2FyZFBsdXNQYXJ0CQDMCAIJAQtTdHJpbmdFbnRyeQIFG2NsYWltZWRCeVVzZXJCb29zdFJld2FyZEtFWQkApgMBBStjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmRQbHVzQm9vc3RSZXdhcmRQYXJ0CQDMCAIJAQtTdHJpbmdFbnRyeQIFD2NsYWltZWRUb3RhbEtFWQkApgMBBSBjbGFpbWVkVG90YWxQbHVzQXZhaWxhYmxlVG9DbGFpbQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQt1c2VyQWRkcmVzcwkAoAMBBQ1taW5SZXdhcmRQYXJ0BQl3eEFzc2V0SWQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MJAKADAQUPYm9vc3RSZXdhcmRQYXJ0BQl3eEFzc2V0SWQJAMwIAgkBFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQUCBWNsYWltBQ51c2VyQWRkcmVzc1N0cgUMbHBBc3NldElkU3RyCQCgAwEFEGF2YWlsYWJsZVRvQ2xhaW0IBQFpDXRyYW5zYWN0aW9uSWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ9jbGFpbVd4UkVBRE9OTFkCDGxwQXNzZXRJZFN0cg51c2VyQWRkcmVzc1N0cgQPc3Rha2VkQnlVc2VyS0VZCQEPa2V5U3Rha2VkQnlVc2VyAgUOdXNlckFkZHJlc3NTdHIFDGxwQXNzZXRJZFN0cgQOc3Rha2VkVG90YWxLRVkJAQ5rZXlTdGFrZWRUb3RhbAEFDGxwQXNzZXRJZFN0cgQQY2xhaW1lZEJ5VXNlcktFWQkBEGtleUNsYWltZWRCeVVzZXICBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBAxzdGFrZWRCeVVzZXIJAQpyZWFkU3Rha2VkAQUPc3Rha2VkQnlVc2VyS0VZBAtzdGFrZWRUb3RhbAkBCnJlYWRTdGFrZWQBBQ5zdGFrZWRUb3RhbEtFWQQNY2xhaW1lZEJ5VXNlcgkBGWdldEJpZ0ludEZyb21TdHJpbmdPclplcm8CBQR0aGlzBRBjbGFpbWVkQnlVc2VyS0VZBA5wb29sQWRkcmVzc1N0cgkBGGdldFN0cmluZ0J5QWRkcmVzc09yRmFpbAIFD2ZhY3RvcnlDb250cmFjdAkBJmtleUZhY3RvcnlMcEFzc2V0VG9Qb29sQ29udHJhY3RBZGRyZXNzAQUMbHBBc3NldElkU3RyBApwb29sV2VpZ2h0CQERQGV4dHJOYXRpdmUoMTA1MCkCBQ9mYWN0b3J5Q29udHJhY3QJARRrZXlGYWN0b3J5UG9vbFdlaWdodAEFDnBvb2xBZGRyZXNzU3RyBBJ3eEVtaXNzaW9uUGVyQmxvY2sJAQxnZXRJbnRPckZhaWwCBRBlbWlzc2lvbkNvbnRyYWN0CQEea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAQSZW1pc3Npb25TdGFydEJsb2NrCQEMZ2V0SW50T3JGYWlsAgUQZW1pc3Npb25Db250cmFjdAkBFWtleUVtaXNzaW9uU3RhcnRCbG9jawAEDHBhc3NlZEJsb2NrcwMJAGYCBRJlbWlzc2lvblN0YXJ0QmxvY2sFBmhlaWdodAAACQBlAgUGaGVpZ2h0BRJlbWlzc2lvblN0YXJ0QmxvY2sEDnBvb2xXeEVtaXNzaW9uCQBrAwkAaAIFEnd4RW1pc3Npb25QZXJCbG9jawUMcGFzc2VkQmxvY2tzBQpwb29sV2VpZ2h0BQ5QT09MV0VJR0hUTVVMVAQMdXNlcld4UmV3YXJkCQBrAwUOcG9vbFd4RW1pc3Npb24FDHN0YWtlZEJ5VXNlcgULc3Rha2VkVG90YWwEDSR0MDI1MTA2MjUyMTgJARByZWZyZXNoSU5URUdSQUxTBAUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgUOcG9vbEFkZHJlc3NTdHIAAAQQd3hUb0NsYWltVXNlck5ldwgFDSR0MDI1MTA2MjUyMTgCXzEEDWludGVncmFsU1RBVEUIBQ0kdDAyNTEwNjI1MjE4Al8yBAVkZWJ1ZwgFDSR0MDI1MTA2MjUyMTgCXzMEEGF2YWlsYWJsZVRvQ2xhaW0JAJgDAQkAzAgCCQC4AgIFEHd4VG9DbGFpbVVzZXJOZXcFDWNsYWltZWRCeVVzZXIJAMwIAgUKemVyb0JpZ0ludAUDbmlsBA5ib29zdEludlJlc3VsdAkBCWFzQW55TGlzdAEJAPwHBAUQYm9vc3RpbmdDb250cmFjdAIUY2xhaW1XeEJvb3N0UkVBRE9OTFkJAMwIAgUMbHBBc3NldElkU3RyCQDMCAIFDnVzZXJBZGRyZXNzU3RyBQNuaWwFA25pbAQSd3hBbW91bnRCb29zdFRvdGFsCQCWAwEJAMwIAgkBBWFzSW50AQkAkQMCBQ5ib29zdEludlJlc3VsdAAACQDMCAIAAAUDbmlsBApib29zdERlYnVnCQEIYXNTdHJpbmcBCQCRAwIFDmJvb3N0SW52UmVzdWx0AAEEDW1pblJld2FyZFBhcnQFEGF2YWlsYWJsZVRvQ2xhaW0ED2Jvb3N0UmV3YXJkUGFydAkAmQMBCQDMCAIJALkCAgUNbWluUmV3YXJkUGFydAkAtgIBAAIJAMwIAgkAtgIBBRJ3eEFtb3VudEJvb3N0VG90YWwFA25pbAQLdG90YWxSZXdhcmQJALcCAgUNbWluUmV3YXJkUGFydAUPYm9vc3RSZXdhcmRQYXJ0CQCUCgIFA25pbAkAuQkCCQDMCAICDiVzJXMlZCVkJWQlZCVzCQDMCAIFDGxwQXNzZXRJZFN0cgkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCCQCmAwEFC3RvdGFsUmV3YXJkCQDMCAIJAKYDAQUNY2xhaW1lZEJ5VXNlcgkAzAgCCQCmAwEFDW1pblJld2FyZFBhcnQJAMwIAgkApgMBBQ9ib29zdFJld2FyZFBhcnQJAMwIAgkArAICCQCsAgIJAKwCAgkArAICBQVkZWJ1ZwICOjoJAKQDAQUMdXNlcld4UmV3YXJkAgk6OkJPT1NUOjoFCmJvb3N0RGVidWcFA25pbAUDU0VQAWkBEnVzZXJzTGlzdFRyYXZlcnNhbAEJbHBBc3NldElkBAtjaGVja0NhbGxlcgMJAAACCQDYBAEICAUBaQZjYWxsZXIFYnl0ZXMJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkBGWtleVZvdGluZ0VtaXNzaW9uQ29udHJhY3QAAgAGCQELbXVzdE1hbmFnZXIBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQIbGlzdE5hbWUJARBnZXRVc2Vyc0xpc3ROYW1lAQUJbHBBc3NldElkBAp1c2VyT3JVbml0CQCiCAEJAQtrZXlOZXh0VXNlcgEFCWxwQXNzZXRJZAQKaGVhZE9yVW5pdAkAoggBCQELa2V5TGlzdEhlYWQBBQhsaXN0TmFtZQQHJG1hdGNoMAUKdXNlck9yVW5pdAMJAAECBQckbWF0Y2gwAgRVbml0BAckbWF0Y2gxBQpoZWFkT3JVbml0AwkAAQIFByRtYXRjaDECBFVuaXQJAJQKAgUDbmlsBwMJAAECBQckbWF0Y2gxAgZTdHJpbmcEBGhlYWQFByRtYXRjaDEJAJQKAgkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TmV4dFVzZXIBBQlscEFzc2V0SWQFBGhlYWQFA25pbAYJAAIBAgtNYXRjaCBlcnJvcgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEC3VzZXJBZGRyZXNzBQckbWF0Y2gwBA1jbGFpbWVkQnlVc2VyCQEZZ2V0QmlnSW50RnJvbVN0cmluZ09yWmVybwIFBHRoaXMJARBrZXlDbGFpbWVkQnlVc2VyAgUJbHBBc3NldElkBQt1c2VyQWRkcmVzcwQLcG9vbEFkZHJlc3MJARhnZXRTdHJpbmdCeUFkZHJlc3NPckZhaWwCBQ9mYWN0b3J5Q29udHJhY3QJASZrZXlGYWN0b3J5THBBc3NldFRvUG9vbENvbnRyYWN0QWRkcmVzcwEFCWxwQXNzZXRJZAQNJHQwMjY4MTMyNjkxNgkBEHJlZnJlc2hJTlRFR1JBTFMEBQlscEFzc2V0SWQFC3VzZXJBZGRyZXNzBQtwb29sQWRkcmVzcwAABBB3eFRvQ2xhaW1Vc2VyTmV3CAUNJHQwMjY4MTMyNjkxNgJfMQQNaW50ZWdyYWxTVEFURQgFDSR0MDI2ODEzMjY5MTYCXzIEBWRlYnVnCAUNJHQwMjY4MTMyNjkxNgJfMwQQYXZhaWxhYmxlVG9DbGFpbQkAuAICBRB3eFRvQ2xhaW1Vc2VyTmV3BQ1jbGFpbWVkQnlVc2VyBAFyAwkAvwICBRBhdmFpbGFibGVUb0NsYWltBQp6ZXJvQmlnSW50CQD8BwQFBHRoaXMCD2NsYWltV3hJTlRFUk5BTAkAzAgCBQlscEFzc2V0SWQJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDbmlsBQR1bml0AwkAAAIFAXIFAXIEDm5leHRVc2VyT3JVbml0CQCiCAEJAQtrZXlMaXN0TmV4dAIFCGxpc3ROYW1lBQt1c2VyQWRkcmVzcwQHJG1hdGNoMQUObmV4dFVzZXJPclVuaXQDCQABAgUHJG1hdGNoMQIEVW5pdAkAlAoCCQDMCAIJAQtEZWxldGVFbnRyeQEJAQtrZXlOZXh0VXNlcgEFCWxwQXNzZXRJZAUDbmlsBwMJAAECBQckbWF0Y2gxAgZTdHJpbmcECG5leHRVc2VyBQckbWF0Y2gxCQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleU5leHRVc2VyAQUJbHBBc3NldElkBQhuZXh0VXNlcgUDbmlsBgkAAgECC01hdGNoIGVycm9yCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQILTWF0Y2ggZXJyb3IJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEOb25Nb2RpZnlXZWlnaHQCDGxwQXNzZXRJZFN0cg5wb29sQWRkcmVzc1N0cgMJAQIhPQIIBQFpBmNhbGxlcgUPZmFjdG9yeUNvbnRyYWN0CQACAQIScGVybWlzc2lvbnMgZGVuaWVkBA0kdDAyNzU5MDI3NzAwCQEUcmVmcmVzaFBvb2xJTlRFR1JBTFMDBQxscEFzc2V0SWRTdHIFDnBvb2xBZGRyZXNzU3RyAAAEEnd4UGVyTHBJbnRlZ3JhbE5ldwgFDSR0MDI3NTkwMjc3MDACXzEEEXBvb2xJbnRlZ3JhbFNUQVRFCAUNJHQwMjc1OTAyNzcwMAJfMgQJcG9vbERFQlVHCAUNJHQwMjc1OTAyNzcwMAJfMwURcG9vbEludGVncmFsU1RBVEUBAnR4AQZ2ZXJpZnkABA90YXJnZXRQdWJsaWNLZXkEByRtYXRjaDAJARZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAJwawUHJG1hdGNoMAUCcGsDCQABAgUHJG1hdGNoMAIEVW5pdAgFAnR4D3NlbmRlclB1YmxpY0tleQkAAgECC01hdGNoIGVycm9yBBFtaWdyYXRvclB1YmxpY0tleQQHJG1hdGNoMAkBF21pZ3JhdG9yUHVibGljS2V5T3JVbml0AAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAJwawUHJG1hdGNoMAUCcGsDCQABAgUHJG1hdGNoMAIEVW5pdAgFAnR4D3NlbmRlclB1YmxpY0tleQkAAgECC01hdGNoIGVycm9yAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAUPdGFyZ2V0UHVibGljS2V5BgkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAURbWlncmF0b3JQdWJsaWNLZXlrWUR6", "chainId": 84, "height": 2117692, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: FvUiXeu4R36wBiUWerVothmY9PBWMpXxBDie2ZJAk4rG Next: HBJhyaqdBX29ChSrFq8PSCKyas9biTXsWa2EA3sGdtXo Diff:
OldNewDifferences
1-{-# STDLIB_VERSION 5 #-}
1+{-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let SCALE8 = 8
8484
8585
8686 func keyFactoryAddress () = "%s%s__config__factoryAddress"
87+
88+
89+func keyVotingEmissionContract () = "%s__votingEmissionContract"
8790
8891
8992 let IdxFactoryCfgStakingDapp = 1
236239
237240 let boostingContract = getBoostingAddressOrFail(factoryCfg)
238241
242+func keyNextUser (lpAssetId) = makeString(["%s%s", lpAssetId, "nextUser"], SEP)
243+
244+
245+func getUsersListName (lpAssetId) = makeString(["users", lpAssetId], SEP)
246+
247+
248+func keyListHead (listName) = makeString(["%s%s%s", listName, "head"], SEP)
249+
250+
251+func keyListSize (listName) = makeString(["%s%s%s", listName, "size"], SEP)
252+
253+
254+func keyListPrev (listName,id) = makeString(["%s%s%s%s", listName, id, "prev"], SEP)
255+
256+
257+func keyListNext (listName,id) = makeString(["%s%s%s%s", listName, id, "next"], SEP)
258+
259+
260+func containsNode (listName,id) = {
261+ let headOrUnit = getString(this, keyListHead(listName))
262+ let prevOrUnit = getString(this, keyListPrev(listName, id))
263+ let nextOrUnit = getString(this, keyListNext(listName, id))
264+ if (if ((id == valueOrElse(headOrUnit, "")))
265+ then true
266+ else (prevOrUnit != unit))
267+ then true
268+ else (nextOrUnit != unit)
269+ }
270+
271+
272+func insertNodeActions (listName,id) = {
273+ let headOrUnit = getString(this, keyListHead(listName))
274+ let listSize = valueOrElse(getInteger(this, keyListSize(listName)), 0)
275+ let checkNode = if (!(containsNode(listName, id)))
276+ then true
277+ else throw("Node exists")
278+ if ((checkNode == checkNode))
279+ then (([IntegerEntry(keyListSize(listName), (listSize + 1))] ++ (if ((headOrUnit != unit))
280+ then [StringEntry(keyListNext(listName, id), value(headOrUnit)), StringEntry(keyListPrev(listName, value(headOrUnit)), id)]
281+ else nil)) ++ [StringEntry(keyListHead(listName), id)])
282+ else throw("Strict value is not equal to itself.")
283+ }
284+
285+
286+func deleteNodeActions (listName,id) = {
287+ let headOrUnit = getString(this, keyListHead(listName))
288+ let listSize = valueOrElse(getInteger(this, keyListSize(listName)), 0)
289+ let prevOrUnit = getString(this, keyListPrev(listName, id))
290+ let nextOrUnit = getString(this, keyListNext(listName, id))
291+ ([IntegerEntry(keyListSize(listName), (listSize - 1))] ++ (if (if ((prevOrUnit != unit))
292+ then (nextOrUnit != unit)
293+ else false)
294+ then [StringEntry(keyListNext(listName, value(prevOrUnit)), value(nextOrUnit)), StringEntry(keyListPrev(listName, value(nextOrUnit)), value(prevOrUnit)), DeleteEntry(keyListPrev(listName, id)), DeleteEntry(keyListNext(listName, id))]
295+ else if ((nextOrUnit != unit))
296+ then [StringEntry(keyListHead(listName), value(nextOrUnit)), DeleteEntry(keyListNext(listName, id)), DeleteEntry(keyListPrev(listName, value(nextOrUnit)))]
297+ else if ((prevOrUnit != unit))
298+ then [DeleteEntry(keyListPrev(listName, id)), DeleteEntry(keyListNext(listName, value(prevOrUnit)))]
299+ else if ((id == valueOrElse(headOrUnit, "")))
300+ then [DeleteEntry(keyListHead(listName))]
301+ else throw(((("invalid node: " + listName) + ".") + id))))
302+ }
303+
304+
239305 func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
240306 then (stakedByUser > zeroBigInt)
241307 else false)
277343 let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * toBigInt(dh)))
278344 let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
279345 let wxPerLpIntegralLastUpdHeightNew = height
280- let debug = makeString([toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), toString(poolWxEmissionPerBlockX3), toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
346+ let debug = makeString([toString(wxPerLpIntegralNew), toString(dh), toString(wxPerLpX3), toString(stakedTotal), toString(poolWxEmissionPerBlockX3), toString(wxEmissionPerBlockX3), toString(poolWeight)], "::")
281347 $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
282348 }
283349
284350
285351 func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
286- let $t01150611628 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
287- let wxPerLpIntegralNew = $t01150611628._1
288- let poolIntegralSTATE = $t01150611628._2
289- let poolDEBUG = $t01150611628._3
352+ let $t01430214424 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
353+ let wxPerLpIntegralNew = $t01430214424._1
354+ let poolIntegralSTATE = $t01430214424._2
355+ let poolDEBUG = $t01430214424._3
290356 let MULT3 = 1000
291357 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
292358 let stakedByUser = readStaked(stakedByUserKEY)
300366 let wxToClaimUserNew = max([(wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11))), zeroBigInt])
301367 let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
302368 let wxPerLpIntegralUserLastUpdHeightNew = height
303- let debug = makeString(["wxToClaimUser", toString(wxToClaimUser), "wxPerLpInteg", toString(wxPerLpIntegralUserLastUpdHeightOrZero), "this.getString", toString(value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))), "wxPerLpIntegralNew", toString(wxPerLpIntegralNew), "wxToClaimUserNew", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast", toString(wxPerLpIntegralUserLast), toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
369+ let debug = makeString([toString(wxToClaimUser), toString(wxPerLpIntegralUserLast), toString(stakedByUser), poolDEBUG, toString(height)], "::")
304370 $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
305371 }
306372
335401 }
336402
337403
338-func mustManager (i) = {
339- let pd = throw("Permission denied")
340- match managerPublicKeyOrUnit() {
341- case pk: ByteVector =>
342- if ((i.callerPublicKey == pk))
343- then true
344- else pd
345- case _: Unit =>
346- if ((i.caller == this))
347- then true
348- else pd
349- case _ =>
350- throw("Match error")
351- }
352- }
404+let permissionDeniedError = throw("Permission denied")
405+
406+func mustThis (i) = if ((i.caller == this))
407+ then true
408+ else permissionDeniedError
409+
410+
411+func mustManager (i) = match managerPublicKeyOrUnit() {
412+ case pk: ByteVector =>
413+ if ((i.callerPublicKey == pk))
414+ then true
415+ else permissionDeniedError
416+ case _: Unit =>
417+ if ((i.caller == this))
418+ then true
419+ else permissionDeniedError
420+ case _ =>
421+ throw("Match error")
422+}
353423
354424
355425 @Callable(i)
357427 let checkCaller = mustManager(i)
358428 if ((checkCaller == checkCaller))
359429 then [StringEntry(keyFactoryAddress(), factoryAddressStr)]
430+ else throw("Strict value is not equal to itself.")
431+ }
432+
433+
434+
435+@Callable(i)
436+func constructorV2 (votingEmissionContract) = {
437+ let cheks = [mustManager(i), if ((addressFromString(votingEmissionContract) != unit))
438+ then true
439+ else "invalid voting emission contract address"]
440+ if ((cheks == cheks))
441+ then [StringEntry(keyVotingEmissionContract(), votingEmissionContract)]
360442 else throw("Strict value is not equal to itself.")
361443 }
362444
414496 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
415497 let stakedByUser = readStaked(stakedByUserKEY)
416498 let stakedTotal = readStaked(stakedTotalKEY)
417- let $t01619616313 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
418- let wxToClaimUserNew = $t01619616313._1
419- let integralSTATE = $t01619616313._2
420- let debug = $t01619616313._3
421- ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
499+ let $t01903419151 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
500+ let wxToClaimUserNew = $t01903419151._1
501+ let integralSTATE = $t01903419151._2
502+ let debug = $t01903419151._3
503+ let listName = getUsersListName(lpAssetIdStr)
504+ let listActions = if (containsNode(listName, userAddressStr))
505+ then nil
506+ else insertNodeActions(listName, userAddressStr)
507+ (([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE) ++ listActions)
422508 }
423509
424510
438524 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
439525 let stakedByUser = readStaked(stakedByUserKEY)
440526 let stakedTotal = readStaked(stakedTotalKEY)
441- let $t01745017568 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
442- let wxToClaimUserNew = $t01745017568._1
443- let integralSTATE = $t01745017568._2
444- let debug = $t01745017568._3
527+ let $t02048620604 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
528+ let wxToClaimUserNew = $t02048620604._1
529+ let integralSTATE = $t02048620604._2
530+ let debug = $t02048620604._3
531+ let listName = getUsersListName(lpAssetIdStr)
532+ let listActions = if (containsNode(listName, userAddressStr))
533+ then deleteNodeActions(listName, userAddressStr)
534+ else nil
445535 if ((amount > stakedByUser))
446536 then throw("passed amount is less then available")
447- else ([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
537+ else (([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE) ++ listActions)
448538 }
449539
450540
451541
452542 @Callable(i)
453543 func claimWx (lpAssetIdStr) = {
454- let userAddress = i.caller
455544 let userAddressStr = toString(i.caller)
456- let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
457- let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
458- let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
459- let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
460- let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
461- let claimedByUser = getBigIntFromStringOrZero(this, claimedByUserKEY)
462- let claimedByUserMinReward = getBigIntFromStringOrZero(this, claimedByUserMinRewardKEY)
463- let claimedByUserBoostReward = getBigIntFromStringOrZero(this, claimedByUserBoostRewardKEY)
464- let claimedTotal = getBigIntFromStringOrZero(this, claimedTotalKEY)
465- let $t01881218924 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
466- let wxToClaimUserNew = $t01881218924._1
467- let integralSTATE = $t01881218924._2
468- let debug = $t01881218924._3
469- let availableToClaim = max([(wxToClaimUserNew - claimedByUser), zeroBigInt])
470- if ((zeroBigInt >= availableToClaim))
471- then throw("nothing to claim")
472- else {
473- let wxAmountBoostTotal = max([asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0]), 0])
474- let minRewardPart = availableToClaim
475- let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
476- let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [toInt(minRewardPart)], nil))[0])
477- let emitBoost = asAnyList(invoke(emissionContract, "emit", [toInt(boostRewardPart)], nil))
478- if ((emitBoost == emitBoost))
479- then {
480- let claimedByUserValue = (claimedByUser + availableToClaim)
481- let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
482- let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
483- let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
545+ let result = invoke(this, "claimWxINTERNAL", [lpAssetIdStr, userAddressStr], nil)
546+ $Tuple2(nil, result)
547+ }
548+
549+
550+
551+@Callable(i)
552+func claimWxINTERNAL (lpAssetIdStr,userAddressStr) = {
553+ let checkCaller = mustThis(i)
554+ if ((checkCaller == checkCaller))
555+ then {
556+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), "claimWxINTERNAL: invalid user address")
557+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
558+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
559+ let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
560+ let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
561+ let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
562+ let claimedByUser = getBigIntFromStringOrZero(this, claimedByUserKEY)
563+ let claimedByUserMinReward = getBigIntFromStringOrZero(this, claimedByUserMinRewardKEY)
564+ let claimedByUserBoostReward = getBigIntFromStringOrZero(this, claimedByUserBoostRewardKEY)
565+ let claimedTotal = getBigIntFromStringOrZero(this, claimedTotalKEY)
566+ let $t02235222464 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
567+ let wxToClaimUserNew = $t02235222464._1
568+ let integralSTATE = $t02235222464._2
569+ let debug = $t02235222464._3
570+ let availableToClaim = max([(wxToClaimUserNew - claimedByUser), zeroBigInt])
571+ if ((zeroBigInt >= availableToClaim))
572+ then throw("nothing to claim")
573+ else {
574+ let wxAmountBoostTotal = max([asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0]), 0])
575+ let minRewardPart = availableToClaim
576+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
577+ let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [toInt(minRewardPart)], nil))[0])
578+ let emitBoost = asAnyList(invoke(emissionContract, "emit", [toInt(boostRewardPart)], nil))
579+ if ((emitBoost == emitBoost))
580+ then {
581+ let claimedByUserValue = (claimedByUser + availableToClaim)
582+ let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
583+ let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
584+ let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
484585 [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)]
586+ }
587+ else throw("Strict value is not equal to itself.")
485588 }
486- else throw("Strict value is not equal to itself.")
487589 }
590+ else throw("Strict value is not equal to itself.")
488591 }
489592
490593
506609 else (height - emissionStartBlock)
507610 let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
508611 let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
509- let $t02156621678 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
510- let wxToClaimUserNew = $t02156621678._1
511- let integralSTATE = $t02156621678._2
512- let debug = $t02156621678._3
612+ let $t02510625218 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
613+ let wxToClaimUserNew = $t02510625218._1
614+ let integralSTATE = $t02510625218._2
615+ let debug = $t02510625218._3
513616 let availableToClaim = max([(wxToClaimUserNew - claimedByUser), zeroBigInt])
514617 let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
515618 let wxAmountBoostTotal = max([asInt(boostInvResult[0]), 0])
517620 let minRewardPart = availableToClaim
518621 let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
519622 let totalReward = (minRewardPart + boostRewardPart)
520- $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))
623+ $Tuple2(nil, makeString(["%s%s%d%d%d%d%s", lpAssetIdStr, userAddressStr, toString(totalReward), toString(claimedByUser), toString(minRewardPart), toString(boostRewardPart), ((((debug + "::") + toString(userWxReward)) + "::BOOST::") + boostDebug)], SEP))
624+ }
625+
626+
627+
628+@Callable(i)
629+func usersListTraversal (lpAssetId) = {
630+ let checkCaller = if ((toBase58String(i.caller.bytes) == valueOrElse(getString(this, keyVotingEmissionContract()), "")))
631+ then true
632+ else mustManager(i)
633+ if ((checkCaller == checkCaller))
634+ then {
635+ let listName = getUsersListName(lpAssetId)
636+ let userOrUnit = getString(keyNextUser(lpAssetId))
637+ let headOrUnit = getString(keyListHead(listName))
638+ match userOrUnit {
639+ case _: Unit =>
640+ match headOrUnit {
641+ case _: Unit =>
642+ $Tuple2(nil, false)
643+ case head: String =>
644+ $Tuple2([StringEntry(keyNextUser(lpAssetId), head)], true)
645+ case _ =>
646+ throw("Match error")
647+ }
648+ case userAddress: String =>
649+ let claimedByUser = getBigIntFromStringOrZero(this, keyClaimedByUser(lpAssetId, userAddress))
650+ let poolAddress = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetId))
651+ let $t02681326916 = refreshINTEGRALS(lpAssetId, userAddress, poolAddress, 0)
652+ let wxToClaimUserNew = $t02681326916._1
653+ let integralSTATE = $t02681326916._2
654+ let debug = $t02681326916._3
655+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
656+ let r = if ((availableToClaim > zeroBigInt))
657+ then invoke(this, "claimWxINTERNAL", [lpAssetId, userAddress], nil)
658+ else unit
659+ if ((r == r))
660+ then {
661+ let nextUserOrUnit = getString(keyListNext(listName, userAddress))
662+ match nextUserOrUnit {
663+ case _: Unit =>
664+ $Tuple2([DeleteEntry(keyNextUser(lpAssetId))], false)
665+ case nextUser: String =>
666+ $Tuple2([StringEntry(keyNextUser(lpAssetId), nextUser)], true)
667+ case _ =>
668+ throw("Match error")
669+ }
670+ }
671+ else throw("Strict value is not equal to itself.")
672+ case _ =>
673+ throw("Match error")
674+ }
675+ }
676+ else throw("Strict value is not equal to itself.")
521677 }
522678
523679
526682 func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
527683 then throw("permissions denied")
528684 else {
529- let $t02260922719 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
530- let wxPerLpIntegralNew = $t02260922719._1
531- let poolIntegralSTATE = $t02260922719._2
532- let poolDEBUG = $t02260922719._3
685+ let $t02759027700 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
686+ let wxPerLpIntegralNew = $t02759027700._1
687+ let poolIntegralSTATE = $t02759027700._2
688+ let poolDEBUG = $t02759027700._3
533689 poolIntegralSTATE
534690 }
535691
Full:
OldNewDifferences
1-{-# STDLIB_VERSION 5 #-}
1+{-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let SCALE8 = 8
55
66 let MULT8 = 100000000
77
88 let SCALE18 = 18
99
1010 let MULT18 = toBigInt(1000000000000000000)
1111
1212 let SEP = "__"
1313
1414 let POOLWEIGHTMULT = MULT8
1515
1616 let zeroBigInt = toBigInt(0)
1717
1818 let oneBigInt = toBigInt(1)
1919
2020 func asAnyList (val) = match val {
2121 case valAnyLyst: List[Any] =>
2222 valAnyLyst
2323 case _ =>
2424 throw("fail to cast into List[Any]")
2525 }
2626
2727
2828 func asInt (val) = match val {
2929 case valInt: Int =>
3030 valInt
3131 case _ =>
3232 throw("fail to cast into Int")
3333 }
3434
3535
3636 func asString (val) = match val {
3737 case valStr: String =>
3838 valStr
3939 case _ =>
4040 throw("fail to cast into Int")
4141 }
4242
4343
4444 func asByteVector (val) = match val {
4545 case valBin: ByteVector =>
4646 valBin
4747 case _ =>
4848 throw("fail to cast into Int")
4949 }
5050
5151
5252 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (("mandatory this." + key) + " is not defined"))
5353
5454
5555 func getStringByAddressOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined"))
5656
5757
5858 func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
5959
6060
6161 func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
6262
6363
6464 func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined"))
6565
6666
6767 func getBigIntFromStringOrZero (address,key) = value(parseBigInt(valueOrElse(getString(address, key), "0")))
6868
6969
7070 func getBigIntFromStringOrDefault (address,key,defaultVal) = match getString(address, key) {
7171 case s: String =>
7272 value(parseBigInt(s))
7373 case _: Unit =>
7474 defaultVal
7575 case _ =>
7676 throw("Match error")
7777 }
7878
7979
8080 func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULT18, toBigInt(origScaleMult))
8181
8282
8383 func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULT18))
8484
8585
8686 func keyFactoryAddress () = "%s%s__config__factoryAddress"
87+
88+
89+func keyVotingEmissionContract () = "%s__votingEmissionContract"
8790
8891
8992 let IdxFactoryCfgStakingDapp = 1
9093
9194 let IdxFactoryCfgBoostingDapp = 2
9295
9396 let IdxFactoryCfgIdoDapp = 3
9497
9598 let IdxFactoryCfgTeamDapp = 4
9699
97100 let IdxFactoryCfgEmissionDapp = 5
98101
99102 let IdxFactoryCfgRestDapp = 6
100103
101104 let IdxFactoryCfgSlippageDapp = 7
102105
103106 func keyFactoryCfg () = "%s__factoryConfig"
104107
105108
106109 func keyManagerPublicKey () = "%s__managerPublicKey"
107110
108111
109112 func keyMigratorPublicKey () = "%s__migratorPublicKey"
110113
111114
112115 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
113116
114117
115118 func keyStablePoolAddonAddr () = "%s__stablePoolAddonAddr"
116119
117120
118121 func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
119122
120123
121124 func keyFactoryLpList () = "%s__lpTokensList"
122125
123126
124127 func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
125128
126129
127130 func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
128131
129132
130133 func readLpList (factory) = split(valueOrElse(getString(factory, keyFactoryLpList()), ""), SEP)
131134
132135
133136 func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP)
134137
135138
136139 func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
137140
138141
139142 func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
140143
141144
142145 func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
143146
144147
145148 func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
146149
147150
148151 func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
149152
150153
151154 func keyEmissionStartBlock () = "%s%s__emission__startBlock"
152155
153156
154157 func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
155158
156159
157160 func keyEmissionEndBlock () = "%s%s__emission__endBlock"
158161
159162
160163 func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP)
161164
162165
163166 func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr)
164167
165168
166169 func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP)
167170
168171
169172 func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP)
170173
171174
172175 func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP)
173176
174177
175178 func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed__total", lpAssetIdStr], SEP)
176179
177180
178181 func readStaked (key) = valueOrElse(getInteger(this, key), 0)
179182
180183
181184 func keyLastTotalLpBalance (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "bal"], SEP)
182185
183186
184187 func keyLastUserLpBalance (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "bal"], SEP)
185188
186189
187190 func keyTotalLpBalanceIntegral (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "balINT"], SEP)
188191
189192
190193 func keyUserLpBalanceIntegral (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "balINT"], SEP)
191194
192195
193196 func keyTotalLpBalanceIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "lastUpd"], SEP)
194197
195198
196199 func keyUserLpBalanceIntegralLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "lastUpd"], SEP)
197200
198201
199202 func keyWxPerLpIntegral (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpInt"], SEP)
200203
201204
202205 func keyWxPerLpIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpIntH"], SEP)
203206
204207
205208 func keyWxToClaimUser (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpInt"], SEP)
206209
207210
208211 func keyWxPerLpIntegralUserLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpIntH"], SEP)
209212
210213
211214 func keyWxPerLp (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLp"], SEP)
212215
213216
214217 func keyWxPerLpX18 (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLpX18"], SEP)
215218
216219
217220 func keyWxPerLpIntegralUserLast (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "uIntL"], SEP)
218221
219222
220223 func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP)
221224
222225
223226 func formatHistoryRecord (userAddress,lpAssetId,type,amount) = makeString(["%s%s%s%d%d%d", userAddress, lpAssetId, type, toString(height), toString(lastBlock.timestamp), toString(amount)], SEP)
224227
225228
226229 func OperationHistoryEntry (type,userAddress,lpAssetId,amount,txId) = StringEntry(keyOperationHistoryRecord(type, userAddress, toBase58String(txId)), formatHistoryRecord(userAddress, lpAssetId, type, amount))
227230
228231
229232 let factoryAddress = getStringOrFail(this, keyFactoryAddress())
230233
231234 let factoryContract = addressFromStringValue(factoryAddress)
232235
233236 let factoryCfg = readFactoryCfgOrFail(factoryContract)
234237
235238 let emissionContract = getEmissionAddressOrFail(factoryCfg)
236239
237240 let boostingContract = getBoostingAddressOrFail(factoryCfg)
238241
242+func keyNextUser (lpAssetId) = makeString(["%s%s", lpAssetId, "nextUser"], SEP)
243+
244+
245+func getUsersListName (lpAssetId) = makeString(["users", lpAssetId], SEP)
246+
247+
248+func keyListHead (listName) = makeString(["%s%s%s", listName, "head"], SEP)
249+
250+
251+func keyListSize (listName) = makeString(["%s%s%s", listName, "size"], SEP)
252+
253+
254+func keyListPrev (listName,id) = makeString(["%s%s%s%s", listName, id, "prev"], SEP)
255+
256+
257+func keyListNext (listName,id) = makeString(["%s%s%s%s", listName, id, "next"], SEP)
258+
259+
260+func containsNode (listName,id) = {
261+ let headOrUnit = getString(this, keyListHead(listName))
262+ let prevOrUnit = getString(this, keyListPrev(listName, id))
263+ let nextOrUnit = getString(this, keyListNext(listName, id))
264+ if (if ((id == valueOrElse(headOrUnit, "")))
265+ then true
266+ else (prevOrUnit != unit))
267+ then true
268+ else (nextOrUnit != unit)
269+ }
270+
271+
272+func insertNodeActions (listName,id) = {
273+ let headOrUnit = getString(this, keyListHead(listName))
274+ let listSize = valueOrElse(getInteger(this, keyListSize(listName)), 0)
275+ let checkNode = if (!(containsNode(listName, id)))
276+ then true
277+ else throw("Node exists")
278+ if ((checkNode == checkNode))
279+ then (([IntegerEntry(keyListSize(listName), (listSize + 1))] ++ (if ((headOrUnit != unit))
280+ then [StringEntry(keyListNext(listName, id), value(headOrUnit)), StringEntry(keyListPrev(listName, value(headOrUnit)), id)]
281+ else nil)) ++ [StringEntry(keyListHead(listName), id)])
282+ else throw("Strict value is not equal to itself.")
283+ }
284+
285+
286+func deleteNodeActions (listName,id) = {
287+ let headOrUnit = getString(this, keyListHead(listName))
288+ let listSize = valueOrElse(getInteger(this, keyListSize(listName)), 0)
289+ let prevOrUnit = getString(this, keyListPrev(listName, id))
290+ let nextOrUnit = getString(this, keyListNext(listName, id))
291+ ([IntegerEntry(keyListSize(listName), (listSize - 1))] ++ (if (if ((prevOrUnit != unit))
292+ then (nextOrUnit != unit)
293+ else false)
294+ then [StringEntry(keyListNext(listName, value(prevOrUnit)), value(nextOrUnit)), StringEntry(keyListPrev(listName, value(nextOrUnit)), value(prevOrUnit)), DeleteEntry(keyListPrev(listName, id)), DeleteEntry(keyListNext(listName, id))]
295+ else if ((nextOrUnit != unit))
296+ then [StringEntry(keyListHead(listName), value(nextOrUnit)), DeleteEntry(keyListNext(listName, id)), DeleteEntry(keyListPrev(listName, value(nextOrUnit)))]
297+ else if ((prevOrUnit != unit))
298+ then [DeleteEntry(keyListPrev(listName, id)), DeleteEntry(keyListNext(listName, value(prevOrUnit)))]
299+ else if ((id == valueOrElse(headOrUnit, "")))
300+ then [DeleteEntry(keyListHead(listName))]
301+ else throw(((("invalid node: " + listName) + ".") + id))))
302+ }
303+
304+
239305 func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
240306 then (stakedByUser > zeroBigInt)
241307 else false)
242308 then zeroBigInt
243309 else if ((stakedByUser == zeroBigInt))
244310 then wxPerLpIntegralNew
245311 else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > zeroBigInt))
246312 then (stakedByUser > zeroBigInt)
247313 else false)
248314 then value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))
249315 else throw("calcWxPerLpIntegralUserLast: unexpected state")
250316
251317
252318 func refreshPoolINTEGRALS (lpAssetIdStr,poolAddressStr,lpDeltaAmount) = {
253319 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
254320 let stakedTotal = toBigInt(readStaked(stakedTotalKEY))
255321 let nonZeroStakedTotal = if ((stakedTotal == zeroBigInt))
256322 then oneBigInt
257323 else stakedTotal
258324 let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
259325 let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
260326 let MULT3 = 1000
261327 let wxEmissionPerBlockX3 = (getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent()) * MULT3)
262328 let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3))
263329 let wxPerLpIntegralKEY = keyWxPerLpIntegral(lpAssetIdStr)
264330 let wxPerLpIntegralLastUpdHeightKEY = keyWxPerLpIntegralLastUpdHeight(lpAssetIdStr)
265331 let wxPerLpKEY = keyWxPerLp(lpAssetIdStr)
266332 let wxPerLpIntegralLastUpdHeight = getIntOrDefault(this, wxPerLpIntegralLastUpdHeightKEY, emissionStartBlock)
267333 let wxPerLpIntegral = getBigIntFromStringOrZero(this, wxPerLpIntegralKEY)
268334 let wxPerLpOrZeroX3 = 0
269335 let dh = max([(height - wxPerLpIntegralLastUpdHeight), 0])
270336 let wxPerLpX3 = if ((wxPerLpOrZeroX3 != 0))
271337 then toBigInt(wxPerLpOrZeroX3)
272338 else fraction(toBigInt(poolWxEmissionPerBlockX3), toBigInt(MULT8), nonZeroStakedTotal)
273339 let stakedTotalNew = (stakedTotal + toBigInt(lpDeltaAmount))
274340 let nonZeroStakedTotalNew = if ((stakedTotalNew == zeroBigInt))
275341 then oneBigInt
276342 else stakedTotalNew
277343 let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * toBigInt(dh)))
278344 let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
279345 let wxPerLpIntegralLastUpdHeightNew = height
280- let debug = makeString([toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), toString(poolWxEmissionPerBlockX3), toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
346+ let debug = makeString([toString(wxPerLpIntegralNew), toString(dh), toString(wxPerLpX3), toString(stakedTotal), toString(poolWxEmissionPerBlockX3), toString(wxEmissionPerBlockX3), toString(poolWeight)], "::")
281347 $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
282348 }
283349
284350
285351 func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
286- let $t01150611628 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
287- let wxPerLpIntegralNew = $t01150611628._1
288- let poolIntegralSTATE = $t01150611628._2
289- let poolDEBUG = $t01150611628._3
352+ let $t01430214424 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
353+ let wxPerLpIntegralNew = $t01430214424._1
354+ let poolIntegralSTATE = $t01430214424._2
355+ let poolDEBUG = $t01430214424._3
290356 let MULT3 = 1000
291357 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
292358 let stakedByUser = readStaked(stakedByUserKEY)
293359 let wxToClaimUserKEY = keyWxToClaimUser(lpAssetIdStr, userAddressStr)
294360 let wxPerLpIntegralUserLastUpdHeightKEY = keyWxPerLpIntegralUserLastUpdHeight(lpAssetIdStr, userAddressStr)
295361 let wxPerLpIntegralUserLastKEY = keyWxPerLpIntegralUserLast(lpAssetIdStr, userAddressStr)
296362 let wxToClaimUser = getBigIntFromStringOrZero(this, wxToClaimUserKEY)
297363 let wxPerLpIntegralUserLastUpdHeightOrZero = getIntOrZero(this, wxPerLpIntegralUserLastUpdHeightKEY)
298364 let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(toBigInt(stakedByUser), toBigInt(wxPerLpIntegralUserLastUpdHeightOrZero), wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
299365 let MULT11 = (MULT8 * MULT3)
300366 let wxToClaimUserNew = max([(wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11))), zeroBigInt])
301367 let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
302368 let wxPerLpIntegralUserLastUpdHeightNew = height
303- let debug = makeString(["wxToClaimUser", toString(wxToClaimUser), "wxPerLpInteg", toString(wxPerLpIntegralUserLastUpdHeightOrZero), "this.getString", toString(value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))), "wxPerLpIntegralNew", toString(wxPerLpIntegralNew), "wxToClaimUserNew", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast", toString(wxPerLpIntegralUserLast), toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
369+ let debug = makeString([toString(wxToClaimUser), toString(wxPerLpIntegralUserLast), toString(stakedByUser), poolDEBUG, toString(height)], "::")
304370 $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
305371 }
306372
307373
308374 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
309375 case s: String =>
310376 fromBase58String(s)
311377 case _: Unit =>
312378 unit
313379 case _ =>
314380 throw("Match error")
315381 }
316382
317383
318384 func migratorPublicKeyOrUnit () = match getString(keyMigratorPublicKey()) {
319385 case s: String =>
320386 fromBase58String(s)
321387 case _: Unit =>
322388 unit
323389 case _ =>
324390 throw("Match error")
325391 }
326392
327393
328394 func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) {
329395 case s: String =>
330396 fromBase58String(s)
331397 case _: Unit =>
332398 unit
333399 case _ =>
334400 throw("Match error")
335401 }
336402
337403
338-func mustManager (i) = {
339- let pd = throw("Permission denied")
340- match managerPublicKeyOrUnit() {
341- case pk: ByteVector =>
342- if ((i.callerPublicKey == pk))
343- then true
344- else pd
345- case _: Unit =>
346- if ((i.caller == this))
347- then true
348- else pd
349- case _ =>
350- throw("Match error")
351- }
352- }
404+let permissionDeniedError = throw("Permission denied")
405+
406+func mustThis (i) = if ((i.caller == this))
407+ then true
408+ else permissionDeniedError
409+
410+
411+func mustManager (i) = match managerPublicKeyOrUnit() {
412+ case pk: ByteVector =>
413+ if ((i.callerPublicKey == pk))
414+ then true
415+ else permissionDeniedError
416+ case _: Unit =>
417+ if ((i.caller == this))
418+ then true
419+ else permissionDeniedError
420+ case _ =>
421+ throw("Match error")
422+}
353423
354424
355425 @Callable(i)
356426 func constructor (factoryAddressStr) = {
357427 let checkCaller = mustManager(i)
358428 if ((checkCaller == checkCaller))
359429 then [StringEntry(keyFactoryAddress(), factoryAddressStr)]
430+ else throw("Strict value is not equal to itself.")
431+ }
432+
433+
434+
435+@Callable(i)
436+func constructorV2 (votingEmissionContract) = {
437+ let cheks = [mustManager(i), if ((addressFromString(votingEmissionContract) != unit))
438+ then true
439+ else "invalid voting emission contract address"]
440+ if ((cheks == cheks))
441+ then [StringEntry(keyVotingEmissionContract(), votingEmissionContract)]
360442 else throw("Strict value is not equal to itself.")
361443 }
362444
363445
364446
365447 @Callable(i)
366448 func setManager (pendingManagerPublicKey) = {
367449 let checkCaller = mustManager(i)
368450 if ((checkCaller == checkCaller))
369451 then {
370452 let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey)
371453 if ((checkManagerPublicKey == checkManagerPublicKey))
372454 then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)]
373455 else throw("Strict value is not equal to itself.")
374456 }
375457 else throw("Strict value is not equal to itself.")
376458 }
377459
378460
379461
380462 @Callable(i)
381463 func confirmManager () = {
382464 let pm = pendingManagerPublicKeyOrUnit()
383465 let hasPM = if (isDefined(pm))
384466 then true
385467 else throw("No pending manager")
386468 if ((hasPM == hasPM))
387469 then {
388470 let checkPM = if ((i.callerPublicKey == value(pm)))
389471 then true
390472 else throw("You are not pending manager")
391473 if ((checkPM == checkPM))
392474 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
393475 else throw("Strict value is not equal to itself.")
394476 }
395477 else throw("Strict value is not equal to itself.")
396478 }
397479
398480
399481
400482 @Callable(i)
401483 func stake () = if ((size(i.payments) != 1))
402484 then throw("invalid payment - exact one payment must be attached")
403485 else {
404486 let pmt = i.payments[0]
405487 let lpAssetId = value(pmt.assetId)
406488 let lpAssetIdStr = toBase58String(lpAssetId)
407489 let amount = pmt.amount
408490 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
409491 let callerStr = toString(i.caller)
410492 let userAddressStr = if ((callerStr == poolAddressStr))
411493 then toString(i.originCaller)
412494 else callerStr
413495 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
414496 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
415497 let stakedByUser = readStaked(stakedByUserKEY)
416498 let stakedTotal = readStaked(stakedTotalKEY)
417- let $t01619616313 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
418- let wxToClaimUserNew = $t01619616313._1
419- let integralSTATE = $t01619616313._2
420- let debug = $t01619616313._3
421- ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
499+ let $t01903419151 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
500+ let wxToClaimUserNew = $t01903419151._1
501+ let integralSTATE = $t01903419151._2
502+ let debug = $t01903419151._3
503+ let listName = getUsersListName(lpAssetIdStr)
504+ let listActions = if (containsNode(listName, userAddressStr))
505+ then nil
506+ else insertNodeActions(listName, userAddressStr)
507+ (([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE) ++ listActions)
422508 }
423509
424510
425511
426512 @Callable(i)
427513 func unstake (lpAssetIdStr,amount) = {
428514 let lpAssetId = fromBase58String(lpAssetIdStr)
429515 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
430516 let poolAddon = valueOrElse(getString(this, keyStablePoolAddonAddr()), poolAddressStr)
431517 let callerStr = toString(i.caller)
432518 let userAddressStr = if (if ((callerStr == poolAddressStr))
433519 then true
434520 else (callerStr == poolAddon))
435521 then toString(i.originCaller)
436522 else callerStr
437523 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
438524 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
439525 let stakedByUser = readStaked(stakedByUserKEY)
440526 let stakedTotal = readStaked(stakedTotalKEY)
441- let $t01745017568 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
442- let wxToClaimUserNew = $t01745017568._1
443- let integralSTATE = $t01745017568._2
444- let debug = $t01745017568._3
527+ let $t02048620604 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
528+ let wxToClaimUserNew = $t02048620604._1
529+ let integralSTATE = $t02048620604._2
530+ let debug = $t02048620604._3
531+ let listName = getUsersListName(lpAssetIdStr)
532+ let listActions = if (containsNode(listName, userAddressStr))
533+ then deleteNodeActions(listName, userAddressStr)
534+ else nil
445535 if ((amount > stakedByUser))
446536 then throw("passed amount is less then available")
447- else ([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
537+ else (([IntegerEntry(stakedByUserKEY, (stakedByUser - amount)), IntegerEntry(stakedTotalKEY, (stakedTotal - amount)), ScriptTransfer(i.caller, amount, lpAssetId), OperationHistoryEntry("unstake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE) ++ listActions)
448538 }
449539
450540
451541
452542 @Callable(i)
453543 func claimWx (lpAssetIdStr) = {
454- let userAddress = i.caller
455544 let userAddressStr = toString(i.caller)
456- let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
457- let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
458- let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
459- let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
460- let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
461- let claimedByUser = getBigIntFromStringOrZero(this, claimedByUserKEY)
462- let claimedByUserMinReward = getBigIntFromStringOrZero(this, claimedByUserMinRewardKEY)
463- let claimedByUserBoostReward = getBigIntFromStringOrZero(this, claimedByUserBoostRewardKEY)
464- let claimedTotal = getBigIntFromStringOrZero(this, claimedTotalKEY)
465- let $t01881218924 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
466- let wxToClaimUserNew = $t01881218924._1
467- let integralSTATE = $t01881218924._2
468- let debug = $t01881218924._3
469- let availableToClaim = max([(wxToClaimUserNew - claimedByUser), zeroBigInt])
470- if ((zeroBigInt >= availableToClaim))
471- then throw("nothing to claim")
472- else {
473- let wxAmountBoostTotal = max([asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0]), 0])
474- let minRewardPart = availableToClaim
475- let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
476- let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [toInt(minRewardPart)], nil))[0])
477- let emitBoost = asAnyList(invoke(emissionContract, "emit", [toInt(boostRewardPart)], nil))
478- if ((emitBoost == emitBoost))
479- then {
480- let claimedByUserValue = (claimedByUser + availableToClaim)
481- let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
482- let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
483- let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
545+ let result = invoke(this, "claimWxINTERNAL", [lpAssetIdStr, userAddressStr], nil)
546+ $Tuple2(nil, result)
547+ }
548+
549+
550+
551+@Callable(i)
552+func claimWxINTERNAL (lpAssetIdStr,userAddressStr) = {
553+ let checkCaller = mustThis(i)
554+ if ((checkCaller == checkCaller))
555+ then {
556+ let userAddress = valueOrErrorMessage(addressFromString(userAddressStr), "claimWxINTERNAL: invalid user address")
557+ let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
558+ let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
559+ let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
560+ let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
561+ let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
562+ let claimedByUser = getBigIntFromStringOrZero(this, claimedByUserKEY)
563+ let claimedByUserMinReward = getBigIntFromStringOrZero(this, claimedByUserMinRewardKEY)
564+ let claimedByUserBoostReward = getBigIntFromStringOrZero(this, claimedByUserBoostRewardKEY)
565+ let claimedTotal = getBigIntFromStringOrZero(this, claimedTotalKEY)
566+ let $t02235222464 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
567+ let wxToClaimUserNew = $t02235222464._1
568+ let integralSTATE = $t02235222464._2
569+ let debug = $t02235222464._3
570+ let availableToClaim = max([(wxToClaimUserNew - claimedByUser), zeroBigInt])
571+ if ((zeroBigInt >= availableToClaim))
572+ then throw("nothing to claim")
573+ else {
574+ let wxAmountBoostTotal = max([asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0]), 0])
575+ let minRewardPart = availableToClaim
576+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
577+ let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [toInt(minRewardPart)], nil))[0])
578+ let emitBoost = asAnyList(invoke(emissionContract, "emit", [toInt(boostRewardPart)], nil))
579+ if ((emitBoost == emitBoost))
580+ then {
581+ let claimedByUserValue = (claimedByUser + availableToClaim)
582+ let claimedByUserMinRewardPlusPart = (claimedByUserMinReward + minRewardPart)
583+ let claimedByUserBoostRewardPlusBoostRewardPart = (claimedByUserMinReward + minRewardPart)
584+ let claimedTotalPlusAvailableToClaim = (claimedByUserMinReward + minRewardPart)
484585 [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)]
586+ }
587+ else throw("Strict value is not equal to itself.")
485588 }
486- else throw("Strict value is not equal to itself.")
487589 }
590+ else throw("Strict value is not equal to itself.")
488591 }
489592
490593
491594
492595 @Callable(i)
493596 func claimWxREADONLY (lpAssetIdStr,userAddressStr) = {
494597 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
495598 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
496599 let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
497600 let stakedByUser = readStaked(stakedByUserKEY)
498601 let stakedTotal = readStaked(stakedTotalKEY)
499602 let claimedByUser = getBigIntFromStringOrZero(this, claimedByUserKEY)
500603 let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
501604 let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
502605 let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
503606 let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
504607 let passedBlocks = if ((emissionStartBlock > height))
505608 then 0
506609 else (height - emissionStartBlock)
507610 let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
508611 let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
509- let $t02156621678 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
510- let wxToClaimUserNew = $t02156621678._1
511- let integralSTATE = $t02156621678._2
512- let debug = $t02156621678._3
612+ let $t02510625218 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
613+ let wxToClaimUserNew = $t02510625218._1
614+ let integralSTATE = $t02510625218._2
615+ let debug = $t02510625218._3
513616 let availableToClaim = max([(wxToClaimUserNew - claimedByUser), zeroBigInt])
514617 let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
515618 let wxAmountBoostTotal = max([asInt(boostInvResult[0]), 0])
516619 let boostDebug = asString(boostInvResult[1])
517620 let minRewardPart = availableToClaim
518621 let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
519622 let totalReward = (minRewardPart + boostRewardPart)
520- $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))
623+ $Tuple2(nil, makeString(["%s%s%d%d%d%d%s", lpAssetIdStr, userAddressStr, toString(totalReward), toString(claimedByUser), toString(minRewardPart), toString(boostRewardPart), ((((debug + "::") + toString(userWxReward)) + "::BOOST::") + boostDebug)], SEP))
624+ }
625+
626+
627+
628+@Callable(i)
629+func usersListTraversal (lpAssetId) = {
630+ let checkCaller = if ((toBase58String(i.caller.bytes) == valueOrElse(getString(this, keyVotingEmissionContract()), "")))
631+ then true
632+ else mustManager(i)
633+ if ((checkCaller == checkCaller))
634+ then {
635+ let listName = getUsersListName(lpAssetId)
636+ let userOrUnit = getString(keyNextUser(lpAssetId))
637+ let headOrUnit = getString(keyListHead(listName))
638+ match userOrUnit {
639+ case _: Unit =>
640+ match headOrUnit {
641+ case _: Unit =>
642+ $Tuple2(nil, false)
643+ case head: String =>
644+ $Tuple2([StringEntry(keyNextUser(lpAssetId), head)], true)
645+ case _ =>
646+ throw("Match error")
647+ }
648+ case userAddress: String =>
649+ let claimedByUser = getBigIntFromStringOrZero(this, keyClaimedByUser(lpAssetId, userAddress))
650+ let poolAddress = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetId))
651+ let $t02681326916 = refreshINTEGRALS(lpAssetId, userAddress, poolAddress, 0)
652+ let wxToClaimUserNew = $t02681326916._1
653+ let integralSTATE = $t02681326916._2
654+ let debug = $t02681326916._3
655+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
656+ let r = if ((availableToClaim > zeroBigInt))
657+ then invoke(this, "claimWxINTERNAL", [lpAssetId, userAddress], nil)
658+ else unit
659+ if ((r == r))
660+ then {
661+ let nextUserOrUnit = getString(keyListNext(listName, userAddress))
662+ match nextUserOrUnit {
663+ case _: Unit =>
664+ $Tuple2([DeleteEntry(keyNextUser(lpAssetId))], false)
665+ case nextUser: String =>
666+ $Tuple2([StringEntry(keyNextUser(lpAssetId), nextUser)], true)
667+ case _ =>
668+ throw("Match error")
669+ }
670+ }
671+ else throw("Strict value is not equal to itself.")
672+ case _ =>
673+ throw("Match error")
674+ }
675+ }
676+ else throw("Strict value is not equal to itself.")
521677 }
522678
523679
524680
525681 @Callable(i)
526682 func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
527683 then throw("permissions denied")
528684 else {
529- let $t02260922719 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
530- let wxPerLpIntegralNew = $t02260922719._1
531- let poolIntegralSTATE = $t02260922719._2
532- let poolDEBUG = $t02260922719._3
685+ let $t02759027700 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
686+ let wxPerLpIntegralNew = $t02759027700._1
687+ let poolIntegralSTATE = $t02759027700._2
688+ let poolDEBUG = $t02759027700._3
533689 poolIntegralSTATE
534690 }
535691
536692
537693 @Verifier(tx)
538694 func verify () = {
539695 let targetPublicKey = match managerPublicKeyOrUnit() {
540696 case pk: ByteVector =>
541697 pk
542698 case _: Unit =>
543699 tx.senderPublicKey
544700 case _ =>
545701 throw("Match error")
546702 }
547703 let migratorPublicKey = match migratorPublicKeyOrUnit() {
548704 case pk: ByteVector =>
549705 pk
550706 case _: Unit =>
551707 tx.senderPublicKey
552708 case _ =>
553709 throw("Match error")
554710 }
555711 if (sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey))
556712 then true
557713 else sigVerify(tx.bodyBytes, tx.proofs[0], migratorPublicKey)
558714 }
559715

github/deemru/w8io/3ef1775 
108.96 ms