tx · 3jdi6X77MRCd5erxJQ1tzpwpJqetjbfo3U1ejbNmsAR4

3NBbSp7yXAeyAmM8uuoenTt3XFfCGQZsHon:  -0.03000000 Waves

2023.05.04 14:18 [2562940] smart account 3NBbSp7yXAeyAmM8uuoenTt3XFfCGQZsHon > SELF 0.00000000 Waves

{ "type": 13, "id": "3jdi6X77MRCd5erxJQ1tzpwpJqetjbfo3U1ejbNmsAR4", "fee": 3000000, "feeAssetId": null, "timestamp": 1683199129465, "version": 2, "chainId": 84, "sender": "3NBbSp7yXAeyAmM8uuoenTt3XFfCGQZsHon", "senderPublicKey": "EdMvX1KG6dSSSsAqgamTtbKQho4ZLojCVgcBU4CDSeix", "proofs": [ "iC7Nhhhjm3DGqtCwV1jpkSSxnKisDm7oPiZBB5z3A64Khdzyf7VcQUFmUpmBuz6A5MT7y9DWbh6FcDUxQWXSxaq" ], "script": "base64:BgIzCAISAwoBCBIAEgQKAgIBEgQKAgIBEgcKBQgICAgIEgASBAoCCAgSABIECgIICBIDCgEIQQAJc2VwYXJhdG9yAgJfXwASc2hhcmVBc3NldERlY2ltYWxzAAgAC3dhdmVzU3RyaW5nAgVXQVZFUwAHc2NhbGUxOACAgJC7utat8A0ADXNjYWxlMThCaWdJbnQJALYCAQUHc2NhbGUxOAEHd3JhcEVycgEDbXNnCQC5CQIJAMwIAgIWbHBfc3Rha2luZ19wb29scy5yaWRlOgkAzAgCBQNtc2cFA25pbAIBIAEIdGhyb3dFcnIBA21zZwkAAgEJAQd3cmFwRXJyAQUDbXNnARJlcnJLZXlJc05vdERlZmluZWQCB2FkZHJlc3MDa2V5CQEHd3JhcEVycgEJALkJAgkAzAgCAgptYW5kYXRvcnkgCQDMCAIJAKUIAQUHYWRkcmVzcwkAzAgCAgEuCQDMCAIFA2tleQkAzAgCAg8gaXMgbm90IGRlZmluZWQFA25pbAIAAQxnZXRTdHJPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ0IAgUHYWRkcmVzcwUDa2V5CQESZXJyS2V5SXNOb3REZWZpbmVkAgUHYWRkcmVzcwUDa2V5AQxnZXRJbnRPckZhaWwCB2FkZHJlc3MDa2V5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUHYWRkcmVzcwUDa2V5CQESZXJyS2V5SXNOb3REZWZpbmVkAgUHYWRkcmVzcwUDa2V5AQxwYXJzZUFzc2V0SWQBBWlucHV0AwkAAAIFBWlucHV0BQt3YXZlc1N0cmluZwUEdW5pdAkA2QQBBQVpbnB1dAEPYXNzZXRJZFRvU3RyaW5nAQVpbnB1dAMJAAACBQVpbnB1dAUEdW5pdAULd2F2ZXNTdHJpbmcJANgEAQkBBXZhbHVlAQUFaW5wdXQBDmVuc3VyZVBvc2l0aXZlAQF2AwkAZwIFAXYAAAUBdgkBCHRocm93RXJyAQIYdmFsdWUgc2hvdWxkIGJlIHBvc2l0aXZlARJrZXlGYWN0b3J5Q29udHJhY3QACQC5CQIJAMwIAgICJXMJAMwIAgIPZmFjdG9yeUNvbnRyYWN0BQNuaWwFCXNlcGFyYXRvcgEUa2V5THBTdGFraW5nQ29udHJhY3QACQC5CQIJAMwIAgICJXMJAMwIAgIRbHBTdGFraW5nQ29udHJhY3QFA25pbAUJc2VwYXJhdG9yARJrZXlTdGFraW5nQ29udHJhY3QACQC5CQIJAMwIAgICJXMJAMwIAgIPc3Rha2luZ0NvbnRyYWN0BQNuaWwFCXNlcGFyYXRvcgETa2V5Qm9vc3RpbmdDb250cmFjdAAJALkJAgkAzAgCAgIlcwkAzAgCAhBib29zdGluZ0NvbnRyYWN0BQNuaWwFCXNlcGFyYXRvcgEPa2V5U3dhcENvbnRyYWN0AAkAuQkCCQDMCAICAiVzCQDMCAICDHN3YXBDb250cmFjdAUDbmlsBQlzZXBhcmF0b3IBFmtleUFzc2V0c1N0b3JlQ29udHJhY3QACQC5CQIJAMwIAgICJXMJAMwIAgITYXNzZXRzU3RvcmVDb250cmFjdAUDbmlsBQlzZXBhcmF0b3IBDmtleVVzZHRBc3NldElkAAkAuQkCCQDMCAICAiVzCQDMCAICC3VzZHRBc3NldElkBQNuaWwFCXNlcGFyYXRvcgEMa2V5V3hBc3NldElkAAkAuQkCCQDMCAICAiVzCQDMCAICCXd4QXNzZXRJZAUDbmlsBQlzZXBhcmF0b3IBC2tleVNodXRkb3duAAkAuQkCCQDMCAICAiVzCQDMCAICCHNodXRkb3duBQNuaWwFCXNlcGFyYXRvcgELa2V5TWluRGVsYXkACQC5CQIJAMwIAgICJXMJAMwIAgIIbWluRGVsYXkFA25pbAUJc2VwYXJhdG9yAQ9rZXlMb2NrRnJhY3Rpb24ACQC5CQIJAMwIAgICJXMJAMwIAgIMbG9ja0ZyYWN0aW9uBQNuaWwFCXNlcGFyYXRvcgEPa2V5U2hhcmVBc3NldElkAQtiYXNlQXNzZXRJZAkAuQkCCQDMCAICBCVzJXMJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkCQDMCAICDHNoYXJlQXNzZXRJZAUDbmlsBQlzZXBhcmF0b3IBDmtleUJhc2VBc3NldElkAQxzaGFyZUFzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQxzaGFyZUFzc2V0SWQJAMwIAgILYmFzZUFzc2V0SWQFA25pbAUJc2VwYXJhdG9yAQlrZXlQZXJpb2QBC2Jhc2VBc3NldElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQULYmFzZUFzc2V0SWQJAMwIAgIGcGVyaW9kBQNuaWwFCXNlcGFyYXRvcgEUa2V5UGVyaW9kU3RhcnRIZWlnaHQCC2Jhc2VBc3NldElkBnBlcmlvZAkAuQkCCQDMCAICBiVzJXMlZAkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQULYmFzZUFzc2V0SWQJAMwIAgIRcGVyaW9kU3RhcnRIZWlnaHQJAMwIAgkApAMBBQZwZXJpb2QFA25pbAUJc2VwYXJhdG9yARtrZXlCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQBC2Jhc2VBc3NldElkCQC5CQIJAMwIAgIEJXMlcwkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQULYmFzZUFzc2V0SWQJAMwIAgIYYmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0BQNuaWwFCXNlcGFyYXRvcgEca2V5U2hhcmVBc3NldEFtb3VudFRvQ29udmVydAELYmFzZUFzc2V0SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQtiYXNlQXNzZXRJZAkAzAgCAhlzaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0BQNuaWwFCXNlcGFyYXRvcgEfa2V5VXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydAILYmFzZUFzc2V0SWQLdXNlckFkZHJlc3MJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkCQDMCAIJAKUIAQULdXNlckFkZHJlc3MJAMwIAgIYYmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0BQNuaWwFCXNlcGFyYXRvcgEla2V5VXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZAILYmFzZUFzc2V0SWQLdXNlckFkZHJlc3MJALkJAgkAzAgCAgglcyVzJXMlcwkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQULYmFzZUFzc2V0SWQJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwkAzAgCAhhiYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQJAMwIAgIGcGVyaW9kBQNuaWwFCXNlcGFyYXRvcgEga2V5VXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQCC2Jhc2VBc3NldElkC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQtiYXNlQXNzZXRJZAkAzAgCCQClCAEFC3VzZXJBZGRyZXNzCQDMCAICGXNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQFA25pbAUJc2VwYXJhdG9yASZrZXlVc2VyU2hhcmVBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZAILYmFzZUFzc2V0SWQLdXNlckFkZHJlc3MJALkJAgkAzAgCAgglcyVzJXMlcwkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQULYmFzZUFzc2V0SWQJAMwIAgkApQgBBQt1c2VyQWRkcmVzcwkAzAgCAhlzaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0CQDMCAICBnBlcmlvZAUDbmlsBQlzZXBhcmF0b3IBDmtleVByaWNlUGVyaW9kAgtiYXNlQXNzZXRJZAZwZXJpb2QJALkJAgkAzAgCAgYlcyVzJWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkCQDMCAICBXByaWNlCQDMCAIJAKQDAQUGcGVyaW9kBQNuaWwFCXNlcGFyYXRvcgEPa2V5UHJpY2VIaXN0b3J5AQtiYXNlQXNzZXRJZAkAuQkCCQDMCAICCiVzJXMlcyVkJWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkCQDMCAICBXByaWNlCQDMCAICB2hpc3RvcnkJAMwIAgkApAMBCAUJbGFzdEJsb2NrBmhlaWdodAkAzAgCCQCkAwEIBQlsYXN0QmxvY2sJdGltZXN0YW1wBQNuaWwFCXNlcGFyYXRvcgERa2V5UHJpY2VQZXJpb2RQdXQCC2Jhc2VBc3NldElkBnBlcmlvZAkAuQkCCQDMCAICCCVzJXMlZCVzCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQtiYXNlQXNzZXRJZAkAzAgCAgVwcmljZQkAzAgCCQCkAwEFBnBlcmlvZAkAzAgCAgNwdXQFA25pbAUJc2VwYXJhdG9yARJrZXlQcmljZVB1dEhpc3RvcnkBC2Jhc2VBc3NldElkCQC5CQIJAMwIAgIMJXMlcyVzJXMlZCVkCQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQtiYXNlQXNzZXRJZAkAzAgCAgVwcmljZQkAzAgCAgdoaXN0b3J5CQDMCAICA3B1dAkAzAgCCQCkAwEIBQlsYXN0QmxvY2sGaGVpZ2h0CQDMCAIJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAFA25pbAUJc2VwYXJhdG9yARFrZXlQcmljZVBlcmlvZEdldAILYmFzZUFzc2V0SWQGcGVyaW9kCQC5CQIJAMwIAgIIJXMlcyVkJXMJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkCQDMCAICBXByaWNlCQDMCAIJAKQDAQUGcGVyaW9kCQDMCAICA2dldAUDbmlsBQlzZXBhcmF0b3IBEmtleVByaWNlR2V0SGlzdG9yeQELYmFzZUFzc2V0SWQJALkJAgkAzAgCAgwlcyVzJXMlcyVkJWQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkCQDMCAICBXByaWNlCQDMCAICB2hpc3RvcnkJAMwIAgIDZ2V0CQDMCAIJAKQDAQgFCWxhc3RCbG9jawZoZWlnaHQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAUDbmlsBQlzZXBhcmF0b3IBD2tleUhpc3RvcnlFbnRyeQULYmFzZUFzc2V0SWQJb3BlcmF0aW9uBnBlcmlvZAt1c2VyQWRkcmVzcwR0eElkCQC5CQIJAMwIAgIIJXMlcyVzJXMJAMwIAgIHaGlzdG9yeQkAzAgCBQlvcGVyYXRpb24JAMwIAgkApQgBBQt1c2VyQWRkcmVzcwkAzAgCCQDYBAEFBHR4SWQJAMwIAgkApAMBBQZoZWlnaHQFA25pbAUJc2VwYXJhdG9yARNrZXlNYW5hZ2VyUHVibGljS2V5AAIUJXNfX21hbmFnZXJQdWJsaWNLZXkBGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAIbJXNfX3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5ARZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAQHJG1hdGNoMAkAoggBCQETa2V5TWFuYWdlclB1YmxpY0tleQADCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQDZBAEFAXMDCQABAgUHJG1hdGNoMAIEVW5pdAUEdW5pdAkAAgECC01hdGNoIGVycm9yAR1wZW5kaW5nTWFuYWdlclB1YmxpY0tleU9yVW5pdAAEByRtYXRjaDAJAKIIAQkBGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAJANkEAQUBcwMJAAECBQckbWF0Y2gwAgRVbml0BQR1bml0CQACAQILTWF0Y2ggZXJyb3IAFXBlcm1pc3Npb25EZW5pZWRFcnJvcgkAAgECEVBlcm1pc3Npb24gZGVuaWVkAQhtdXN0VGhpcwEBaQMJAAACCAUBaQZjYWxsZXIFBHRoaXMGBRVwZXJtaXNzaW9uRGVuaWVkRXJyb3IBC211c3RNYW5hZ2VyAQFpBAckbWF0Y2gwCQEWbWFuYWdlclB1YmxpY0tleU9yVW5pdAADCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQCcGsFByRtYXRjaDADCQAAAggFAWkPY2FsbGVyUHVibGljS2V5BQJwawYFFXBlcm1pc3Npb25EZW5pZWRFcnJvcgMJAAECBQckbWF0Y2gwAgRVbml0CQEIbXVzdFRoaXMBBQFpCQACAQILTWF0Y2ggZXJyb3IACHNodXRkb3duCQELdmFsdWVPckVsc2UCCQCgCAEJAQtrZXlTaHV0ZG93bgAHAQ1zaHV0ZG93bkNoZWNrAQFpAwMJAQEhAQUIc2h1dGRvd24GCQELbXVzdE1hbmFnZXIBBQFpBgkAAgECFW9wZXJhdGlvbiBpcyBkaXNhYmxlZAAPZmFjdG9yeUNvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQEMZ2V0U3RyT3JGYWlsAgUEdGhpcwkBEmtleUZhY3RvcnlDb250cmFjdAAAEWxwU3Rha2luZ0NvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQEMZ2V0U3RyT3JGYWlsAgUEdGhpcwkBFGtleUxwU3Rha2luZ0NvbnRyYWN0AAAPc3Rha2luZ0NvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQEMZ2V0U3RyT3JGYWlsAgUEdGhpcwkBEmtleVN0YWtpbmdDb250cmFjdAAAEGJvb3N0aW5nQ29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQxnZXRTdHJPckZhaWwCBQR0aGlzCQETa2V5Qm9vc3RpbmdDb250cmFjdAAADHN3YXBDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQkBDGdldFN0ck9yRmFpbAIFBHRoaXMJAQ9rZXlTd2FwQ29udHJhY3QAABNhc3NldHNTdG9yZUNvbnRyYWN0CQERQGV4dHJOYXRpdmUoMTA2MikBCQEMZ2V0U3RyT3JGYWlsAgUEdGhpcwkBFmtleUFzc2V0c1N0b3JlQ29udHJhY3QAAAt1c2R0QXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEJAQxnZXRTdHJPckZhaWwCBQR0aGlzCQEOa2V5VXNkdEFzc2V0SWQAAAl3eEFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBCQEMZ2V0U3RyT3JGYWlsAgUEdGhpcwkBDGtleVd4QXNzZXRJZAAAD21pbkRlbGF5RGVmYXVsdACgCwAIbWluRGVsYXkJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBC2tleU1pbkRlbGF5AAUPbWluRGVsYXlEZWZhdWx0ABZsb2NrRnJhY3Rpb25NdWx0aXBsaWVyAIDC1y8AE2xvY2tGcmFjdGlvbkRlZmF1bHQJAGsDAAEFFmxvY2tGcmFjdGlvbk11bHRpcGxpZXIAAgAMbG9ja0ZyYWN0aW9uCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ9rZXlMb2NrRnJhY3Rpb24ABRNsb2NrRnJhY3Rpb25EZWZhdWx0AQtnZXRQb29sSW5mbwENYW1vdW50QXNzZXRJZAQQYW1vdW50QXNzZXRJZFN0cgkBD2Fzc2V0SWRUb1N0cmluZwEFDWFtb3VudEFzc2V0SWQED3ByaWNlQXNzZXRJZFN0cgkBD2Fzc2V0SWRUb1N0cmluZwEFC3VzZHRBc3NldElkBA5wb29sSW5mb09wdGlvbgoAAUAJAPwHBAUPZmFjdG9yeUNvbnRyYWN0AhBwb29sSW5mb1JFQURPTkxZCQDMCAIFEGFtb3VudEFzc2V0SWRTdHIJAMwIAgUPcHJpY2VBc3NldElkU3RyBQNuaWwFA25pbAMJAAECBQFAAhUoQWRkcmVzcywgQnl0ZVZlY3RvcikFAUAFBHVuaXQFDnBvb2xJbmZvT3B0aW9uAQljYWxjUHJpY2UCCWxwQXNzZXRJZAxzaGFyZUFzc2V0SWQEDnNoYXJlQXNzZXRJbmZvCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAOwHAQUMc2hhcmVBc3NldElkAh5mYWlsZWQgdG8gZ2V0IHNoYXJlIGFzc2V0IGluZm8EEnNoYXJlQXNzZXRFbWlzc2lvbggFDnNoYXJlQXNzZXRJbmZvCHF1YW50aXR5BAxzdGFrZWRBbW91bnQJAQ5lbnN1cmVQb3NpdGl2ZQEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgoAAUAJAPwHBAUPc3Rha2luZ0NvbnRyYWN0AhRzdGFrZWRCeVVzZXJSRUFET05MWQkAzAgCCQEPYXNzZXRJZFRvU3RyaW5nAQUJbHBBc3NldElkCQDMCAIJAKUIAQUEdGhpcwUDbmlsBQNuaWwDCQABAgUBQAIDSW50BQFABQR1bml0CQEHd3JhcEVycgECI2ludmFsaWQgc3Rha2VkQnlVc2VyUkVBRE9OTFkgcmVzdWx0BAVwcmljZQMJAAACBRJzaGFyZUFzc2V0RW1pc3Npb24AAAUNc2NhbGUxOEJpZ0ludAkAvQIECQC2AgEFDHN0YWtlZEFtb3VudAUNc2NhbGUxOEJpZ0ludAkAtgIBBRJzaGFyZUFzc2V0RW1pc3Npb24FBUZMT09SBQVwcmljZQoBaQEKc2V0TWFuYWdlcgEXcGVuZGluZ01hbmFnZXJQdWJsaWNLZXkEC2NoZWNrQ2FsbGVyCQELbXVzdE1hbmFnZXIBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgQVY2hlY2tNYW5hZ2VyUHVibGljS2V5CQDZBAEFF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5AwkAAAIFFWNoZWNrTWFuYWdlclB1YmxpY0tleQUVY2hlY2tNYW5hZ2VyUHVibGljS2V5CQDMCAIJAQtTdHJpbmdFbnRyeQIJARprZXlQZW5kaW5nTWFuYWdlclB1YmxpY0tleQAFF3BlbmRpbmdNYW5hZ2VyUHVibGljS2V5BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEOY29uZmlybU1hbmFnZXIABAJwbQkBHXBlbmRpbmdNYW5hZ2VyUHVibGljS2V5T3JVbml0AAQFaGFzUE0DCQEJaXNEZWZpbmVkAQUCcG0GCQEIdGhyb3dFcnIBAhJubyBwZW5kaW5nIG1hbmFnZXIDCQAAAgUFaGFzUE0FBWhhc1BNBAdjaGVja1BNAwkAAAIIBQFpD2NhbGxlclB1YmxpY0tleQkBBXZhbHVlAQUCcG0GCQEIdGhyb3dFcnIBAht5b3UgYXJlIG5vdCBwZW5kaW5nIG1hbmFnZXIDCQAAAgUHY2hlY2tQTQUHY2hlY2tQTQkAzAgCCQELU3RyaW5nRW50cnkCCQETa2V5TWFuYWdlclB1YmxpY0tleQAJANgEAQkBBXZhbHVlAQUCcG0JAMwIAgkBC0RlbGV0ZUVudHJ5AQkBGmtleVBlbmRpbmdNYW5hZ2VyUHVibGljS2V5AAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBGVtaXQCB2Fzc2V0SWQGYW1vdW50BAtjaGVja0NhbGxlcgkBCG11c3RUaGlzAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIEDGlzUmVpc3N1YWJsZQYJAJQKAgkAzAgCCQEHUmVpc3N1ZQMFB2Fzc2V0SWQFBmFtb3VudAUMaXNSZWlzc3VhYmxlBQNuaWwFBmFtb3VudAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQRidXJuAgdhc3NldElkBmFtb3VudAQLY2hlY2tDYWxsZXIJAQhtdXN0VGhpcwEFAWkDCQAAAgULY2hlY2tDYWxsZXIFC2NoZWNrQ2FsbGVyCQCUCgIJAMwIAgkBBEJ1cm4CBQdhc3NldElkBQZhbW91bnQFA25pbAUGYW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBmNyZWF0ZQUOYmFzZUFzc2V0SWRTdHIPc2hhcmVBc3NldElkU3RyDnNoYXJlQXNzZXROYW1lFXNoYXJlQXNzZXREZXNjcmlwdGlvbg5zaGFyZUFzc2V0TG9nbwQPc2hhcmVBc3NldExhYmVsAgpTVEFLSU5HX0xQBAtiYXNlQXNzZXRJZAkBDHBhcnNlQXNzZXRJZAEFDmJhc2VBc3NldElkU3RyBAZjaGVja3MJAMwIAgkBC211c3RNYW5hZ2VyAQUBaQkAzAgCAwkBCWlzRGVmaW5lZAEJAQtnZXRQb29sSW5mbwEFC2Jhc2VBc3NldElkBgkBCHRocm93RXJyAQISaW52YWxpZCBiYXNlIGFzc2V0BQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEC2NvbW1vblN0YXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEJa2V5UGVyaW9kAQULYmFzZUFzc2V0SWQAAAUDbmlsAwkAAAIFD3NoYXJlQXNzZXRJZFN0cgIABBVzaGFyZUFzc2V0SXNzdWVBbW91bnQAAQQVc2hhcmVBc3NldElzc3VlQWN0aW9uCQDCCAUFDnNoYXJlQXNzZXROYW1lBRVzaGFyZUFzc2V0RGVzY3JpcHRpb24FFXNoYXJlQXNzZXRJc3N1ZUFtb3VudAUSc2hhcmVBc3NldERlY2ltYWxzBgQWY2FsY3VsYXRlZFNoYXJlQXNzZXRJZAkAuAgBBRVzaGFyZUFzc2V0SXNzdWVBY3Rpb24EFHNoYXJlQXNzZXRCdXJuQWN0aW9uCQEEQnVybgIFFmNhbGN1bGF0ZWRTaGFyZUFzc2V0SWQFFXNoYXJlQXNzZXRJc3N1ZUFtb3VudAQZY2FsY3VsYXRlZFNoYXJlQXNzZXRJZFN0cgkA2AQBBRZjYWxjdWxhdGVkU2hhcmVBc3NldElkBA5jcmVhdGVPclVwZGF0ZQkA/AcEBRNhc3NldHNTdG9yZUNvbnRyYWN0Ag5jcmVhdGVPclVwZGF0ZQkAzAgCBRljYWxjdWxhdGVkU2hhcmVBc3NldElkU3RyCQDMCAIFDnNoYXJlQXNzZXRMb2dvCQDMCAIHBQNuaWwFA25pbAMJAAACBQ5jcmVhdGVPclVwZGF0ZQUOY3JlYXRlT3JVcGRhdGUECGFkZExhYmVsCQD8BwQFE2Fzc2V0c1N0b3JlQ29udHJhY3QCCGFkZExhYmVsCQDMCAIFGWNhbGN1bGF0ZWRTaGFyZUFzc2V0SWRTdHIJAMwIAgUPc2hhcmVBc3NldExhYmVsBQNuaWwFA25pbAMJAAACBQhhZGRMYWJlbAUIYWRkTGFiZWwJAJQKAgkAzggCBQtjb21tb25TdGF0ZQkAzAgCBRVzaGFyZUFzc2V0SXNzdWVBY3Rpb24JAMwIAgUUc2hhcmVBc3NldEJ1cm5BY3Rpb24JAMwIAgkBC1N0cmluZ0VudHJ5AgkBD2tleVNoYXJlQXNzZXRJZAEFC2Jhc2VBc3NldElkBRljYWxjdWxhdGVkU2hhcmVBc3NldElkU3RyCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQ5rZXlCYXNlQXNzZXRJZAEFFmNhbGN1bGF0ZWRTaGFyZUFzc2V0SWQFDmJhc2VBc3NldElkU3RyBQNuaWwFGWNhbGN1bGF0ZWRTaGFyZUFzc2V0SWRTdHIJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4EDHNoYXJlQXNzZXRJZAkA2QQBBQ9zaGFyZUFzc2V0SWRTdHIEDnNoYXJlQXNzZXRJbmZvCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAOwHAQUMc2hhcmVBc3NldElkCQEHd3JhcEVycgECFmludmFsaWQgc2hhcmUgYXNzZXQgaWQEC2NoZWNrSXNzdWVyAwkAAAIIBQ5zaGFyZUFzc2V0SW5mbwZpc3N1ZXIFEWxwU3Rha2luZ0NvbnRyYWN0BgkBCHRocm93RXJyAQIdaW52YWxpZCBzaGFyZSBhc3NldCBpZCBpc3N1ZXIDCQAAAgULY2hlY2tJc3N1ZXIFC2NoZWNrSXNzdWVyCQCUCgIJAM4IAgULY29tbW9uU3RhdGUJAMwIAgkBC1N0cmluZ0VudHJ5AgkBD2tleVNoYXJlQXNzZXRJZAEFC2Jhc2VBc3NldElkBQ9zaGFyZUFzc2V0SWRTdHIJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDmtleUJhc2VBc3NldElkAQUMc2hhcmVBc3NldElkBQ5iYXNlQXNzZXRJZFN0cgUDbmlsBQ9zaGFyZUFzc2V0SWRTdHIJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEDcHV0AAQDcG10AwkAAAIJAJADAQgFAWkIcGF5bWVudHMAAQkAkQMCCAUBaQhwYXltZW50cwAACQEIdGhyb3dFcnIBAh1leGFjdGx5IDEgcGF5bWVudCBpcyBleHBlY3RlZAQLYmFzZUFzc2V0SWQIBQNwbXQHYXNzZXRJZAQLdXNlckFkZHJlc3MIBQFpBmNhbGxlcgQGY2hlY2tzCQDMCAIJAQ1zaHV0ZG93bkNoZWNrAQUBaQkAzAgCAwkBCWlzRGVmaW5lZAEJAKIIAQkBD2tleVNoYXJlQXNzZXRJZAEFC2Jhc2VBc3NldElkBgkBCHRocm93RXJyAQINaW52YWxpZCBhc3NldAUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBA0kdDAxMTY0MDExNzQzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQtnZXRQb29sSW5mbwEFC2Jhc2VBc3NldElkCQEHd3JhcEVycgECDWludmFsaWQgYXNzZXQEC3Bvb2xBZGRyZXNzCAUNJHQwMTE2NDAxMTc0MwJfMQQJbHBBc3NldElkCAUNJHQwMTE2NDAxMTc0MwJfMgQGcGVyaW9kCQEFdmFsdWUBCQCfCAEJAQlrZXlQZXJpb2QBBQtiYXNlQXNzZXRJZAQodXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZE9wdGlvbgkAnwgBCQEla2V5VXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZAIFC2Jhc2VBc3NldElkBQt1c2VyQWRkcmVzcwQZY2xhaW1TaGFyZUFzc2V0SW52b2NhdGlvbgMJAAACBSh1c2VyQmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kT3B0aW9uBQR1bml0BQR1bml0BCJ1c2VyQmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kCQEFdmFsdWUBBSh1c2VyQmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kT3B0aW9uAwkAAAIFInVzZXJCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnRQZXJpb2QFBnBlcmlvZAUEdW5pdAkA/AcEBQR0aGlzAg9jbGFpbVNoYXJlQXNzZXQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFC2Jhc2VBc3NldElkCQDMCAIJAKUIAQULdXNlckFkZHJlc3MFA25pbAUDbmlsAwkAAAIFGWNsYWltU2hhcmVBc3NldEludm9jYXRpb24FGWNsYWltU2hhcmVBc3NldEludm9jYXRpb24EGGJhc2VBc3NldEFtb3VudFRvQ29udmVydAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEba2V5QmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0AQULYmFzZUFzc2V0SWQAAAQcdXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEfa2V5VXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydAIFC2Jhc2VBc3NldElkBQt1c2VyQWRkcmVzcwAACQCUCgIJAMwIAgkBDEludGVnZXJFbnRyeQIJARtrZXlCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQBBQtiYXNlQXNzZXRJZAkAZAIFGGJhc2VBc3NldEFtb3VudFRvQ29udmVydAgFA3BtdAZhbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJAR9rZXlVc2VyQmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0AgULYmFzZUFzc2V0SWQFC3VzZXJBZGRyZXNzCQBkAgUcdXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydAgFA3BtdAZhbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJASVrZXlVc2VyQmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kAgULYmFzZUFzc2V0SWQFC3VzZXJBZGRyZXNzBQZwZXJpb2QJAMwIAgkBC1N0cmluZ0VudHJ5AgkBD2tleUhpc3RvcnlFbnRyeQUFC2Jhc2VBc3NldElkAgNwdXQFBnBlcmlvZAULdXNlckFkZHJlc3MIBQFpDXRyYW5zYWN0aW9uSWQJALkJAgkAzAgCCQCkAwEIBQNwbXQGYW1vdW50CQDMCAIJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAMwIAgkApAMBBRx1c2VyQmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0BQNuaWwFCXNlcGFyYXRvcgUDbmlsBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBD2NsYWltU2hhcmVBc3NldAIOYmFzZUFzc2V0SWRTdHIOdXNlckFkZHJlc3NTdHIEBmNoZWNrcwkAzAgCCQENc2h1dGRvd25DaGVjawEFAWkFA25pbAMJAAACBQZjaGVja3MFBmNoZWNrcwQLdXNlckFkZHJlc3MDCQAAAgUOdXNlckFkZHJlc3NTdHICAAgFAWkGY2FsbGVyBAtjaGVja0NhbGxlcgkBCG11c3RUaGlzAQUBaQMJAAACBQtjaGVja0NhbGxlcgULY2hlY2tDYWxsZXIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQ51c2VyQWRkcmVzc1N0cgkBB3dyYXBFcnIBAhRpbnZhbGlkIHVzZXIgYWRkcmVzcwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgMJAAACBQt1c2VyQWRkcmVzcwULdXNlckFkZHJlc3MEC2Jhc2VBc3NldElkCQEMcGFyc2VBc3NldElkAQUOYmFzZUFzc2V0SWRTdHIEDHNoYXJlQXNzZXRJZAkBBXZhbHVlAQkBDHBhcnNlQXNzZXRJZAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEPa2V5U2hhcmVBc3NldElkAQULYmFzZUFzc2V0SWQJAQd3cmFwRXJyAQIVaW52YWxpZCBiYXNlIGFzc2V0IGlkAwkAAAIFDHNoYXJlQXNzZXRJZAUMc2hhcmVBc3NldElkBAZwZXJpb2QJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBCQEJa2V5UGVyaW9kAQULYmFzZUFzc2V0SWQJAQd3cmFwRXJyAQIOaW52YWxpZCBwZXJpb2QDCQAAAgUGcGVyaW9kBQZwZXJpb2QEHHVzZXJCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBH2tleVVzZXJCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQCBQtiYXNlQXNzZXRJZAULdXNlckFkZHJlc3MAAAQUY2hlY2tBbW91bnRUb0NvbnZlcnQDCQBmAgUcdXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydAAABgkBCHRocm93RXJyAQIQbm90aGluZyB0byBjbGFpbQMJAAACBRRjaGVja0Ftb3VudFRvQ29udmVydAUUY2hlY2tBbW91bnRUb0NvbnZlcnQEInVzZXJCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnRQZXJpb2QJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBCQEla2V5VXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZAIFC2Jhc2VBc3NldElkBQt1c2VyQWRkcmVzcwkBB3dyYXBFcnIBAhRmYWlsZWQgdG8gZ2V0IHBlcmlvZAQLY2hlY2tQZXJpb2QDCQBmAgUGcGVyaW9kBSJ1c2VyQmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kBgkBCHRocm93RXJyAQIOaW52YWxpZCBwZXJpb2QDCQAAAgULY2hlY2tQZXJpb2QFC2NoZWNrUGVyaW9kBAVwcmljZQkAngMBCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKEIAQkBEWtleVByaWNlUGVyaW9kUHV0AgULYmFzZUFzc2V0SWQFInVzZXJCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnRQZXJpb2QJAQd3cmFwRXJyAQITZmFpbGVkIHRvIGdldCBwcmljZQQQc2hhcmVBc3NldEFtb3VudAkAoAMBCQC8AgMJALYCAQUcdXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydAUNc2NhbGUxOEJpZ0ludAUFcHJpY2UJAJQKAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBH2tleVVzZXJCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQCBQtiYXNlQXNzZXRJZAULdXNlckFkZHJlc3MAAAkAzAgCCQELRGVsZXRlRW50cnkBCQEla2V5VXNlckJhc2VBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZAIFC2Jhc2VBc3NldElkBQt1c2VyQWRkcmVzcwkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQt1c2VyQWRkcmVzcwUQc2hhcmVBc3NldEFtb3VudAUMc2hhcmVBc3NldElkCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQ9rZXlIaXN0b3J5RW50cnkFBQtiYXNlQXNzZXRJZAIPY2xhaW1TaGFyZUFzc2V0BQZwZXJpb2QFC3VzZXJBZGRyZXNzCAUBaQ10cmFuc2FjdGlvbklkCQC5CQIJAMwIAgkApAMBBRBzaGFyZUFzc2V0QW1vdW50CQDMCAIJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAMwIAgkApgMBBQVwcmljZQkAzAgCCQCkAwEFHHVzZXJCYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQFA25pbAUJc2VwYXJhdG9yBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEDZ2V0AAQGY2hlY2tzCQDMCAIJAQ1zaHV0ZG93bkNoZWNrAQUBaQUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBANwbXQDCQAAAgkAkAMBCAUBaQhwYXltZW50cwABCQCRAwIIBQFpCHBheW1lbnRzAAAJAQh0aHJvd0VycgECHWV4YWN0bHkgMSBwYXltZW50IGlzIGV4cGVjdGVkBAxzaGFyZUFzc2V0SWQIBQNwbXQHYXNzZXRJZAQLYmFzZUFzc2V0SWQJAQV2YWx1ZQEJAQxwYXJzZUFzc2V0SWQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBDmtleUJhc2VBc3NldElkAQUMc2hhcmVBc3NldElkCQEHd3JhcEVycgECFmludmFsaWQgc2hhcmUgYXNzZXQgaWQDCQAAAgULYmFzZUFzc2V0SWQFC2Jhc2VBc3NldElkBAt1c2VyQWRkcmVzcwgFAWkGY2FsbGVyBA0kdDAxNTgyMDE2MDA5CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQtnZXRQb29sSW5mbwEFC2Jhc2VBc3NldElkCQEHd3JhcEVycgECDWludmFsaWQgYXNzZXQEC3Bvb2xBZGRyZXNzCAUNJHQwMTU4MjAxNjAwOQJfMQQJbHBBc3NldElkCAUNJHQwMTU4MjAxNjAwOQJfMgQGcGVyaW9kCQEFdmFsdWUBCQCfCAEJAQlrZXlQZXJpb2QBBQtiYXNlQXNzZXRJZAQpdXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnRQZXJpb2RPcHRpb24JAJ8IAQkBJmtleVVzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kAgULYmFzZUFzc2V0SWQFC3VzZXJBZGRyZXNzBBhjbGFpbUJhc2VBc3NldEludm9jYXRpb24DCQAAAgUpdXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnRQZXJpb2RPcHRpb24FBHVuaXQFBHVuaXQEI3VzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kCQEFdmFsdWUBBSl1c2VyU2hhcmVBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZE9wdGlvbgMJAAACBSN1c2VyU2hhcmVBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZAUGcGVyaW9kBQR1bml0CQD8BwQFBHRoaXMCDmNsYWltQmFzZUFzc2V0CQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQtiYXNlQXNzZXRJZAkAzAgCCQClCAEFC3VzZXJBZGRyZXNzBQNuaWwFA25pbAMJAAACBRhjbGFpbUJhc2VBc3NldEludm9jYXRpb24FGGNsYWltQmFzZUFzc2V0SW52b2NhdGlvbgQZc2hhcmVBc3NldEFtb3VudFRvQ29udmVydAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEca2V5U2hhcmVBc3NldEFtb3VudFRvQ29udmVydAEFC2Jhc2VBc3NldElkAAAEHXVzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0CQELdmFsdWVPckVsc2UCCQCfCAEJASBrZXlVc2VyU2hhcmVBc3NldEFtb3VudFRvQ29udmVydAIFC2Jhc2VBc3NldElkBQt1c2VyQWRkcmVzcwAACQCUCgIJAMwIAgkBDEludGVnZXJFbnRyeQIJARxrZXlTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0AQULYmFzZUFzc2V0SWQJAGQCBRlzaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0CAUDcG10BmFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBIGtleVVzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0AgULYmFzZUFzc2V0SWQFC3VzZXJBZGRyZXNzCQBkAgUddXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQIBQNwbXQGYW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEma2V5VXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnRQZXJpb2QCBQtiYXNlQXNzZXRJZAULdXNlckFkZHJlc3MFBnBlcmlvZAkAzAgCCQELU3RyaW5nRW50cnkCCQEPa2V5SGlzdG9yeUVudHJ5BQULYmFzZUFzc2V0SWQCA2dldAUGcGVyaW9kBQt1c2VyQWRkcmVzcwgFAWkNdHJhbnNhY3Rpb25JZAkAuQkCCQDMCAIJAKQDAQgFA3BtdAZhbW91bnQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCkAwEFHXVzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0BQNuaWwFCXNlcGFyYXRvcgUDbmlsBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNsYWltQmFzZUFzc2V0Ag5iYXNlQXNzZXRJZFN0cg51c2VyQWRkcmVzc1N0cgQGY2hlY2tzCQDMCAIJAQ1zaHV0ZG93bkNoZWNrAQUBaQUDbmlsAwkAAAIFBmNoZWNrcwUGY2hlY2tzBAt1c2VyQWRkcmVzcwMJAAACBQ51c2VyQWRkcmVzc1N0cgIACAUBaQZjYWxsZXIEC2NoZWNrQ2FsbGVyCQEIbXVzdFRoaXMBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFDnVzZXJBZGRyZXNzU3RyCQEHd3JhcEVycgECFGludmFsaWQgdXNlciBhZGRyZXNzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAwkAAAIFC3VzZXJBZGRyZXNzBQt1c2VyQWRkcmVzcwQLYmFzZUFzc2V0SWQJAQxwYXJzZUFzc2V0SWQBBQ5iYXNlQXNzZXRJZFN0cgQMc2hhcmVBc3NldElkCQEFdmFsdWUBCQEMcGFyc2VBc3NldElkAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJAQ9rZXlTaGFyZUFzc2V0SWQBBQtiYXNlQXNzZXRJZAkBB3dyYXBFcnIBAhVpbnZhbGlkIGJhc2UgYXNzZXQgaWQDCQAAAgUMc2hhcmVBc3NldElkBQxzaGFyZUFzc2V0SWQEBnBlcmlvZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCfCAEJAQlrZXlQZXJpb2QBBQtiYXNlQXNzZXRJZAkBB3dyYXBFcnIBAg5pbnZhbGlkIHBlcmlvZAMJAAACBQZwZXJpb2QFBnBlcmlvZAQddXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBIGtleVVzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0AgULYmFzZUFzc2V0SWQFC3VzZXJBZGRyZXNzAAAEI3VzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQkBJmtleVVzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kAgULYmFzZUFzc2V0SWQFC3VzZXJBZGRyZXNzCQEHd3JhcEVycgECFGZhaWxlZCB0byBnZXQgcGVyaW9kBAtjaGVja1BlcmlvZAMJAGYCBQZwZXJpb2QFI3VzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kBgkBCHRocm93RXJyAQIOaW52YWxpZCBwZXJpb2QDCQAAAgULY2hlY2tQZXJpb2QFC2NoZWNrUGVyaW9kBAVwcmljZQkAngMBCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKEIAQkBEWtleVByaWNlUGVyaW9kR2V0AgULYmFzZUFzc2V0SWQFI3VzZXJTaGFyZUFzc2V0QW1vdW50VG9Db252ZXJ0UGVyaW9kCQEHd3JhcEVycgECE2ZhaWxlZCB0byBnZXQgcHJpY2UED2Jhc2VBc3NldEFtb3VudAkAoAMBCQC8AgMJALYCAQUddXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQFBXByaWNlBQ1zY2FsZTE4QmlnSW50CQCUCgIJAMwIAgkBDEludGVnZXJFbnRyeQIJASBrZXlVc2VyU2hhcmVBc3NldEFtb3VudFRvQ29udmVydAIFC2Jhc2VBc3NldElkBQt1c2VyQWRkcmVzcwAACQDMCAIJAQtEZWxldGVFbnRyeQEJASZrZXlVc2VyU2hhcmVBc3NldEFtb3VudFRvQ29udmVydFBlcmlvZAIFC2Jhc2VBc3NldElkBQt1c2VyQWRkcmVzcwkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQt1c2VyQWRkcmVzcwUPYmFzZUFzc2V0QW1vdW50BQtiYXNlQXNzZXRJZAkAzAgCCQELU3RyaW5nRW50cnkCCQEPa2V5SGlzdG9yeUVudHJ5BQULYmFzZUFzc2V0SWQCDmNsYWltQmFzZUFzc2V0BQZwZXJpb2QFC3VzZXJBZGRyZXNzCAUBaQ10cmFuc2FjdGlvbklkCQC5CQIJAMwIAgkApAMBBQ9iYXNlQXNzZXRBbW91bnQJAMwIAgkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQCmAwEFBXByaWNlCQDMCAIJAKQDAQUjdXNlclNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnRQZXJpb2QFA25pbAUJc2VwYXJhdG9yBQNuaWwFBHVuaXQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEIZmluYWxpemUBDmJhc2VBc3NldElkU3RyBAZjaGVja3MJAMwIAgkBDXNodXRkb3duQ2hlY2sBBQFpBQNuaWwDCQAAAgUGY2hlY2tzBQZjaGVja3MEC2Jhc2VBc3NldElkCQEMcGFyc2VBc3NldElkAQUOYmFzZUFzc2V0SWRTdHIEDHNoYXJlQXNzZXRJZAkBBXZhbHVlAQkBDHBhcnNlQXNzZXRJZAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEPa2V5U2hhcmVBc3NldElkAQULYmFzZUFzc2V0SWQJAQd3cmFwRXJyAQIVaW52YWxpZCBiYXNlIGFzc2V0IGlkAwkAAAIFDHNoYXJlQXNzZXRJZAUMc2hhcmVBc3NldElkBA5zaGFyZUFzc2V0SW5mbwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQDsBwEFDHNoYXJlQXNzZXRJZAkBB3dyYXBFcnIBAhZpbnZhbGlkIHNoYXJlIGFzc2V0IGlkBAZwZXJpb2QJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnwgBCQEJa2V5UGVyaW9kAQULYmFzZUFzc2V0SWQJAQd3cmFwRXJyAQIOaW52YWxpZCBwZXJpb2QDCQAAAgUGcGVyaW9kBQZwZXJpb2QEF3BlcmlvZFN0YXJ0SGVpZ2h0T3B0aW9uCQCfCAEJARRrZXlQZXJpb2RTdGFydEhlaWdodAIFC2Jhc2VBc3NldElkBQZwZXJpb2QECmNoZWNrRGVsYXkDCQAAAgUXcGVyaW9kU3RhcnRIZWlnaHRPcHRpb24FBHVuaXQFBHVuaXQEBWRlbGF5CQBlAgUGaGVpZ2h0CQEFdmFsdWUBBRdwZXJpb2RTdGFydEhlaWdodE9wdGlvbgQMYmxvY2tzVG9XYWl0CQCWAwEJAMwIAgAACQDMCAIJAGUCBQhtaW5EZWxheQUFZGVsYXkFA25pbAMJAAACBQxibG9ja3NUb1dhaXQAAAUEdW5pdAkBCHRocm93RXJyAQkAuQkCCQDMCAICIWZpbmFsaXphdGlvbiB3aWxsIGJlIHBvc3NpYmxlIGluIAkAzAgCCQCkAwEFDGJsb2Nrc1RvV2FpdAkAzAgCAgcgYmxvY2tzBQNuaWwCAAMJAAACBQpjaGVja0RlbGF5BQpjaGVja0RlbGF5BA0kdDAyMTExMzIxMjk0CQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQtnZXRQb29sSW5mbwEFC2Jhc2VBc3NldElkCQEHd3JhcEVycgECDWludmFsaWQgYXNzZXQEC3Bvb2xBZGRyZXNzCAUNJHQwMjExMTMyMTI5NAJfMQQJbHBBc3NldElkCAUNJHQwMjExMTMyMTI5NAJfMgQNc3Rha2luZ1Jld2FyZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCgABQAkA/AcEBQ9zdGFraW5nQ29udHJhY3QCEWNsYWltV3hEb05vdFRocm93CQDMCAIJAQ9hc3NldElkVG9TdHJpbmcBBQlscEFzc2V0SWQFA25pbAUDbmlsAwkAAQIFAUACA0ludAUBQAUEdW5pdAkBB3dyYXBFcnIBAhZpbnZhbGlkIGNsYWltV3ggcmVzdWx0AwkAAAIFDXN0YWtpbmdSZXdhcmQFDXN0YWtpbmdSZXdhcmQEGGJhc2VBc3NldEFtb3VudFRvQ29udmVydAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEba2V5QmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0AQULYmFzZUFzc2V0SWQAAAQZc2hhcmVBc3NldEFtb3VudFRvQ29udmVydAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEca2V5U2hhcmVBc3NldEFtb3VudFRvQ29udmVydAEFC2Jhc2VBc3NldElkAAAEG2NoZWNrRmluYWxpemF0aW9uSXNSZXF1aXJlZAQWaXNGaW5hbGl6YXRpb25SZXF1aXJlZAMDCQBmAgUNc3Rha2luZ1Jld2FyZAAABgkAZgIFGGJhc2VBc3NldEFtb3VudFRvQ29udmVydAAABgkAZgIFGXNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQAAAMFFmlzRmluYWxpemF0aW9uUmVxdWlyZWQGCQEIdGhyb3dFcnIBAhNub3RoaW5nIHRvIGZpbmFsaXplAwkAAAIFG2NoZWNrRmluYWxpemF0aW9uSXNSZXF1aXJlZAUbY2hlY2tGaW5hbGl6YXRpb25Jc1JlcXVpcmVkBBB1c2VTdGFraW5nUmV3YXJkAwkAZgIFDXN0YWtpbmdSZXdhcmQAAAQIbG9ja1BhcnQJAGsDBQ1zdGFraW5nUmV3YXJkBQxsb2NrRnJhY3Rpb24FFmxvY2tGcmFjdGlvbk11bHRpcGxpZXIEC2NvbnZlcnRQYXJ0CQBlAgUNc3Rha2luZ1Jld2FyZAUIbG9ja1BhcnQEAXIJAPwHBAUQYm9vc3RpbmdDb250cmFjdAIXdXNlck1heER1cmF0aW9uUkVBRE9OTFkJAMwIAgkApQgBBQR0aGlzBQNuaWwFA25pbAQEbG9jawMJAGYCBQhsb2NrUGFydAAABAckbWF0Y2gwBQFyAwMDCQABAggFByRtYXRjaDACXzECBlN0cmluZwkAAQIIBQckbWF0Y2gwAl8yAgNJbnQHCQABAgUHJG1hdGNoMAINKFN0cmluZywgSW50KQcECGZ1bmN0aW9uCAUHJG1hdGNoMAJfMQQIZHVyYXRpb24IBQckbWF0Y2gwAl8yAwkAZgIFCGxvY2tQYXJ0AAAJAPwHBAUQYm9vc3RpbmdDb250cmFjdAUIZnVuY3Rpb24JAMwIAgUIZHVyYXRpb24FA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgUJd3hBc3NldElkBQhsb2NrUGFydAUDbmlsBQR1bml0CQEIdGhyb3dFcnIBAhNpbnZhbGlkIGxvY2sgcGFyYW1zBQR1bml0AwkAAAIFBGxvY2sFBGxvY2sED2NvbnZlcnRlZEFtb3VudAMJAGYCBQtjb252ZXJ0UGFydAAABAlpbkFzc2V0SWQFCXd4QXNzZXRJZAQQbWluaW11bVRvUmVjZWl2ZQAABA1vdXRBc3NldElkU3RyCQEPYXNzZXRJZFRvU3RyaW5nAQULdXNkdEFzc2V0SWQEDXRhcmdldEFkZHJlc3MJAKUIAQUEdGhpcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCgABQAkA/AcEBQxzd2FwQ29udHJhY3QCBHN3YXAJAMwIAgUQbWluaW11bVRvUmVjZWl2ZQkAzAgCBQ1vdXRBc3NldElkU3RyCQDMCAIFDXRhcmdldEFkZHJlc3MFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgUJaW5Bc3NldElkBQtjb252ZXJ0UGFydAUDbmlsAwkAAQIFAUACA0ludAUBQAUEdW5pdAkBB3dyYXBFcnIBAhNpbnZhbGlkIHN3YXAgcmVzdWx0AAADCQAAAgUPY29udmVydGVkQW1vdW50BQ9jb252ZXJ0ZWRBbW91bnQEDWxwQXNzZXRBbW91bnQDCQBmAgUPY29udmVydGVkQW1vdW50AAAEDG1pbk91dEFtb3VudAAABAlhdXRvU3Rha2UGCQETdmFsdWVPckVycm9yTWVzc2FnZQIKAAFACQD8BwQFC3Bvb2xBZGRyZXNzAgtwdXRPbmVUa25WMgkAzAgCBQxtaW5PdXRBbW91bnQJAMwIAgUJYXV0b1N0YWtlBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIFC3VzZHRBc3NldElkBQ9jb252ZXJ0ZWRBbW91bnQFA25pbAMJAAECBQFAAgNJbnQFAUAFBHVuaXQJAQd3cmFwRXJyAQIaaW52YWxpZCBwdXRPbmVUa25WMiByZXN1bHQAAAMJAAACBQ1scEFzc2V0QW1vdW50BQ1scEFzc2V0QW1vdW50BQ1scEFzc2V0QW1vdW50CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQR1bml0AwkAAAIFEHVzZVN0YWtpbmdSZXdhcmQFEHVzZVN0YWtpbmdSZXdhcmQECmdldEFjdGlvbnMDCQBmAgUZc2hhcmVBc3NldEFtb3VudFRvQ29udmVydAAABAVwcmljZQkBCWNhbGNQcmljZQIFCWxwQXNzZXRJZAUMc2hhcmVBc3NldElkAwkAAAIFBXByaWNlBQVwcmljZQQNdW5zdGFrZUFtb3VudAkAoAMBCQC9AgQJALYCAQUZc2hhcmVBc3NldEFtb3VudFRvQ29udmVydAUFcHJpY2UFDXNjYWxlMThCaWdJbnQFBUZMT09SBA9iYXNlQXNzZXRBbW91bnQECm91dEFzc2V0SWQFC2Jhc2VBc3NldElkBAxtaW5PdXRBbW91bnQAAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCgABQAkA/AcEBQtwb29sQWRkcmVzcwIVdW5zdGFrZUFuZEdldE9uZVRrblYyCQDMCAIFDXVuc3Rha2VBbW91bnQJAMwIAgkBD2Fzc2V0SWRUb1N0cmluZwEFCm91dEFzc2V0SWQJAMwIAgUMbWluT3V0QW1vdW50BQNuaWwFA25pbAMJAAECBQFAAgNJbnQFAUAFBHVuaXQJAQd3cmFwRXJyAQIkaW52YWxpZCB1bnN0YWtlQW5kR2V0T25lVGtuVjIgcmVzdWx0AwkAAAIFD2Jhc2VBc3NldEFtb3VudAUPYmFzZUFzc2V0QW1vdW50BA5zaGFyZUFzc2V0QnVybgMJAAACCAUOc2hhcmVBc3NldEluZm8GaXNzdWVyBQR0aGlzCQD8BwQFBHRoaXMCBGJ1cm4JAMwIAgUMc2hhcmVBc3NldElkCQDMCAIFGXNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQFA25pbAUDbmlsCQEIdGhyb3dFcnIBAhppbnZhbGlkIHNoYXJlIGFzc2V0IGlzc3VlcgMJAAACBQ5zaGFyZUFzc2V0QnVybgUOc2hhcmVBc3NldEJ1cm4ECHByaWNlR2V0CQC9AgQJALYCAQUPYmFzZUFzc2V0QW1vdW50BQ1zY2FsZTE4QmlnSW50CQC2AgEFGXNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQFBUZMT09SBBVwcmljZUdldFVwZGF0ZUFjdGlvbnMJAMwIAgkBC0JpbmFyeUVudHJ5AgkBEWtleVByaWNlUGVyaW9kR2V0AgULYmFzZUFzc2V0SWQFBnBlcmlvZAkAnQMBBQhwcmljZUdldAkAzAgCCQELU3RyaW5nRW50cnkCCQESa2V5UHJpY2VHZXRIaXN0b3J5AQULYmFzZUFzc2V0SWQJAKYDAQUIcHJpY2VHZXQFA25pbAUVcHJpY2VHZXRVcGRhdGVBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUKZ2V0QWN0aW9ucwUKZ2V0QWN0aW9ucwQKcHV0QWN0aW9ucwMJAGYCBRhiYXNlQXNzZXRBbW91bnRUb0NvbnZlcnQAAAQNbHBBc3NldEFtb3VudAQMbWluT3V0QW1vdW50AAAECWF1dG9TdGFrZQYJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgoAAUAJAPwHBAULcG9vbEFkZHJlc3MCC3B1dE9uZVRrblYyCQDMCAIFDG1pbk91dEFtb3VudAkAzAgCBQlhdXRvU3Rha2UFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgULYmFzZUFzc2V0SWQFGGJhc2VBc3NldEFtb3VudFRvQ29udmVydAUDbmlsAwkAAQIFAUACA0ludAUBQAUEdW5pdAkBB3dyYXBFcnIBAhppbnZhbGlkIHB1dE9uZVRrblYyIHJlc3VsdAMJAAACBQ1scEFzc2V0QW1vdW50BQ1scEFzc2V0QW1vdW50BAVwcmljZQkBCWNhbGNQcmljZQIFCWxwQXNzZXRJZAUMc2hhcmVBc3NldElkAwkAAAIFBXByaWNlBQVwcmljZQQKY2hlY2tQcmljZQMJAQIhPQIJAQV2YWx1ZQEJAKADAQUFcHJpY2UAAAYJAAIBAg1wcmljZSBpcyBaRVJPAwkAAAIFCmNoZWNrUHJpY2UFCmNoZWNrUHJpY2UEEHNoYXJlQXNzZXRBbW91bnQJAKADAQkAvQIECQC2AgEFDWxwQXNzZXRBbW91bnQFDXNjYWxlMThCaWdJbnQFBXByaWNlBQVGTE9PUgQVY2hlY2tTaGFyZUFzc2V0QW1vdW50AwkBAiE9AgkBBXZhbHVlAQkAoAMBBQVwcmljZQAABgkAAgECGHNoYXJlQXNzZXRBbW91bnQgaXMgWkVSTwMJAAACBRVjaGVja1NoYXJlQXNzZXRBbW91bnQFFWNoZWNrU2hhcmVBc3NldEFtb3VudAQRc2hhcmVBc3NldFJlaXNzdWUDCQAAAggFDnNoYXJlQXNzZXRJbmZvBmlzc3VlcgUEdGhpcwkA/AcEBQR0aGlzAgRlbWl0CQDMCAIFDHNoYXJlQXNzZXRJZAkAzAgCBRBzaGFyZUFzc2V0QW1vdW50BQNuaWwFA25pbAkBCHRocm93RXJyAQIaaW52YWxpZCBzaGFyZSBhc3NldCBpc3N1ZXIDCQAAAgURc2hhcmVBc3NldFJlaXNzdWUFEXNoYXJlQXNzZXRSZWlzc3VlBAhwcmljZVB1dAkAvAIDCQC2AgEFGGJhc2VBc3NldEFtb3VudFRvQ29udmVydAUNc2NhbGUxOEJpZ0ludAkAtgIBBRBzaGFyZUFzc2V0QW1vdW50BBVwcmljZVB1dFVwZGF0ZUFjdGlvbnMJAMwIAgkBC0JpbmFyeUVudHJ5AgkBEWtleVByaWNlUGVyaW9kUHV0AgULYmFzZUFzc2V0SWQFBnBlcmlvZAkAnQMBBQhwcmljZVB1dAkAzAgCCQELU3RyaW5nRW50cnkCCQESa2V5UHJpY2VQdXRIaXN0b3J5AQULYmFzZUFzc2V0SWQJAKYDAQUIcHJpY2VQdXQFA25pbAUVcHJpY2VQdXRVcGRhdGVBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUKcHV0QWN0aW9ucwUKcHV0QWN0aW9ucwQJbmV3UGVyaW9kCQBkAgUGcGVyaW9kAAEECWxhc3RQcmljZQkBCWNhbGNQcmljZQIFCWxwQXNzZXRJZAUMc2hhcmVBc3NldElkBAdhY3Rpb25zCQDOCAIJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBCWtleVBlcmlvZAEFC2Jhc2VBc3NldElkBQluZXdQZXJpb2QJAMwIAgkBDEludGVnZXJFbnRyeQIJARRrZXlQZXJpb2RTdGFydEhlaWdodAIFC2Jhc2VBc3NldElkBQluZXdQZXJpb2QFBmhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBHGtleVNoYXJlQXNzZXRBbW91bnRUb0NvbnZlcnQBBQtiYXNlQXNzZXRJZAAACQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEba2V5QmFzZUFzc2V0QW1vdW50VG9Db252ZXJ0AQULYmFzZUFzc2V0SWQAAAkAzAgCCQELQmluYXJ5RW50cnkCCQEOa2V5UHJpY2VQZXJpb2QCBQtiYXNlQXNzZXRJZAUGcGVyaW9kCQCdAwEFCWxhc3RQcmljZQkAzAgCCQELU3RyaW5nRW50cnkCCQEPa2V5UHJpY2VIaXN0b3J5AQULYmFzZUFzc2V0SWQJAKYDAQUJbGFzdFByaWNlBQNuaWwFCnB1dEFjdGlvbnMFCmdldEFjdGlvbnMJAJQKAgUHYWN0aW9ucwkAnQMBBQlsYXN0UHJpY2UJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BAnR4AQZ2ZXJpZnkABA90YXJnZXRQdWJsaWNLZXkEByRtYXRjaDAJARZtYW5hZ2VyUHVibGljS2V5T3JVbml0AAMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAJwawUHJG1hdGNoMAUCcGsDCQABAgUHJG1hdGNoMAIEVW5pdAgFAnR4D3NlbmRlclB1YmxpY0tleQkAAgECC01hdGNoIGVycm9yCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAABQ90YXJnZXRQdWJsaWNLZXkE5BN+", "height": 2562940, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 6UbA2vXAJ7Yx86rq3mLMaa36ArB2Uw9a5dLycxV1FiWg Next: 44QSQ6Sg6oZgzHsCfE4fUs5TizBPBu9auyhe7JdzDdgZ Diff:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let SEP = "__"
4+let separator = "__"
55
6-let feeScale = toBigInt(100000000)
6+let shareAssetDecimals = 8
77
8-func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), ("No data for this.key=" + key))
8+let wavesString = "WAVES"
9+
10+let scale18 = 1000000000000000000
11+
12+let scale18BigInt = toBigInt(scale18)
13+
14+func wrapErr (msg) = makeString(["lp_staking_pools.ride:", msg], " ")
915
1016
11-let poolDisabled = throw("Pool disabled")
17+func throwErr (msg) = throw(wrapErr(msg))
1218
13-let poolNotExist = throw("Pool is not exist")
1419
15-let slippageTooBig = throw("Slippage is too big")
20+func errKeyIsNotDefined (address,key) = wrapErr(makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
21+
22+
23+func getStrOrFail (address,key) = valueOrErrorMessage(getString(address, key), errKeyIsNotDefined(address, key))
24+
25+
26+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), errKeyIsNotDefined(address, key))
27+
28+
29+func parseAssetId (input) = if ((input == wavesString))
30+ then unit
31+ else fromBase58String(input)
32+
33+
34+func assetIdToString (input) = if ((input == unit))
35+ then wavesString
36+ else toBase58String(value(input))
37+
38+
39+func ensurePositive (v) = if ((v >= 0))
40+ then v
41+ else throwErr("value should be positive")
42+
43+
44+func keyFactoryContract () = makeString(["%s", "factoryContract"], separator)
45+
46+
47+func keyLpStakingContract () = makeString(["%s", "lpStakingContract"], separator)
48+
49+
50+func keyStakingContract () = makeString(["%s", "stakingContract"], separator)
51+
52+
53+func keyBoostingContract () = makeString(["%s", "boostingContract"], separator)
54+
55+
56+func keySwapContract () = makeString(["%s", "swapContract"], separator)
57+
58+
59+func keyAssetsStoreContract () = makeString(["%s", "assetsStoreContract"], separator)
60+
61+
62+func keyUsdtAssetId () = makeString(["%s", "usdtAssetId"], separator)
63+
64+
65+func keyWxAssetId () = makeString(["%s", "wxAssetId"], separator)
66+
67+
68+func keyShutdown () = makeString(["%s", "shutdown"], separator)
69+
70+
71+func keyMinDelay () = makeString(["%s", "minDelay"], separator)
72+
73+
74+func keyLockFraction () = makeString(["%s", "lockFraction"], separator)
75+
76+
77+func keyShareAssetId (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "shareAssetId"], separator)
78+
79+
80+func keyBaseAssetId (shareAssetId) = makeString(["%s%s", assetIdToString(shareAssetId), "baseAssetId"], separator)
81+
82+
83+func keyPeriod (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "period"], separator)
84+
85+
86+func keyPeriodStartHeight (baseAssetId,period) = makeString(["%s%s%d", assetIdToString(baseAssetId), "periodStartHeight", toString(period)], separator)
87+
88+
89+func keyBaseAssetAmountToConvert (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "baseAssetAmountToConvert"], separator)
90+
91+
92+func keyShareAssetAmountToConvert (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "shareAssetAmountToConvert"], separator)
93+
94+
95+func keyUserBaseAssetAmountToConvert (baseAssetId,userAddress) = makeString(["%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "baseAssetAmountToConvert"], separator)
96+
97+
98+func keyUserBaseAssetAmountToConvertPeriod (baseAssetId,userAddress) = makeString(["%s%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "baseAssetAmountToConvert", "period"], separator)
99+
100+
101+func keyUserShareAssetAmountToConvert (baseAssetId,userAddress) = makeString(["%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "shareAssetAmountToConvert"], separator)
102+
103+
104+func keyUserShareAssetAmountToConvertPeriod (baseAssetId,userAddress) = makeString(["%s%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "shareAssetAmountToConvert", "period"], separator)
105+
106+
107+func keyPricePeriod (baseAssetId,period) = makeString(["%s%s%d", assetIdToString(baseAssetId), "price", toString(period)], separator)
108+
109+
110+func keyPriceHistory (baseAssetId) = makeString(["%s%s%s%d%d", assetIdToString(baseAssetId), "price", "history", toString(lastBlock.height), toString(lastBlock.timestamp)], separator)
111+
112+
113+func keyPricePeriodPut (baseAssetId,period) = makeString(["%s%s%d%s", assetIdToString(baseAssetId), "price", toString(period), "put"], separator)
114+
115+
116+func keyPricePutHistory (baseAssetId) = makeString(["%s%s%s%s%d%d", assetIdToString(baseAssetId), "price", "history", "put", toString(lastBlock.height), toString(lastBlock.timestamp)], separator)
117+
118+
119+func keyPricePeriodGet (baseAssetId,period) = makeString(["%s%s%d%s", assetIdToString(baseAssetId), "price", toString(period), "get"], separator)
120+
121+
122+func keyPriceGetHistory (baseAssetId) = makeString(["%s%s%s%s%d%d", assetIdToString(baseAssetId), "price", "history", "get", toString(lastBlock.height), toString(lastBlock.timestamp)], separator)
123+
124+
125+func keyHistoryEntry (baseAssetId,operation,period,userAddress,txId) = makeString(["%s%s%s%s", "history", operation, toString(userAddress), toBase58String(txId), toString(height)], separator)
126+
16127
17128 func keyManagerPublicKey () = "%s__managerPublicKey"
18129
19130
20131 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
21-
22-
23-func fc () = "%s__factoryContract"
24-
25-
26-let factoryContract = addressFromStringValue(getStringOrFail(fc()))
27-
28-func protocolFee () = makeString(["%s", "protocolFee"], SEP)
29-
30-
31-func poolFee () = makeString(["%s", "poolFee"], SEP)
32-
33-
34-func getStringOrFailFromAddress (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
35-
36-
37-let keyFeeCollectorAddress = "%s__feeCollectorAddress"
38-
39-let feeCollectorAddress = addressFromStringValue(getStringOrFailFromAddress(factoryContract, keyFeeCollectorAddress))
40-
41-func asInt (val) = match val {
42- case valInt: Int =>
43- valInt
44- case _ =>
45- throw("fail to cast into Int")
46-}
47-
48-
49-func dataMappingPoolAssets (internalAmountAssetStr,internalPriceAssetStr) = makeString(["%d%d", toString(internalAmountAssetStr), toString(internalPriceAssetStr)], SEP)
50132
51133
52134 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
69151 }
70152
71153
72-func isManager (i) = match managerPublicKeyOrUnit() {
154+let permissionDeniedError = throw("Permission denied")
155+
156+func mustThis (i) = if ((i.caller == this))
157+ then true
158+ else permissionDeniedError
159+
160+
161+func mustManager (i) = match managerPublicKeyOrUnit() {
73162 case pk: ByteVector =>
74- (i.callerPublicKey == pk)
163+ if ((i.callerPublicKey == pk))
164+ then true
165+ else permissionDeniedError
75166 case _: Unit =>
76- (i.caller == this)
167+ mustThis(i)
77168 case _ =>
78169 throw("Match error")
79170 }
80171
81172
82-func mustManager (i) = if (isManager(i))
173+let shutdown = valueOrElse(getBoolean(keyShutdown()), false)
174+
175+func shutdownCheck (i) = if (if (!(shutdown))
83176 then true
84- else throw("permission denied")
177+ else mustManager(i))
178+ then true
179+ else throw("operation is disabled")
85180
86181
87-func getAccBalance (assetId) = if ((assetId == "WAVES"))
88- then wavesBalance(this).available
89- else assetBalance(this, fromBase58String(assetId))
182+let factoryContract = addressFromStringValue(getStrOrFail(this, keyFactoryContract()))
90183
184+let lpStakingContract = addressFromStringValue(getStrOrFail(this, keyLpStakingContract()))
91185
92-func getPoolAddressAndCheckPoolStatus (assetIn,assetOut) = {
93- let lpNonReverse = {
94- let @ = invoke(factoryContract, "getLpAssetFromPoolAssetsREADONLY", [assetIn, assetOut], nil)
95- if ($isInstanceOf(@, "String"))
186+let stakingContract = addressFromStringValue(getStrOrFail(this, keyStakingContract()))
187+
188+let boostingContract = addressFromStringValue(getStrOrFail(this, keyBoostingContract()))
189+
190+let swapContract = addressFromStringValue(getStrOrFail(this, keySwapContract()))
191+
192+let assetsStoreContract = addressFromStringValue(getStrOrFail(this, keyAssetsStoreContract()))
193+
194+let usdtAssetId = parseAssetId(getStrOrFail(this, keyUsdtAssetId()))
195+
196+let wxAssetId = parseAssetId(getStrOrFail(this, keyWxAssetId()))
197+
198+let minDelayDefault = 1440
199+
200+let minDelay = valueOrElse(getInteger(this, keyMinDelay()), minDelayDefault)
201+
202+let lockFractionMultiplier = 100000000
203+
204+let lockFractionDefault = fraction(1, lockFractionMultiplier, 2)
205+
206+let lockFraction = valueOrElse(getInteger(this, keyLockFraction()), lockFractionDefault)
207+
208+func getPoolInfo (amountAssetId) = {
209+ let amountAssetIdStr = assetIdToString(amountAssetId)
210+ let priceAssetIdStr = assetIdToString(usdtAssetId)
211+ let poolInfoOption = {
212+ let @ = invoke(factoryContract, "poolInfoREADONLY", [amountAssetIdStr, priceAssetIdStr], nil)
213+ if ($isInstanceOf(@, "(Address, ByteVector)"))
96214 then @
97215 else unit
98216 }
99- let lpReverse = {
100- let @ = invoke(factoryContract, "getLpAssetFromPoolAssetsREADONLY", [assetOut, assetIn], nil)
101- if ($isInstanceOf(@, "String"))
102- then @
103- else unit
104- }
105- let $t025332992 = if ((lpNonReverse != unit))
106- then {
107- let pool = {
108- let @ = invoke(factoryContract, "getPoolAddressFromLpAssetREADONLY", [value(lpNonReverse)], nil)
109- if ($isInstanceOf(@, "String"))
110- then @
111- else throw(($getType(@) + " couldn't be cast to String"))
112- }
113- $Tuple2(false, pool)
114- }
115- else if ((lpReverse != unit))
116- then {
117- let pool = {
118- let @ = invoke(factoryContract, "getPoolAddressFromLpAssetREADONLY", [value(lpReverse)], nil)
119- if ($isInstanceOf(@, "String"))
120- then @
121- else throw(($getType(@) + " couldn't be cast to String"))
122- }
123- $Tuple2(true, pool)
124- }
125- else poolNotExist
126- let isReverse = $t025332992._1
127- let pool = $t025332992._2
128- let poolStatus = {
129- let @ = invoke(factoryContract, "getPoolStatusREADONLY", [pool], nil)
130- if ($isInstanceOf(@, "Int"))
131- then @
132- else throw(($getType(@) + " couldn't be cast to Int"))
133- }
134- let check = if ((poolStatus == 1))
135- then true
136- else poolDisabled
137- if ((check == check))
138- then {
139- let poolAdr = addressFromStringValue(valueOrElse(pool, ""))
140- $Tuple2(poolAdr, isReverse)
141- }
142- else throw("Strict value is not equal to itself.")
217+ poolInfoOption
143218 }
144219
145220
146-@Callable(i)
147-func swapCalculateREADONLY (amountIn,assetIn,assetOut) = {
148- let prFee = value(getInteger(protocolFee()))
149- let feeProtocolAmountCalc = fraction(toBigInt(amountIn), toBigInt(prFee), feeScale)
150- let plFee = value(getInteger(poolFee()))
151- let feePoolAmountCalc = fraction(toBigInt(amountIn), toBigInt(plFee), feeScale)
152- let feeProtocolAmount = if ((toInt(feeProtocolAmountCalc) == 0))
153- then toBigInt(1)
154- else feeProtocolAmountCalc
155- let feePoolAmount = if ((toInt(feePoolAmountCalc) == 0))
156- then toBigInt(1)
157- else feePoolAmountCalc
158- let cleanAmountIn = ((toBigInt(amountIn) - feeProtocolAmount) - feePoolAmount)
159- let $t039804058 = getPoolAddressAndCheckPoolStatus(assetIn, assetOut)
160- let poolAdr = $t039804058._1
161- let isReverse = $t039804058._2
162- let res = {
163- let @ = invoke(poolAdr, "calculateAmountOutForSwapREADONLY", [toInt(cleanAmountIn), isReverse, toInt(feePoolAmount)], nil)
221+func calcPrice (lpAssetId,shareAssetId) = {
222+ let shareAssetInfo = valueOrErrorMessage(assetInfo(shareAssetId), "failed to get share asset info")
223+ let shareAssetEmission = shareAssetInfo.quantity
224+ let stakedAmount = ensurePositive(valueOrErrorMessage({
225+ let @ = invoke(stakingContract, "stakedByUserREADONLY", [assetIdToString(lpAssetId), toString(this)], nil)
164226 if ($isInstanceOf(@, "Int"))
165227 then @
166- else throw(($getType(@) + " couldn't be cast to Int"))
167- }
168- $Tuple2(nil, res)
228+ else unit
229+ }, wrapErr("invalid stakedByUserREADONLY result")))
230+ let price = if ((shareAssetEmission == 0))
231+ then scale18BigInt
232+ else fraction(toBigInt(stakedAmount), scale18BigInt, toBigInt(shareAssetEmission), FLOOR)
233+ price
169234 }
170-
171-
172-
173-@Callable(i)
174-func swap (amountOutMin,assetOutRaw,addressTo) = {
175- let assetOut = if ((assetOutRaw == ""))
176- then "WAVES"
177- else assetOutRaw
178- let pmt = value(i.payments[0])
179- let assetIn = if ((pmt.assetId == unit))
180- then "WAVES"
181- else toBase58String(value(pmt.assetId))
182- let amountIn = value(pmt.amount)
183- let prFee = value(getInteger(protocolFee()))
184- let feeProtocolAmountCalc = fraction(toBigInt(amountIn), toBigInt(prFee), feeScale)
185- let plFee = value(getInteger(poolFee()))
186- let feePoolAmountCalc = fraction(toBigInt(amountIn), toBigInt(plFee), feeScale)
187- let feeProtocolAmount = if ((toInt(feeProtocolAmountCalc) == 0))
188- then toBigInt(1)
189- else feeProtocolAmountCalc
190- let feePoolAmount = if ((toInt(feePoolAmountCalc) == 0))
191- then toBigInt(1)
192- else feePoolAmountCalc
193- let cleanAmountIn = ((toBigInt(amountIn) - feeProtocolAmount) - feePoolAmount)
194- let checks = [if ((size(i.payments) == 1))
195- then true
196- else throw("exactly 1 payment are expected")]
197- if ((checks == checks))
198- then {
199- let $t052605338 = getPoolAddressAndCheckPoolStatus(assetIn, assetOut)
200- let poolAdr = $t052605338._1
201- let isReverse = $t052605338._2
202- let assetInAttachedPayment = if ((assetIn == "WAVES"))
203- then unit
204- else fromBase58String(assetIn)
205- let totalGetRaw = {
206- let @ = invoke(poolAdr, "calculateAmountOutForSwapAndSendTokens", [toInt(cleanAmountIn), isReverse, amountOutMin, addressTo, toInt(feePoolAmount)], [AttachedPayment(assetInAttachedPayment, toInt(cleanAmountIn))])
207- if ($isInstanceOf(@, "Int"))
208- then @
209- else throw(($getType(@) + " couldn't be cast to Int"))
210- }
211- $Tuple2([ScriptTransfer(feeCollectorAddress, toInt(feeProtocolAmount), assetInAttachedPayment), ScriptTransfer(poolAdr, toInt(feePoolAmount), assetInAttachedPayment)], totalGetRaw)
212- }
213- else throw("Strict value is not equal to itself.")
214- }
215-
216235
217236
218237 @Callable(i)
235254 let pm = pendingManagerPublicKeyOrUnit()
236255 let hasPM = if (isDefined(pm))
237256 then true
238- else throw("no pending manager")
257+ else throwErr("no pending manager")
239258 if ((hasPM == hasPM))
240259 then {
241260 let checkPM = if ((i.callerPublicKey == value(pm)))
242261 then true
243- else throw("you are not pending manager")
262+ else throwErr("you are not pending manager")
244263 if ((checkPM == checkPM))
245264 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
265+ else throw("Strict value is not equal to itself.")
266+ }
267+ else throw("Strict value is not equal to itself.")
268+ }
269+
270+
271+
272+@Callable(i)
273+func emit (assetId,amount) = {
274+ let checkCaller = mustThis(i)
275+ if ((checkCaller == checkCaller))
276+ then {
277+ let isReissuable = true
278+ $Tuple2([Reissue(assetId, amount, isReissuable)], amount)
279+ }
280+ else throw("Strict value is not equal to itself.")
281+ }
282+
283+
284+
285+@Callable(i)
286+func burn (assetId,amount) = {
287+ let checkCaller = mustThis(i)
288+ if ((checkCaller == checkCaller))
289+ then $Tuple2([Burn(assetId, amount)], amount)
290+ else throw("Strict value is not equal to itself.")
291+ }
292+
293+
294+
295+@Callable(i)
296+func create (baseAssetIdStr,shareAssetIdStr,shareAssetName,shareAssetDescription,shareAssetLogo) = {
297+ let shareAssetLabel = "STAKING_LP"
298+ let baseAssetId = parseAssetId(baseAssetIdStr)
299+ let checks = [mustManager(i), if (isDefined(getPoolInfo(baseAssetId)))
300+ then true
301+ else throwErr("invalid base asset")]
302+ if ((checks == checks))
303+ then {
304+ let commonState = [IntegerEntry(keyPeriod(baseAssetId), 0)]
305+ if ((shareAssetIdStr == ""))
306+ then {
307+ let shareAssetIssueAmount = 1
308+ let shareAssetIssueAction = Issue(shareAssetName, shareAssetDescription, shareAssetIssueAmount, shareAssetDecimals, true)
309+ let calculatedShareAssetId = calculateAssetId(shareAssetIssueAction)
310+ let shareAssetBurnAction = Burn(calculatedShareAssetId, shareAssetIssueAmount)
311+ let calculatedShareAssetIdStr = toBase58String(calculatedShareAssetId)
312+ let createOrUpdate = invoke(assetsStoreContract, "createOrUpdate", [calculatedShareAssetIdStr, shareAssetLogo, false], nil)
313+ if ((createOrUpdate == createOrUpdate))
314+ then {
315+ let addLabel = invoke(assetsStoreContract, "addLabel", [calculatedShareAssetIdStr, shareAssetLabel], nil)
316+ if ((addLabel == addLabel))
317+ then $Tuple2((commonState ++ [shareAssetIssueAction, shareAssetBurnAction, StringEntry(keyShareAssetId(baseAssetId), calculatedShareAssetIdStr), StringEntry(keyBaseAssetId(calculatedShareAssetId), baseAssetIdStr)]), calculatedShareAssetIdStr)
318+ else throw("Strict value is not equal to itself.")
319+ }
320+ else throw("Strict value is not equal to itself.")
321+ }
322+ else {
323+ let shareAssetId = fromBase58String(shareAssetIdStr)
324+ let shareAssetInfo = valueOrErrorMessage(assetInfo(shareAssetId), wrapErr("invalid share asset id"))
325+ let checkIssuer = if ((shareAssetInfo.issuer == lpStakingContract))
326+ then true
327+ else throwErr("invalid share asset id issuer")
328+ if ((checkIssuer == checkIssuer))
329+ then $Tuple2((commonState ++ [StringEntry(keyShareAssetId(baseAssetId), shareAssetIdStr), StringEntry(keyBaseAssetId(shareAssetId), baseAssetIdStr)]), shareAssetIdStr)
330+ else throw("Strict value is not equal to itself.")
331+ }
332+ }
333+ else throw("Strict value is not equal to itself.")
334+ }
335+
336+
337+
338+@Callable(i)
339+func put () = {
340+ let pmt = if ((size(i.payments) == 1))
341+ then i.payments[0]
342+ else throwErr("exactly 1 payment is expected")
343+ let baseAssetId = pmt.assetId
344+ let userAddress = i.caller
345+ let checks = [shutdownCheck(i), if (isDefined(getString(keyShareAssetId(baseAssetId))))
346+ then true
347+ else throwErr("invalid asset")]
348+ if ((checks == checks))
349+ then {
350+ let $t01164011743 = valueOrErrorMessage(getPoolInfo(baseAssetId), wrapErr("invalid asset"))
351+ let poolAddress = $t01164011743._1
352+ let lpAssetId = $t01164011743._2
353+ let period = value(getInteger(keyPeriod(baseAssetId)))
354+ let userBaseAssetAmountToConvertPeriodOption = getInteger(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress))
355+ let claimShareAssetInvocation = if ((userBaseAssetAmountToConvertPeriodOption == unit))
356+ then unit
357+ else {
358+ let userBaseAssetAmountToConvertPeriod = value(userBaseAssetAmountToConvertPeriodOption)
359+ if ((userBaseAssetAmountToConvertPeriod == period))
360+ then unit
361+ else invoke(this, "claimShareAsset", [assetIdToString(baseAssetId), toString(userAddress)], nil)
362+ }
363+ if ((claimShareAssetInvocation == claimShareAssetInvocation))
364+ then {
365+ let baseAssetAmountToConvert = valueOrElse(getInteger(keyBaseAssetAmountToConvert(baseAssetId)), 0)
366+ let userBaseAssetAmountToConvert = valueOrElse(getInteger(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress)), 0)
367+ $Tuple2([IntegerEntry(keyBaseAssetAmountToConvert(baseAssetId), (baseAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress), (userBaseAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress), period), StringEntry(keyHistoryEntry(baseAssetId, "put", period, userAddress, i.transactionId), makeString([toString(pmt.amount), toString(lastBlock.timestamp), toString(userBaseAssetAmountToConvert)], separator))], unit)
368+ }
369+ else throw("Strict value is not equal to itself.")
370+ }
371+ else throw("Strict value is not equal to itself.")
372+ }
373+
374+
375+
376+@Callable(i)
377+func claimShareAsset (baseAssetIdStr,userAddressStr) = {
378+ let checks = [shutdownCheck(i)]
379+ if ((checks == checks))
380+ then {
381+ let userAddress = if ((userAddressStr == ""))
382+ then i.caller
383+ else {
384+ let checkCaller = mustThis(i)
385+ if ((checkCaller == checkCaller))
386+ then valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
387+ else throw("Strict value is not equal to itself.")
388+ }
389+ if ((userAddress == userAddress))
390+ then {
391+ let baseAssetId = parseAssetId(baseAssetIdStr)
392+ let shareAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyShareAssetId(baseAssetId)), wrapErr("invalid base asset id"))))
393+ if ((shareAssetId == shareAssetId))
394+ then {
395+ let period = valueOrErrorMessage(getInteger(keyPeriod(baseAssetId)), wrapErr("invalid period"))
396+ if ((period == period))
397+ then {
398+ let userBaseAssetAmountToConvert = valueOrElse(getInteger(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress)), 0)
399+ let checkAmountToConvert = if ((userBaseAssetAmountToConvert > 0))
400+ then true
401+ else throwErr("nothing to claim")
402+ if ((checkAmountToConvert == checkAmountToConvert))
403+ then {
404+ let userBaseAssetAmountToConvertPeriod = valueOrErrorMessage(getInteger(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress)), wrapErr("failed to get period"))
405+ let checkPeriod = if ((period > userBaseAssetAmountToConvertPeriod))
406+ then true
407+ else throwErr("invalid period")
408+ if ((checkPeriod == checkPeriod))
409+ then {
410+ let price = toBigInt(valueOrErrorMessage(getBinary(keyPricePeriodPut(baseAssetId, userBaseAssetAmountToConvertPeriod)), wrapErr("failed to get price")))
411+ let shareAssetAmount = toInt(fraction(toBigInt(userBaseAssetAmountToConvert), scale18BigInt, price))
412+ $Tuple2([IntegerEntry(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress), 0), DeleteEntry(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress)), ScriptTransfer(userAddress, shareAssetAmount, shareAssetId), StringEntry(keyHistoryEntry(baseAssetId, "claimShareAsset", period, userAddress, i.transactionId), makeString([toString(shareAssetAmount), toString(lastBlock.timestamp), toString(price), toString(userBaseAssetAmountToConvert)], separator))], unit)
413+ }
414+ else throw("Strict value is not equal to itself.")
415+ }
416+ else throw("Strict value is not equal to itself.")
417+ }
418+ else throw("Strict value is not equal to itself.")
419+ }
420+ else throw("Strict value is not equal to itself.")
421+ }
422+ else throw("Strict value is not equal to itself.")
423+ }
424+ else throw("Strict value is not equal to itself.")
425+ }
426+
427+
428+
429+@Callable(i)
430+func get () = {
431+ let checks = [shutdownCheck(i)]
432+ if ((checks == checks))
433+ then {
434+ let pmt = if ((size(i.payments) == 1))
435+ then i.payments[0]
436+ else throwErr("exactly 1 payment is expected")
437+ let shareAssetId = pmt.assetId
438+ let baseAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyBaseAssetId(shareAssetId)), wrapErr("invalid share asset id"))))
439+ if ((baseAssetId == baseAssetId))
440+ then {
441+ let userAddress = i.caller
442+ let $t01582016009 = valueOrErrorMessage(getPoolInfo(baseAssetId), wrapErr("invalid asset"))
443+ let poolAddress = $t01582016009._1
444+ let lpAssetId = $t01582016009._2
445+ let period = value(getInteger(keyPeriod(baseAssetId)))
446+ let userShareAssetAmountToConvertPeriodOption = getInteger(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress))
447+ let claimBaseAssetInvocation = if ((userShareAssetAmountToConvertPeriodOption == unit))
448+ then unit
449+ else {
450+ let userShareAssetAmountToConvertPeriod = value(userShareAssetAmountToConvertPeriodOption)
451+ if ((userShareAssetAmountToConvertPeriod == period))
452+ then unit
453+ else invoke(this, "claimBaseAsset", [assetIdToString(baseAssetId), toString(userAddress)], nil)
454+ }
455+ if ((claimBaseAssetInvocation == claimBaseAssetInvocation))
456+ then {
457+ let shareAssetAmountToConvert = valueOrElse(getInteger(keyShareAssetAmountToConvert(baseAssetId)), 0)
458+ let userShareAssetAmountToConvert = valueOrElse(getInteger(keyUserShareAssetAmountToConvert(baseAssetId, userAddress)), 0)
459+ $Tuple2([IntegerEntry(keyShareAssetAmountToConvert(baseAssetId), (shareAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserShareAssetAmountToConvert(baseAssetId, userAddress), (userShareAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress), period), StringEntry(keyHistoryEntry(baseAssetId, "get", period, userAddress, i.transactionId), makeString([toString(pmt.amount), toString(lastBlock.timestamp), toString(userShareAssetAmountToConvert)], separator))], unit)
460+ }
461+ else throw("Strict value is not equal to itself.")
462+ }
463+ else throw("Strict value is not equal to itself.")
464+ }
465+ else throw("Strict value is not equal to itself.")
466+ }
467+
468+
469+
470+@Callable(i)
471+func claimBaseAsset (baseAssetIdStr,userAddressStr) = {
472+ let checks = [shutdownCheck(i)]
473+ if ((checks == checks))
474+ then {
475+ let userAddress = if ((userAddressStr == ""))
476+ then i.caller
477+ else {
478+ let checkCaller = mustThis(i)
479+ if ((checkCaller == checkCaller))
480+ then valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
481+ else throw("Strict value is not equal to itself.")
482+ }
483+ if ((userAddress == userAddress))
484+ then {
485+ let baseAssetId = parseAssetId(baseAssetIdStr)
486+ let shareAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyShareAssetId(baseAssetId)), wrapErr("invalid base asset id"))))
487+ if ((shareAssetId == shareAssetId))
488+ then {
489+ let period = valueOrErrorMessage(getInteger(keyPeriod(baseAssetId)), wrapErr("invalid period"))
490+ if ((period == period))
491+ then {
492+ let userShareAssetAmountToConvert = valueOrElse(getInteger(keyUserShareAssetAmountToConvert(baseAssetId, userAddress)), 0)
493+ let userShareAssetAmountToConvertPeriod = valueOrErrorMessage(getInteger(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress)), wrapErr("failed to get period"))
494+ let checkPeriod = if ((period > userShareAssetAmountToConvertPeriod))
495+ then true
496+ else throwErr("invalid period")
497+ if ((checkPeriod == checkPeriod))
498+ then {
499+ let price = toBigInt(valueOrErrorMessage(getBinary(keyPricePeriodGet(baseAssetId, userShareAssetAmountToConvertPeriod)), wrapErr("failed to get price")))
500+ let baseAssetAmount = toInt(fraction(toBigInt(userShareAssetAmountToConvert), price, scale18BigInt))
501+ $Tuple2([IntegerEntry(keyUserShareAssetAmountToConvert(baseAssetId, userAddress), 0), DeleteEntry(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress)), ScriptTransfer(userAddress, baseAssetAmount, baseAssetId), StringEntry(keyHistoryEntry(baseAssetId, "claimBaseAsset", period, userAddress, i.transactionId), makeString([toString(baseAssetAmount), toString(lastBlock.timestamp), toString(price), toString(userShareAssetAmountToConvertPeriod)], separator))], unit)
502+ }
503+ else throw("Strict value is not equal to itself.")
504+ }
505+ else throw("Strict value is not equal to itself.")
506+ }
507+ else throw("Strict value is not equal to itself.")
508+ }
509+ else throw("Strict value is not equal to itself.")
510+ }
511+ else throw("Strict value is not equal to itself.")
512+ }
513+
514+
515+
516+@Callable(i)
517+func finalize (baseAssetIdStr) = {
518+ let checks = [shutdownCheck(i)]
519+ if ((checks == checks))
520+ then {
521+ let baseAssetId = parseAssetId(baseAssetIdStr)
522+ let shareAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyShareAssetId(baseAssetId)), wrapErr("invalid base asset id"))))
523+ if ((shareAssetId == shareAssetId))
524+ then {
525+ let shareAssetInfo = valueOrErrorMessage(assetInfo(shareAssetId), wrapErr("invalid share asset id"))
526+ let period = valueOrErrorMessage(getInteger(keyPeriod(baseAssetId)), wrapErr("invalid period"))
527+ if ((period == period))
528+ then {
529+ let periodStartHeightOption = getInteger(keyPeriodStartHeight(baseAssetId, period))
530+ let checkDelay = if ((periodStartHeightOption == unit))
531+ then unit
532+ else {
533+ let delay = (height - value(periodStartHeightOption))
534+ let blocksToWait = max([0, (minDelay - delay)])
535+ if ((blocksToWait == 0))
536+ then unit
537+ else throwErr(makeString(["finalization will be possible in ", toString(blocksToWait), " blocks"], ""))
538+ }
539+ if ((checkDelay == checkDelay))
540+ then {
541+ let $t02111321294 = valueOrErrorMessage(getPoolInfo(baseAssetId), wrapErr("invalid asset"))
542+ let poolAddress = $t02111321294._1
543+ let lpAssetId = $t02111321294._2
544+ let stakingReward = valueOrErrorMessage({
545+ let @ = invoke(stakingContract, "claimWxDoNotThrow", [assetIdToString(lpAssetId)], nil)
546+ if ($isInstanceOf(@, "Int"))
547+ then @
548+ else unit
549+ }, wrapErr("invalid claimWx result"))
550+ if ((stakingReward == stakingReward))
551+ then {
552+ let baseAssetAmountToConvert = valueOrElse(getInteger(keyBaseAssetAmountToConvert(baseAssetId)), 0)
553+ let shareAssetAmountToConvert = valueOrElse(getInteger(keyShareAssetAmountToConvert(baseAssetId)), 0)
554+ let checkFinalizationIsRequired = {
555+ let isFinalizationRequired = if (if ((stakingReward > 0))
556+ then true
557+ else (baseAssetAmountToConvert > 0))
558+ then true
559+ else (shareAssetAmountToConvert > 0)
560+ if (isFinalizationRequired)
561+ then true
562+ else throwErr("nothing to finalize")
563+ }
564+ if ((checkFinalizationIsRequired == checkFinalizationIsRequired))
565+ then {
566+ let useStakingReward = if ((stakingReward > 0))
567+ then {
568+ let lockPart = fraction(stakingReward, lockFraction, lockFractionMultiplier)
569+ let convertPart = (stakingReward - lockPart)
570+ let r = invoke(boostingContract, "userMaxDurationREADONLY", [toString(this)], nil)
571+ let lock = if ((lockPart > 0))
572+ then match r {
573+ case _ =>
574+ if (if (if ($isInstanceOf($match0._1, "String"))
575+ then $isInstanceOf($match0._2, "Int")
576+ else false)
577+ then $isInstanceOf($match0, "(String, Int)")
578+ else false)
579+ then {
580+ let function = $match0._1
581+ let duration = $match0._2
582+ if ((lockPart > 0))
583+ then invoke(boostingContract, function, [duration], [AttachedPayment(wxAssetId, lockPart)])
584+ else unit
585+ }
586+ else throwErr("invalid lock params")
587+ }
588+ else unit
589+ if ((lock == lock))
590+ then {
591+ let convertedAmount = if ((convertPart > 0))
592+ then {
593+ let inAssetId = wxAssetId
594+ let minimumToReceive = 0
595+ let outAssetIdStr = assetIdToString(usdtAssetId)
596+ let targetAddress = toString(this)
597+ valueOrErrorMessage({
598+ let @ = invoke(swapContract, "swap", [minimumToReceive, outAssetIdStr, targetAddress], [AttachedPayment(inAssetId, convertPart)])
599+ if ($isInstanceOf(@, "Int"))
600+ then @
601+ else unit
602+ }, wrapErr("invalid swap result"))
603+ }
604+ else 0
605+ if ((convertedAmount == convertedAmount))
606+ then {
607+ let lpAssetAmount = if ((convertedAmount > 0))
608+ then {
609+ let minOutAmount = 0
610+ let autoStake = true
611+ valueOrErrorMessage({
612+ let @ = invoke(poolAddress, "putOneTknV2", [minOutAmount, autoStake], [AttachedPayment(usdtAssetId, convertedAmount)])
613+ if ($isInstanceOf(@, "Int"))
614+ then @
615+ else unit
616+ }, wrapErr("invalid putOneTknV2 result"))
617+ }
618+ else 0
619+ if ((lpAssetAmount == lpAssetAmount))
620+ then lpAssetAmount
621+ else throw("Strict value is not equal to itself.")
622+ }
623+ else throw("Strict value is not equal to itself.")
624+ }
625+ else throw("Strict value is not equal to itself.")
626+ }
627+ else unit
628+ if ((useStakingReward == useStakingReward))
629+ then {
630+ let getActions = if ((shareAssetAmountToConvert > 0))
631+ then {
632+ let price = calcPrice(lpAssetId, shareAssetId)
633+ if ((price == price))
634+ then {
635+ let unstakeAmount = toInt(fraction(toBigInt(shareAssetAmountToConvert), price, scale18BigInt, FLOOR))
636+ let baseAssetAmount = {
637+ let outAssetId = baseAssetId
638+ let minOutAmount = 0
639+ valueOrErrorMessage({
640+ let @ = invoke(poolAddress, "unstakeAndGetOneTknV2", [unstakeAmount, assetIdToString(outAssetId), minOutAmount], nil)
641+ if ($isInstanceOf(@, "Int"))
642+ then @
643+ else unit
644+ }, wrapErr("invalid unstakeAndGetOneTknV2 result"))
645+ }
646+ if ((baseAssetAmount == baseAssetAmount))
647+ then {
648+ let shareAssetBurn = if ((shareAssetInfo.issuer == this))
649+ then invoke(this, "burn", [shareAssetId, shareAssetAmountToConvert], nil)
650+ else throwErr("invalid share asset issuer")
651+ if ((shareAssetBurn == shareAssetBurn))
652+ then {
653+ let priceGet = fraction(toBigInt(baseAssetAmount), scale18BigInt, toBigInt(shareAssetAmountToConvert), FLOOR)
654+ let priceGetUpdateActions = [BinaryEntry(keyPricePeriodGet(baseAssetId, period), toBytes(priceGet)), StringEntry(keyPriceGetHistory(baseAssetId), toString(priceGet))]
655+ priceGetUpdateActions
656+ }
657+ else throw("Strict value is not equal to itself.")
658+ }
659+ else throw("Strict value is not equal to itself.")
660+ }
661+ else throw("Strict value is not equal to itself.")
662+ }
663+ else nil
664+ if ((getActions == getActions))
665+ then {
666+ let putActions = if ((baseAssetAmountToConvert > 0))
667+ then {
668+ let lpAssetAmount = {
669+ let minOutAmount = 0
670+ let autoStake = true
671+ valueOrErrorMessage({
672+ let @ = invoke(poolAddress, "putOneTknV2", [minOutAmount, autoStake], [AttachedPayment(baseAssetId, baseAssetAmountToConvert)])
673+ if ($isInstanceOf(@, "Int"))
674+ then @
675+ else unit
676+ }, wrapErr("invalid putOneTknV2 result"))
677+ }
678+ if ((lpAssetAmount == lpAssetAmount))
679+ then {
680+ let price = calcPrice(lpAssetId, shareAssetId)
681+ if ((price == price))
682+ then {
683+ let checkPrice = if ((value(toInt(price)) != 0))
684+ then true
685+ else throw("price is ZERO")
686+ if ((checkPrice == checkPrice))
687+ then {
688+ let shareAssetAmount = toInt(fraction(toBigInt(lpAssetAmount), scale18BigInt, price, FLOOR))
689+ let checkShareAssetAmount = if ((value(toInt(price)) != 0))
690+ then true
691+ else throw("shareAssetAmount is ZERO")
692+ if ((checkShareAssetAmount == checkShareAssetAmount))
693+ then {
694+ let shareAssetReissue = if ((shareAssetInfo.issuer == this))
695+ then invoke(this, "emit", [shareAssetId, shareAssetAmount], nil)
696+ else throwErr("invalid share asset issuer")
697+ if ((shareAssetReissue == shareAssetReissue))
698+ then {
699+ let pricePut = fraction(toBigInt(baseAssetAmountToConvert), scale18BigInt, toBigInt(shareAssetAmount))
700+ let pricePutUpdateActions = [BinaryEntry(keyPricePeriodPut(baseAssetId, period), toBytes(pricePut)), StringEntry(keyPricePutHistory(baseAssetId), toString(pricePut))]
701+ pricePutUpdateActions
702+ }
703+ else throw("Strict value is not equal to itself.")
704+ }
705+ else throw("Strict value is not equal to itself.")
706+ }
707+ else throw("Strict value is not equal to itself.")
708+ }
709+ else throw("Strict value is not equal to itself.")
710+ }
711+ else throw("Strict value is not equal to itself.")
712+ }
713+ else nil
714+ if ((putActions == putActions))
715+ then {
716+ let newPeriod = (period + 1)
717+ let lastPrice = calcPrice(lpAssetId, shareAssetId)
718+ let actions = (([IntegerEntry(keyPeriod(baseAssetId), newPeriod), IntegerEntry(keyPeriodStartHeight(baseAssetId, newPeriod), height), IntegerEntry(keyShareAssetAmountToConvert(baseAssetId), 0), IntegerEntry(keyBaseAssetAmountToConvert(baseAssetId), 0), BinaryEntry(keyPricePeriod(baseAssetId, period), toBytes(lastPrice)), StringEntry(keyPriceHistory(baseAssetId), toString(lastPrice))] ++ putActions) ++ getActions)
719+ $Tuple2(actions, toBytes(lastPrice))
720+ }
721+ else throw("Strict value is not equal to itself.")
722+ }
723+ else throw("Strict value is not equal to itself.")
724+ }
725+ else throw("Strict value is not equal to itself.")
726+ }
727+ else throw("Strict value is not equal to itself.")
728+ }
729+ else throw("Strict value is not equal to itself.")
730+ }
731+ else throw("Strict value is not equal to itself.")
732+ }
733+ else throw("Strict value is not equal to itself.")
734+ }
246735 else throw("Strict value is not equal to itself.")
247736 }
248737 else throw("Strict value is not equal to itself.")
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
4-let SEP = "__"
4+let separator = "__"
55
6-let feeScale = toBigInt(100000000)
6+let shareAssetDecimals = 8
77
8-func getStringOrFail (key) = valueOrErrorMessage(getString(this, key), ("No data for this.key=" + key))
8+let wavesString = "WAVES"
9+
10+let scale18 = 1000000000000000000
11+
12+let scale18BigInt = toBigInt(scale18)
13+
14+func wrapErr (msg) = makeString(["lp_staking_pools.ride:", msg], " ")
915
1016
11-let poolDisabled = throw("Pool disabled")
17+func throwErr (msg) = throw(wrapErr(msg))
1218
13-let poolNotExist = throw("Pool is not exist")
1419
15-let slippageTooBig = throw("Slippage is too big")
20+func errKeyIsNotDefined (address,key) = wrapErr(makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
21+
22+
23+func getStrOrFail (address,key) = valueOrErrorMessage(getString(address, key), errKeyIsNotDefined(address, key))
24+
25+
26+func getIntOrFail (address,key) = valueOrErrorMessage(getInteger(address, key), errKeyIsNotDefined(address, key))
27+
28+
29+func parseAssetId (input) = if ((input == wavesString))
30+ then unit
31+ else fromBase58String(input)
32+
33+
34+func assetIdToString (input) = if ((input == unit))
35+ then wavesString
36+ else toBase58String(value(input))
37+
38+
39+func ensurePositive (v) = if ((v >= 0))
40+ then v
41+ else throwErr("value should be positive")
42+
43+
44+func keyFactoryContract () = makeString(["%s", "factoryContract"], separator)
45+
46+
47+func keyLpStakingContract () = makeString(["%s", "lpStakingContract"], separator)
48+
49+
50+func keyStakingContract () = makeString(["%s", "stakingContract"], separator)
51+
52+
53+func keyBoostingContract () = makeString(["%s", "boostingContract"], separator)
54+
55+
56+func keySwapContract () = makeString(["%s", "swapContract"], separator)
57+
58+
59+func keyAssetsStoreContract () = makeString(["%s", "assetsStoreContract"], separator)
60+
61+
62+func keyUsdtAssetId () = makeString(["%s", "usdtAssetId"], separator)
63+
64+
65+func keyWxAssetId () = makeString(["%s", "wxAssetId"], separator)
66+
67+
68+func keyShutdown () = makeString(["%s", "shutdown"], separator)
69+
70+
71+func keyMinDelay () = makeString(["%s", "minDelay"], separator)
72+
73+
74+func keyLockFraction () = makeString(["%s", "lockFraction"], separator)
75+
76+
77+func keyShareAssetId (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "shareAssetId"], separator)
78+
79+
80+func keyBaseAssetId (shareAssetId) = makeString(["%s%s", assetIdToString(shareAssetId), "baseAssetId"], separator)
81+
82+
83+func keyPeriod (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "period"], separator)
84+
85+
86+func keyPeriodStartHeight (baseAssetId,period) = makeString(["%s%s%d", assetIdToString(baseAssetId), "periodStartHeight", toString(period)], separator)
87+
88+
89+func keyBaseAssetAmountToConvert (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "baseAssetAmountToConvert"], separator)
90+
91+
92+func keyShareAssetAmountToConvert (baseAssetId) = makeString(["%s%s", assetIdToString(baseAssetId), "shareAssetAmountToConvert"], separator)
93+
94+
95+func keyUserBaseAssetAmountToConvert (baseAssetId,userAddress) = makeString(["%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "baseAssetAmountToConvert"], separator)
96+
97+
98+func keyUserBaseAssetAmountToConvertPeriod (baseAssetId,userAddress) = makeString(["%s%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "baseAssetAmountToConvert", "period"], separator)
99+
100+
101+func keyUserShareAssetAmountToConvert (baseAssetId,userAddress) = makeString(["%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "shareAssetAmountToConvert"], separator)
102+
103+
104+func keyUserShareAssetAmountToConvertPeriod (baseAssetId,userAddress) = makeString(["%s%s%s%s", assetIdToString(baseAssetId), toString(userAddress), "shareAssetAmountToConvert", "period"], separator)
105+
106+
107+func keyPricePeriod (baseAssetId,period) = makeString(["%s%s%d", assetIdToString(baseAssetId), "price", toString(period)], separator)
108+
109+
110+func keyPriceHistory (baseAssetId) = makeString(["%s%s%s%d%d", assetIdToString(baseAssetId), "price", "history", toString(lastBlock.height), toString(lastBlock.timestamp)], separator)
111+
112+
113+func keyPricePeriodPut (baseAssetId,period) = makeString(["%s%s%d%s", assetIdToString(baseAssetId), "price", toString(period), "put"], separator)
114+
115+
116+func keyPricePutHistory (baseAssetId) = makeString(["%s%s%s%s%d%d", assetIdToString(baseAssetId), "price", "history", "put", toString(lastBlock.height), toString(lastBlock.timestamp)], separator)
117+
118+
119+func keyPricePeriodGet (baseAssetId,period) = makeString(["%s%s%d%s", assetIdToString(baseAssetId), "price", toString(period), "get"], separator)
120+
121+
122+func keyPriceGetHistory (baseAssetId) = makeString(["%s%s%s%s%d%d", assetIdToString(baseAssetId), "price", "history", "get", toString(lastBlock.height), toString(lastBlock.timestamp)], separator)
123+
124+
125+func keyHistoryEntry (baseAssetId,operation,period,userAddress,txId) = makeString(["%s%s%s%s", "history", operation, toString(userAddress), toBase58String(txId), toString(height)], separator)
126+
16127
17128 func keyManagerPublicKey () = "%s__managerPublicKey"
18129
19130
20131 func keyPendingManagerPublicKey () = "%s__pendingManagerPublicKey"
21-
22-
23-func fc () = "%s__factoryContract"
24-
25-
26-let factoryContract = addressFromStringValue(getStringOrFail(fc()))
27-
28-func protocolFee () = makeString(["%s", "protocolFee"], SEP)
29-
30-
31-func poolFee () = makeString(["%s", "poolFee"], SEP)
32-
33-
34-func getStringOrFailFromAddress (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
35-
36-
37-let keyFeeCollectorAddress = "%s__feeCollectorAddress"
38-
39-let feeCollectorAddress = addressFromStringValue(getStringOrFailFromAddress(factoryContract, keyFeeCollectorAddress))
40-
41-func asInt (val) = match val {
42- case valInt: Int =>
43- valInt
44- case _ =>
45- throw("fail to cast into Int")
46-}
47-
48-
49-func dataMappingPoolAssets (internalAmountAssetStr,internalPriceAssetStr) = makeString(["%d%d", toString(internalAmountAssetStr), toString(internalPriceAssetStr)], SEP)
50132
51133
52134 func managerPublicKeyOrUnit () = match getString(keyManagerPublicKey()) {
53135 case s: String =>
54136 fromBase58String(s)
55137 case _: Unit =>
56138 unit
57139 case _ =>
58140 throw("Match error")
59141 }
60142
61143
62144 func pendingManagerPublicKeyOrUnit () = match getString(keyPendingManagerPublicKey()) {
63145 case s: String =>
64146 fromBase58String(s)
65147 case _: Unit =>
66148 unit
67149 case _ =>
68150 throw("Match error")
69151 }
70152
71153
72-func isManager (i) = match managerPublicKeyOrUnit() {
154+let permissionDeniedError = throw("Permission denied")
155+
156+func mustThis (i) = if ((i.caller == this))
157+ then true
158+ else permissionDeniedError
159+
160+
161+func mustManager (i) = match managerPublicKeyOrUnit() {
73162 case pk: ByteVector =>
74- (i.callerPublicKey == pk)
163+ if ((i.callerPublicKey == pk))
164+ then true
165+ else permissionDeniedError
75166 case _: Unit =>
76- (i.caller == this)
167+ mustThis(i)
77168 case _ =>
78169 throw("Match error")
79170 }
80171
81172
82-func mustManager (i) = if (isManager(i))
173+let shutdown = valueOrElse(getBoolean(keyShutdown()), false)
174+
175+func shutdownCheck (i) = if (if (!(shutdown))
83176 then true
84- else throw("permission denied")
177+ else mustManager(i))
178+ then true
179+ else throw("operation is disabled")
85180
86181
87-func getAccBalance (assetId) = if ((assetId == "WAVES"))
88- then wavesBalance(this).available
89- else assetBalance(this, fromBase58String(assetId))
182+let factoryContract = addressFromStringValue(getStrOrFail(this, keyFactoryContract()))
90183
184+let lpStakingContract = addressFromStringValue(getStrOrFail(this, keyLpStakingContract()))
91185
92-func getPoolAddressAndCheckPoolStatus (assetIn,assetOut) = {
93- let lpNonReverse = {
94- let @ = invoke(factoryContract, "getLpAssetFromPoolAssetsREADONLY", [assetIn, assetOut], nil)
95- if ($isInstanceOf(@, "String"))
186+let stakingContract = addressFromStringValue(getStrOrFail(this, keyStakingContract()))
187+
188+let boostingContract = addressFromStringValue(getStrOrFail(this, keyBoostingContract()))
189+
190+let swapContract = addressFromStringValue(getStrOrFail(this, keySwapContract()))
191+
192+let assetsStoreContract = addressFromStringValue(getStrOrFail(this, keyAssetsStoreContract()))
193+
194+let usdtAssetId = parseAssetId(getStrOrFail(this, keyUsdtAssetId()))
195+
196+let wxAssetId = parseAssetId(getStrOrFail(this, keyWxAssetId()))
197+
198+let minDelayDefault = 1440
199+
200+let minDelay = valueOrElse(getInteger(this, keyMinDelay()), minDelayDefault)
201+
202+let lockFractionMultiplier = 100000000
203+
204+let lockFractionDefault = fraction(1, lockFractionMultiplier, 2)
205+
206+let lockFraction = valueOrElse(getInteger(this, keyLockFraction()), lockFractionDefault)
207+
208+func getPoolInfo (amountAssetId) = {
209+ let amountAssetIdStr = assetIdToString(amountAssetId)
210+ let priceAssetIdStr = assetIdToString(usdtAssetId)
211+ let poolInfoOption = {
212+ let @ = invoke(factoryContract, "poolInfoREADONLY", [amountAssetIdStr, priceAssetIdStr], nil)
213+ if ($isInstanceOf(@, "(Address, ByteVector)"))
96214 then @
97215 else unit
98216 }
99- let lpReverse = {
100- let @ = invoke(factoryContract, "getLpAssetFromPoolAssetsREADONLY", [assetOut, assetIn], nil)
101- if ($isInstanceOf(@, "String"))
102- then @
103- else unit
104- }
105- let $t025332992 = if ((lpNonReverse != unit))
106- then {
107- let pool = {
108- let @ = invoke(factoryContract, "getPoolAddressFromLpAssetREADONLY", [value(lpNonReverse)], nil)
109- if ($isInstanceOf(@, "String"))
110- then @
111- else throw(($getType(@) + " couldn't be cast to String"))
112- }
113- $Tuple2(false, pool)
114- }
115- else if ((lpReverse != unit))
116- then {
117- let pool = {
118- let @ = invoke(factoryContract, "getPoolAddressFromLpAssetREADONLY", [value(lpReverse)], nil)
119- if ($isInstanceOf(@, "String"))
120- then @
121- else throw(($getType(@) + " couldn't be cast to String"))
122- }
123- $Tuple2(true, pool)
124- }
125- else poolNotExist
126- let isReverse = $t025332992._1
127- let pool = $t025332992._2
128- let poolStatus = {
129- let @ = invoke(factoryContract, "getPoolStatusREADONLY", [pool], nil)
130- if ($isInstanceOf(@, "Int"))
131- then @
132- else throw(($getType(@) + " couldn't be cast to Int"))
133- }
134- let check = if ((poolStatus == 1))
135- then true
136- else poolDisabled
137- if ((check == check))
138- then {
139- let poolAdr = addressFromStringValue(valueOrElse(pool, ""))
140- $Tuple2(poolAdr, isReverse)
141- }
142- else throw("Strict value is not equal to itself.")
217+ poolInfoOption
143218 }
144219
145220
146-@Callable(i)
147-func swapCalculateREADONLY (amountIn,assetIn,assetOut) = {
148- let prFee = value(getInteger(protocolFee()))
149- let feeProtocolAmountCalc = fraction(toBigInt(amountIn), toBigInt(prFee), feeScale)
150- let plFee = value(getInteger(poolFee()))
151- let feePoolAmountCalc = fraction(toBigInt(amountIn), toBigInt(plFee), feeScale)
152- let feeProtocolAmount = if ((toInt(feeProtocolAmountCalc) == 0))
153- then toBigInt(1)
154- else feeProtocolAmountCalc
155- let feePoolAmount = if ((toInt(feePoolAmountCalc) == 0))
156- then toBigInt(1)
157- else feePoolAmountCalc
158- let cleanAmountIn = ((toBigInt(amountIn) - feeProtocolAmount) - feePoolAmount)
159- let $t039804058 = getPoolAddressAndCheckPoolStatus(assetIn, assetOut)
160- let poolAdr = $t039804058._1
161- let isReverse = $t039804058._2
162- let res = {
163- let @ = invoke(poolAdr, "calculateAmountOutForSwapREADONLY", [toInt(cleanAmountIn), isReverse, toInt(feePoolAmount)], nil)
221+func calcPrice (lpAssetId,shareAssetId) = {
222+ let shareAssetInfo = valueOrErrorMessage(assetInfo(shareAssetId), "failed to get share asset info")
223+ let shareAssetEmission = shareAssetInfo.quantity
224+ let stakedAmount = ensurePositive(valueOrErrorMessage({
225+ let @ = invoke(stakingContract, "stakedByUserREADONLY", [assetIdToString(lpAssetId), toString(this)], nil)
164226 if ($isInstanceOf(@, "Int"))
165227 then @
166- else throw(($getType(@) + " couldn't be cast to Int"))
167- }
168- $Tuple2(nil, res)
228+ else unit
229+ }, wrapErr("invalid stakedByUserREADONLY result")))
230+ let price = if ((shareAssetEmission == 0))
231+ then scale18BigInt
232+ else fraction(toBigInt(stakedAmount), scale18BigInt, toBigInt(shareAssetEmission), FLOOR)
233+ price
169234 }
170-
171-
172-
173-@Callable(i)
174-func swap (amountOutMin,assetOutRaw,addressTo) = {
175- let assetOut = if ((assetOutRaw == ""))
176- then "WAVES"
177- else assetOutRaw
178- let pmt = value(i.payments[0])
179- let assetIn = if ((pmt.assetId == unit))
180- then "WAVES"
181- else toBase58String(value(pmt.assetId))
182- let amountIn = value(pmt.amount)
183- let prFee = value(getInteger(protocolFee()))
184- let feeProtocolAmountCalc = fraction(toBigInt(amountIn), toBigInt(prFee), feeScale)
185- let plFee = value(getInteger(poolFee()))
186- let feePoolAmountCalc = fraction(toBigInt(amountIn), toBigInt(plFee), feeScale)
187- let feeProtocolAmount = if ((toInt(feeProtocolAmountCalc) == 0))
188- then toBigInt(1)
189- else feeProtocolAmountCalc
190- let feePoolAmount = if ((toInt(feePoolAmountCalc) == 0))
191- then toBigInt(1)
192- else feePoolAmountCalc
193- let cleanAmountIn = ((toBigInt(amountIn) - feeProtocolAmount) - feePoolAmount)
194- let checks = [if ((size(i.payments) == 1))
195- then true
196- else throw("exactly 1 payment are expected")]
197- if ((checks == checks))
198- then {
199- let $t052605338 = getPoolAddressAndCheckPoolStatus(assetIn, assetOut)
200- let poolAdr = $t052605338._1
201- let isReverse = $t052605338._2
202- let assetInAttachedPayment = if ((assetIn == "WAVES"))
203- then unit
204- else fromBase58String(assetIn)
205- let totalGetRaw = {
206- let @ = invoke(poolAdr, "calculateAmountOutForSwapAndSendTokens", [toInt(cleanAmountIn), isReverse, amountOutMin, addressTo, toInt(feePoolAmount)], [AttachedPayment(assetInAttachedPayment, toInt(cleanAmountIn))])
207- if ($isInstanceOf(@, "Int"))
208- then @
209- else throw(($getType(@) + " couldn't be cast to Int"))
210- }
211- $Tuple2([ScriptTransfer(feeCollectorAddress, toInt(feeProtocolAmount), assetInAttachedPayment), ScriptTransfer(poolAdr, toInt(feePoolAmount), assetInAttachedPayment)], totalGetRaw)
212- }
213- else throw("Strict value is not equal to itself.")
214- }
215-
216235
217236
218237 @Callable(i)
219238 func setManager (pendingManagerPublicKey) = {
220239 let checkCaller = mustManager(i)
221240 if ((checkCaller == checkCaller))
222241 then {
223242 let checkManagerPublicKey = fromBase58String(pendingManagerPublicKey)
224243 if ((checkManagerPublicKey == checkManagerPublicKey))
225244 then [StringEntry(keyPendingManagerPublicKey(), pendingManagerPublicKey)]
226245 else throw("Strict value is not equal to itself.")
227246 }
228247 else throw("Strict value is not equal to itself.")
229248 }
230249
231250
232251
233252 @Callable(i)
234253 func confirmManager () = {
235254 let pm = pendingManagerPublicKeyOrUnit()
236255 let hasPM = if (isDefined(pm))
237256 then true
238- else throw("no pending manager")
257+ else throwErr("no pending manager")
239258 if ((hasPM == hasPM))
240259 then {
241260 let checkPM = if ((i.callerPublicKey == value(pm)))
242261 then true
243- else throw("you are not pending manager")
262+ else throwErr("you are not pending manager")
244263 if ((checkPM == checkPM))
245264 then [StringEntry(keyManagerPublicKey(), toBase58String(value(pm))), DeleteEntry(keyPendingManagerPublicKey())]
265+ else throw("Strict value is not equal to itself.")
266+ }
267+ else throw("Strict value is not equal to itself.")
268+ }
269+
270+
271+
272+@Callable(i)
273+func emit (assetId,amount) = {
274+ let checkCaller = mustThis(i)
275+ if ((checkCaller == checkCaller))
276+ then {
277+ let isReissuable = true
278+ $Tuple2([Reissue(assetId, amount, isReissuable)], amount)
279+ }
280+ else throw("Strict value is not equal to itself.")
281+ }
282+
283+
284+
285+@Callable(i)
286+func burn (assetId,amount) = {
287+ let checkCaller = mustThis(i)
288+ if ((checkCaller == checkCaller))
289+ then $Tuple2([Burn(assetId, amount)], amount)
290+ else throw("Strict value is not equal to itself.")
291+ }
292+
293+
294+
295+@Callable(i)
296+func create (baseAssetIdStr,shareAssetIdStr,shareAssetName,shareAssetDescription,shareAssetLogo) = {
297+ let shareAssetLabel = "STAKING_LP"
298+ let baseAssetId = parseAssetId(baseAssetIdStr)
299+ let checks = [mustManager(i), if (isDefined(getPoolInfo(baseAssetId)))
300+ then true
301+ else throwErr("invalid base asset")]
302+ if ((checks == checks))
303+ then {
304+ let commonState = [IntegerEntry(keyPeriod(baseAssetId), 0)]
305+ if ((shareAssetIdStr == ""))
306+ then {
307+ let shareAssetIssueAmount = 1
308+ let shareAssetIssueAction = Issue(shareAssetName, shareAssetDescription, shareAssetIssueAmount, shareAssetDecimals, true)
309+ let calculatedShareAssetId = calculateAssetId(shareAssetIssueAction)
310+ let shareAssetBurnAction = Burn(calculatedShareAssetId, shareAssetIssueAmount)
311+ let calculatedShareAssetIdStr = toBase58String(calculatedShareAssetId)
312+ let createOrUpdate = invoke(assetsStoreContract, "createOrUpdate", [calculatedShareAssetIdStr, shareAssetLogo, false], nil)
313+ if ((createOrUpdate == createOrUpdate))
314+ then {
315+ let addLabel = invoke(assetsStoreContract, "addLabel", [calculatedShareAssetIdStr, shareAssetLabel], nil)
316+ if ((addLabel == addLabel))
317+ then $Tuple2((commonState ++ [shareAssetIssueAction, shareAssetBurnAction, StringEntry(keyShareAssetId(baseAssetId), calculatedShareAssetIdStr), StringEntry(keyBaseAssetId(calculatedShareAssetId), baseAssetIdStr)]), calculatedShareAssetIdStr)
318+ else throw("Strict value is not equal to itself.")
319+ }
320+ else throw("Strict value is not equal to itself.")
321+ }
322+ else {
323+ let shareAssetId = fromBase58String(shareAssetIdStr)
324+ let shareAssetInfo = valueOrErrorMessage(assetInfo(shareAssetId), wrapErr("invalid share asset id"))
325+ let checkIssuer = if ((shareAssetInfo.issuer == lpStakingContract))
326+ then true
327+ else throwErr("invalid share asset id issuer")
328+ if ((checkIssuer == checkIssuer))
329+ then $Tuple2((commonState ++ [StringEntry(keyShareAssetId(baseAssetId), shareAssetIdStr), StringEntry(keyBaseAssetId(shareAssetId), baseAssetIdStr)]), shareAssetIdStr)
330+ else throw("Strict value is not equal to itself.")
331+ }
332+ }
333+ else throw("Strict value is not equal to itself.")
334+ }
335+
336+
337+
338+@Callable(i)
339+func put () = {
340+ let pmt = if ((size(i.payments) == 1))
341+ then i.payments[0]
342+ else throwErr("exactly 1 payment is expected")
343+ let baseAssetId = pmt.assetId
344+ let userAddress = i.caller
345+ let checks = [shutdownCheck(i), if (isDefined(getString(keyShareAssetId(baseAssetId))))
346+ then true
347+ else throwErr("invalid asset")]
348+ if ((checks == checks))
349+ then {
350+ let $t01164011743 = valueOrErrorMessage(getPoolInfo(baseAssetId), wrapErr("invalid asset"))
351+ let poolAddress = $t01164011743._1
352+ let lpAssetId = $t01164011743._2
353+ let period = value(getInteger(keyPeriod(baseAssetId)))
354+ let userBaseAssetAmountToConvertPeriodOption = getInteger(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress))
355+ let claimShareAssetInvocation = if ((userBaseAssetAmountToConvertPeriodOption == unit))
356+ then unit
357+ else {
358+ let userBaseAssetAmountToConvertPeriod = value(userBaseAssetAmountToConvertPeriodOption)
359+ if ((userBaseAssetAmountToConvertPeriod == period))
360+ then unit
361+ else invoke(this, "claimShareAsset", [assetIdToString(baseAssetId), toString(userAddress)], nil)
362+ }
363+ if ((claimShareAssetInvocation == claimShareAssetInvocation))
364+ then {
365+ let baseAssetAmountToConvert = valueOrElse(getInteger(keyBaseAssetAmountToConvert(baseAssetId)), 0)
366+ let userBaseAssetAmountToConvert = valueOrElse(getInteger(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress)), 0)
367+ $Tuple2([IntegerEntry(keyBaseAssetAmountToConvert(baseAssetId), (baseAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress), (userBaseAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress), period), StringEntry(keyHistoryEntry(baseAssetId, "put", period, userAddress, i.transactionId), makeString([toString(pmt.amount), toString(lastBlock.timestamp), toString(userBaseAssetAmountToConvert)], separator))], unit)
368+ }
369+ else throw("Strict value is not equal to itself.")
370+ }
371+ else throw("Strict value is not equal to itself.")
372+ }
373+
374+
375+
376+@Callable(i)
377+func claimShareAsset (baseAssetIdStr,userAddressStr) = {
378+ let checks = [shutdownCheck(i)]
379+ if ((checks == checks))
380+ then {
381+ let userAddress = if ((userAddressStr == ""))
382+ then i.caller
383+ else {
384+ let checkCaller = mustThis(i)
385+ if ((checkCaller == checkCaller))
386+ then valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
387+ else throw("Strict value is not equal to itself.")
388+ }
389+ if ((userAddress == userAddress))
390+ then {
391+ let baseAssetId = parseAssetId(baseAssetIdStr)
392+ let shareAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyShareAssetId(baseAssetId)), wrapErr("invalid base asset id"))))
393+ if ((shareAssetId == shareAssetId))
394+ then {
395+ let period = valueOrErrorMessage(getInteger(keyPeriod(baseAssetId)), wrapErr("invalid period"))
396+ if ((period == period))
397+ then {
398+ let userBaseAssetAmountToConvert = valueOrElse(getInteger(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress)), 0)
399+ let checkAmountToConvert = if ((userBaseAssetAmountToConvert > 0))
400+ then true
401+ else throwErr("nothing to claim")
402+ if ((checkAmountToConvert == checkAmountToConvert))
403+ then {
404+ let userBaseAssetAmountToConvertPeriod = valueOrErrorMessage(getInteger(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress)), wrapErr("failed to get period"))
405+ let checkPeriod = if ((period > userBaseAssetAmountToConvertPeriod))
406+ then true
407+ else throwErr("invalid period")
408+ if ((checkPeriod == checkPeriod))
409+ then {
410+ let price = toBigInt(valueOrErrorMessage(getBinary(keyPricePeriodPut(baseAssetId, userBaseAssetAmountToConvertPeriod)), wrapErr("failed to get price")))
411+ let shareAssetAmount = toInt(fraction(toBigInt(userBaseAssetAmountToConvert), scale18BigInt, price))
412+ $Tuple2([IntegerEntry(keyUserBaseAssetAmountToConvert(baseAssetId, userAddress), 0), DeleteEntry(keyUserBaseAssetAmountToConvertPeriod(baseAssetId, userAddress)), ScriptTransfer(userAddress, shareAssetAmount, shareAssetId), StringEntry(keyHistoryEntry(baseAssetId, "claimShareAsset", period, userAddress, i.transactionId), makeString([toString(shareAssetAmount), toString(lastBlock.timestamp), toString(price), toString(userBaseAssetAmountToConvert)], separator))], unit)
413+ }
414+ else throw("Strict value is not equal to itself.")
415+ }
416+ else throw("Strict value is not equal to itself.")
417+ }
418+ else throw("Strict value is not equal to itself.")
419+ }
420+ else throw("Strict value is not equal to itself.")
421+ }
422+ else throw("Strict value is not equal to itself.")
423+ }
424+ else throw("Strict value is not equal to itself.")
425+ }
426+
427+
428+
429+@Callable(i)
430+func get () = {
431+ let checks = [shutdownCheck(i)]
432+ if ((checks == checks))
433+ then {
434+ let pmt = if ((size(i.payments) == 1))
435+ then i.payments[0]
436+ else throwErr("exactly 1 payment is expected")
437+ let shareAssetId = pmt.assetId
438+ let baseAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyBaseAssetId(shareAssetId)), wrapErr("invalid share asset id"))))
439+ if ((baseAssetId == baseAssetId))
440+ then {
441+ let userAddress = i.caller
442+ let $t01582016009 = valueOrErrorMessage(getPoolInfo(baseAssetId), wrapErr("invalid asset"))
443+ let poolAddress = $t01582016009._1
444+ let lpAssetId = $t01582016009._2
445+ let period = value(getInteger(keyPeriod(baseAssetId)))
446+ let userShareAssetAmountToConvertPeriodOption = getInteger(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress))
447+ let claimBaseAssetInvocation = if ((userShareAssetAmountToConvertPeriodOption == unit))
448+ then unit
449+ else {
450+ let userShareAssetAmountToConvertPeriod = value(userShareAssetAmountToConvertPeriodOption)
451+ if ((userShareAssetAmountToConvertPeriod == period))
452+ then unit
453+ else invoke(this, "claimBaseAsset", [assetIdToString(baseAssetId), toString(userAddress)], nil)
454+ }
455+ if ((claimBaseAssetInvocation == claimBaseAssetInvocation))
456+ then {
457+ let shareAssetAmountToConvert = valueOrElse(getInteger(keyShareAssetAmountToConvert(baseAssetId)), 0)
458+ let userShareAssetAmountToConvert = valueOrElse(getInteger(keyUserShareAssetAmountToConvert(baseAssetId, userAddress)), 0)
459+ $Tuple2([IntegerEntry(keyShareAssetAmountToConvert(baseAssetId), (shareAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserShareAssetAmountToConvert(baseAssetId, userAddress), (userShareAssetAmountToConvert + pmt.amount)), IntegerEntry(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress), period), StringEntry(keyHistoryEntry(baseAssetId, "get", period, userAddress, i.transactionId), makeString([toString(pmt.amount), toString(lastBlock.timestamp), toString(userShareAssetAmountToConvert)], separator))], unit)
460+ }
461+ else throw("Strict value is not equal to itself.")
462+ }
463+ else throw("Strict value is not equal to itself.")
464+ }
465+ else throw("Strict value is not equal to itself.")
466+ }
467+
468+
469+
470+@Callable(i)
471+func claimBaseAsset (baseAssetIdStr,userAddressStr) = {
472+ let checks = [shutdownCheck(i)]
473+ if ((checks == checks))
474+ then {
475+ let userAddress = if ((userAddressStr == ""))
476+ then i.caller
477+ else {
478+ let checkCaller = mustThis(i)
479+ if ((checkCaller == checkCaller))
480+ then valueOrErrorMessage(addressFromString(userAddressStr), wrapErr("invalid user address"))
481+ else throw("Strict value is not equal to itself.")
482+ }
483+ if ((userAddress == userAddress))
484+ then {
485+ let baseAssetId = parseAssetId(baseAssetIdStr)
486+ let shareAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyShareAssetId(baseAssetId)), wrapErr("invalid base asset id"))))
487+ if ((shareAssetId == shareAssetId))
488+ then {
489+ let period = valueOrErrorMessage(getInteger(keyPeriod(baseAssetId)), wrapErr("invalid period"))
490+ if ((period == period))
491+ then {
492+ let userShareAssetAmountToConvert = valueOrElse(getInteger(keyUserShareAssetAmountToConvert(baseAssetId, userAddress)), 0)
493+ let userShareAssetAmountToConvertPeriod = valueOrErrorMessage(getInteger(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress)), wrapErr("failed to get period"))
494+ let checkPeriod = if ((period > userShareAssetAmountToConvertPeriod))
495+ then true
496+ else throwErr("invalid period")
497+ if ((checkPeriod == checkPeriod))
498+ then {
499+ let price = toBigInt(valueOrErrorMessage(getBinary(keyPricePeriodGet(baseAssetId, userShareAssetAmountToConvertPeriod)), wrapErr("failed to get price")))
500+ let baseAssetAmount = toInt(fraction(toBigInt(userShareAssetAmountToConvert), price, scale18BigInt))
501+ $Tuple2([IntegerEntry(keyUserShareAssetAmountToConvert(baseAssetId, userAddress), 0), DeleteEntry(keyUserShareAssetAmountToConvertPeriod(baseAssetId, userAddress)), ScriptTransfer(userAddress, baseAssetAmount, baseAssetId), StringEntry(keyHistoryEntry(baseAssetId, "claimBaseAsset", period, userAddress, i.transactionId), makeString([toString(baseAssetAmount), toString(lastBlock.timestamp), toString(price), toString(userShareAssetAmountToConvertPeriod)], separator))], unit)
502+ }
503+ else throw("Strict value is not equal to itself.")
504+ }
505+ else throw("Strict value is not equal to itself.")
506+ }
507+ else throw("Strict value is not equal to itself.")
508+ }
509+ else throw("Strict value is not equal to itself.")
510+ }
511+ else throw("Strict value is not equal to itself.")
512+ }
513+
514+
515+
516+@Callable(i)
517+func finalize (baseAssetIdStr) = {
518+ let checks = [shutdownCheck(i)]
519+ if ((checks == checks))
520+ then {
521+ let baseAssetId = parseAssetId(baseAssetIdStr)
522+ let shareAssetId = value(parseAssetId(valueOrErrorMessage(getString(keyShareAssetId(baseAssetId)), wrapErr("invalid base asset id"))))
523+ if ((shareAssetId == shareAssetId))
524+ then {
525+ let shareAssetInfo = valueOrErrorMessage(assetInfo(shareAssetId), wrapErr("invalid share asset id"))
526+ let period = valueOrErrorMessage(getInteger(keyPeriod(baseAssetId)), wrapErr("invalid period"))
527+ if ((period == period))
528+ then {
529+ let periodStartHeightOption = getInteger(keyPeriodStartHeight(baseAssetId, period))
530+ let checkDelay = if ((periodStartHeightOption == unit))
531+ then unit
532+ else {
533+ let delay = (height - value(periodStartHeightOption))
534+ let blocksToWait = max([0, (minDelay - delay)])
535+ if ((blocksToWait == 0))
536+ then unit
537+ else throwErr(makeString(["finalization will be possible in ", toString(blocksToWait), " blocks"], ""))
538+ }
539+ if ((checkDelay == checkDelay))
540+ then {
541+ let $t02111321294 = valueOrErrorMessage(getPoolInfo(baseAssetId), wrapErr("invalid asset"))
542+ let poolAddress = $t02111321294._1
543+ let lpAssetId = $t02111321294._2
544+ let stakingReward = valueOrErrorMessage({
545+ let @ = invoke(stakingContract, "claimWxDoNotThrow", [assetIdToString(lpAssetId)], nil)
546+ if ($isInstanceOf(@, "Int"))
547+ then @
548+ else unit
549+ }, wrapErr("invalid claimWx result"))
550+ if ((stakingReward == stakingReward))
551+ then {
552+ let baseAssetAmountToConvert = valueOrElse(getInteger(keyBaseAssetAmountToConvert(baseAssetId)), 0)
553+ let shareAssetAmountToConvert = valueOrElse(getInteger(keyShareAssetAmountToConvert(baseAssetId)), 0)
554+ let checkFinalizationIsRequired = {
555+ let isFinalizationRequired = if (if ((stakingReward > 0))
556+ then true
557+ else (baseAssetAmountToConvert > 0))
558+ then true
559+ else (shareAssetAmountToConvert > 0)
560+ if (isFinalizationRequired)
561+ then true
562+ else throwErr("nothing to finalize")
563+ }
564+ if ((checkFinalizationIsRequired == checkFinalizationIsRequired))
565+ then {
566+ let useStakingReward = if ((stakingReward > 0))
567+ then {
568+ let lockPart = fraction(stakingReward, lockFraction, lockFractionMultiplier)
569+ let convertPart = (stakingReward - lockPart)
570+ let r = invoke(boostingContract, "userMaxDurationREADONLY", [toString(this)], nil)
571+ let lock = if ((lockPart > 0))
572+ then match r {
573+ case _ =>
574+ if (if (if ($isInstanceOf($match0._1, "String"))
575+ then $isInstanceOf($match0._2, "Int")
576+ else false)
577+ then $isInstanceOf($match0, "(String, Int)")
578+ else false)
579+ then {
580+ let function = $match0._1
581+ let duration = $match0._2
582+ if ((lockPart > 0))
583+ then invoke(boostingContract, function, [duration], [AttachedPayment(wxAssetId, lockPart)])
584+ else unit
585+ }
586+ else throwErr("invalid lock params")
587+ }
588+ else unit
589+ if ((lock == lock))
590+ then {
591+ let convertedAmount = if ((convertPart > 0))
592+ then {
593+ let inAssetId = wxAssetId
594+ let minimumToReceive = 0
595+ let outAssetIdStr = assetIdToString(usdtAssetId)
596+ let targetAddress = toString(this)
597+ valueOrErrorMessage({
598+ let @ = invoke(swapContract, "swap", [minimumToReceive, outAssetIdStr, targetAddress], [AttachedPayment(inAssetId, convertPart)])
599+ if ($isInstanceOf(@, "Int"))
600+ then @
601+ else unit
602+ }, wrapErr("invalid swap result"))
603+ }
604+ else 0
605+ if ((convertedAmount == convertedAmount))
606+ then {
607+ let lpAssetAmount = if ((convertedAmount > 0))
608+ then {
609+ let minOutAmount = 0
610+ let autoStake = true
611+ valueOrErrorMessage({
612+ let @ = invoke(poolAddress, "putOneTknV2", [minOutAmount, autoStake], [AttachedPayment(usdtAssetId, convertedAmount)])
613+ if ($isInstanceOf(@, "Int"))
614+ then @
615+ else unit
616+ }, wrapErr("invalid putOneTknV2 result"))
617+ }
618+ else 0
619+ if ((lpAssetAmount == lpAssetAmount))
620+ then lpAssetAmount
621+ else throw("Strict value is not equal to itself.")
622+ }
623+ else throw("Strict value is not equal to itself.")
624+ }
625+ else throw("Strict value is not equal to itself.")
626+ }
627+ else unit
628+ if ((useStakingReward == useStakingReward))
629+ then {
630+ let getActions = if ((shareAssetAmountToConvert > 0))
631+ then {
632+ let price = calcPrice(lpAssetId, shareAssetId)
633+ if ((price == price))
634+ then {
635+ let unstakeAmount = toInt(fraction(toBigInt(shareAssetAmountToConvert), price, scale18BigInt, FLOOR))
636+ let baseAssetAmount = {
637+ let outAssetId = baseAssetId
638+ let minOutAmount = 0
639+ valueOrErrorMessage({
640+ let @ = invoke(poolAddress, "unstakeAndGetOneTknV2", [unstakeAmount, assetIdToString(outAssetId), minOutAmount], nil)
641+ if ($isInstanceOf(@, "Int"))
642+ then @
643+ else unit
644+ }, wrapErr("invalid unstakeAndGetOneTknV2 result"))
645+ }
646+ if ((baseAssetAmount == baseAssetAmount))
647+ then {
648+ let shareAssetBurn = if ((shareAssetInfo.issuer == this))
649+ then invoke(this, "burn", [shareAssetId, shareAssetAmountToConvert], nil)
650+ else throwErr("invalid share asset issuer")
651+ if ((shareAssetBurn == shareAssetBurn))
652+ then {
653+ let priceGet = fraction(toBigInt(baseAssetAmount), scale18BigInt, toBigInt(shareAssetAmountToConvert), FLOOR)
654+ let priceGetUpdateActions = [BinaryEntry(keyPricePeriodGet(baseAssetId, period), toBytes(priceGet)), StringEntry(keyPriceGetHistory(baseAssetId), toString(priceGet))]
655+ priceGetUpdateActions
656+ }
657+ else throw("Strict value is not equal to itself.")
658+ }
659+ else throw("Strict value is not equal to itself.")
660+ }
661+ else throw("Strict value is not equal to itself.")
662+ }
663+ else nil
664+ if ((getActions == getActions))
665+ then {
666+ let putActions = if ((baseAssetAmountToConvert > 0))
667+ then {
668+ let lpAssetAmount = {
669+ let minOutAmount = 0
670+ let autoStake = true
671+ valueOrErrorMessage({
672+ let @ = invoke(poolAddress, "putOneTknV2", [minOutAmount, autoStake], [AttachedPayment(baseAssetId, baseAssetAmountToConvert)])
673+ if ($isInstanceOf(@, "Int"))
674+ then @
675+ else unit
676+ }, wrapErr("invalid putOneTknV2 result"))
677+ }
678+ if ((lpAssetAmount == lpAssetAmount))
679+ then {
680+ let price = calcPrice(lpAssetId, shareAssetId)
681+ if ((price == price))
682+ then {
683+ let checkPrice = if ((value(toInt(price)) != 0))
684+ then true
685+ else throw("price is ZERO")
686+ if ((checkPrice == checkPrice))
687+ then {
688+ let shareAssetAmount = toInt(fraction(toBigInt(lpAssetAmount), scale18BigInt, price, FLOOR))
689+ let checkShareAssetAmount = if ((value(toInt(price)) != 0))
690+ then true
691+ else throw("shareAssetAmount is ZERO")
692+ if ((checkShareAssetAmount == checkShareAssetAmount))
693+ then {
694+ let shareAssetReissue = if ((shareAssetInfo.issuer == this))
695+ then invoke(this, "emit", [shareAssetId, shareAssetAmount], nil)
696+ else throwErr("invalid share asset issuer")
697+ if ((shareAssetReissue == shareAssetReissue))
698+ then {
699+ let pricePut = fraction(toBigInt(baseAssetAmountToConvert), scale18BigInt, toBigInt(shareAssetAmount))
700+ let pricePutUpdateActions = [BinaryEntry(keyPricePeriodPut(baseAssetId, period), toBytes(pricePut)), StringEntry(keyPricePutHistory(baseAssetId), toString(pricePut))]
701+ pricePutUpdateActions
702+ }
703+ else throw("Strict value is not equal to itself.")
704+ }
705+ else throw("Strict value is not equal to itself.")
706+ }
707+ else throw("Strict value is not equal to itself.")
708+ }
709+ else throw("Strict value is not equal to itself.")
710+ }
711+ else throw("Strict value is not equal to itself.")
712+ }
713+ else nil
714+ if ((putActions == putActions))
715+ then {
716+ let newPeriod = (period + 1)
717+ let lastPrice = calcPrice(lpAssetId, shareAssetId)
718+ let actions = (([IntegerEntry(keyPeriod(baseAssetId), newPeriod), IntegerEntry(keyPeriodStartHeight(baseAssetId, newPeriod), height), IntegerEntry(keyShareAssetAmountToConvert(baseAssetId), 0), IntegerEntry(keyBaseAssetAmountToConvert(baseAssetId), 0), BinaryEntry(keyPricePeriod(baseAssetId, period), toBytes(lastPrice)), StringEntry(keyPriceHistory(baseAssetId), toString(lastPrice))] ++ putActions) ++ getActions)
719+ $Tuple2(actions, toBytes(lastPrice))
720+ }
721+ else throw("Strict value is not equal to itself.")
722+ }
723+ else throw("Strict value is not equal to itself.")
724+ }
725+ else throw("Strict value is not equal to itself.")
726+ }
727+ else throw("Strict value is not equal to itself.")
728+ }
729+ else throw("Strict value is not equal to itself.")
730+ }
731+ else throw("Strict value is not equal to itself.")
732+ }
733+ else throw("Strict value is not equal to itself.")
734+ }
246735 else throw("Strict value is not equal to itself.")
247736 }
248737 else throw("Strict value is not equal to itself.")
249738 }
250739
251740
252741 @Verifier(tx)
253742 func verify () = {
254743 let targetPublicKey = match managerPublicKeyOrUnit() {
255744 case pk: ByteVector =>
256745 pk
257746 case _: Unit =>
258747 tx.senderPublicKey
259748 case _ =>
260749 throw("Match error")
261750 }
262751 sigVerify(tx.bodyBytes, tx.proofs[0], targetPublicKey)
263752 }
264753

github/deemru/w8io/026f985 
61.57 ms