tx · 6GJFDyiBBeMWrmLmVuTwACQwiMeFL9wix6mWJk9BtMKH

3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz:  -0.02900000 Waves

2022.06.27 12:41 [2114679] smart account 3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz > SELF 0.00000000 Waves

{ "type": 13, "id": "6GJFDyiBBeMWrmLmVuTwACQwiMeFL9wix6mWJk9BtMKH", "fee": 2900000, "feeAssetId": null, "timestamp": 1656322919117, "version": 1, "sender": "3Mx3zmXrMcLFCafMuPtXAzR4ZPVeZYb6qLz", "senderPublicKey": "D28XoueZWsMfm8Y5pa6C5ZFuYoWgre2Wm8tzJANJgMnq", "proofs": [ "2FZvKR4BorV72cDZSdgEJV54qWF4ssSiNP4QrkUymcRGb1MVMzTC1VV1H2F7DUeVw3SPVBg2va8qzZxUGC5zbVBu" ], "script": "base64:BgI3CAISAwoBCBIDCgEIEgMKAQgSABIAEgQKAggBEgMKAQgSBAoCCAgSBAoCCAgSAwoBCBIECgIICF8ABlNDQUxFOAAIAAVNVUxUOACAwtcvAAdTQ0FMRTE4ABIABk1VTFQxOAkAtgIBAICAkLu61q3wDQADU0VQAgJfXwAOUE9PTFdFSUdIVE1VTFQFBU1VTFQ4AAp6ZXJvQmlnSW50CQC2AgEAAAAJb25lQmlnSW50CQC2AgEAAQEJYXNBbnlMaXN0AQN2YWwEByRtYXRjaDAFA3ZhbAMJAAECBQckbWF0Y2gwAglMaXN0W0FueV0ECnZhbEFueUx5c3QFByRtYXRjaDAFCnZhbEFueUx5c3QJAAIBAhtmYWlsIHRvIGNhc3QgaW50byBMaXN0W0FueV0BBWFzSW50AQN2YWwEByRtYXRjaDAFA3ZhbAMJAAECBQckbWF0Y2gwAgNJbnQEBnZhbEludAUHJG1hdGNoMAUGdmFsSW50CQACAQIVZmFpbCB0byBjYXN0IGludG8gSW50AQhhc1N0cmluZwEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAZ2YWxTdHIFByRtYXRjaDAFBnZhbFN0cgkAAgECFWZhaWwgdG8gY2FzdCBpbnRvIEludAEMYXNCeXRlVmVjdG9yAQN2YWwEByRtYXRjaDAFA3ZhbAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAZ2YWxCaW4FByRtYXRjaDAFBnZhbEJpbgkAAgECFWZhaWwgdG8gY2FzdCBpbnRvIEludAEPZ2V0U3RyaW5nT3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFB2FkZHJlc3MFA2tleQkArAICCQCsAgICD21hbmRhdG9yeSB0aGlzLgUDa2V5Ag8gaXMgbm90IGRlZmluZWQBGGdldFN0cmluZ0J5QWRkcmVzc09yRmFpbAIHYWRkcmVzcwNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQdhZGRyZXNzBQNrZXkJAKwCAgkArAICCQCsAgIJAKwCAgIKbWFuZGF0b3J5IAkApQgBBQdhZGRyZXNzAgEuBQNrZXkCDyBpcyBub3QgZGVmaW5lZAEMZ2V0SW50T3JaZXJvAgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmggCBQdhZGRyZXNzBQNrZXkAAAEPZ2V0SW50T3JEZWZhdWx0AwdhZGRyZXNzA2tleQpkZWZhdWx0VmFsCQELdmFsdWVPckVsc2UCCQCaCAIFB2FkZHJlc3MFA2tleQUKZGVmYXVsdFZhbAEMZ2V0SW50T3JGYWlsAgdhZGRyZXNzA2tleQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFB2FkZHJlc3MFA2tleQkArAICCQCsAgICD21hbmRhdG9yeSB0aGlzLgUDa2V5Ag8gaXMgbm90IGRlZmluZWQBGWdldEJpZ0ludEZyb21TdHJpbmdPclplcm8CB2FkZHJlc3MDa2V5CQEFdmFsdWUBCQCoAwEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUHYWRkcmVzcwUDa2V5AgEwARxnZXRCaWdJbnRGcm9tU3RyaW5nT3JEZWZhdWx0AwdhZGRyZXNzA2tleQpkZWZhdWx0VmFsBAckbWF0Y2gwCQCdCAIFB2FkZHJlc3MFA2tleQMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJAQV2YWx1ZQEJAKgDAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQpkZWZhdWx0VmFsCQACAQILTWF0Y2ggZXJyb3IBBXRvWDE4AgdvcmlnVmFsDW9yaWdTY2FsZU11bHQJALwCAwkAtgIBBQdvcmlnVmFsBQZNVUxUMTgJALYCAQUNb3JpZ1NjYWxlTXVsdAEHZnJvbVgxOAIDdmFsD3Jlc3VsdFNjYWxlTXVsdAkAoAMBCQC8AgMFA3ZhbAkAtgIBBQ9yZXN1bHRTY2FsZU11bHQFBk1VTFQxOAERa2V5RmFjdG9yeUFkZHJlc3MAAhwlcyVzX19jb25maWdfX2ZhY3RvcnlBZGRyZXNzARlrZXlWb3RpbmdFbWlzc2lvbkNvbnRyYWN0AAIaJXNfX3ZvdGluZ0VtaXNzaW9uQ29udHJhY3QAGElkeEZhY3RvcnlDZmdTdGFraW5nRGFwcAABABlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwAAIAFElkeEZhY3RvcnlDZmdJZG9EYXBwAAMAFUlkeEZhY3RvcnlDZmdUZWFtRGFwcAAEABlJZHhGYWN0b3J5Q2ZnRW1pc3Npb25EYXBwAAUAFUlkeEZhY3RvcnlDZmdSZXN0RGFwcAAGABlJZHhGYWN0b3J5Q2ZnU2xpcHBhZ2VEYXBwAAcBDWtleUZhY3RvcnlDZmcAAhElc19fZmFjdG9yeUNvbmZpZwETa2V5TWFuYWdlclB1YmxpY0tleQACFCVzX19tYW5hZ2VyUHVibGljS2V5ARRrZXlNaWdyYXRvclB1YmxpY0tleQACFSVzX19taWdyYXRvclB1YmxpY0tleQEaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkAAhslc19fcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkBFmtleVN0YWJsZVBvb2xBZGRvbkFkZHIAAhclc19fc3RhYmxlUG9vbEFkZG9uQWRkcgEaa2V5RmFjdG9yeUxwMkFzc2V0c01hcHBpbmcBCmxwQXNzZXRTdHIJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgUKbHBBc3NldFN0cgkAzAgCAh5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFA25pbAUDU0VQARBrZXlGYWN0b3J5THBMaXN0AAIQJXNfX2xwVG9rZW5zTGlzdAEma2V5RmFjdG9yeUxwQXNzZXRUb1Bvb2xDb250cmFjdEFkZHJlc3MBCmxwQXNzZXRTdHIJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgUKbHBBc3NldFN0cgkAzAgCAh5tYXBwaW5nc19fbHBBc3NldDJQb29sQ29udHJhY3QFA25pbAUDU0VQARRrZXlGYWN0b3J5UG9vbFdlaWdodAEPY29udHJhY3RBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgpwb29sV2VpZ2h0CQDMCAIFD2NvbnRyYWN0QWRkcmVzcwUDbmlsBQNTRVABCnJlYWRMcExpc3QBB2ZhY3RvcnkJALUJAgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQdmYWN0b3J5CQEQa2V5RmFjdG9yeUxwTGlzdAACAAUDU0VQARRyZWFkRmFjdG9yeUNmZ09yRmFpbAEHZmFjdG9yeQkAtQkCCQEYZ2V0U3RyaW5nQnlBZGRyZXNzT3JGYWlsAgUHZmFjdG9yeQkBDWtleUZhY3RvcnlDZmcABQNTRVABGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAEKZmFjdG9yeUNmZwkBEUBleHRyTmF0aXZlKDEwNjIpAQkAkQMCBQpmYWN0b3J5Q2ZnBRlJZHhGYWN0b3J5Q2ZnQm9vc3RpbmdEYXBwARhnZXRFbWlzc2lvbkFkZHJlc3NPckZhaWwBCmZhY3RvcnlDZmcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUKZmFjdG9yeUNmZwUZSWR4RmFjdG9yeUNmZ0VtaXNzaW9uRGFwcAEXZ2V0U3Rha2luZ0FkZHJlc3NPckZhaWwBCmZhY3RvcnlDZmcJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUKZmFjdG9yeUNmZwUYSWR4RmFjdG9yeUNmZ1N0YWtpbmdEYXBwAR5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQAAhslcyVzX19yYXRlUGVyQmxvY2tfX2N1cnJlbnQBIWtleUVtaXNzaW9uUmF0ZVBlckJsb2NrTWF4Q3VycmVudAACHiVzJXNfX3JhdGVQZXJCbG9ja01heF9fY3VycmVudAEVa2V5RW1pc3Npb25TdGFydEJsb2NrAAIaJXMlc19fZW1pc3Npb25fX3N0YXJ0QmxvY2sBG2tleUVtaXNzaW9uRHVyYXRpb25JbkJsb2NrcwACGCVzJXNfX2VtaXNzaW9uX19kdXJhdGlvbgETa2V5RW1pc3Npb25FbmRCbG9jawACGCVzJXNfX2VtaXNzaW9uX19lbmRCbG9jawEPa2V5U3Rha2VkQnlVc2VyAg51c2VyQWRkcmVzc1N0cgxscEFzc2V0SWRTdHIJALkJAgkAzAgCAg4lcyVzJXNfX3N0YWtlZAkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCBQxscEFzc2V0SWRTdHIFA25pbAUDU0VQAQ5rZXlTdGFrZWRUb3RhbAEMbHBBc3NldElkU3RyCQCsAgICFyVzJXMlc19fc3Rha2VkX190b3RhbF9fBQxscEFzc2V0SWRTdHIBEGtleUNsYWltZWRCeVVzZXICDGxwQXNzZXRJZFN0cg51c2VyQWRkcmVzc1N0cgkAuQkCCQDMCAICDyVzJXMlc19fY2xhaW1lZAkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCBQxscEFzc2V0SWRTdHIFA25pbAUDU0VQARlrZXlDbGFpbWVkQnlVc2VyTWluUmV3YXJkAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIJALkJAgkAzAgCAhglcyVzJXNfX2NsYWltZWRNaW5SZXdhcmQJAMwIAgUOdXNlckFkZHJlc3NTdHIJAMwIAgUMbHBBc3NldElkU3RyBQNuaWwFA1NFUAEba2V5Q2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIJALkJAgkAzAgCAholcyVzJXNfX2NsYWltZWRCb29zdFJld2FyZAkAzAgCBQ51c2VyQWRkcmVzc1N0cgkAzAgCBQxscEFzc2V0SWRTdHIFA25pbAUDU0VQAQ9rZXlDbGFpbWVkVG90YWwBDGxwQXNzZXRJZFN0cgkAuQkCCQDMCAICFiVzJXMlc19fY2xhaW1lZF9fdG90YWwJAMwIAgUMbHBBc3NldElkU3RyBQNuaWwFA1NFUAEKcmVhZFN0YWtlZAEDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFA2tleQAAARVrZXlMYXN0VG90YWxMcEJhbGFuY2UBCWxwQXNzZXRJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgIFdG90YWwJAMwIAgIDYmFsBQNuaWwFA1NFUAEUa2V5TGFzdFVzZXJMcEJhbGFuY2UCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIDYmFsBQNuaWwFA1NFUAEZa2V5VG90YWxMcEJhbGFuY2VJbnRlZ3JhbAEJbHBBc3NldElkCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAgV0b3RhbAkAzAgCAgZiYWxJTlQFA25pbAUDU0VQARhrZXlVc2VyTHBCYWxhbmNlSW50ZWdyYWwCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIGYmFsSU5UBQNuaWwFA1NFUAEma2V5VG90YWxMcEJhbGFuY2VJbnRlZ3JhbExhc3RVcGRIZWlnaHQBCWxwQXNzZXRJZAkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgIFdG90YWwJAMwIAgIHbGFzdFVwZAUDbmlsBQNTRVABJWtleVVzZXJMcEJhbGFuY2VJbnRlZ3JhbExhc3RVcGRIZWlnaHQCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIHbGFzdFVwZAUDbmlsBQNTRVABEmtleVd4UGVyTHBJbnRlZ3JhbAEJbHBBc3NldElkCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgUJbHBBc3NldElkCQDMCAICBmNvbW1vbgkAzAgCAgVscEludAUDbmlsBQNTRVABH2tleVd4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHQBCWxwQXNzZXRJZAkAuQkCCQDMCAICCCVzJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAgZjb21tb24JAMwIAgIGbHBJbnRIBQNuaWwFA1NFUAEQa2V5V3hUb0NsYWltVXNlcgIJbHBBc3NldElkC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgUJbHBBc3NldElkCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAICBWxwSW50BQNuaWwFA1NFUAEja2V5V3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHQCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICCCVzJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCAgZscEludEgFA25pbAUDU0VQAQprZXlXeFBlckxwAQlscEFzc2V0SWQJALkJAgkAzAgCAgIlcwkAzAgCBQlscEFzc2V0SWQJAMwIAgIHd3hQZXJMcAUDbmlsBQNTRVABDWtleVd4UGVyTHBYMTgBCWxwQXNzZXRJZAkAuQkCCQDMCAICAiVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAgp3eFBlckxwWDE4BQNuaWwFA1NFUAEaa2V5V3hQZXJMcEludGVncmFsVXNlckxhc3QCCWxwQXNzZXRJZAt1c2VyQWRkcmVzcwkAuQkCCQDMCAICCCVzJXMlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCAgV1SW50TAUDbmlsBQNTRVABGWtleU9wZXJhdGlvbkhpc3RvcnlSZWNvcmQDBHR5cGULdXNlckFkZHJlc3MGdHhJZDU4CQC5CQIJAMwIAgIRJXMlcyVzJXNfX2hpc3RvcnkJAMwIAgUEdHlwZQkAzAgCBQt1c2VyQWRkcmVzcwkAzAgCBQZ0eElkNTgFA25pbAUDU0VQARNmb3JtYXRIaXN0b3J5UmVjb3JkBAt1c2VyQWRkcmVzcwlscEFzc2V0SWQEdHlwZQZhbW91bnQJALkJAgkAzAgCAgwlcyVzJXMlZCVkJWQJAMwIAgULdXNlckFkZHJlc3MJAMwIAgUJbHBBc3NldElkCQDMCAIFBHR5cGUJAMwIAgkApAMBBQZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCkAwEFBmFtb3VudAUDbmlsBQNTRVABFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQUEdHlwZQt1c2VyQWRkcmVzcwlscEFzc2V0SWQGYW1vdW50BHR4SWQJAQtTdHJpbmdFbnRyeQIJARlrZXlPcGVyYXRpb25IaXN0b3J5UmVjb3JkAwUEdHlwZQULdXNlckFkZHJlc3MJANgEAQUEdHhJZAkBE2Zvcm1hdEhpc3RvcnlSZWNvcmQEBQt1c2VyQWRkcmVzcwUJbHBBc3NldElkBQR0eXBlBQZhbW91bnQADmZhY3RvcnlBZGRyZXNzCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwkBEWtleUZhY3RvcnlBZGRyZXNzAAAPZmFjdG9yeUNvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBBQ5mYWN0b3J5QWRkcmVzcwAKZmFjdG9yeUNmZwkBFHJlYWRGYWN0b3J5Q2ZnT3JGYWlsAQUPZmFjdG9yeUNvbnRyYWN0ABBlbWlzc2lvbkNvbnRyYWN0CQEYZ2V0RW1pc3Npb25BZGRyZXNzT3JGYWlsAQUKZmFjdG9yeUNmZwAQYm9vc3RpbmdDb250cmFjdAkBGGdldEJvb3N0aW5nQWRkcmVzc09yRmFpbAEFCmZhY3RvcnlDZmcBC2tleU5leHRVc2VyAQlscEFzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIFCWxwQXNzZXRJZAkAzAgCAghuZXh0VXNlcgUDbmlsBQNTRVABEGdldFVzZXJzTGlzdE5hbWUBCWxwQXNzZXRJZAkAuQkCCQDMCAICBXVzZXJzCQDMCAIFCWxwQXNzZXRJZAUDbmlsBQNTRVABC2tleUxpc3RIZWFkAQhsaXN0TmFtZQkAuQkCCQDMCAICBiVzJXMlcwkAzAgCBQhsaXN0TmFtZQkAzAgCAgRoZWFkBQNuaWwFA1NFUAELa2V5TGlzdFNpemUBCGxpc3ROYW1lCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAIFCGxpc3ROYW1lCQDMCAICBHNpemUFA25pbAUDU0VQAQtrZXlMaXN0UHJldgIIbGlzdE5hbWUCaWQJALkJAgkAzAgCAgglcyVzJXMlcwkAzAgCBQhsaXN0TmFtZQkAzAgCBQJpZAkAzAgCAgRwcmV2BQNuaWwFA1NFUAELa2V5TGlzdE5leHQCCGxpc3ROYW1lAmlkCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgUIbGlzdE5hbWUJAMwIAgUCaWQJAMwIAgIEbmV4dAUDbmlsBQNTRVABDGNvbnRhaW5zTm9kZQIIbGlzdE5hbWUCaWQECmhlYWRPclVuaXQJAJ0IAgUEdGhpcwkBC2tleUxpc3RIZWFkAQUIbGlzdE5hbWUECnByZXZPclVuaXQJAJ0IAgUEdGhpcwkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUFAmlkBApuZXh0T3JVbml0CQCdCAIFBHRoaXMJAQtrZXlMaXN0TmV4dAIFCGxpc3ROYW1lBQJpZAMDCQAAAgUCaWQJAQt2YWx1ZU9yRWxzZQIFCmhlYWRPclVuaXQCAAYJAQIhPQIFCnByZXZPclVuaXQFBHVuaXQGCQECIT0CBQpuZXh0T3JVbml0BQR1bml0ARFpbnNlcnROb2RlQWN0aW9ucwIIbGlzdE5hbWUCaWQECmhlYWRPclVuaXQJAJ0IAgUEdGhpcwkBC2tleUxpc3RIZWFkAQUIbGlzdE5hbWUECGxpc3RTaXplCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQtrZXlMaXN0U2l6ZQEFCGxpc3ROYW1lAAAECWNoZWNrTm9kZQMJAQEhAQkBDGNvbnRhaW5zTm9kZQIFCGxpc3ROYW1lBQJpZAYJAAIBAgtOb2RlIGV4aXN0cwMJAAACBQljaGVja05vZGUFCWNoZWNrTm9kZQkAzggCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJAQtrZXlMaXN0U2l6ZQEFCGxpc3ROYW1lCQBkAgUIbGlzdFNpemUAAQUDbmlsAwkBAiE9AgUKaGVhZE9yVW5pdAUEdW5pdAkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TGlzdE5leHQCBQhsaXN0TmFtZQUCaWQJAQV2YWx1ZQEFCmhlYWRPclVuaXQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCmhlYWRPclVuaXQFAmlkBQNuaWwFA25pbAkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TGlzdEhlYWQBBQhsaXN0TmFtZQUCaWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgERZGVsZXRlTm9kZUFjdGlvbnMCCGxpc3ROYW1lAmlkBApoZWFkT3JVbml0CQCdCAIFBHRoaXMJAQtrZXlMaXN0SGVhZAEFCGxpc3ROYW1lBAhsaXN0U2l6ZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQELa2V5TGlzdFNpemUBBQhsaXN0TmFtZQAABApwcmV2T3JVbml0CQCdCAIFBHRoaXMJAQtrZXlMaXN0UHJldgIFCGxpc3ROYW1lBQJpZAQKbmV4dE9yVW5pdAkAnQgCBQR0aGlzCQELa2V5TGlzdE5leHQCBQhsaXN0TmFtZQUCaWQJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBC2tleUxpc3RTaXplAQUIbGlzdE5hbWUJAGUCBQhsaXN0U2l6ZQABBQNuaWwDAwkBAiE9AgUKcHJldk9yVW5pdAUEdW5pdAkBAiE9AgUKbmV4dE9yVW5pdAUEdW5pdAcJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleUxpc3ROZXh0AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCnByZXZPclVuaXQJAQV2YWx1ZQEFCm5leHRPclVuaXQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCm5leHRPclVuaXQJAQV2YWx1ZQEFCnByZXZPclVuaXQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUFAmlkCQDMCAIJAQtEZWxldGVFbnRyeQEJAQtrZXlMaXN0TmV4dAIFCGxpc3ROYW1lBQJpZAUDbmlsAwkBAiE9AgUKbmV4dE9yVW5pdAUEdW5pdAkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TGlzdEhlYWQBBQhsaXN0TmFtZQkBBXZhbHVlAQUKbmV4dE9yVW5pdAkAzAgCCQELRGVsZXRlRW50cnkBCQELa2V5TGlzdE5leHQCBQhsaXN0TmFtZQUCaWQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUJAQV2YWx1ZQEFCm5leHRPclVuaXQFA25pbAMJAQIhPQIFCnByZXZPclVuaXQFBHVuaXQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleUxpc3RQcmV2AgUIbGlzdE5hbWUFAmlkCQDMCAIJAQtEZWxldGVFbnRyeQEJAQtrZXlMaXN0TmV4dAIFCGxpc3ROYW1lCQEFdmFsdWUBBQpwcmV2T3JVbml0BQNuaWwDCQAAAgUCaWQJAQt2YWx1ZU9yRWxzZQIFCmhlYWRPclVuaXQCAAkAzAgCCQELRGVsZXRlRW50cnkBCQELa2V5TGlzdEhlYWQBBQhsaXN0TmFtZQUDbmlsCQACAQkArAICCQCsAgIJAKwCAgIOaW52YWxpZCBub2RlOiAFCGxpc3ROYW1lAgEuBQJpZAEbY2FsY1d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0BAxzdGFrZWRCeVVzZXImd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8Sd3hQZXJMcEludGVncmFsTmV3Gnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0S0VZAwMJAAACBSZ3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE9yWmVybwUKemVyb0JpZ0ludAkAvwICBQxzdGFrZWRCeVVzZXIFCnplcm9CaWdJbnQHBQp6ZXJvQmlnSW50AwkAAAIFDHN0YWtlZEJ5VXNlcgUKemVyb0JpZ0ludAUSd3hQZXJMcEludGVncmFsTmV3AwMJAL8CAgUmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8FCnplcm9CaWdJbnQJAL8CAgUMc3Rha2VkQnlVc2VyBQp6ZXJvQmlnSW50BwkBBXZhbHVlAQkAqAMBCQEPZ2V0U3RyaW5nT3JGYWlsAgUEdGhpcwUad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJAAIBAi1jYWxjV3hQZXJMcEludGVncmFsVXNlckxhc3Q6IHVuZXhwZWN0ZWQgc3RhdGUBFHJlZnJlc2hQb29sSU5URUdSQUxTAwxscEFzc2V0SWRTdHIOcG9vbEFkZHJlc3NTdHINbHBEZWx0YUFtb3VudAQOc3Rha2VkVG90YWxLRVkJAQ5rZXlTdGFrZWRUb3RhbAEFDGxwQXNzZXRJZFN0cgQLc3Rha2VkVG90YWwJALYCAQkBCnJlYWRTdGFrZWQBBQ5zdGFrZWRUb3RhbEtFWQQSbm9uWmVyb1N0YWtlZFRvdGFsAwkAAAIFC3N0YWtlZFRvdGFsBQp6ZXJvQmlnSW50BQlvbmVCaWdJbnQFC3N0YWtlZFRvdGFsBApwb29sV2VpZ2h0CQERQGV4dHJOYXRpdmUoMTA1MCkCBQ9mYWN0b3J5Q29udHJhY3QJARRrZXlGYWN0b3J5UG9vbFdlaWdodAEFDnBvb2xBZGRyZXNzU3RyBBJlbWlzc2lvblN0YXJ0QmxvY2sJAQxnZXRJbnRPckZhaWwCBRBlbWlzc2lvbkNvbnRyYWN0CQEVa2V5RW1pc3Npb25TdGFydEJsb2NrAAQFTVVMVDMA6AcEFHd4RW1pc3Npb25QZXJCbG9ja1gzCQBoAgkBDGdldEludE9yRmFpbAIFEGVtaXNzaW9uQ29udHJhY3QJAR5rZXlFbWlzc2lvblJhdGVQZXJCbG9ja0N1cnJlbnQABQVNVUxUMwQYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQBrAwUUd3hFbWlzc2lvblBlckJsb2NrWDMFCnBvb2xXZWlnaHQJAGgCBQ5QT09MV0VJR0hUTVVMVAADBBJ3eFBlckxwSW50ZWdyYWxLRVkJARJrZXlXeFBlckxwSW50ZWdyYWwBBQxscEFzc2V0SWRTdHIEH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkJAR9rZXlXeFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0AQUMbHBBc3NldElkU3RyBAp3eFBlckxwS0VZCQEKa2V5V3hQZXJMcAEFDGxwQXNzZXRJZFN0cgQcd3hQZXJMcEludGVncmFsTGFzdFVwZEhlaWdodAkBD2dldEludE9yRGVmYXVsdAMFBHRoaXMFH3d4UGVyTHBJbnRlZ3JhbExhc3RVcGRIZWlnaHRLRVkFEmVtaXNzaW9uU3RhcnRCbG9jawQPd3hQZXJMcEludGVncmFsCQEZZ2V0QmlnSW50RnJvbVN0cmluZ09yWmVybwIFBHRoaXMFEnd4UGVyTHBJbnRlZ3JhbEtFWQQPd3hQZXJMcE9yWmVyb1gzAAAEAmRoCQCWAwEJAMwIAgkAZQIFBmhlaWdodAUcd3hQZXJMcEludGVncmFsTGFzdFVwZEhlaWdodAkAzAgCAAAFA25pbAQJd3hQZXJMcFgzAwkBAiE9AgUPd3hQZXJMcE9yWmVyb1gzAAAJALYCAQUPd3hQZXJMcE9yWmVyb1gzCQC8AgMJALYCAQUYcG9vbFd4RW1pc3Npb25QZXJCbG9ja1gzCQC2AgEFBU1VTFQ4BRJub25aZXJvU3Rha2VkVG90YWwEDnN0YWtlZFRvdGFsTmV3CQC3AgIFC3N0YWtlZFRvdGFsCQC2AgEFDWxwRGVsdGFBbW91bnQEFW5vblplcm9TdGFrZWRUb3RhbE5ldwMJAAACBQ5zdGFrZWRUb3RhbE5ldwUKemVyb0JpZ0ludAUJb25lQmlnSW50BQ5zdGFrZWRUb3RhbE5ldwQSd3hQZXJMcEludGVncmFsTmV3CQC3AgIFD3d4UGVyTHBJbnRlZ3JhbAkAuQICBQl3eFBlckxwWDMJALYCAQUCZGgEDHd4UGVyTHBYM05ldwkAugICCQC2AgEFGHBvb2xXeEVtaXNzaW9uUGVyQmxvY2tYMwUVbm9uWmVyb1N0YWtlZFRvdGFsTmV3BB93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0TmV3BQZoZWlnaHQEBWRlYnVnCQC5CQIJAMwIAgITd3hQZXJMcEludGVncmFsTmV3PQkAzAgCCQCmAwEFEnd4UGVyTHBJbnRlZ3JhbE5ldwkAzAgCAgNkaD0JAMwIAgkApAMBBQJkaAkAzAgCAgp3eFBlckxwWDM9CQDMCAIJAKYDAQUJd3hQZXJMcFgzCQDMCAICDHN0YWtlZFRvdGFsPQkAzAgCCQCmAwEFC3N0YWtlZFRvdGFsCQDMCAICGXBvb2xXeEVtaXNzaW9uUGVyQmxvY2tYMz0JAMwIAgkApAMBBRhwb29sV3hFbWlzc2lvblBlckJsb2NrWDMJAMwIAgIVd3hFbWlzc2lvblBlckJsb2NrWDM9CQDMCAIJAKQDAQUUd3hFbWlzc2lvblBlckJsb2NrWDMJAMwIAgILcG9vbFdlaWdodD0JAMwIAgkApAMBBQpwb29sV2VpZ2h0BQNuaWwCAjo6CQCVCgMFEnd4UGVyTHBJbnRlZ3JhbE5ldwkAzAgCCQELU3RyaW5nRW50cnkCBRJ3eFBlckxwSW50ZWdyYWxLRVkJAKYDAQUSd3hQZXJMcEludGVncmFsTmV3CQDMCAIJAQxJbnRlZ2VyRW50cnkCBR93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0S0VZBR93eFBlckxwSW50ZWdyYWxMYXN0VXBkSGVpZ2h0TmV3CQDMCAIJAQtTdHJpbmdFbnRyeQIFCnd4UGVyTHBLRVkJAKYDAQUMd3hQZXJMcFgzTmV3BQNuaWwFBWRlYnVnARByZWZyZXNoSU5URUdSQUxTBAxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIOcG9vbEFkZHJlc3NTdHINbHBEZWx0YUFtb3VudAQNJHQwMTQ0NzMxNDU5NQkBFHJlZnJlc2hQb29sSU5URUdSQUxTAwUMbHBBc3NldElkU3RyBQ5wb29sQWRkcmVzc1N0cgUNbHBEZWx0YUFtb3VudAQSd3hQZXJMcEludGVncmFsTmV3CAUNJHQwMTQ0NzMxNDU5NQJfMQQRcG9vbEludGVncmFsU1RBVEUIBQ0kdDAxNDQ3MzE0NTk1Al8yBAlwb29sREVCVUcIBQ0kdDAxNDQ3MzE0NTk1Al8zBAVNVUxUMwDoBwQPc3Rha2VkQnlVc2VyS0VZCQEPa2V5U3Rha2VkQnlVc2VyAgUOdXNlckFkZHJlc3NTdHIFDGxwQXNzZXRJZFN0cgQMc3Rha2VkQnlVc2VyCQEKcmVhZFN0YWtlZAEFD3N0YWtlZEJ5VXNlcktFWQQQd3hUb0NsYWltVXNlcktFWQkBEGtleVd4VG9DbGFpbVVzZXICBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBCN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodEtFWQkBI2tleVd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0AgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgQad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJARprZXlXeFBlckxwSW50ZWdyYWxVc2VyTGFzdAIFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIEDXd4VG9DbGFpbVVzZXIJARlnZXRCaWdJbnRGcm9tU3RyaW5nT3JaZXJvAgUEdGhpcwUQd3hUb0NsYWltVXNlcktFWQQmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8JAQxnZXRJbnRPclplcm8CBQR0aGlzBSN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodEtFWQQXd3hQZXJMcEludGVncmFsVXNlckxhc3QJARtjYWxjV3hQZXJMcEludGVncmFsVXNlckxhc3QECQC2AgEFDHN0YWtlZEJ5VXNlcgkAtgIBBSZ3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodE9yWmVybwUSd3hQZXJMcEludGVncmFsTmV3BRp3eFBlckxwSW50ZWdyYWxVc2VyTGFzdEtFWQQGTVVMVDExCQBoAgUFTVVMVDgFBU1VTFQzBBB3eFRvQ2xhaW1Vc2VyTmV3CQC3AgIFDXd4VG9DbGFpbVVzZXIJALwCAwkAuAICBRJ3eFBlckxwSW50ZWdyYWxOZXcFF3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0CQC2AgEFDHN0YWtlZEJ5VXNlcgkAtgIBBQZNVUxUMTEEGnd4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0TmV3BRJ3eFBlckxwSW50ZWdyYWxOZXcEI3d4UGVyTHBJbnRlZ3JhbFVzZXJMYXN0VXBkSGVpZ2h0TmV3BQZoZWlnaHQEBWRlYnVnCQC5CQIJAMwIAgInd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm89CQDMCAIJAKQDAQUmd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHRPclplcm8JAMwIAgITd3hQZXJMcEludGVncmFsTmV3PQkAzAgCCQCmAwEFEnd4UGVyTHBJbnRlZ3JhbE5ldwkAzAgCAhF3eFRvQ2xhaW1Vc2VyTmV3PQkAzAgCCQCmAwEFEHd4VG9DbGFpbVVzZXJOZXcJAMwIAgIYd3hQZXJMcEludGVncmFsVXNlckxhc3Q9CQDMCAIJAKYDAQUXd3hQZXJMcEludGVncmFsVXNlckxhc3QJAMwIAgINc3Rha2VkQnlVc2VyPQkAzAgCCQCkAwEFDHN0YWtlZEJ5VXNlcgkAzAgCAgpwb29sREVCVUc9CQDMCAIFCXBvb2xERUJVRwkAzAgCAgdoZWlnaHQ9CQDMCAIJAKQDAQUGaGVpZ2h0BQNuaWwCAjo6CQCVCgMFEHd4VG9DbGFpbVVzZXJOZXcJAM4IAgURcG9vbEludGVncmFsU1RBVEUJAMwIAgkBC1N0cmluZ0VudHJ5AgUQd3hUb0NsYWltVXNlcktFWQkApgMBBRB3eFRvQ2xhaW1Vc2VyTmV3CQDMCAIJAQxJbnRlZ2VyRW50cnkCBSN3eFBlckxwSW50ZWdyYWxVc2VyTGFzdFVwZEhlaWdodEtFWQUjd3hQZXJMcEludGVncmFsVXNlckxhc3RVcGRIZWlnaHROZXcJAMwIAgkBC1N0cmluZ0VudHJ5AgUad3hQZXJMcEludGVncmFsVXNlckxhc3RLRVkJAKYDAQUad3hQZXJMcEludGVncmFsVXNlckxhc3ROZXcFA25pbAUFZGVidWcBFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQABAckbWF0Y2gwCQCiCAEJARNrZXlNYW5hZ2VyUHVibGljS2V5AAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJANkEAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IBF21pZ3JhdG9yUHVibGljS2V5T3JVbml0AAQHJG1hdGNoMAkAoggBCQEUa2V5TWlncmF0b3JQdWJsaWNLZXkAAwkAAQIFByRtYXRjaDACBlN0cmluZwQBcwUHJG1hdGNoMAkA2QQBBQFzAwkAAQIFByRtYXRjaDACBFVuaXQFBHVuaXQJAAIBAgtNYXRjaCBlcnJvcgEdcGVuZGluZ01hbmFnZXJQdWJsaWNLZXlPclVuaXQABAckbWF0Y2gwCQCiCAEJARprZXlQZW5kaW5nTWFuYWdlclB1YmxpY0tleQADCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQDZBAEFAXMDCQABAgUHJG1hdGNoMAIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yABVwZXJtaXNzaW9uRGVuaWVkRXJyb3IJAAIBAhFQZXJtaXNzaW9uIGRlbmllZAEIbXVzdFRoaXMBAWkDCQAAAggFAWkGY2FsbGVyBQR0aGlzBgUVcGVybWlzc2lvbkRlbmllZEVycm9yAQttdXN0TWFuYWdlcgEBaQQHJG1hdGNoMAkBFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAnBrBQckbWF0Y2gwAwkAAAIIBQFpD2NhbGxlclB1YmxpY0tleQUCcGsGBRVwZXJtaXNzaW9uRGVuaWVkRXJyb3IDCQABAgUHJG1hdGNoMAIEVW5pdAMJAAACCAUBaQZjYWxsZXIFBHRoaXMGBRVwZXJtaXNzaW9uRGVuaWVkRXJyb3IJAAIBAgtNYXRjaCBlcnJvcgsBaQELY29uc3RydWN0b3IBEWZhY3RvcnlBZGRyZXNzU3RyBAtjaGVja0NhbGxlcgkBC211c3RNYW5hZ2VyAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEWtleUZhY3RvcnlBZGRyZXNzAAURZmFjdG9yeUFkZHJlc3NTdHIFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1jb25zdHJ1Y3RvclYyARZ2b3RpbmdFbWlzc2lvbkNvbnRyYWN0BAVjaGVrcwkAzAgCCQELbXVzdE1hbmFnZXIBBQFpCQDMCAIDCQECIT0CCQCmCAEFFnZvdGluZ0VtaXNzaW9uQ29udHJhY3QFBHVuaXQGAihpbnZhbGlkIHZvdGluZyBlbWlzc2lvbiBjb250cmFjdCBhZGRyZXNzBQNuaWwDCQAAAgUFY2hla3MFBWNoZWtzCQDMCAIJAQtTdHJpbmdFbnRyeQIJARlrZXlWb3RpbmdFbWlzc2lvbkNvbnRyYWN0AAUWdm90aW5nRW1pc3Npb25Db250cmFjdAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCnNldE1hbmFnZXIBF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5BAtjaGVja0NhbGxlcgkBC211c3RNYW5hZ2VyAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIEFWNoZWNrTWFuYWdlclB1YmxpY0tleQkA2QQBBRdwZW5kaW5nTWFuYWdlclB1YmxpY0tleQMJAAACBRVjaGVja01hbmFnZXJQdWJsaWNLZXkFFWNoZWNrTWFuYWdlclB1YmxpY0tleQkAzAgCCQELU3RyaW5nRW50cnkCCQEaa2V5UGVuZGluZ01hbmFnZXJQdWJsaWNLZXkABRdwZW5kaW5nTWFuYWdlclB1YmxpY0tleQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNvbmZpcm1NYW5hZ2VyAAQCcG0JAR1wZW5kaW5nTWFuYWdlclB1YmxpY0tleU9yVW5pdAAEBWhhc1BNAwkBCWlzRGVmaW5lZAEFAnBtBgkAAgECEk5vIHBlbmRpbmcgbWFuYWdlcgMJAAACBQVoYXNQTQUFaGFzUE0EB2NoZWNrUE0DCQAAAggFAWkPY2FsbGVyUHVibGljS2V5CQEFdmFsdWUBBQJwbQYJAAIBAhtZb3UgYXJlIG5vdCBwZW5kaW5nIG1hbmFnZXIDCQAAAgUHY2hlY2tQTQUHY2hlY2tQTQkAzAgCCQELU3RyaW5nRW50cnkCCQETa2V5TWFuYWdlclB1YmxpY0tleQAJANgEAQkBBXZhbHVlAQUCcG0JAMwIAgkBC0RlbGV0ZUVudHJ5AQkBGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBXN0YWtlAAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECNGludmFsaWQgcGF5bWVudCAtIGV4YWN0IG9uZSBwYXltZW50IG11c3QgYmUgYXR0YWNoZWQEA3BtdAkAkQMCCAUBaQhwYXltZW50cwAABAlscEFzc2V0SWQJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAQMbHBBc3NldElkU3RyCQDYBAEFCWxwQXNzZXRJZAQGYW1vdW50CAUDcG10BmFtb3VudAQOcG9vbEFkZHJlc3NTdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQ9mYWN0b3J5Q29udHJhY3QJARprZXlGYWN0b3J5THAyQXNzZXRzTWFwcGluZwEFDGxwQXNzZXRJZFN0cgkArAICAhV1bnN1cHBvcnRlZCBscCBhc3NldCAFDGxwQXNzZXRJZFN0cgQJY2FsbGVyU3RyCQClCAEIBQFpBmNhbGxlcgQOdXNlckFkZHJlc3NTdHIDCQAAAgUJY2FsbGVyU3RyBQ5wb29sQWRkcmVzc1N0cgkApQgBCAUBaQxvcmlnaW5DYWxsZXIFCWNhbGxlclN0cgQPc3Rha2VkQnlVc2VyS0VZCQEPa2V5U3Rha2VkQnlVc2VyAgUOdXNlckFkZHJlc3NTdHIFDGxwQXNzZXRJZFN0cgQOc3Rha2VkVG90YWxLRVkJAQ5rZXlTdGFrZWRUb3RhbAEFDGxwQXNzZXRJZFN0cgQMc3Rha2VkQnlVc2VyCQEKcmVhZFN0YWtlZAEFD3N0YWtlZEJ5VXNlcktFWQQLc3Rha2VkVG90YWwJAQpyZWFkU3Rha2VkAQUOc3Rha2VkVG90YWxLRVkEDSR0MDE5NDY0MTk1ODEJARByZWZyZXNoSU5URUdSQUxTBAUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgUOcG9vbEFkZHJlc3NTdHIFBmFtb3VudAQQd3hUb0NsYWltVXNlck5ldwgFDSR0MDE5NDY0MTk1ODECXzEEDWludGVncmFsU1RBVEUIBQ0kdDAxOTQ2NDE5NTgxAl8yBAVkZWJ1ZwgFDSR0MDE5NDY0MTk1ODECXzMECGxpc3ROYW1lCQEQZ2V0VXNlcnNMaXN0TmFtZQEFDGxwQXNzZXRJZFN0cgQLbGlzdEFjdGlvbnMDCQEMY29udGFpbnNOb2RlAgUIbGlzdE5hbWUFDnVzZXJBZGRyZXNzU3RyBQNuaWwJARFpbnNlcnROb2RlQWN0aW9ucwIFCGxpc3ROYW1lBQ51c2VyQWRkcmVzc1N0cgkAzggCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIFD3N0YWtlZEJ5VXNlcktFWQkAZAIFDHN0YWtlZEJ5VXNlcgUGYW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5zdGFrZWRUb3RhbEtFWQkAZAIFC3N0YWtlZFRvdGFsBQZhbW91bnQJAMwIAgkBFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQUCBXN0YWtlBQ51c2VyQWRkcmVzc1N0cgUMbHBBc3NldElkU3RyBQZhbW91bnQIBQFpDXRyYW5zYWN0aW9uSWQFA25pbAUNaW50ZWdyYWxTVEFURQULbGlzdEFjdGlvbnMBaQEHdW5zdGFrZQIMbHBBc3NldElkU3RyBmFtb3VudAQJbHBBc3NldElkCQDZBAEFDGxwQXNzZXRJZFN0cgQOcG9vbEFkZHJlc3NTdHIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQ9mYWN0b3J5Q29udHJhY3QJARprZXlGYWN0b3J5THAyQXNzZXRzTWFwcGluZwEFDGxwQXNzZXRJZFN0cgkArAICAhV1bnN1cHBvcnRlZCBscCBhc3NldCAFDGxwQXNzZXRJZFN0cgQJcG9vbEFkZG9uCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMJARZrZXlTdGFibGVQb29sQWRkb25BZGRyAAUOcG9vbEFkZHJlc3NTdHIECWNhbGxlclN0cgkApQgBCAUBaQZjYWxsZXIEDnVzZXJBZGRyZXNzU3RyAwMJAAACBQljYWxsZXJTdHIFDnBvb2xBZGRyZXNzU3RyBgkAAAIFCWNhbGxlclN0cgUJcG9vbEFkZG9uCQClCAEIBQFpDG9yaWdpbkNhbGxlcgUJY2FsbGVyU3RyBA9zdGFrZWRCeVVzZXJLRVkJAQ9rZXlTdGFrZWRCeVVzZXICBQ51c2VyQWRkcmVzc1N0cgUMbHBBc3NldElkU3RyBA5zdGFrZWRUb3RhbEtFWQkBDmtleVN0YWtlZFRvdGFsAQUMbHBBc3NldElkU3RyBAxzdGFrZWRCeVVzZXIJAQpyZWFkU3Rha2VkAQUPc3Rha2VkQnlVc2VyS0VZBAtzdGFrZWRUb3RhbAkBCnJlYWRTdGFrZWQBBQ5zdGFrZWRUb3RhbEtFWQQNJHQwMjA5MTYyMTAzNAkBEHJlZnJlc2hJTlRFR1JBTFMEBQxscEFzc2V0SWRTdHIFDnVzZXJBZGRyZXNzU3RyBQ5wb29sQWRkcmVzc1N0cgkBAS0BBQZhbW91bnQEEHd4VG9DbGFpbVVzZXJOZXcIBQ0kdDAyMDkxNjIxMDM0Al8xBA1pbnRlZ3JhbFNUQVRFCAUNJHQwMjA5MTYyMTAzNAJfMgQFZGVidWcIBQ0kdDAyMDkxNjIxMDM0Al8zBAhsaXN0TmFtZQkBEGdldFVzZXJzTGlzdE5hbWUBBQxscEFzc2V0SWRTdHIEC2xpc3RBY3Rpb25zAwkBDGNvbnRhaW5zTm9kZQIFCGxpc3ROYW1lBQ51c2VyQWRkcmVzc1N0cgkBEWRlbGV0ZU5vZGVBY3Rpb25zAgUIbGlzdE5hbWUFDnVzZXJBZGRyZXNzU3RyBQNuaWwDCQBmAgUGYW1vdW50BQxzdGFrZWRCeVVzZXIJAAIBAiRwYXNzZWQgYW1vdW50IGlzIGxlc3MgdGhlbiBhdmFpbGFibGUJAM4IAgkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9zdGFrZWRCeVVzZXJLRVkJAGUCBQxzdGFrZWRCeVVzZXIFBmFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgUOc3Rha2VkVG90YWxLRVkJAGUCBQtzdGFrZWRUb3RhbAUGYW1vdW50CQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMIBQFpBmNhbGxlcgUGYW1vdW50BQlscEFzc2V0SWQJAMwIAgkBFU9wZXJhdGlvbkhpc3RvcnlFbnRyeQUCB3Vuc3Rha2UFDnVzZXJBZGRyZXNzU3RyBQxscEFzc2V0SWRTdHIFBmFtb3VudAgFAWkNdHJhbnNhY3Rpb25JZAUDbmlsBQ1pbnRlZ3JhbFNUQVRFBQtsaXN0QWN0aW9ucwFpAQdjbGFpbVd4AQxscEFzc2V0SWRTdHIEDnVzZXJBZGRyZXNzU3RyCQClCAEIBQFpBmNhbGxlcgQGcmVzdWx0CQD8BwQFBHRoaXMCD2NsYWltV3hJTlRFUk5BTAkAzAgCBQxscEFzc2V0SWRTdHIJAMwIAgUOdXNlckFkZHJlc3NTdHIFA25pbAUDbmlsCQCUCgIFA25pbAUGcmVzdWx0AWkBD2NsYWltV3hJTlRFUk5BTAIMbHBBc3NldElkU3RyDnVzZXJBZGRyZXNzU3RyBAtjaGVja0NhbGxlcgkBCG11c3RUaGlzAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIEC3VzZXJBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUOdXNlckFkZHJlc3NTdHICJWNsYWltV3hJTlRFUk5BTDogaW52YWxpZCB1c2VyIGFkZHJlc3MEDnBvb2xBZGRyZXNzU3RyCQEYZ2V0U3RyaW5nQnlBZGRyZXNzT3JGYWlsAgUPZmFjdG9yeUNvbnRyYWN0CQEma2V5RmFjdG9yeUxwQXNzZXRUb1Bvb2xDb250cmFjdEFkZHJlc3MBBQxscEFzc2V0SWRTdHIEEGNsYWltZWRCeVVzZXJLRVkJARBrZXlDbGFpbWVkQnlVc2VyAgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgQPY2xhaW1lZFRvdGFsS0VZCQEPa2V5Q2xhaW1lZFRvdGFsAQUMbHBBc3NldElkU3RyBBljbGFpbWVkQnlVc2VyTWluUmV3YXJkS0VZCQEZa2V5Q2xhaW1lZEJ5VXNlck1pblJld2FyZAIFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIEG2NsYWltZWRCeVVzZXJCb29zdFJld2FyZEtFWQkBG2tleUNsYWltZWRCeVVzZXJCb29zdFJld2FyZAIFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIEDWNsYWltZWRCeVVzZXIJALYCAQkBDGdldEludE9yWmVybwIFBHRoaXMFEGNsYWltZWRCeVVzZXJLRVkEFmNsYWltZWRCeVVzZXJNaW5SZXdhcmQJALYCAQkBDGdldEludE9yWmVybwIFBHRoaXMFGWNsYWltZWRCeVVzZXJNaW5SZXdhcmRLRVkEGGNsYWltZWRCeVVzZXJCb29zdFJld2FyZAkAtgIBCQEMZ2V0SW50T3JaZXJvAgUEdGhpcwUbY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkS0VZBAxjbGFpbWVkVG90YWwJARlnZXRCaWdJbnRGcm9tU3RyaW5nT3JaZXJvAgUEdGhpcwUPY2xhaW1lZFRvdGFsS0VZBA0kdDAyMjc3NjIyODg4CQEQcmVmcmVzaElOVEVHUkFMUwQFDGxwQXNzZXRJZFN0cgUOdXNlckFkZHJlc3NTdHIFDnBvb2xBZGRyZXNzU3RyAAAEEHd4VG9DbGFpbVVzZXJOZXcIBQ0kdDAyMjc3NjIyODg4Al8xBA1pbnRlZ3JhbFNUQVRFCAUNJHQwMjI3NzYyMjg4OAJfMgQFZGVidWcIBQ0kdDAyMjc3NjIyODg4Al8zBBBhdmFpbGFibGVUb0NsYWltCQC4AgIFEHd4VG9DbGFpbVVzZXJOZXcFDWNsYWltZWRCeVVzZXIDCQDAAgIFCnplcm9CaWdJbnQFEGF2YWlsYWJsZVRvQ2xhaW0JAAIBAhBub3RoaW5nIHRvIGNsYWltBBJ3eEFtb3VudEJvb3N0VG90YWwJAQVhc0ludAEJAJEDAgkBCWFzQW55TGlzdAEJAPwHBAUQYm9vc3RpbmdDb250cmFjdAIMY2xhaW1XeEJvb3N0CQDMCAIFDGxwQXNzZXRJZFN0cgkAzAgCBQ51c2VyQWRkcmVzc1N0cgUDbmlsBQNuaWwAAAQNbWluUmV3YXJkUGFydAUQYXZhaWxhYmxlVG9DbGFpbQQPYm9vc3RSZXdhcmRQYXJ0CQCZAwEJAMwIAgkAuQICBQ1taW5SZXdhcmRQYXJ0CQC2AgEAAgkAzAgCCQC2AgEFEnd4QW1vdW50Qm9vc3RUb3RhbAUDbmlsBAl3eEFzc2V0SWQJAQxhc0J5dGVWZWN0b3IBCQCRAwIJAQlhc0FueUxpc3QBCQD8BwQFEGVtaXNzaW9uQ29udHJhY3QCBGVtaXQJAMwIAgkAoAMBBQ1taW5SZXdhcmRQYXJ0BQNuaWwFA25pbAAABAllbWl0Qm9vc3QJAQlhc0FueUxpc3QBCQD8BwQFEGVtaXNzaW9uQ29udHJhY3QCBGVtaXQJAMwIAgkAoAMBBQ9ib29zdFJld2FyZFBhcnQFA25pbAUDbmlsAwkAAAIFCWVtaXRCb29zdAUJZW1pdEJvb3N0BBJjbGFpbWVkQnlVc2VyVmFsdWUJALcCAgUNY2xhaW1lZEJ5VXNlcgUQYXZhaWxhYmxlVG9DbGFpbQQeY2xhaW1lZEJ5VXNlck1pblJld2FyZFBsdXNQYXJ0CQC3AgIFFmNsYWltZWRCeVVzZXJNaW5SZXdhcmQFDW1pblJld2FyZFBhcnQEK2NsYWltZWRCeVVzZXJCb29zdFJld2FyZFBsdXNCb29zdFJld2FyZFBhcnQJALcCAgUWY2xhaW1lZEJ5VXNlck1pblJld2FyZAUNbWluUmV3YXJkUGFydAQgY2xhaW1lZFRvdGFsUGx1c0F2YWlsYWJsZVRvQ2xhaW0JALcCAgUWY2xhaW1lZEJ5VXNlck1pblJld2FyZAUNbWluUmV3YXJkUGFydAkAzAgCCQELU3RyaW5nRW50cnkCBRBjbGFpbWVkQnlVc2VyS0VZCQCmAwEFEmNsYWltZWRCeVVzZXJWYWx1ZQkAzAgCCQELU3RyaW5nRW50cnkCBRljbGFpbWVkQnlVc2VyTWluUmV3YXJkS0VZCQCmAwEFHmNsYWltZWRCeVVzZXJNaW5SZXdhcmRQbHVzUGFydAkAzAgCCQELU3RyaW5nRW50cnkCBRtjbGFpbWVkQnlVc2VyQm9vc3RSZXdhcmRLRVkJAKYDAQUrY2xhaW1lZEJ5VXNlckJvb3N0UmV3YXJkUGx1c0Jvb3N0UmV3YXJkUGFydAkAzAgCCQELU3RyaW5nRW50cnkCBQ9jbGFpbWVkVG90YWxLRVkJAKYDAQUgY2xhaW1lZFRvdGFsUGx1c0F2YWlsYWJsZVRvQ2xhaW0JAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwULdXNlckFkZHJlc3MJAKADAQUNbWluUmV3YXJkUGFydAUJd3hBc3NldElkCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFC3VzZXJBZGRyZXNzCQCgAwEFD2Jvb3N0UmV3YXJkUGFydAUJd3hBc3NldElkCQDMCAIJARVPcGVyYXRpb25IaXN0b3J5RW50cnkFAgVjbGFpbQUOdXNlckFkZHJlc3NTdHIFDGxwQXNzZXRJZFN0cgkAoAMBBRBhdmFpbGFibGVUb0NsYWltCAUBaQ10cmFuc2FjdGlvbklkBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEPY2xhaW1XeFJFQURPTkxZAgxscEFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIED3N0YWtlZEJ5VXNlcktFWQkBD2tleVN0YWtlZEJ5VXNlcgIFDnVzZXJBZGRyZXNzU3RyBQxscEFzc2V0SWRTdHIEDnN0YWtlZFRvdGFsS0VZCQEOa2V5U3Rha2VkVG90YWwBBQxscEFzc2V0SWRTdHIEEGNsYWltZWRCeVVzZXJLRVkJARBrZXlDbGFpbWVkQnlVc2VyAgUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgQMc3Rha2VkQnlVc2VyCQEKcmVhZFN0YWtlZAEFD3N0YWtlZEJ5VXNlcktFWQQLc3Rha2VkVG90YWwJAQpyZWFkU3Rha2VkAQUOc3Rha2VkVG90YWxLRVkEDWNsYWltZWRCeVVzZXIJAQxnZXRJbnRPclplcm8CBQR0aGlzBRBjbGFpbWVkQnlVc2VyS0VZBA5wb29sQWRkcmVzc1N0cgkBGGdldFN0cmluZ0J5QWRkcmVzc09yRmFpbAIFD2ZhY3RvcnlDb250cmFjdAkBJmtleUZhY3RvcnlMcEFzc2V0VG9Qb29sQ29udHJhY3RBZGRyZXNzAQUMbHBBc3NldElkU3RyBApwb29sV2VpZ2h0CQERQGV4dHJOYXRpdmUoMTA1MCkCBQ9mYWN0b3J5Q29udHJhY3QJARRrZXlGYWN0b3J5UG9vbFdlaWdodAEFDnBvb2xBZGRyZXNzU3RyBBJ3eEVtaXNzaW9uUGVyQmxvY2sJAQxnZXRJbnRPckZhaWwCBRBlbWlzc2lvbkNvbnRyYWN0CQEea2V5RW1pc3Npb25SYXRlUGVyQmxvY2tDdXJyZW50AAQSZW1pc3Npb25TdGFydEJsb2NrCQEMZ2V0SW50T3JGYWlsAgUQZW1pc3Npb25Db250cmFjdAkBFWtleUVtaXNzaW9uU3RhcnRCbG9jawAEDHBhc3NlZEJsb2NrcwMJAGYCBRJlbWlzc2lvblN0YXJ0QmxvY2sFBmhlaWdodAAACQBlAgUGaGVpZ2h0BRJlbWlzc2lvblN0YXJ0QmxvY2sEDnBvb2xXeEVtaXNzaW9uCQBrAwkAaAIFEnd4RW1pc3Npb25QZXJCbG9jawUMcGFzc2VkQmxvY2tzBQpwb29sV2VpZ2h0BQ5QT09MV0VJR0hUTVVMVAQMdXNlcld4UmV3YXJkCQBrAwUOcG9vbFd4RW1pc3Npb24FDHN0YWtlZEJ5VXNlcgULc3Rha2VkVG90YWwEDSR0MDI1NDg4MjU2MDAJARByZWZyZXNoSU5URUdSQUxTBAUMbHBBc3NldElkU3RyBQ51c2VyQWRkcmVzc1N0cgUOcG9vbEFkZHJlc3NTdHIAAAQQd3hUb0NsYWltVXNlck5ldwgFDSR0MDI1NDg4MjU2MDACXzEEDWludGVncmFsU1RBVEUIBQ0kdDAyNTQ4ODI1NjAwAl8yBAVkZWJ1ZwgFDSR0MDI1NDg4MjU2MDACXzMEEGF2YWlsYWJsZVRvQ2xhaW0JALgCAgUQd3hUb0NsYWltVXNlck5ldwkAtgIBBQ1jbGFpbWVkQnlVc2VyBA5ib29zdEludlJlc3VsdAkBCWFzQW55TGlzdAEJAPwHBAUQYm9vc3RpbmdDb250cmFjdAIUY2xhaW1XeEJvb3N0UkVBRE9OTFkJAMwIAgUMbHBBc3NldElkU3RyCQDMCAIFDnVzZXJBZGRyZXNzU3RyBQNuaWwFA25pbAQSd3hBbW91bnRCb29zdFRvdGFsCQEFYXNJbnQBCQCRAwIFDmJvb3N0SW52UmVzdWx0AAAECmJvb3N0RGVidWcJAQhhc1N0cmluZwEJAJEDAgUOYm9vc3RJbnZSZXN1bHQAAQQNbWluUmV3YXJkUGFydAUQYXZhaWxhYmxlVG9DbGFpbQQPYm9vc3RSZXdhcmRQYXJ0CQCZAwEJAMwIAgkAuQICBQ1taW5SZXdhcmRQYXJ0CQC2AgEAAgkAzAgCCQC2AgEFEnd4QW1vdW50Qm9vc3RUb3RhbAUDbmlsBAt0b3RhbFJld2FyZAkAtwICBQ1taW5SZXdhcmRQYXJ0BQ9ib29zdFJld2FyZFBhcnQJAJQKAgUDbmlsCQC5CQIJAMwIAgIOJXMlcyVkJWQlZCVkJXMJAMwIAgUMbHBBc3NldElkU3RyCQDMCAIFDnVzZXJBZGRyZXNzU3RyCQDMCAIJAKYDAQULdG90YWxSZXdhcmQJAMwIAgkApAMBBQ1jbGFpbWVkQnlVc2VyCQDMCAIJAKYDAQUNbWluUmV3YXJkUGFydAkAzAgCCQCmAwEFD2Jvb3N0UmV3YXJkUGFydAkAzAgCCQCsAgIJAKwCAgkArAICCQCsAgIFBWRlYnVnAgI6OgkApAMBBQx1c2VyV3hSZXdhcmQCDjo6Qk9PU1RERUJVRzo6BQpib29zdERlYnVnBQNuaWwFA1NFUAFpARJ1c2Vyc0xpc3RUcmF2ZXJzYWwBCWxwQXNzZXRJZAQLY2hlY2tDYWxsZXIDCQAAAgkA2AQBCAgFAWkGY2FsbGVyBWJ5dGVzCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMJARlrZXlWb3RpbmdFbWlzc2lvbkNvbnRyYWN0AAIABgkBC211c3RNYW5hZ2VyAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIECGxpc3ROYW1lCQEQZ2V0VXNlcnNMaXN0TmFtZQEFCWxwQXNzZXRJZAQKdXNlck9yVW5pdAkAoggBCQELa2V5TmV4dFVzZXIBBQlscEFzc2V0SWQECmhlYWRPclVuaXQJAKIIAQkBC2tleUxpc3RIZWFkAQUIbGlzdE5hbWUEByRtYXRjaDAFCnVzZXJPclVuaXQDCQABAgUHJG1hdGNoMAIEVW5pdAQHJG1hdGNoMQUKaGVhZE9yVW5pdAMJAAECBQckbWF0Y2gxAgRVbml0CQCUCgIFA25pbAcDCQABAgUHJG1hdGNoMQIGU3RyaW5nBARoZWFkBQckbWF0Y2gxCQCUCgIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBC2tleU5leHRVc2VyAQUJbHBBc3NldElkBQRoZWFkBQNuaWwGCQACAQILTWF0Y2ggZXJyb3IDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAt1c2VyQWRkcmVzcwUHJG1hdGNoMAQNY2xhaW1lZEJ5VXNlcgkBDGdldEludE9yWmVybwIFBHRoaXMJARBrZXlDbGFpbWVkQnlVc2VyAgUJbHBBc3NldElkBQt1c2VyQWRkcmVzcwQLcG9vbEFkZHJlc3MJARhnZXRTdHJpbmdCeUFkZHJlc3NPckZhaWwCBQ9mYWN0b3J5Q29udHJhY3QJASZrZXlGYWN0b3J5THBBc3NldFRvUG9vbENvbnRyYWN0QWRkcmVzcwEFCWxwQXNzZXRJZAQNJHQwMjcxNjkyNzI3MgkBEHJlZnJlc2hJTlRFR1JBTFMEBQlscEFzc2V0SWQFC3VzZXJBZGRyZXNzBQtwb29sQWRkcmVzcwAABBB3eFRvQ2xhaW1Vc2VyTmV3CAUNJHQwMjcxNjkyNzI3MgJfMQQNaW50ZWdyYWxTVEFURQgFDSR0MDI3MTY5MjcyNzICXzIEBWRlYnVnCAUNJHQwMjcxNjkyNzI3MgJfMwQQYXZhaWxhYmxlVG9DbGFpbQkAuAICBRB3eFRvQ2xhaW1Vc2VyTmV3CQC2AgEFDWNsYWltZWRCeVVzZXIEAXIDCQC/AgIFEGF2YWlsYWJsZVRvQ2xhaW0FCnplcm9CaWdJbnQJAPwHBAUEdGhpcwIPY2xhaW1XeElOVEVSTkFMCQDMCAIFCWxwQXNzZXRJZAkAzAgCBQt1c2VyQWRkcmVzcwUDbmlsBQNuaWwFBHVuaXQDCQAAAgUBcgUBcgQObmV4dFVzZXJPclVuaXQJAKIIAQkBC2tleUxpc3ROZXh0AgUIbGlzdE5hbWUFC3VzZXJBZGRyZXNzBAckbWF0Y2gxBQ5uZXh0VXNlck9yVW5pdAMJAAECBQckbWF0Y2gxAgRVbml0CQCUCgIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBC2tleU5leHRVc2VyAQUJbHBBc3NldElkBQNuaWwHAwkAAQIFByRtYXRjaDECBlN0cmluZwQIbmV4dFVzZXIFByRtYXRjaDEJAJQKAgkAzAgCCQELU3RyaW5nRW50cnkCCQELa2V5TmV4dFVzZXIBBQlscEFzc2V0SWQFCG5leHRVc2VyBQNuaWwGCQACAQILTWF0Y2ggZXJyb3IJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAgtNYXRjaCBlcnJvcgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ5vbk1vZGlmeVdlaWdodAIMbHBBc3NldElkU3RyDnBvb2xBZGRyZXNzU3RyAwkBAiE9AggFAWkGY2FsbGVyBQ9mYWN0b3J5Q29udHJhY3QJAAIBAhJwZXJtaXNzaW9ucyBkZW5pZWQEDSR0MDI3OTU3MjgwNjcJARRyZWZyZXNoUG9vbElOVEVHUkFMUwMFDGxwQXNzZXRJZFN0cgUOcG9vbEFkZHJlc3NTdHIAAAQSd3hQZXJMcEludGVncmFsTmV3CAUNJHQwMjc5NTcyODA2NwJfMQQRcG9vbEludGVncmFsU1RBVEUIBQ0kdDAyNzk1NzI4MDY3Al8yBAlwb29sREVCVUcIBQ0kdDAyNzk1NzI4MDY3Al8zBRFwb29sSW50ZWdyYWxTVEFURQECdHgBBnZlcmlmeQAED3RhcmdldFB1YmxpY0tleQQHJG1hdGNoMAkBFm1hbmFnZXJQdWJsaWNLZXlPclVuaXQAAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAnBrBQckbWF0Y2gwBQJwawMJAAECBQckbWF0Y2gwAgRVbml0CAUCdHgPc2VuZGVyUHVibGljS2V5CQACAQILTWF0Y2ggZXJyb3IEEW1pZ3JhdG9yUHVibGljS2V5BAckbWF0Y2gwCQEXbWlncmF0b3JQdWJsaWNLZXlPclVuaXQAAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAnBrBQckbWF0Y2gwBQJwawMJAAECBQckbWF0Y2gwAgRVbml0CAUCdHgPc2VuZGVyUHVibGljS2V5CQACAQILTWF0Y2ggZXJyb3IDCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAABQ90YXJnZXRQdWJsaWNLZXkGCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAABRFtaWdyYXRvclB1YmxpY0tlea4bmFM=", "chainId": 84, "height": 2114679, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: ELz9FeMZ1AavkUU5Grx8MGuVqH3KySp3KUov8LjHfy7U Next: 9puiTqag5FdcqPMpFLqKJ5uahNN2cj56tNBduaiiDYVS Diff:
OldNewDifferences
1-{-# STDLIB_VERSION 5 #-}
1+{-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let SCALE8 = 8
1212 let SEP = "__"
1313
1414 let POOLWEIGHTMULT = MULT8
15+
16+let zeroBigInt = toBigInt(0)
17+
18+let oneBigInt = toBigInt(1)
1519
1620 func asAnyList (val) = match val {
1721 case valAnyLyst: List[Any] =>
4549 }
4650
4751
48-func getStringOrFail (key) = valueOrErrorMessage(getString(key), (("mandatory this." + key) + " is not defined"))
52+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (("mandatory this." + key) + " is not defined"))
4953
5054
5155 func getStringByAddressOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined"))
6064 func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined"))
6165
6266
67+func getBigIntFromStringOrZero (address,key) = value(parseBigInt(valueOrElse(getString(address, key), "0")))
68+
69+
70+func getBigIntFromStringOrDefault (address,key,defaultVal) = match getString(address, key) {
71+ case s: String =>
72+ value(parseBigInt(s))
73+ case _: Unit =>
74+ defaultVal
75+ case _ =>
76+ throw("Match error")
77+}
78+
79+
6380 func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULT18, toBigInt(origScaleMult))
6481
6582
6784
6885
6986 func keyFactoryAddress () = "%s%s__config__factoryAddress"
87+
88+
89+func keyVotingEmissionContract () = "%s__votingEmissionContract"
7090
7191
7292 let IdxFactoryCfgStakingDapp = 1
87107
88108
89109 func keyManagerPublicKey () = "%s__managerPublicKey"
110+
111+
112+func keyMigratorPublicKey () = "%s__migratorPublicKey"
90113
91114
92115 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
152175 func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP)
153176
154177
155-func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed", "total", lpAssetIdStr], SEP)
178+func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed__total", lpAssetIdStr], SEP)
156179
157180
158181 func readStaked (key) = valueOrElse(getInteger(this, key), 0)
206229 func OperationHistoryEntry (type,userAddress,lpAssetId,amount,txId) = StringEntry(keyOperationHistoryRecord(type, userAddress, toBase58String(txId)), formatHistoryRecord(userAddress, lpAssetId, type, amount))
207230
208231
209-let factoryAddress = getStringOrFail(keyFactoryAddress())
232+let factoryAddress = getStringOrFail(this, keyFactoryAddress())
210233
211234 let factoryContract = addressFromStringValue(factoryAddress)
212235
216239
217240 let boostingContract = getBoostingAddressOrFail(factoryCfg)
218241
219-func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == 0))
220- then (stakedByUser > 0)
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+
305+func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
306+ then (stakedByUser > zeroBigInt)
221307 else false)
222- then 0
223- else if ((stakedByUser == 0))
308+ then zeroBigInt
309+ else if ((stakedByUser == zeroBigInt))
224310 then wxPerLpIntegralNew
225- else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > 0))
226- then (stakedByUser > 0)
311+ else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > zeroBigInt))
312+ then (stakedByUser > zeroBigInt)
227313 else false)
228- then getIntOrFail(this, wxPerLpIntegralUserLastKEY)
314+ then value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))
229315 else throw("calcWxPerLpIntegralUserLast: unexpected state")
230316
231317
232318 func refreshPoolINTEGRALS (lpAssetIdStr,poolAddressStr,lpDeltaAmount) = {
233319 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
234- let stakedTotal = readStaked(stakedTotalKEY)
320+ let stakedTotal = toBigInt(readStaked(stakedTotalKEY))
321+ let nonZeroStakedTotal = if ((stakedTotal == zeroBigInt))
322+ then oneBigInt
323+ else stakedTotal
235324 let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
236325 let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
237326 let MULT3 = 1000
241330 let wxPerLpIntegralLastUpdHeightKEY = keyWxPerLpIntegralLastUpdHeight(lpAssetIdStr)
242331 let wxPerLpKEY = keyWxPerLp(lpAssetIdStr)
243332 let wxPerLpIntegralLastUpdHeight = getIntOrDefault(this, wxPerLpIntegralLastUpdHeightKEY, emissionStartBlock)
244- let wxPerLpIntegral = getIntOrZero(this, wxPerLpIntegralKEY)
333+ let wxPerLpIntegral = getBigIntFromStringOrZero(this, wxPerLpIntegralKEY)
245334 let wxPerLpOrZeroX3 = 0
246335 let dh = max([(height - wxPerLpIntegralLastUpdHeight), 0])
247336 let wxPerLpX3 = if ((wxPerLpOrZeroX3 != 0))
248- then wxPerLpOrZeroX3
249- else fraction(poolWxEmissionPerBlockX3, MULT8, stakedTotal)
250- let stakedTotalNew = (stakedTotal + lpDeltaAmount)
251- let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * dh))
252- let wxPerLpX3New = (poolWxEmissionPerBlockX3 / stakedTotalNew)
337+ then toBigInt(wxPerLpOrZeroX3)
338+ else fraction(toBigInt(poolWxEmissionPerBlockX3), toBigInt(MULT8), nonZeroStakedTotal)
339+ let stakedTotalNew = (stakedTotal + toBigInt(lpDeltaAmount))
340+ let nonZeroStakedTotalNew = if ((stakedTotalNew == zeroBigInt))
341+ then oneBigInt
342+ else stakedTotalNew
343+ let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * toBigInt(dh)))
344+ let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
253345 let wxPerLpIntegralLastUpdHeightNew = height
254- let debug = makeString([toString(wxPerLpIntegralNew), toString(dh), toString(wxPerLpX3), toString(stakedTotal), toString(poolWxEmissionPerBlockX3), toString(wxEmissionPerBlockX3), toString(poolWeight)], "::")
255- $Tuple3(wxPerLpIntegralNew, [IntegerEntry(wxPerLpIntegralKEY, wxPerLpIntegralNew), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), IntegerEntry(wxPerLpKEY, wxPerLpX3New)], debug)
346+ let debug = makeString(["wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), "poolWxEmissionPerBlockX3=", toString(poolWxEmissionPerBlockX3), "wxEmissionPerBlockX3=", toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
347+ $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
256348 }
257349
258350
259351 func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
260- let $t01049410616 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
261- let wxPerLpIntegralNew = $t01049410616._1
262- let poolIntegralSTATE = $t01049410616._2
263- let poolDEBUG = $t01049410616._3
352+ let $t01447314595 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
353+ let wxPerLpIntegralNew = $t01447314595._1
354+ let poolIntegralSTATE = $t01447314595._2
355+ let poolDEBUG = $t01447314595._3
264356 let MULT3 = 1000
265357 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
266358 let stakedByUser = readStaked(stakedByUserKEY)
267359 let wxToClaimUserKEY = keyWxToClaimUser(lpAssetIdStr, userAddressStr)
268360 let wxPerLpIntegralUserLastUpdHeightKEY = keyWxPerLpIntegralUserLastUpdHeight(lpAssetIdStr, userAddressStr)
269361 let wxPerLpIntegralUserLastKEY = keyWxPerLpIntegralUserLast(lpAssetIdStr, userAddressStr)
270- let wxToClaimUser = getIntOrZero(this, wxToClaimUserKEY)
362+ let wxToClaimUser = getBigIntFromStringOrZero(this, wxToClaimUserKEY)
271363 let wxPerLpIntegralUserLastUpdHeightOrZero = getIntOrZero(this, wxPerLpIntegralUserLastUpdHeightKEY)
272- let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(stakedByUser, wxPerLpIntegralUserLastUpdHeightOrZero, wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
273- let wxToClaimUserNew = (wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), stakedByUser, (MULT8 * MULT3)))
364+ let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(toBigInt(stakedByUser), toBigInt(wxPerLpIntegralUserLastUpdHeightOrZero), wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
365+ let MULT11 = (MULT8 * MULT3)
366+ let wxToClaimUserNew = (wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11)))
274367 let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
275368 let wxPerLpIntegralUserLastUpdHeightNew = height
276- let debug = makeString([toString(wxToClaimUserNew), toString(wxPerLpIntegralUserLast), toString(stakedByUser), poolDEBUG, toString(height)], "::")
277- $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [IntegerEntry(wxToClaimUserKEY, wxToClaimUserNew), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), IntegerEntry(wxPerLpIntegralUserLastKEY, wxPerLpIntegralUserLastNew)]), debug)
369+ let debug = makeString(["wxPerLpIntegralUserLastUpdHeightOrZero=", toString(wxPerLpIntegralUserLastUpdHeightOrZero), "wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "wxToClaimUserNew=", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast=", toString(wxPerLpIntegralUserLast), "stakedByUser=", toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
370+ $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
278371 }
279372
280373
281374 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
375+ case s: String =>
376+ fromBase58String(s)
377+ case _: Unit =>
378+ unit
379+ case _ =>
380+ throw("Match error")
381+}
382+
383+
384+func migratorPublicKeyOrUnit () = match getString(keyMigratorPublicKey()) {
282385 case s: String =>
283386 fromBase58String(s)
284387 case _: Unit =>
298401 }
299402
300403
301-func mustManager (i) = {
302- let pd = throw("Permission denied")
303- match managerPublicKeyOrUnit() {
304- case pk: ByteVector =>
305- if ((i.callerPublicKey == pk))
306- then true
307- else pd
308- case _: Unit =>
309- if ((i.caller == this))
310- then true
311- else pd
312- case _ =>
313- throw("Match error")
314- }
315- }
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+}
316423
317424
318425 @Callable(i)
320427 let checkCaller = mustManager(i)
321428 if ((checkCaller == checkCaller))
322429 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)]
323442 else throw("Strict value is not equal to itself.")
324443 }
325444
377496 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
378497 let stakedByUser = readStaked(stakedByUserKEY)
379498 let stakedTotal = readStaked(stakedTotalKEY)
380- let $t01427414391 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
381- let wxToClaimUserNew = $t01427414391._1
382- let integralSTATE = $t01427414391._2
383- let debug = $t01427414391._3
384- ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
499+ let $t01946419581 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
500+ let wxToClaimUserNew = $t01946419581._1
501+ let integralSTATE = $t01946419581._2
502+ let debug = $t01946419581._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)
385508 }
386509
387510
401524 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
402525 let stakedByUser = readStaked(stakedByUserKEY)
403526 let stakedTotal = readStaked(stakedTotalKEY)
404- let $t01552815646 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
405- let wxToClaimUserNew = $t01552815646._1
406- let integralSTATE = $t01552815646._2
407- let debug = $t01552815646._3
527+ let $t02091621034 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
528+ let wxToClaimUserNew = $t02091621034._1
529+ let integralSTATE = $t02091621034._2
530+ let debug = $t02091621034._3
531+ let listName = getUsersListName(lpAssetIdStr)
532+ let listActions = if (containsNode(listName, userAddressStr))
533+ then deleteNodeActions(listName, userAddressStr)
534+ else nil
408535 if ((amount > stakedByUser))
409536 then throw("passed amount is less then available")
410- 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)
411538 }
412539
413540
414541
415542 @Callable(i)
416543 func claimWx (lpAssetIdStr) = {
417- let userAddress = i.caller
418544 let userAddressStr = toString(i.caller)
419- let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
420- let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
421- let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
422- let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
423- let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
424- let claimedByUser = getIntOrZero(this, claimedByUserKEY)
425- let claimedByUserMinReward = getIntOrZero(this, claimedByUserMinRewardKEY)
426- let claimedByUserBoostReward = getIntOrZero(this, claimedByUserBoostRewardKEY)
427- let claimedTotal = getIntOrZero(this, claimedTotalKEY)
428- let $t01683816950 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
429- let wxToClaimUserNew = $t01683816950._1
430- let integralSTATE = $t01683816950._2
431- let debug = $t01683816950._3
432- let availableToClaim = (wxToClaimUserNew - claimedByUser)
433- if ((0 >= availableToClaim))
434- then throw("nothing to claim")
435- else {
436- let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0])
437- let minRewardPart = availableToClaim
438- let boostRewardPart = min([(minRewardPart * 2), wxAmountBoostTotal])
439- let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [minRewardPart], nil))[0])
440- let emitBoost = asAnyList(invoke(emissionContract, "emit", [boostRewardPart], nil))
441- if ((emitBoost == emitBoost))
442- then [IntegerEntry(claimedByUserKEY, (claimedByUser + availableToClaim)), IntegerEntry(claimedByUserMinRewardKEY, (claimedByUserMinReward + minRewardPart)), IntegerEntry(claimedByUserBoostRewardKEY, (claimedByUserBoostReward + boostRewardPart)), IntegerEntry(claimedTotalKEY, (claimedTotal + availableToClaim)), ScriptTransfer(userAddress, minRewardPart, wxAssetId), ScriptTransfer(userAddress, boostRewardPart, wxAssetId), OperationHistoryEntry("claim", userAddressStr, lpAssetIdStr, availableToClaim, i.transactionId)]
443- else throw("Strict value is not equal to itself.")
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 = toBigInt(getIntOrZero(this, claimedByUserKEY))
563+ let claimedByUserMinReward = toBigInt(getIntOrZero(this, claimedByUserMinRewardKEY))
564+ let claimedByUserBoostReward = toBigInt(getIntOrZero(this, claimedByUserBoostRewardKEY))
565+ let claimedTotal = getBigIntFromStringOrZero(this, claimedTotalKEY)
566+ let $t02277622888 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
567+ let wxToClaimUserNew = $t02277622888._1
568+ let integralSTATE = $t02277622888._2
569+ let debug = $t02277622888._3
570+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
571+ if ((zeroBigInt >= availableToClaim))
572+ then throw("nothing to claim")
573+ else {
574+ let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[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)
585+[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.")
588+ }
444589 }
590+ else throw("Strict value is not equal to itself.")
445591 }
446592
447593
463609 else (height - emissionStartBlock)
464610 let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
465611 let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
466- let $t01915119263 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
467- let wxToClaimUserNew = $t01915119263._1
468- let integralSTATE = $t01915119263._2
469- let debug = $t01915119263._3
470- let availableToClaim = (wxToClaimUserNew - claimedByUser)
612+ let $t02548825600 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
613+ let wxToClaimUserNew = $t02548825600._1
614+ let integralSTATE = $t02548825600._2
615+ let debug = $t02548825600._3
616+ let availableToClaim = (wxToClaimUserNew - toBigInt(claimedByUser))
471617 let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
472618 let wxAmountBoostTotal = asInt(boostInvResult[0])
473619 let boostDebug = asString(boostInvResult[1])
474620 let minRewardPart = availableToClaim
475- let boostRewardPart = min([(minRewardPart * 2), wxAmountBoostTotal])
621+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
476622 let totalReward = (minRewardPart + boostRewardPart)
477623 $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))
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 = getIntOrZero(this, keyClaimedByUser(lpAssetId, userAddress))
650+ let poolAddress = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetId))
651+ let $t02716927272 = refreshINTEGRALS(lpAssetId, userAddress, poolAddress, 0)
652+ let wxToClaimUserNew = $t02716927272._1
653+ let integralSTATE = $t02716927272._2
654+ let debug = $t02716927272._3
655+ let availableToClaim = (wxToClaimUserNew - toBigInt(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.")
478677 }
479678
480679
483682 func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
484683 then throw("permissions denied")
485684 else {
486- let $t02014320253 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
487- let wxPerLpIntegralNew = $t02014320253._1
488- let poolIntegralSTATE = $t02014320253._2
489- let poolDEBUG = $t02014320253._3
685+ let $t02795728067 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
686+ let wxPerLpIntegralNew = $t02795728067._1
687+ let poolIntegralSTATE = $t02795728067._2
688+ let poolDEBUG = $t02795728067._3
490689 poolIntegralSTATE
491690 }
492691
501700 case _ =>
502701 throw("Match error")
503702 }
504- sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
703+ let migratorPublicKey = match migratorPublicKeyOrUnit() {
704+ case pk: ByteVector =>
705+ pk
706+ case _: Unit =>
707+ tx.senderPublicKey
708+ case _ =>
709+ throw("Match error")
710+ }
711+ if (sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey))
712+ then true
713+ else sigVerify(tx.bodyBytes, tx.proofs[0], migratorPublicKey)
505714 }
506715
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
15+
16+let zeroBigInt = toBigInt(0)
17+
18+let oneBigInt = toBigInt(1)
1519
1620 func asAnyList (val) = match val {
1721 case valAnyLyst: List[Any] =>
1822 valAnyLyst
1923 case _ =>
2024 throw("fail to cast into List[Any]")
2125 }
2226
2327
2428 func asInt (val) = match val {
2529 case valInt: Int =>
2630 valInt
2731 case _ =>
2832 throw("fail to cast into Int")
2933 }
3034
3135
3236 func asString (val) = match val {
3337 case valStr: String =>
3438 valStr
3539 case _ =>
3640 throw("fail to cast into Int")
3741 }
3842
3943
4044 func asByteVector (val) = match val {
4145 case valBin: ByteVector =>
4246 valBin
4347 case _ =>
4448 throw("fail to cast into Int")
4549 }
4650
4751
48-func getStringOrFail (key) = valueOrErrorMessage(getString(key), (("mandatory this." + key) + " is not defined"))
52+func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), (("mandatory this." + key) + " is not defined"))
4953
5054
5155 func getStringByAddressOrFail (address,key) = valueOrErrorMessage(getString(address, key), (((("mandatory " + toString(address)) + ".") + key) + " is not defined"))
5256
5357
5458 func getIntOrZero (address,key) = valueOrElse(getInteger(address, key), 0)
5559
5660
5761 func getIntOrDefault (address,key,defaultVal) = valueOrElse(getInteger(address, key), defaultVal)
5862
5963
6064 func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), (("mandatory this." + key) + " is not defined"))
6165
6266
67+func getBigIntFromStringOrZero (address,key) = value(parseBigInt(valueOrElse(getString(address, key), "0")))
68+
69+
70+func getBigIntFromStringOrDefault (address,key,defaultVal) = match getString(address, key) {
71+ case s: String =>
72+ value(parseBigInt(s))
73+ case _: Unit =>
74+ defaultVal
75+ case _ =>
76+ throw("Match error")
77+}
78+
79+
6380 func toX18 (origVal,origScaleMult) = fraction(toBigInt(origVal), MULT18, toBigInt(origScaleMult))
6481
6582
6683 func fromX18 (val,resultScaleMult) = toInt(fraction(val, toBigInt(resultScaleMult), MULT18))
6784
6885
6986 func keyFactoryAddress () = "%s%s__config__factoryAddress"
87+
88+
89+func keyVotingEmissionContract () = "%s__votingEmissionContract"
7090
7191
7292 let IdxFactoryCfgStakingDapp = 1
7393
7494 let IdxFactoryCfgBoostingDapp = 2
7595
7696 let IdxFactoryCfgIdoDapp = 3
7797
7898 let IdxFactoryCfgTeamDapp = 4
7999
80100 let IdxFactoryCfgEmissionDapp = 5
81101
82102 let IdxFactoryCfgRestDapp = 6
83103
84104 let IdxFactoryCfgSlippageDapp = 7
85105
86106 func keyFactoryCfg () = "%s__factoryConfig"
87107
88108
89109 func keyManagerPublicKey () = "%s__managerPublicKey"
110+
111+
112+func keyMigratorPublicKey () = "%s__migratorPublicKey"
90113
91114
92115 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
93116
94117
95118 func keyStablePoolAddonAddr () = "%s__stablePoolAddonAddr"
96119
97120
98121 func keyFactoryLp2AssetsMapping (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
99122
100123
101124 func keyFactoryLpList () = "%s__lpTokensList"
102125
103126
104127 func keyFactoryLpAssetToPoolContractAddress (lpAssetStr) = makeString(["%s%s%s", lpAssetStr, "mappings__lpAsset2PoolContract"], SEP)
105128
106129
107130 func keyFactoryPoolWeight (contractAddress) = makeString(["%s%s", "poolWeight", contractAddress], SEP)
108131
109132
110133 func readLpList (factory) = split(valueOrElse(getString(factory, keyFactoryLpList()), ""), SEP)
111134
112135
113136 func readFactoryCfgOrFail (factory) = split(getStringByAddressOrFail(factory, keyFactoryCfg()), SEP)
114137
115138
116139 func getBoostingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgBoostingDapp])
117140
118141
119142 func getEmissionAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgEmissionDapp])
120143
121144
122145 func getStakingAddressOrFail (factoryCfg) = addressFromStringValue(factoryCfg[IdxFactoryCfgStakingDapp])
123146
124147
125148 func keyEmissionRatePerBlockCurrent () = "%s%s__ratePerBlock__current"
126149
127150
128151 func keyEmissionRatePerBlockMaxCurrent () = "%s%s__ratePerBlockMax__current"
129152
130153
131154 func keyEmissionStartBlock () = "%s%s__emission__startBlock"
132155
133156
134157 func keyEmissionDurationInBlocks () = "%s%s__emission__duration"
135158
136159
137160 func keyEmissionEndBlock () = "%s%s__emission__endBlock"
138161
139162
140163 func keyStakedByUser (userAddressStr,lpAssetIdStr) = makeString(["%s%s%s__staked", userAddressStr, lpAssetIdStr], SEP)
141164
142165
143166 func keyStakedTotal (lpAssetIdStr) = ("%s%s%s__staked__total__" + lpAssetIdStr)
144167
145168
146169 func keyClaimedByUser (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimed", userAddressStr, lpAssetIdStr], SEP)
147170
148171
149172 func keyClaimedByUserMinReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedMinReward", userAddressStr, lpAssetIdStr], SEP)
150173
151174
152175 func keyClaimedByUserBoostReward (lpAssetIdStr,userAddressStr) = makeString(["%s%s%s__claimedBoostReward", userAddressStr, lpAssetIdStr], SEP)
153176
154177
155-func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed", "total", lpAssetIdStr], SEP)
178+func keyClaimedTotal (lpAssetIdStr) = makeString(["%s%s%s__claimed__total", lpAssetIdStr], SEP)
156179
157180
158181 func readStaked (key) = valueOrElse(getInteger(this, key), 0)
159182
160183
161184 func keyLastTotalLpBalance (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "bal"], SEP)
162185
163186
164187 func keyLastUserLpBalance (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "bal"], SEP)
165188
166189
167190 func keyTotalLpBalanceIntegral (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "balINT"], SEP)
168191
169192
170193 func keyUserLpBalanceIntegral (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "balINT"], SEP)
171194
172195
173196 func keyTotalLpBalanceIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s", lpAssetId, "total", "lastUpd"], SEP)
174197
175198
176199 func keyUserLpBalanceIntegralLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s", lpAssetId, userAddress, "lastUpd"], SEP)
177200
178201
179202 func keyWxPerLpIntegral (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpInt"], SEP)
180203
181204
182205 func keyWxPerLpIntegralLastUpdHeight (lpAssetId) = makeString(["%s%s%s%s", lpAssetId, "common", "lpIntH"], SEP)
183206
184207
185208 func keyWxToClaimUser (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpInt"], SEP)
186209
187210
188211 func keyWxPerLpIntegralUserLastUpdHeight (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "lpIntH"], SEP)
189212
190213
191214 func keyWxPerLp (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLp"], SEP)
192215
193216
194217 func keyWxPerLpX18 (lpAssetId) = makeString(["%s", lpAssetId, "wxPerLpX18"], SEP)
195218
196219
197220 func keyWxPerLpIntegralUserLast (lpAssetId,userAddress) = makeString(["%s%s%s%s", lpAssetId, userAddress, "uIntL"], SEP)
198221
199222
200223 func keyOperationHistoryRecord (type,userAddress,txId58) = makeString(["%s%s%s%s__history", type, userAddress, txId58], SEP)
201224
202225
203226 func formatHistoryRecord (userAddress,lpAssetId,type,amount) = makeString(["%s%s%s%d%d%d", userAddress, lpAssetId, type, toString(height), toString(lastBlock.timestamp), toString(amount)], SEP)
204227
205228
206229 func OperationHistoryEntry (type,userAddress,lpAssetId,amount,txId) = StringEntry(keyOperationHistoryRecord(type, userAddress, toBase58String(txId)), formatHistoryRecord(userAddress, lpAssetId, type, amount))
207230
208231
209-let factoryAddress = getStringOrFail(keyFactoryAddress())
232+let factoryAddress = getStringOrFail(this, keyFactoryAddress())
210233
211234 let factoryContract = addressFromStringValue(factoryAddress)
212235
213236 let factoryCfg = readFactoryCfgOrFail(factoryContract)
214237
215238 let emissionContract = getEmissionAddressOrFail(factoryCfg)
216239
217240 let boostingContract = getBoostingAddressOrFail(factoryCfg)
218241
219-func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == 0))
220- then (stakedByUser > 0)
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+
305+func calcWxPerLpIntegralUserLast (stakedByUser,wxPerLpIntegralUserLastUpdHeightOrZero,wxPerLpIntegralNew,wxPerLpIntegralUserLastKEY) = if (if ((wxPerLpIntegralUserLastUpdHeightOrZero == zeroBigInt))
306+ then (stakedByUser > zeroBigInt)
221307 else false)
222- then 0
223- else if ((stakedByUser == 0))
308+ then zeroBigInt
309+ else if ((stakedByUser == zeroBigInt))
224310 then wxPerLpIntegralNew
225- else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > 0))
226- then (stakedByUser > 0)
311+ else if (if ((wxPerLpIntegralUserLastUpdHeightOrZero > zeroBigInt))
312+ then (stakedByUser > zeroBigInt)
227313 else false)
228- then getIntOrFail(this, wxPerLpIntegralUserLastKEY)
314+ then value(parseBigInt(getStringOrFail(this, wxPerLpIntegralUserLastKEY)))
229315 else throw("calcWxPerLpIntegralUserLast: unexpected state")
230316
231317
232318 func refreshPoolINTEGRALS (lpAssetIdStr,poolAddressStr,lpDeltaAmount) = {
233319 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
234- let stakedTotal = readStaked(stakedTotalKEY)
320+ let stakedTotal = toBigInt(readStaked(stakedTotalKEY))
321+ let nonZeroStakedTotal = if ((stakedTotal == zeroBigInt))
322+ then oneBigInt
323+ else stakedTotal
235324 let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
236325 let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
237326 let MULT3 = 1000
238327 let wxEmissionPerBlockX3 = (getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent()) * MULT3)
239328 let poolWxEmissionPerBlockX3 = fraction(wxEmissionPerBlockX3, poolWeight, (POOLWEIGHTMULT * 3))
240329 let wxPerLpIntegralKEY = keyWxPerLpIntegral(lpAssetIdStr)
241330 let wxPerLpIntegralLastUpdHeightKEY = keyWxPerLpIntegralLastUpdHeight(lpAssetIdStr)
242331 let wxPerLpKEY = keyWxPerLp(lpAssetIdStr)
243332 let wxPerLpIntegralLastUpdHeight = getIntOrDefault(this, wxPerLpIntegralLastUpdHeightKEY, emissionStartBlock)
244- let wxPerLpIntegral = getIntOrZero(this, wxPerLpIntegralKEY)
333+ let wxPerLpIntegral = getBigIntFromStringOrZero(this, wxPerLpIntegralKEY)
245334 let wxPerLpOrZeroX3 = 0
246335 let dh = max([(height - wxPerLpIntegralLastUpdHeight), 0])
247336 let wxPerLpX3 = if ((wxPerLpOrZeroX3 != 0))
248- then wxPerLpOrZeroX3
249- else fraction(poolWxEmissionPerBlockX3, MULT8, stakedTotal)
250- let stakedTotalNew = (stakedTotal + lpDeltaAmount)
251- let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * dh))
252- let wxPerLpX3New = (poolWxEmissionPerBlockX3 / stakedTotalNew)
337+ then toBigInt(wxPerLpOrZeroX3)
338+ else fraction(toBigInt(poolWxEmissionPerBlockX3), toBigInt(MULT8), nonZeroStakedTotal)
339+ let stakedTotalNew = (stakedTotal + toBigInt(lpDeltaAmount))
340+ let nonZeroStakedTotalNew = if ((stakedTotalNew == zeroBigInt))
341+ then oneBigInt
342+ else stakedTotalNew
343+ let wxPerLpIntegralNew = (wxPerLpIntegral + (wxPerLpX3 * toBigInt(dh)))
344+ let wxPerLpX3New = (toBigInt(poolWxEmissionPerBlockX3) / nonZeroStakedTotalNew)
253345 let wxPerLpIntegralLastUpdHeightNew = height
254- let debug = makeString([toString(wxPerLpIntegralNew), toString(dh), toString(wxPerLpX3), toString(stakedTotal), toString(poolWxEmissionPerBlockX3), toString(wxEmissionPerBlockX3), toString(poolWeight)], "::")
255- $Tuple3(wxPerLpIntegralNew, [IntegerEntry(wxPerLpIntegralKEY, wxPerLpIntegralNew), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), IntegerEntry(wxPerLpKEY, wxPerLpX3New)], debug)
346+ let debug = makeString(["wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "dh=", toString(dh), "wxPerLpX3=", toString(wxPerLpX3), "stakedTotal=", toString(stakedTotal), "poolWxEmissionPerBlockX3=", toString(poolWxEmissionPerBlockX3), "wxEmissionPerBlockX3=", toString(wxEmissionPerBlockX3), "poolWeight=", toString(poolWeight)], "::")
347+ $Tuple3(wxPerLpIntegralNew, [StringEntry(wxPerLpIntegralKEY, toString(wxPerLpIntegralNew)), IntegerEntry(wxPerLpIntegralLastUpdHeightKEY, wxPerLpIntegralLastUpdHeightNew), StringEntry(wxPerLpKEY, toString(wxPerLpX3New))], debug)
256348 }
257349
258350
259351 func refreshINTEGRALS (lpAssetIdStr,userAddressStr,poolAddressStr,lpDeltaAmount) = {
260- let $t01049410616 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
261- let wxPerLpIntegralNew = $t01049410616._1
262- let poolIntegralSTATE = $t01049410616._2
263- let poolDEBUG = $t01049410616._3
352+ let $t01447314595 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, lpDeltaAmount)
353+ let wxPerLpIntegralNew = $t01447314595._1
354+ let poolIntegralSTATE = $t01447314595._2
355+ let poolDEBUG = $t01447314595._3
264356 let MULT3 = 1000
265357 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
266358 let stakedByUser = readStaked(stakedByUserKEY)
267359 let wxToClaimUserKEY = keyWxToClaimUser(lpAssetIdStr, userAddressStr)
268360 let wxPerLpIntegralUserLastUpdHeightKEY = keyWxPerLpIntegralUserLastUpdHeight(lpAssetIdStr, userAddressStr)
269361 let wxPerLpIntegralUserLastKEY = keyWxPerLpIntegralUserLast(lpAssetIdStr, userAddressStr)
270- let wxToClaimUser = getIntOrZero(this, wxToClaimUserKEY)
362+ let wxToClaimUser = getBigIntFromStringOrZero(this, wxToClaimUserKEY)
271363 let wxPerLpIntegralUserLastUpdHeightOrZero = getIntOrZero(this, wxPerLpIntegralUserLastUpdHeightKEY)
272- let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(stakedByUser, wxPerLpIntegralUserLastUpdHeightOrZero, wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
273- let wxToClaimUserNew = (wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), stakedByUser, (MULT8 * MULT3)))
364+ let wxPerLpIntegralUserLast = calcWxPerLpIntegralUserLast(toBigInt(stakedByUser), toBigInt(wxPerLpIntegralUserLastUpdHeightOrZero), wxPerLpIntegralNew, wxPerLpIntegralUserLastKEY)
365+ let MULT11 = (MULT8 * MULT3)
366+ let wxToClaimUserNew = (wxToClaimUser + fraction((wxPerLpIntegralNew - wxPerLpIntegralUserLast), toBigInt(stakedByUser), toBigInt(MULT11)))
274367 let wxPerLpIntegralUserLastNew = wxPerLpIntegralNew
275368 let wxPerLpIntegralUserLastUpdHeightNew = height
276- let debug = makeString([toString(wxToClaimUserNew), toString(wxPerLpIntegralUserLast), toString(stakedByUser), poolDEBUG, toString(height)], "::")
277- $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [IntegerEntry(wxToClaimUserKEY, wxToClaimUserNew), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), IntegerEntry(wxPerLpIntegralUserLastKEY, wxPerLpIntegralUserLastNew)]), debug)
369+ let debug = makeString(["wxPerLpIntegralUserLastUpdHeightOrZero=", toString(wxPerLpIntegralUserLastUpdHeightOrZero), "wxPerLpIntegralNew=", toString(wxPerLpIntegralNew), "wxToClaimUserNew=", toString(wxToClaimUserNew), "wxPerLpIntegralUserLast=", toString(wxPerLpIntegralUserLast), "stakedByUser=", toString(stakedByUser), "poolDEBUG=", poolDEBUG, "height=", toString(height)], "::")
370+ $Tuple3(wxToClaimUserNew, (poolIntegralSTATE ++ [StringEntry(wxToClaimUserKEY, toString(wxToClaimUserNew)), IntegerEntry(wxPerLpIntegralUserLastUpdHeightKEY, wxPerLpIntegralUserLastUpdHeightNew), StringEntry(wxPerLpIntegralUserLastKEY, toString(wxPerLpIntegralUserLastNew))]), debug)
278371 }
279372
280373
281374 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
375+ case s: String =>
376+ fromBase58String(s)
377+ case _: Unit =>
378+ unit
379+ case _ =>
380+ throw("Match error")
381+}
382+
383+
384+func migratorPublicKeyOrUnit () = match getString(keyMigratorPublicKey()) {
282385 case s: String =>
283386 fromBase58String(s)
284387 case _: Unit =>
285388 unit
286389 case _ =>
287390 throw("Match error")
288391 }
289392
290393
291394 func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) {
292395 case s: String =>
293396 fromBase58String(s)
294397 case _: Unit =>
295398 unit
296399 case _ =>
297400 throw("Match error")
298401 }
299402
300403
301-func mustManager (i) = {
302- let pd = throw("Permission denied")
303- match managerPublicKeyOrUnit() {
304- case pk: ByteVector =>
305- if ((i.callerPublicKey == pk))
306- then true
307- else pd
308- case _: Unit =>
309- if ((i.caller == this))
310- then true
311- else pd
312- case _ =>
313- throw("Match error")
314- }
315- }
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+}
316423
317424
318425 @Callable(i)
319426 func constructor (factoryAddressStr) = {
320427 let checkCaller = mustManager(i)
321428 if ((checkCaller == checkCaller))
322429 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)]
323442 else throw("Strict value is not equal to itself.")
324443 }
325444
326445
327446
328447 @Callable(i)
329448 func setManager (pendingManagerPublicKey) = {
330449 let checkCaller = mustManager(i)
331450 if ((checkCaller == checkCaller))
332451 then {
333452 let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey)
334453 if ((checkManagerPublicKey == checkManagerPublicKey))
335454 then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)]
336455 else throw("Strict value is not equal to itself.")
337456 }
338457 else throw("Strict value is not equal to itself.")
339458 }
340459
341460
342461
343462 @Callable(i)
344463 func confirmManager () = {
345464 let pm = pendingManagerPublicKeyOrUnit()
346465 let hasPM = if (isDefined(pm))
347466 then true
348467 else throw("No pending manager")
349468 if ((hasPM == hasPM))
350469 then {
351470 let checkPM = if ((i.callerPublicKey == value(pm)))
352471 then true
353472 else throw("You are not pending manager")
354473 if ((checkPM == checkPM))
355474 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
356475 else throw("Strict value is not equal to itself.")
357476 }
358477 else throw("Strict value is not equal to itself.")
359478 }
360479
361480
362481
363482 @Callable(i)
364483 func stake () = if ((size(i.payments) != 1))
365484 then throw("invalid payment - exact one payment must be attached")
366485 else {
367486 let pmt = i.payments[0]
368487 let lpAssetId = value(pmt.assetId)
369488 let lpAssetIdStr = toBase58String(lpAssetId)
370489 let amount = pmt.amount
371490 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
372491 let callerStr = toString(i.caller)
373492 let userAddressStr = if ((callerStr == poolAddressStr))
374493 then toString(i.originCaller)
375494 else callerStr
376495 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
377496 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
378497 let stakedByUser = readStaked(stakedByUserKEY)
379498 let stakedTotal = readStaked(stakedTotalKEY)
380- let $t01427414391 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
381- let wxToClaimUserNew = $t01427414391._1
382- let integralSTATE = $t01427414391._2
383- let debug = $t01427414391._3
384- ([IntegerEntry(stakedByUserKEY, (stakedByUser + amount)), IntegerEntry(stakedTotalKEY, (stakedTotal + amount)), OperationHistoryEntry("stake", userAddressStr, lpAssetIdStr, amount, i.transactionId)] ++ integralSTATE)
499+ let $t01946419581 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, amount)
500+ let wxToClaimUserNew = $t01946419581._1
501+ let integralSTATE = $t01946419581._2
502+ let debug = $t01946419581._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)
385508 }
386509
387510
388511
389512 @Callable(i)
390513 func unstake (lpAssetIdStr,amount) = {
391514 let lpAssetId = fromBase58String(lpAssetIdStr)
392515 let poolAddressStr = valueOrErrorMessage(getString(factoryContract, keyFactoryLp2AssetsMapping(lpAssetIdStr)), ("unsupported lp asset " + lpAssetIdStr))
393516 let poolAddon = valueOrElse(getString(this, keyStablePoolAddonAddr()), poolAddressStr)
394517 let callerStr = toString(i.caller)
395518 let userAddressStr = if (if ((callerStr == poolAddressStr))
396519 then true
397520 else (callerStr == poolAddon))
398521 then toString(i.originCaller)
399522 else callerStr
400523 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
401524 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
402525 let stakedByUser = readStaked(stakedByUserKEY)
403526 let stakedTotal = readStaked(stakedTotalKEY)
404- let $t01552815646 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
405- let wxToClaimUserNew = $t01552815646._1
406- let integralSTATE = $t01552815646._2
407- let debug = $t01552815646._3
527+ let $t02091621034 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, -(amount))
528+ let wxToClaimUserNew = $t02091621034._1
529+ let integralSTATE = $t02091621034._2
530+ let debug = $t02091621034._3
531+ let listName = getUsersListName(lpAssetIdStr)
532+ let listActions = if (containsNode(listName, userAddressStr))
533+ then deleteNodeActions(listName, userAddressStr)
534+ else nil
408535 if ((amount > stakedByUser))
409536 then throw("passed amount is less then available")
410- 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)
411538 }
412539
413540
414541
415542 @Callable(i)
416543 func claimWx (lpAssetIdStr) = {
417- let userAddress = i.caller
418544 let userAddressStr = toString(i.caller)
419- let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
420- let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
421- let claimedTotalKEY = keyClaimedTotal(lpAssetIdStr)
422- let claimedByUserMinRewardKEY = keyClaimedByUserMinReward(lpAssetIdStr, userAddressStr)
423- let claimedByUserBoostRewardKEY = keyClaimedByUserBoostReward(lpAssetIdStr, userAddressStr)
424- let claimedByUser = getIntOrZero(this, claimedByUserKEY)
425- let claimedByUserMinReward = getIntOrZero(this, claimedByUserMinRewardKEY)
426- let claimedByUserBoostReward = getIntOrZero(this, claimedByUserBoostRewardKEY)
427- let claimedTotal = getIntOrZero(this, claimedTotalKEY)
428- let $t01683816950 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
429- let wxToClaimUserNew = $t01683816950._1
430- let integralSTATE = $t01683816950._2
431- let debug = $t01683816950._3
432- let availableToClaim = (wxToClaimUserNew - claimedByUser)
433- if ((0 >= availableToClaim))
434- then throw("nothing to claim")
435- else {
436- let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[0])
437- let minRewardPart = availableToClaim
438- let boostRewardPart = min([(minRewardPart * 2), wxAmountBoostTotal])
439- let wxAssetId = asByteVector(asAnyList(invoke(emissionContract, "emit", [minRewardPart], nil))[0])
440- let emitBoost = asAnyList(invoke(emissionContract, "emit", [boostRewardPart], nil))
441- if ((emitBoost == emitBoost))
442- then [IntegerEntry(claimedByUserKEY, (claimedByUser + availableToClaim)), IntegerEntry(claimedByUserMinRewardKEY, (claimedByUserMinReward + minRewardPart)), IntegerEntry(claimedByUserBoostRewardKEY, (claimedByUserBoostReward + boostRewardPart)), IntegerEntry(claimedTotalKEY, (claimedTotal + availableToClaim)), ScriptTransfer(userAddress, minRewardPart, wxAssetId), ScriptTransfer(userAddress, boostRewardPart, wxAssetId), OperationHistoryEntry("claim", userAddressStr, lpAssetIdStr, availableToClaim, i.transactionId)]
443- else throw("Strict value is not equal to itself.")
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 = toBigInt(getIntOrZero(this, claimedByUserKEY))
563+ let claimedByUserMinReward = toBigInt(getIntOrZero(this, claimedByUserMinRewardKEY))
564+ let claimedByUserBoostReward = toBigInt(getIntOrZero(this, claimedByUserBoostRewardKEY))
565+ let claimedTotal = getBigIntFromStringOrZero(this, claimedTotalKEY)
566+ let $t02277622888 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
567+ let wxToClaimUserNew = $t02277622888._1
568+ let integralSTATE = $t02277622888._2
569+ let debug = $t02277622888._3
570+ let availableToClaim = (wxToClaimUserNew - claimedByUser)
571+ if ((zeroBigInt >= availableToClaim))
572+ then throw("nothing to claim")
573+ else {
574+ let wxAmountBoostTotal = asInt(asAnyList(invoke(boostingContract, "claimWxBoost", [lpAssetIdStr, userAddressStr], nil))[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)
585+[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.")
588+ }
444589 }
590+ else throw("Strict value is not equal to itself.")
445591 }
446592
447593
448594
449595 @Callable(i)
450596 func claimWxREADONLY (lpAssetIdStr,userAddressStr) = {
451597 let stakedByUserKEY = keyStakedByUser(userAddressStr, lpAssetIdStr)
452598 let stakedTotalKEY = keyStakedTotal(lpAssetIdStr)
453599 let claimedByUserKEY = keyClaimedByUser(lpAssetIdStr, userAddressStr)
454600 let stakedByUser = readStaked(stakedByUserKEY)
455601 let stakedTotal = readStaked(stakedTotalKEY)
456602 let claimedByUser = getIntOrZero(this, claimedByUserKEY)
457603 let poolAddressStr = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetIdStr))
458604 let poolWeight = getIntegerValue(factoryContract, keyFactoryPoolWeight(poolAddressStr))
459605 let wxEmissionPerBlock = getIntOrFail(emissionContract, keyEmissionRatePerBlockCurrent())
460606 let emissionStartBlock = getIntOrFail(emissionContract, keyEmissionStartBlock())
461607 let passedBlocks = if ((emissionStartBlock > height))
462608 then 0
463609 else (height - emissionStartBlock)
464610 let poolWxEmission = fraction((wxEmissionPerBlock * passedBlocks), poolWeight, POOLWEIGHTMULT)
465611 let userWxReward = fraction(poolWxEmission, stakedByUser, stakedTotal)
466- let $t01915119263 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
467- let wxToClaimUserNew = $t01915119263._1
468- let integralSTATE = $t01915119263._2
469- let debug = $t01915119263._3
470- let availableToClaim = (wxToClaimUserNew - claimedByUser)
612+ let $t02548825600 = refreshINTEGRALS(lpAssetIdStr, userAddressStr, poolAddressStr, 0)
613+ let wxToClaimUserNew = $t02548825600._1
614+ let integralSTATE = $t02548825600._2
615+ let debug = $t02548825600._3
616+ let availableToClaim = (wxToClaimUserNew - toBigInt(claimedByUser))
471617 let boostInvResult = asAnyList(invoke(boostingContract, "claimWxBoostREADONLY", [lpAssetIdStr, userAddressStr], nil))
472618 let wxAmountBoostTotal = asInt(boostInvResult[0])
473619 let boostDebug = asString(boostInvResult[1])
474620 let minRewardPart = availableToClaim
475- let boostRewardPart = min([(minRewardPart * 2), wxAmountBoostTotal])
621+ let boostRewardPart = min([(minRewardPart * toBigInt(2)), toBigInt(wxAmountBoostTotal)])
476622 let totalReward = (minRewardPart + boostRewardPart)
477623 $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))
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 = getIntOrZero(this, keyClaimedByUser(lpAssetId, userAddress))
650+ let poolAddress = getStringByAddressOrFail(factoryContract, keyFactoryLpAssetToPoolContractAddress(lpAssetId))
651+ let $t02716927272 = refreshINTEGRALS(lpAssetId, userAddress, poolAddress, 0)
652+ let wxToClaimUserNew = $t02716927272._1
653+ let integralSTATE = $t02716927272._2
654+ let debug = $t02716927272._3
655+ let availableToClaim = (wxToClaimUserNew - toBigInt(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.")
478677 }
479678
480679
481680
482681 @Callable(i)
483682 func onModifyWeight (lpAssetIdStr,poolAddressStr) = if ((i.caller != factoryContract))
484683 then throw("permissions denied")
485684 else {
486- let $t02014320253 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
487- let wxPerLpIntegralNew = $t02014320253._1
488- let poolIntegralSTATE = $t02014320253._2
489- let poolDEBUG = $t02014320253._3
685+ let $t02795728067 = refreshPoolINTEGRALS(lpAssetIdStr, poolAddressStr, 0)
686+ let wxPerLpIntegralNew = $t02795728067._1
687+ let poolIntegralSTATE = $t02795728067._2
688+ let poolDEBUG = $t02795728067._3
490689 poolIntegralSTATE
491690 }
492691
493692
494693 @Verifier(tx)
495694 func verify () = {
496695 let targetPublicKey = match managerPublicKeyOrUnit() {
497696 case pk: ByteVector =>
498697 pk
499698 case _: Unit =>
500699 tx.senderPublicKey
501700 case _ =>
502701 throw("Match error")
503702 }
504- sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
703+ let migratorPublicKey = match migratorPublicKeyOrUnit() {
704+ case pk: ByteVector =>
705+ pk
706+ case _: Unit =>
707+ tx.senderPublicKey
708+ case _ =>
709+ throw("Match error")
710+ }
711+ if (sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey))
712+ then true
713+ else sigVerify(tx.bodyBytes, tx.proofs[0], migratorPublicKey)
505714 }
506715

github/deemru/w8io/873ac7e 
89.70 ms